xref: /aosp_15_r20/external/deqp/modules/egl/teglBufferAgeTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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, &currentBufferAge));
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, &currentBuffer);
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, &currentBuffer);
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