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 m_eglConfig = getEGLConfig(m_eglTestCtx.getLibrary(), m_eglDisplay, m_preserveColorBuffer);
394
395 if (m_eglConfig == DE_NULL)
396 TCU_THROW(NotSupportedError, "No supported config found");
397
398 //create surface and context and make them current
399 initEGLSurface(m_eglConfig);
400 initEGLContext(m_eglConfig);
401
402 m_eglTestCtx.initGLFunctions(&m_gl, glu::ApiType::es(2,0));
403
404 if (eglu::hasExtension(egl, m_eglDisplay, "EGL_EXT_buffer_age") == false)
405 TCU_THROW(NotSupportedError, "EGL_EXT_buffer_age is not supported");
406
407 m_gles2Renderer = new GLES2Renderer(m_gl);
408 m_refRenderer = new ReferenceRenderer();
409 }
410
deinit(void)411 void BufferAgeTest::deinit (void)
412 {
413 const Library& egl = m_eglTestCtx.getLibrary();
414
415 delete m_refRenderer;
416 m_refRenderer = DE_NULL;
417
418 delete m_gles2Renderer;
419 m_gles2Renderer = DE_NULL;
420
421 if (m_eglContext != EGL_NO_CONTEXT)
422 {
423 egl.makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
424 egl.destroyContext(m_eglDisplay, m_eglContext);
425 m_eglContext = EGL_NO_CONTEXT;
426 }
427
428 if (m_eglSurface != EGL_NO_SURFACE)
429 {
430 egl.destroySurface(m_eglDisplay, m_eglSurface);
431 m_eglSurface = EGL_NO_SURFACE;
432 }
433
434 if (m_eglDisplay != EGL_NO_DISPLAY)
435 {
436 egl.terminate(m_eglDisplay);
437 m_eglDisplay = EGL_NO_DISPLAY;
438 }
439
440 delete m_window;
441 m_window = DE_NULL;
442 }
443
initEGLSurface(EGLConfig config)444 void BufferAgeTest::initEGLSurface (EGLConfig config)
445 {
446 const eglu::NativeWindowFactory& factory = eglu::selectNativeWindowFactory(m_eglTestCtx.getNativeDisplayFactory(), m_testCtx.getCommandLine());
447 m_window = factory.createWindow(&m_eglTestCtx.getNativeDisplay(), m_eglDisplay, config, DE_NULL,
448 eglu::WindowParams(480, 480, eglu::parseWindowVisibility(m_testCtx.getCommandLine())));
449 m_eglSurface = eglu::createWindowSurface(m_eglTestCtx.getNativeDisplay(), *m_window, m_eglDisplay, config, DE_NULL);
450 }
451
initEGLContext(EGLConfig config)452 void BufferAgeTest::initEGLContext (EGLConfig config)
453 {
454 const Library& egl = m_eglTestCtx.getLibrary();
455 const EGLint attribList[] =
456 {
457 EGL_CONTEXT_CLIENT_VERSION, 2,
458 EGL_NONE
459 };
460
461 egl.bindAPI(EGL_OPENGL_ES_API);
462 m_eglContext = egl.createContext(m_eglDisplay, config, EGL_NO_CONTEXT, attribList);
463 EGLU_CHECK_MSG(egl, "eglCreateContext");
464 DE_ASSERT(m_eglSurface != EGL_NO_SURFACE);
465 egl.makeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);
466 EGLU_CHECK_MSG(egl, "eglMakeCurrent");
467 }
468
469 // return indices of frames that have been written to the given buffer
getFramesOnBuffer(const vector<int> & bufferAges,int frameNdx)470 vector<int> getFramesOnBuffer (const vector<int>& bufferAges, int frameNdx)
471 {
472 DE_ASSERT(frameNdx < (int)bufferAges.size());
473 vector<int> frameOnBuffer;
474 int age = bufferAges[frameNdx];
475 while (age != 0)
476 {
477 frameNdx = frameNdx - age;
478 DE_ASSERT(frameNdx >= 0);
479 frameOnBuffer.push_back(frameNdx);
480 age = bufferAges[frameNdx];
481 }
482
483 reverse(frameOnBuffer.begin(), frameOnBuffer.end());
484 return frameOnBuffer;
485 }
486
iterate(void)487 TestCase::IterateResult BufferAgeTest::iterate (void)
488 {
489 de::Random rnd (m_seed);
490 const Library& egl = m_eglTestCtx.getLibrary();
491 tcu::TestLog& log = m_testCtx.getLog();
492 const int width = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_WIDTH);
493 const int height = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_HEIGHT);
494 const float clearRed = rnd.getFloat();
495 const float clearGreen = rnd.getFloat();
496 const float clearBlue = rnd.getFloat();
497 const tcu::Vec4 clearColor (clearRed, clearGreen, clearBlue, 1.0f);
498 const int numFrames = 20;
499 FrameSequence frameSequence;
500 vector<int> bufferAges;
501
502 if (m_preserveColorBuffer)
503 EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED));
504 else
505 EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED));
506
507 for (int frameNdx = 0; frameNdx < numFrames; frameNdx++)
508 {
509 tcu::Surface currentBuffer (width, height);
510 tcu::Surface refBuffer (width, height);
511 Frame newFrame (width, height);
512 EGLint currentBufferAge = -1;
513
514 if (frameNdx % 2 == 0)
515 generateRandomFrame(&newFrame, m_evenFrameDrawType, rnd);
516 else
517 generateRandomFrame(&newFrame, m_oddFrameDrawType, rnd);
518
519 frameSequence.push_back(newFrame);
520
521 EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_EXT, ¤tBufferAge));
522
523 if (currentBufferAge > frameNdx || currentBufferAge < 0) // invalid buffer age
524 {
525 std::ostringstream stream;
526 stream << "Fail, the age is invalid. Age: " << currentBufferAge << ", frameNdx: " << frameNdx;
527 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, stream.str().c_str());
528 return STOP;
529 }
530
531 if (frameNdx > 0 && m_preserveColorBuffer && currentBufferAge != 1)
532 {
533 std::ostringstream stream;
534 stream << "Fail, EGL_BUFFER_PRESERVED is set to true, but buffer age is: " << currentBufferAge << " (should be 1)";
535 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, stream.str().c_str());
536 return STOP;
537 }
538
539 bufferAges.push_back(currentBufferAge);
540 DE_ASSERT((int)bufferAges.size() == frameNdx+1);
541
542 // during first half, just keep rendering without reading pixel back to mimic ordinary use case
543 if (frameNdx < numFrames/2)
544 {
545 if (currentBufferAge == 0)
546 clearColorScreen(m_gl, clearColor);
547
548 m_gles2Renderer->render(width, height, newFrame);
549
550 if (m_resizeType == RESIZETYPE_BEFORE_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 EGLU_CHECK_CALL(egl, swapBuffers(m_eglDisplay, m_eglSurface));
559
560 if (m_resizeType == RESIZETYPE_AFTER_SWAP)
561 {
562 if (frameNdx % 2 == 0)
563 m_window->setSurfaceSize(IVec2(width*2, height/2));
564 else
565 m_window->setSurfaceSize(IVec2(height/2, width*2));
566 }
567
568 continue;
569 }
570
571 // do verification in the second half
572 if (currentBufferAge > 0) //buffer contain previous content, need to verify
573 {
574 const vector<int> framesOnBuffer = getFramesOnBuffer(bufferAges, frameNdx);
575 readPixels(m_gl, ¤tBuffer);
576 clearColorReference(&refBuffer, clearColor);
577
578 for (vector<int>::const_iterator it = framesOnBuffer.begin(); it != framesOnBuffer.end(); it++)
579 m_refRenderer->render(&refBuffer, frameSequence[*it]);
580
581 if (compareToReference(log, refBuffer, currentBuffer, frameNdx, frameNdx-currentBufferAge) == false)
582 {
583 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail, buffer content is not well preserved when age > 0");
584 return STOP;
585 }
586 }
587 else // currentBufferAge == 0, content is undefined, clear the buffer, currentBufferAge < 0 is ruled out at the beginning
588 {
589 clearColorScreen(m_gl, clearColor);
590 clearColorReference(&refBuffer, clearColor);
591 }
592
593 m_gles2Renderer->render(width, height, newFrame);
594 m_refRenderer->render(&refBuffer, newFrame);
595
596 readPixels(m_gl, ¤tBuffer);
597
598 if (compareToReference(log, refBuffer, currentBuffer, frameNdx, frameNdx) == false)
599 {
600 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail, render result is wrong");
601 return STOP;
602 }
603
604 if (m_resizeType == RESIZETYPE_BEFORE_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 EGLU_CHECK_CALL(egl, swapBuffers(m_eglDisplay, m_eglSurface));
613
614 if (m_resizeType == RESIZETYPE_AFTER_SWAP)
615 {
616 if (frameNdx % 2 == 0)
617 m_window->setSurfaceSize(IVec2(width*2, height/2));
618 else
619 m_window->setSurfaceSize(IVec2(height/2, width*2));
620 }
621 }
622
623 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
624 return STOP;
625 }
626
generateDrawTypeName(const vector<BufferAgeTest::DrawType> & drawTypes)627 string generateDrawTypeName (const vector<BufferAgeTest::DrawType>& drawTypes)
628 {
629 std::ostringstream stream;
630 if (drawTypes.size() == 0)
631 return string("_none");
632
633 for (size_t ndx = 0; ndx < drawTypes.size(); ndx++)
634 {
635 if (drawTypes[ndx] == BufferAgeTest::DRAWTYPE_GLES2_RENDER)
636 stream << "_render";
637 else if (drawTypes[ndx] == BufferAgeTest::DRAWTYPE_GLES2_CLEAR)
638 stream << "_clear";
639 else
640 DE_ASSERT(false);
641 }
642 return stream.str();
643 }
644
generateTestName(const vector<BufferAgeTest::DrawType> & oddFrameDrawType,const vector<BufferAgeTest::DrawType> & evenFrameDrawType)645 string generateTestName (const vector<BufferAgeTest::DrawType>& oddFrameDrawType, const vector<BufferAgeTest::DrawType>& evenFrameDrawType)
646 {
647 return "odd" + generateDrawTypeName(oddFrameDrawType) + "_even" + generateDrawTypeName(evenFrameDrawType);
648 }
649
generateResizeGroupName(BufferAgeTest::ResizeType resizeType)650 string generateResizeGroupName (BufferAgeTest::ResizeType resizeType)
651 {
652 switch (resizeType)
653 {
654 case BufferAgeTest::RESIZETYPE_NONE:
655 return "no_resize";
656
657 case BufferAgeTest::RESIZETYPE_AFTER_SWAP:
658 return "resize_after_swap";
659
660 case BufferAgeTest::RESIZETYPE_BEFORE_SWAP:
661 return "resize_before_swap";
662
663 default:
664 DE_FATAL("Unknown resize type");
665 return "";
666 }
667 }
668
isWindow(const eglu::CandidateConfig & c)669 bool isWindow (const eglu::CandidateConfig& c)
670 {
671 return (c.surfaceType() & EGL_WINDOW_BIT) == EGL_WINDOW_BIT;
672 }
673
isES2Renderable(const eglu::CandidateConfig & c)674 bool isES2Renderable (const eglu::CandidateConfig& c)
675 {
676 return (c.get(EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT) == EGL_OPENGL_ES2_BIT;
677 }
678
hasPreserveSwap(const eglu::CandidateConfig & c)679 bool hasPreserveSwap (const eglu::CandidateConfig& c)
680 {
681 return (c.surfaceType() & EGL_SWAP_BEHAVIOR_PRESERVED_BIT) == EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
682 }
683
getEGLConfig(const Library & egl,EGLDisplay eglDisplay,bool preserveColorBuffer)684 EGLConfig getEGLConfig (const Library& egl, EGLDisplay eglDisplay, bool preserveColorBuffer)
685 {
686 eglu::FilterList filters;
687 filters << isWindow << isES2Renderable;
688 if (preserveColorBuffer)
689 filters << hasPreserveSwap;
690 return eglu::chooseSingleConfig(egl, eglDisplay, filters);
691 }
692
clearColorScreen(const glw::Functions & gl,const tcu::Vec4 & clearColor)693 void clearColorScreen (const glw::Functions& gl, const tcu::Vec4& clearColor)
694 {
695 gl.clearColor(clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w());
696 gl.clear(GL_COLOR_BUFFER_BIT);
697 }
698
clearColorReference(tcu::Surface * ref,const tcu::Vec4 & clearColor)699 void clearColorReference (tcu::Surface* ref, const tcu::Vec4& clearColor)
700 {
701 tcu::clear(ref->getAccess(), clearColor);
702 }
703
readPixels(const glw::Functions & gl,tcu::Surface * screen)704 void readPixels (const glw::Functions& gl, tcu::Surface* screen)
705 {
706 gl.readPixels(0, 0, screen->getWidth(), screen->getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, screen->getAccess().getDataPtr());
707 }
708
windowToDeviceCoordinates(int x,int length)709 float windowToDeviceCoordinates (int x, int length)
710 {
711 return (2.0f * float(x) / float(length)) - 1.0f;
712 }
713
compareToReference(tcu::TestLog & log,const tcu::Surface & reference,const tcu::Surface & buffer,int frameNdx,int bufferNum)714 bool compareToReference (tcu::TestLog& log, const tcu::Surface& reference, const tcu::Surface& buffer, int frameNdx, int bufferNum)
715 {
716 std::ostringstream stream;
717 stream << "FrameNdx = " << frameNdx << ", compare current buffer (numbered: " << bufferNum << ") to reference";
718 return tcu::intThresholdPositionDeviationCompare(log, "buffer age test", stream.str().c_str(), reference.getAccess(), buffer.getAccess(),
719 tcu::UVec4(8, 8, 8, 0), tcu::IVec3(2,2,0), true, tcu::COMPARE_LOG_RESULT);
720 }
721
722 } // anonymous
723
BufferAgeTests(EglTestContext & eglTestCtx)724 BufferAgeTests::BufferAgeTests (EglTestContext& eglTestCtx)
725 : TestCaseGroup(eglTestCtx, "buffer_age", "Color buffer age tests")
726 {
727 }
728
init(void)729 void BufferAgeTests::init (void)
730 {
731 const BufferAgeTest::DrawType clearRender[] =
732 {
733 BufferAgeTest::DRAWTYPE_GLES2_CLEAR,
734 BufferAgeTest::DRAWTYPE_GLES2_RENDER
735 };
736
737 const BufferAgeTest::DrawType renderClear[] =
738 {
739 BufferAgeTest::DRAWTYPE_GLES2_RENDER,
740 BufferAgeTest::DRAWTYPE_GLES2_CLEAR
741 };
742
743 const BufferAgeTest::ResizeType resizeTypes[] =
744 {
745 BufferAgeTest::RESIZETYPE_NONE,
746 BufferAgeTest::RESIZETYPE_BEFORE_SWAP,
747 BufferAgeTest::RESIZETYPE_AFTER_SWAP
748 };
749
750 vector< vector<BufferAgeTest::DrawType> > frameDrawTypes;
751 frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> ());
752 frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (1, BufferAgeTest::DRAWTYPE_GLES2_CLEAR));
753 frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (1, BufferAgeTest::DRAWTYPE_GLES2_RENDER));
754 frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (2, BufferAgeTest::DRAWTYPE_GLES2_CLEAR));
755 frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (2, BufferAgeTest::DRAWTYPE_GLES2_RENDER));
756 frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (DE_ARRAY_BEGIN(clearRender), DE_ARRAY_END(clearRender)));
757 frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (DE_ARRAY_BEGIN(renderClear), DE_ARRAY_END(renderClear)));
758
759 for (int preserveNdx = 0; preserveNdx < 2; preserveNdx++)
760 {
761 const bool preserve = (preserveNdx == 0);
762 TestCaseGroup* const preserveGroup = new TestCaseGroup(m_eglTestCtx, (preserve ? "preserve" : "no_preserve"), "");
763
764 for (size_t resizeTypeNdx = 0; resizeTypeNdx < DE_LENGTH_OF_ARRAY(resizeTypes); resizeTypeNdx++)
765 {
766 const BufferAgeTest::ResizeType resizeType = resizeTypes[resizeTypeNdx];
767 TestCaseGroup* const resizeGroup = new TestCaseGroup(m_eglTestCtx, generateResizeGroupName(resizeType).c_str(), "");
768
769 for (size_t evenNdx = 0; evenNdx < frameDrawTypes.size(); evenNdx++)
770 {
771 const vector<BufferAgeTest::DrawType>& evenFrameDrawType = frameDrawTypes[evenNdx];
772
773 for (size_t oddNdx = evenNdx; oddNdx < frameDrawTypes.size(); oddNdx++)
774 {
775 const vector<BufferAgeTest::DrawType>& oddFrameDrawType = frameDrawTypes[oddNdx];
776 const std::string name = generateTestName(oddFrameDrawType, evenFrameDrawType);
777 resizeGroup->addChild(new BufferAgeTest(m_eglTestCtx, preserve, oddFrameDrawType, evenFrameDrawType, BufferAgeTest::RESIZETYPE_NONE, name.c_str(), ""));
778 }
779 }
780
781 preserveGroup->addChild(resizeGroup);
782 }
783 addChild(preserveGroup);
784 }
785 }
786
787 } // egl
788 } // deqp
789