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 EXT_buffer_age
22 *//*--------------------------------------------------------------------*/
23
24 #include "teglBufferAgeTests.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 BufferAgeTest : public TestCase
74 {
75 public:
76 enum DrawType
77 {
78 DRAWTYPE_GLES2_CLEAR,
79 DRAWTYPE_GLES2_RENDER
80 };
81
82 enum ResizeType
83 {
84 RESIZETYPE_NONE = 0,
85 RESIZETYPE_BEFORE_SWAP,
86 RESIZETYPE_AFTER_SWAP,
87
88 RESIZETYPE_LAST
89 };
90
91 BufferAgeTest (EglTestContext& eglTestCtx,
92 bool preserveColorBuffer,
93 const vector<DrawType>& oddFrameDrawType,
94 const vector<DrawType>& evenFrameDrawType,
95 ResizeType resizeType,
96 const char* name,
97 const char* description);
98
99 ~BufferAgeTest (void);
100
101 void init (void);
102 void deinit (void);
103 IterateResult iterate (void);
104
105 private:
106 void initEGLSurface (EGLConfig config);
107 void initEGLContext (EGLConfig config);
108
109 const int m_seed;
110 const bool m_preserveColorBuffer;
111 const vector<DrawType> m_oddFrameDrawType;
112 const vector<DrawType> m_evenFrameDrawType;
113 const ResizeType m_resizeType;
114
115 EGLDisplay m_eglDisplay;
116 eglu::NativeWindow* m_window;
117 EGLSurface m_eglSurface;
118 EGLConfig m_eglConfig;
119 EGLContext m_eglContext;
120 glw::Functions m_gl;
121
122 GLES2Renderer* m_gles2Renderer;
123 ReferenceRenderer* m_refRenderer;
124
125 };
126
127 struct ColoredRect
128 {
129 public:
130 ColoredRect (const IVec2& bottomLeft_, const IVec2& topRight_, const Color& color_);
131 IVec2 bottomLeft;
132 IVec2 topRight;
133 Color color;
134 };
135
ColoredRect(const IVec2 & bottomLeft_,const IVec2 & topRight_,const Color & color_)136 ColoredRect::ColoredRect (const IVec2& bottomLeft_, const IVec2& topRight_, const Color& color_)
137 : bottomLeft(bottomLeft_)
138 , topRight (topRight_)
139 , color (color_)
140 {
141 }
142
143 struct DrawCommand
144 {
145 DrawCommand (const BufferAgeTest::DrawType drawType_, const ColoredRect& rect_);
146 BufferAgeTest::DrawType drawType;
147 ColoredRect rect;
148 };
149
DrawCommand(const BufferAgeTest::DrawType drawType_,const ColoredRect & rect_)150 DrawCommand::DrawCommand (const BufferAgeTest::DrawType drawType_, const ColoredRect& rect_)
151 : drawType(drawType_)
152 , rect (rect_)
153 {
154 }
155
156 struct Frame
157 {
158 Frame (int width_, int height_);
159 int width;
160 int height;
161 vector<DrawCommand> draws;
162 };
163
Frame(int width_,int height_)164 Frame::Frame (int width_, int height_)
165 : width(width_)
166 , height(height_)
167 {
168 }
169
170
171 // (x1,y1) lie in the lower-left quadrant while (x2,y2) lie in the upper-right.
172 // the coords are multiplied by 4 to amplify the minimial difference between coords to 4 (if not zero)
173 // to avoid the situation where two edges are too close to each other which makes the rounding error
174 // intoleratable by compareToReference()
generateRandomFrame(Frame * dst,const vector<BufferAgeTest::DrawType> & drawTypes,de::Random & rnd)175 void generateRandomFrame (Frame* dst, const vector<BufferAgeTest::DrawType>& drawTypes, de::Random& rnd)
176 {
177 for (size_t ndx = 0; ndx < drawTypes.size(); ndx++)
178 {
179 const int x1 = rnd.getInt(0, (dst->width-1)/8) * 4;
180 const int y1 = rnd.getInt(0, (dst->height-1)/8) * 4;
181 const int x2 = rnd.getInt((dst->width-1)/8, (dst->width-1)/4) * 4;
182 const int y2 = rnd.getInt((dst->height-1)/8, (dst->height-1)/4) * 4;
183 const GLubyte r = rnd.getUint8();
184 const GLubyte g = rnd.getUint8();
185 const GLubyte b = rnd.getUint8();
186 const ColoredRect coloredRect (IVec2(x1, y1), IVec2(x2, y2), Color(r, g, b));
187 const DrawCommand drawCommand (drawTypes[ndx], coloredRect);
188 (*dst).draws.push_back(drawCommand);
189 }
190 }
191
192 typedef vector<Frame> FrameSequence;
193
194 //helper function declaration
195 EGLConfig getEGLConfig (const Library& egl, EGLDisplay eglDisplay, bool preserveColorBuffer);
196 void clearColorScreen (const glw::Functions& gl, const tcu::Vec4& clearColor);
197 void clearColorReference (tcu::Surface* ref, const tcu::Vec4& clearColor);
198 void readPixels (const glw::Functions& gl, tcu::Surface* screen);
199 float windowToDeviceCoordinates (int x, int length);
200 bool compareToReference (tcu::TestLog& log, const tcu::Surface& reference, const tcu::Surface& buffer, int frameNdx, int bufferNum);
201 vector<int> getFramesOnBuffer (const vector<int>& bufferAges, int frameNdx);
202
203 class GLES2Renderer
204 {
205 public:
206 GLES2Renderer (const glw::Functions& gl);
207 ~GLES2Renderer (void);
208 void render (int width, int height, const Frame& frame) const;
209
210 private:
211 GLES2Renderer (const GLES2Renderer&);
212 GLES2Renderer& operator= (const GLES2Renderer&);
213
214 const glw::Functions& m_gl;
215 glu::ShaderProgram m_glProgram;
216 glw::GLuint m_coordLoc;
217 glw::GLuint m_colorLoc;
218 };
219
220 // generate sources for vertex and fragment buffer
getSources(void)221 glu::ProgramSources getSources (void)
222 {
223 const char* const vertexShaderSource =
224 "attribute mediump vec4 a_pos;\n"
225 "attribute mediump vec4 a_color;\n"
226 "varying mediump vec4 v_color;\n"
227 "void main(void)\n"
228 "{\n"
229 "\tv_color = a_color;\n"
230 "\tgl_Position = a_pos;\n"
231 "}";
232
233 const char* const fragmentShaderSource =
234 "varying mediump vec4 v_color;\n"
235 "void main(void)\n"
236 "{\n"
237 "\tgl_FragColor = v_color;\n"
238 "}";
239
240 return glu::makeVtxFragSources(vertexShaderSource, fragmentShaderSource);
241 }
242
GLES2Renderer(const glw::Functions & gl)243 GLES2Renderer::GLES2Renderer (const glw::Functions& gl)
244 : m_gl (gl)
245 , m_glProgram (gl, getSources())
246 , m_coordLoc ((glw::GLuint)-1)
247 , m_colorLoc ((glw::GLuint)-1)
248 {
249 m_colorLoc = m_gl.getAttribLocation(m_glProgram.getProgram(), "a_color");
250 m_coordLoc = m_gl.getAttribLocation(m_glProgram.getProgram(), "a_pos");
251 GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to get attribute locations");
252 }
253
~GLES2Renderer(void)254 GLES2Renderer::~GLES2Renderer (void)
255 {
256 }
257
render(int width,int height,const Frame & frame) const258 void GLES2Renderer::render (int width, int height, const Frame& frame) const
259 {
260 for (size_t drawNdx = 0; drawNdx < frame.draws.size(); drawNdx++)
261 {
262 const ColoredRect& coloredRect = frame.draws[drawNdx].rect;
263 if (frame.draws[drawNdx].drawType == BufferAgeTest::DRAWTYPE_GLES2_RENDER)
264 {
265 float x1 = windowToDeviceCoordinates(coloredRect.bottomLeft.x(), width);
266 float y1 = windowToDeviceCoordinates(coloredRect.bottomLeft.y(), height);
267 float x2 = windowToDeviceCoordinates(coloredRect.topRight.x(), width);
268 float y2 = windowToDeviceCoordinates(coloredRect.topRight.y(), height);
269
270 const glw::GLfloat coords[] =
271 {
272 x1, y1, 0.0f, 1.0f,
273 x1, y2, 0.0f, 1.0f,
274 x2, y2, 0.0f, 1.0f,
275
276 x2, y2, 0.0f, 1.0f,
277 x2, y1, 0.0f, 1.0f,
278 x1, y1, 0.0f, 1.0f
279 };
280
281 const glw::GLubyte colors[] =
282 {
283 coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255,
284 coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255,
285 coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255,
286
287 coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255,
288 coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255,
289 coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255,
290 };
291
292 m_gl.useProgram(m_glProgram.getProgram());
293 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() failed");
294
295 m_gl.enableVertexAttribArray(m_coordLoc);
296 m_gl.enableVertexAttribArray(m_colorLoc);
297 GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to enable attributes");
298
299 m_gl.vertexAttribPointer(m_coordLoc, 4, GL_FLOAT, GL_FALSE, 0, coords);
300 m_gl.vertexAttribPointer(m_colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, colors);
301 GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to set attribute pointers");
302
303 m_gl.drawArrays(GL_TRIANGLES, 0, DE_LENGTH_OF_ARRAY(coords)/4);
304 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays(), failed");
305
306 m_gl.disableVertexAttribArray(m_coordLoc);
307 m_gl.disableVertexAttribArray(m_colorLoc);
308 GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to disable attributes");
309
310 m_gl.useProgram(0);
311 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() failed");
312 }
313 else if (frame.draws[drawNdx].drawType == BufferAgeTest::DRAWTYPE_GLES2_CLEAR)
314 {
315 m_gl.enable(GL_SCISSOR_TEST);
316 m_gl.scissor(coloredRect.bottomLeft.x(), coloredRect.bottomLeft.y(),
317 coloredRect.topRight.x()-coloredRect.bottomLeft.x(), coloredRect.topRight.y()-coloredRect.bottomLeft.y());
318 m_gl.clearColor(coloredRect.color.x()/255.0f, coloredRect.color.y()/255.0f, coloredRect.color.z()/255.0f, 1.0f);
319 m_gl.clear(GL_COLOR_BUFFER_BIT);
320 m_gl.disable(GL_SCISSOR_TEST);
321 }
322 else
323 DE_ASSERT(false);
324 }
325 }
326
327 class ReferenceRenderer
328 {
329 public:
330 ReferenceRenderer (void);
331 void render (tcu::Surface* target, const Frame& frame) const;
332 private:
333 ReferenceRenderer (const ReferenceRenderer&);
334 ReferenceRenderer& operator= (const ReferenceRenderer&);
335 };
336
ReferenceRenderer(void)337 ReferenceRenderer::ReferenceRenderer(void)
338 {
339 }
340
render(tcu::Surface * target,const Frame & frame) const341 void ReferenceRenderer::render (tcu::Surface* target, const Frame& frame) const
342 {
343 for (size_t drawNdx = 0; drawNdx < frame.draws.size(); drawNdx++)
344 {
345 const ColoredRect& coloredRect = frame.draws[drawNdx].rect;
346 if (frame.draws[drawNdx].drawType == BufferAgeTest::DRAWTYPE_GLES2_RENDER || frame.draws[drawNdx].drawType == BufferAgeTest::DRAWTYPE_GLES2_CLEAR)
347 {
348 // tcu does not support degenerate subregions. Since they correspond to no-op rendering, just skip them.
349 if (coloredRect.bottomLeft.x() == coloredRect.topRight.x() || coloredRect.bottomLeft.y() == coloredRect.topRight.y())
350 continue;
351
352 const tcu::UVec4 color(coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255);
353 tcu::clear(tcu::getSubregion(target->getAccess(), coloredRect.bottomLeft.x(), coloredRect.bottomLeft.y(),
354 coloredRect.topRight.x()-coloredRect.bottomLeft.x(), coloredRect.topRight.y()-coloredRect.bottomLeft.y()), color);
355 }
356 else
357 DE_ASSERT(false);
358 }
359 }
360
BufferAgeTest(EglTestContext & eglTestCtx,bool preserveColorBuffer,const vector<DrawType> & oddFrameDrawType,const vector<DrawType> & evenFrameDrawType,ResizeType resizeType,const char * name,const char * description)361 BufferAgeTest::BufferAgeTest (EglTestContext& eglTestCtx,
362 bool preserveColorBuffer,
363 const vector<DrawType>& oddFrameDrawType,
364 const vector<DrawType>& evenFrameDrawType,
365 ResizeType resizeType,
366 const char* name,
367 const char* description)
368 : TestCase (eglTestCtx, name, description)
369 , m_seed (deStringHash(name))
370 , m_preserveColorBuffer (preserveColorBuffer)
371 , m_oddFrameDrawType (oddFrameDrawType)
372 , m_evenFrameDrawType (evenFrameDrawType)
373 , m_resizeType (resizeType)
374 , m_eglDisplay (EGL_NO_DISPLAY)
375 , m_window (DE_NULL)
376 , m_eglSurface (EGL_NO_SURFACE)
377 , m_eglContext (EGL_NO_CONTEXT)
378 , m_gles2Renderer (DE_NULL)
379 , m_refRenderer (DE_NULL)
380 {
381 }
382
~BufferAgeTest(void)383 BufferAgeTest::~BufferAgeTest (void)
384 {
385 deinit();
386 }
387
init(void)388 void BufferAgeTest::init (void)
389 {
390 const Library& egl = m_eglTestCtx.getLibrary();
391
392 m_eglDisplay = eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay());
393
394 if (eglu::hasExtension(egl, m_eglDisplay, "EGL_EXT_buffer_age") == false)
395 {
396 egl.terminate(m_eglDisplay);
397 m_eglDisplay = EGL_NO_DISPLAY;
398 TCU_THROW(NotSupportedError, "EGL_EXT_buffer_age is not supported");
399 }
400
401 m_eglConfig = getEGLConfig(m_eglTestCtx.getLibrary(), m_eglDisplay, m_preserveColorBuffer);
402
403 if (m_eglConfig == DE_NULL)
404 TCU_THROW(NotSupportedError, "No supported config found");
405
406 //create surface and context and make them current
407 initEGLSurface(m_eglConfig);
408 initEGLContext(m_eglConfig);
409
410 m_eglTestCtx.initGLFunctions(&m_gl, glu::ApiType::es(2,0));
411
412 m_gles2Renderer = new GLES2Renderer(m_gl);
413 m_refRenderer = new ReferenceRenderer();
414 }
415
deinit(void)416 void BufferAgeTest::deinit (void)
417 {
418 const Library& egl = m_eglTestCtx.getLibrary();
419
420 delete m_refRenderer;
421 m_refRenderer = DE_NULL;
422
423 delete m_gles2Renderer;
424 m_gles2Renderer = DE_NULL;
425
426 if (m_eglContext != EGL_NO_CONTEXT)
427 {
428 egl.makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
429 egl.destroyContext(m_eglDisplay, m_eglContext);
430 m_eglContext = EGL_NO_CONTEXT;
431 }
432
433 if (m_eglSurface != EGL_NO_SURFACE)
434 {
435 egl.destroySurface(m_eglDisplay, m_eglSurface);
436 m_eglSurface = EGL_NO_SURFACE;
437 }
438
439 if (m_eglDisplay != EGL_NO_DISPLAY)
440 {
441 egl.terminate(m_eglDisplay);
442 m_eglDisplay = EGL_NO_DISPLAY;
443 }
444
445 delete m_window;
446 m_window = DE_NULL;
447 }
448
initEGLSurface(EGLConfig config)449 void BufferAgeTest::initEGLSurface (EGLConfig config)
450 {
451 const eglu::NativeWindowFactory& factory = eglu::selectNativeWindowFactory(m_eglTestCtx.getNativeDisplayFactory(), m_testCtx.getCommandLine());
452 m_window = factory.createWindow(&m_eglTestCtx.getNativeDisplay(), m_eglDisplay, config, DE_NULL,
453 eglu::WindowParams(480, 480, eglu::parseWindowVisibility(m_testCtx.getCommandLine())));
454 m_eglSurface = eglu::createWindowSurface(m_eglTestCtx.getNativeDisplay(), *m_window, m_eglDisplay, config, DE_NULL);
455 }
456
initEGLContext(EGLConfig config)457 void BufferAgeTest::initEGLContext (EGLConfig config)
458 {
459 const Library& egl = m_eglTestCtx.getLibrary();
460 const EGLint attribList[] =
461 {
462 EGL_CONTEXT_CLIENT_VERSION, 2,
463 EGL_NONE
464 };
465
466 egl.bindAPI(EGL_OPENGL_ES_API);
467 m_eglContext = egl.createContext(m_eglDisplay, config, EGL_NO_CONTEXT, attribList);
468 EGLU_CHECK_MSG(egl, "eglCreateContext");
469 DE_ASSERT(m_eglSurface != EGL_NO_SURFACE);
470 egl.makeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);
471 EGLU_CHECK_MSG(egl, "eglMakeCurrent");
472 }
473
474 // return indices of frames that have been written to the given buffer
getFramesOnBuffer(const vector<int> & bufferAges,int frameNdx)475 vector<int> getFramesOnBuffer (const vector<int>& bufferAges, int frameNdx)
476 {
477 DE_ASSERT(frameNdx < (int)bufferAges.size());
478 vector<int> frameOnBuffer;
479 int age = bufferAges[frameNdx];
480 while (age != 0)
481 {
482 frameNdx = frameNdx - age;
483 DE_ASSERT(frameNdx >= 0);
484 frameOnBuffer.push_back(frameNdx);
485 age = bufferAges[frameNdx];
486 }
487
488 reverse(frameOnBuffer.begin(), frameOnBuffer.end());
489 return frameOnBuffer;
490 }
491
iterate(void)492 TestCase::IterateResult BufferAgeTest::iterate (void)
493 {
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
507 if (m_preserveColorBuffer)
508 EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED));
509 else
510 EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED));
511
512 for (int frameNdx = 0; frameNdx < numFrames; frameNdx++)
513 {
514 tcu::Surface currentBuffer (width, height);
515 tcu::Surface refBuffer (width, height);
516 Frame newFrame (width, height);
517 EGLint currentBufferAge = -1;
518
519 if (frameNdx % 2 == 0)
520 generateRandomFrame(&newFrame, m_evenFrameDrawType, rnd);
521 else
522 generateRandomFrame(&newFrame, m_oddFrameDrawType, rnd);
523
524 frameSequence.push_back(newFrame);
525
526 EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_EXT, ¤tBufferAge));
527
528 if (currentBufferAge > frameNdx || currentBufferAge < 0) // invalid buffer age
529 {
530 std::ostringstream stream;
531 stream << "Fail, the age is invalid. Age: " << currentBufferAge << ", frameNdx: " << frameNdx;
532 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, stream.str().c_str());
533 return STOP;
534 }
535
536 if (frameNdx > 0 && m_preserveColorBuffer && currentBufferAge != 1)
537 {
538 std::ostringstream stream;
539 stream << "Fail, EGL_BUFFER_PRESERVED is set to true, but buffer age is: " << currentBufferAge << " (should be 1)";
540 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, stream.str().c_str());
541 return STOP;
542 }
543
544 bufferAges.push_back(currentBufferAge);
545 DE_ASSERT((int)bufferAges.size() == frameNdx+1);
546
547 // during first half, just keep rendering without reading pixel back to mimic ordinary use case
548 if (frameNdx < numFrames/2)
549 {
550 if (currentBufferAge == 0)
551 clearColorScreen(m_gl, clearColor);
552
553 m_gles2Renderer->render(width, height, newFrame);
554
555 if (m_resizeType == RESIZETYPE_BEFORE_SWAP)
556 {
557 if (frameNdx % 2 == 0)
558 m_window->setSurfaceSize(IVec2(width*2, height/2));
559 else
560 m_window->setSurfaceSize(IVec2(height/2, width*2));
561 }
562
563 EGLU_CHECK_CALL(egl, swapBuffers(m_eglDisplay, m_eglSurface));
564
565 if (m_resizeType == RESIZETYPE_AFTER_SWAP)
566 {
567 if (frameNdx % 2 == 0)
568 m_window->setSurfaceSize(IVec2(width*2, height/2));
569 else
570 m_window->setSurfaceSize(IVec2(height/2, width*2));
571 }
572
573 continue;
574 }
575
576 // do verification in the second half
577 if (currentBufferAge > 0) //buffer contain previous content, need to verify
578 {
579 const vector<int> framesOnBuffer = getFramesOnBuffer(bufferAges, frameNdx);
580 readPixels(m_gl, ¤tBuffer);
581 clearColorReference(&refBuffer, clearColor);
582
583 for (vector<int>::const_iterator it = framesOnBuffer.begin(); it != framesOnBuffer.end(); it++)
584 m_refRenderer->render(&refBuffer, frameSequence[*it]);
585
586 if (compareToReference(log, refBuffer, currentBuffer, frameNdx, frameNdx-currentBufferAge) == false)
587 {
588 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail, buffer content is not well preserved when age > 0");
589 return STOP;
590 }
591 }
592 else // currentBufferAge == 0, content is undefined, clear the buffer, currentBufferAge < 0 is ruled out at the beginning
593 {
594 clearColorScreen(m_gl, clearColor);
595 clearColorReference(&refBuffer, clearColor);
596 }
597
598 m_gles2Renderer->render(width, height, newFrame);
599 m_refRenderer->render(&refBuffer, newFrame);
600
601 readPixels(m_gl, ¤tBuffer);
602
603 if (compareToReference(log, refBuffer, currentBuffer, frameNdx, frameNdx) == false)
604 {
605 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail, render result is wrong");
606 return STOP;
607 }
608
609 if (m_resizeType == RESIZETYPE_BEFORE_SWAP)
610 {
611 if (frameNdx % 2 == 0)
612 m_window->setSurfaceSize(IVec2(width*2, height/2));
613 else
614 m_window->setSurfaceSize(IVec2(height/2, width*2));
615 }
616
617 EGLU_CHECK_CALL(egl, swapBuffers(m_eglDisplay, m_eglSurface));
618
619 if (m_resizeType == RESIZETYPE_AFTER_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
628 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
629 return STOP;
630 }
631
generateDrawTypeName(const vector<BufferAgeTest::DrawType> & drawTypes)632 string generateDrawTypeName (const vector<BufferAgeTest::DrawType>& drawTypes)
633 {
634 std::ostringstream stream;
635 if (drawTypes.size() == 0)
636 return string("_none");
637
638 for (size_t ndx = 0; ndx < drawTypes.size(); ndx++)
639 {
640 if (drawTypes[ndx] == BufferAgeTest::DRAWTYPE_GLES2_RENDER)
641 stream << "_render";
642 else if (drawTypes[ndx] == BufferAgeTest::DRAWTYPE_GLES2_CLEAR)
643 stream << "_clear";
644 else
645 DE_ASSERT(false);
646 }
647 return stream.str();
648 }
649
generateTestName(const vector<BufferAgeTest::DrawType> & oddFrameDrawType,const vector<BufferAgeTest::DrawType> & evenFrameDrawType)650 string generateTestName (const vector<BufferAgeTest::DrawType>& oddFrameDrawType, const vector<BufferAgeTest::DrawType>& evenFrameDrawType)
651 {
652 return "odd" + generateDrawTypeName(oddFrameDrawType) + "_even" + generateDrawTypeName(evenFrameDrawType);
653 }
654
generateResizeGroupName(BufferAgeTest::ResizeType resizeType)655 string generateResizeGroupName (BufferAgeTest::ResizeType resizeType)
656 {
657 switch (resizeType)
658 {
659 case BufferAgeTest::RESIZETYPE_NONE:
660 return "no_resize";
661
662 case BufferAgeTest::RESIZETYPE_AFTER_SWAP:
663 return "resize_after_swap";
664
665 case BufferAgeTest::RESIZETYPE_BEFORE_SWAP:
666 return "resize_before_swap";
667
668 default:
669 DE_FATAL("Unknown resize type");
670 return "";
671 }
672 }
673
isWindow(const eglu::CandidateConfig & c)674 bool isWindow (const eglu::CandidateConfig& c)
675 {
676 return (c.surfaceType() & EGL_WINDOW_BIT) == EGL_WINDOW_BIT;
677 }
678
isES2Renderable(const eglu::CandidateConfig & c)679 bool isES2Renderable (const eglu::CandidateConfig& c)
680 {
681 return (c.get(EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT) == EGL_OPENGL_ES2_BIT;
682 }
683
hasPreserveSwap(const eglu::CandidateConfig & c)684 bool hasPreserveSwap (const eglu::CandidateConfig& c)
685 {
686 return (c.surfaceType() & EGL_SWAP_BEHAVIOR_PRESERVED_BIT) == EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
687 }
688
getEGLConfig(const Library & egl,EGLDisplay eglDisplay,bool preserveColorBuffer)689 EGLConfig getEGLConfig (const Library& egl, EGLDisplay eglDisplay, bool preserveColorBuffer)
690 {
691 eglu::FilterList filters;
692 filters << isWindow << isES2Renderable;
693 if (preserveColorBuffer)
694 filters << hasPreserveSwap;
695 return eglu::chooseSingleConfig(egl, eglDisplay, filters);
696 }
697
clearColorScreen(const glw::Functions & gl,const tcu::Vec4 & clearColor)698 void clearColorScreen (const glw::Functions& gl, const tcu::Vec4& clearColor)
699 {
700 gl.clearColor(clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w());
701 gl.clear(GL_COLOR_BUFFER_BIT);
702 }
703
clearColorReference(tcu::Surface * ref,const tcu::Vec4 & clearColor)704 void clearColorReference (tcu::Surface* ref, const tcu::Vec4& clearColor)
705 {
706 tcu::clear(ref->getAccess(), clearColor);
707 }
708
readPixels(const glw::Functions & gl,tcu::Surface * screen)709 void readPixels (const glw::Functions& gl, tcu::Surface* screen)
710 {
711 gl.readPixels(0, 0, screen->getWidth(), screen->getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, screen->getAccess().getDataPtr());
712 }
713
windowToDeviceCoordinates(int x,int length)714 float windowToDeviceCoordinates (int x, int length)
715 {
716 return (2.0f * float(x) / float(length)) - 1.0f;
717 }
718
compareToReference(tcu::TestLog & log,const tcu::Surface & reference,const tcu::Surface & buffer,int frameNdx,int bufferNum)719 bool compareToReference (tcu::TestLog& log, const tcu::Surface& reference, const tcu::Surface& buffer, int frameNdx, int bufferNum)
720 {
721 std::ostringstream stream;
722 stream << "FrameNdx = " << frameNdx << ", compare current buffer (numbered: " << bufferNum << ") to reference";
723 return tcu::intThresholdPositionDeviationCompare(log, "buffer age test", stream.str().c_str(), reference.getAccess(), buffer.getAccess(),
724 tcu::UVec4(8, 8, 8, 0), tcu::IVec3(2,2,0), true, tcu::COMPARE_LOG_RESULT);
725 }
726
727 } // anonymous
728
BufferAgeTests(EglTestContext & eglTestCtx)729 BufferAgeTests::BufferAgeTests (EglTestContext& eglTestCtx)
730 : TestCaseGroup(eglTestCtx, "buffer_age", "Color buffer age tests")
731 {
732 }
733
init(void)734 void BufferAgeTests::init (void)
735 {
736 const BufferAgeTest::DrawType clearRender[] =
737 {
738 BufferAgeTest::DRAWTYPE_GLES2_CLEAR,
739 BufferAgeTest::DRAWTYPE_GLES2_RENDER
740 };
741
742 const BufferAgeTest::DrawType renderClear[] =
743 {
744 BufferAgeTest::DRAWTYPE_GLES2_RENDER,
745 BufferAgeTest::DRAWTYPE_GLES2_CLEAR
746 };
747
748 const BufferAgeTest::ResizeType resizeTypes[] =
749 {
750 BufferAgeTest::RESIZETYPE_NONE,
751 BufferAgeTest::RESIZETYPE_BEFORE_SWAP,
752 BufferAgeTest::RESIZETYPE_AFTER_SWAP
753 };
754
755 vector< vector<BufferAgeTest::DrawType> > frameDrawTypes;
756 frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> ());
757 frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (1, BufferAgeTest::DRAWTYPE_GLES2_CLEAR));
758 frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (1, BufferAgeTest::DRAWTYPE_GLES2_RENDER));
759 frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (2, BufferAgeTest::DRAWTYPE_GLES2_CLEAR));
760 frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (2, BufferAgeTest::DRAWTYPE_GLES2_RENDER));
761 frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (DE_ARRAY_BEGIN(clearRender), DE_ARRAY_END(clearRender)));
762 frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (DE_ARRAY_BEGIN(renderClear), DE_ARRAY_END(renderClear)));
763
764 for (int preserveNdx = 0; preserveNdx < 2; preserveNdx++)
765 {
766 const bool preserve = (preserveNdx == 0);
767 TestCaseGroup* const preserveGroup = new TestCaseGroup(m_eglTestCtx, (preserve ? "preserve" : "no_preserve"), "");
768
769 for (size_t resizeTypeNdx = 0; resizeTypeNdx < DE_LENGTH_OF_ARRAY(resizeTypes); resizeTypeNdx++)
770 {
771 const BufferAgeTest::ResizeType resizeType = resizeTypes[resizeTypeNdx];
772 TestCaseGroup* const resizeGroup = new TestCaseGroup(m_eglTestCtx, generateResizeGroupName(resizeType).c_str(), "");
773
774 for (size_t evenNdx = 0; evenNdx < frameDrawTypes.size(); evenNdx++)
775 {
776 const vector<BufferAgeTest::DrawType>& evenFrameDrawType = frameDrawTypes[evenNdx];
777
778 for (size_t oddNdx = evenNdx; oddNdx < frameDrawTypes.size(); oddNdx++)
779 {
780 const vector<BufferAgeTest::DrawType>& oddFrameDrawType = frameDrawTypes[oddNdx];
781 const std::string name = generateTestName(oddFrameDrawType, evenFrameDrawType);
782 resizeGroup->addChild(new BufferAgeTest(m_eglTestCtx, preserve, oddFrameDrawType, evenFrameDrawType, BufferAgeTest::RESIZETYPE_NONE, name.c_str(), ""));
783 }
784 }
785
786 preserveGroup->addChild(resizeGroup);
787 }
788 addChild(preserveGroup);
789 }
790 }
791
792 } // egl
793 } // deqp
794