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