xref: /aosp_15_r20/external/deqp/modules/egl/teglSwapBuffersTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program EGL Module
3  * ---------------------------------------
4  *
5  * Copyright 2014 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 eglSwapBuffers() interaction with native window.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "teglSwapBuffersTests.hpp"
25 
26 #include "teglSimpleConfigCase.hpp"
27 
28 #include "egluNativeWindow.hpp"
29 #include "egluUtil.hpp"
30 #include "egluUnique.hpp"
31 #include "eglwLibrary.hpp"
32 #include "eglwEnums.hpp"
33 
34 #include "gluDefs.hpp"
35 #include "glwEnums.hpp"
36 #include "glwFunctions.hpp"
37 
38 #include "tcuTestLog.hpp"
39 #include "tcuSurface.hpp"
40 #include "tcuTexture.hpp"
41 #include "tcuTextureUtil.hpp"
42 #include "tcuImageCompare.hpp"
43 #include "tcuVector.hpp"
44 #include "tcuVectorUtil.hpp"
45 
46 #include "deUniquePtr.hpp"
47 #include "deThread.hpp"
48 
49 #include <string>
50 #include <vector>
51 #include <sstream>
52 
53 namespace deqp
54 {
55 namespace egl
56 {
57 
58 using std::string;
59 using std::vector;
60 using tcu::TestLog;
61 using namespace eglw;
62 
63 namespace
64 {
65 
createGLES2Context(const Library & egl,EGLDisplay display,EGLConfig config)66 EGLContext createGLES2Context(const Library &egl, EGLDisplay display, EGLConfig config)
67 {
68     EGLContext context        = EGL_NO_CONTEXT;
69     const EGLint attribList[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
70 
71     EGLU_CHECK_CALL(egl, bindAPI(EGL_OPENGL_ES_API));
72 
73     context = egl.createContext(display, config, EGL_NO_CONTEXT, attribList);
74     EGLU_CHECK_MSG(egl, "eglCreateContext() failed");
75     TCU_CHECK(context);
76 
77     return context;
78 }
79 
80 class SwapBuffersTest : public SimpleConfigCase
81 {
82 public:
83     SwapBuffersTest(EglTestContext &eglTestCtx, const NamedFilterList &filters);
84     ~SwapBuffersTest(void);
85 
86 private:
87     void executeForConfig(EGLDisplay display, EGLConfig config);
88 
89     // Not allowed
90     SwapBuffersTest(const SwapBuffersTest &);
91     SwapBuffersTest &operator=(const SwapBuffersTest &);
92 };
93 
SwapBuffersTest(EglTestContext & eglTestCtx,const NamedFilterList & filters)94 SwapBuffersTest::SwapBuffersTest(EglTestContext &eglTestCtx, const NamedFilterList &filters)
95     : SimpleConfigCase(eglTestCtx, filters.getName(), filters.getDescription(), filters)
96 {
97 }
98 
~SwapBuffersTest(void)99 SwapBuffersTest::~SwapBuffersTest(void)
100 {
101 }
102 
getConfigIdString(const Library & egl,EGLDisplay display,EGLConfig config)103 string getConfigIdString(const Library &egl, EGLDisplay display, EGLConfig config)
104 {
105     std::ostringstream stream;
106     EGLint id;
107 
108     EGLU_CHECK_CALL(egl, getConfigAttrib(display, config, EGL_CONFIG_ID, &id));
109 
110     stream << id;
111 
112     return stream.str();
113 }
114 
createGLES2Program(const glw::Functions & gl,TestLog & log)115 uint32_t createGLES2Program(const glw::Functions &gl, TestLog &log)
116 {
117     const char *const vertexShaderSource = "attribute highp vec2 a_pos;\n"
118                                            "void main (void)\n"
119                                            "{\n"
120                                            "\tgl_Position = vec4(a_pos, 0.0, 1.0);\n"
121                                            "}";
122 
123     const char *const fragmentShaderSource = "void main (void)\n"
124                                              "{\n"
125                                              "\tgl_FragColor = vec4(0.9, 0.1, 0.4, 1.0);\n"
126                                              "}";
127 
128     uint32_t program        = 0;
129     uint32_t vertexShader   = 0;
130     uint32_t fragmentShader = 0;
131 
132     int32_t vertexCompileStatus;
133     string vertexInfoLog;
134     int32_t fragmentCompileStatus;
135     string fragmentInfoLog;
136     int32_t linkStatus;
137     string programInfoLog;
138 
139     try
140     {
141         program        = gl.createProgram();
142         vertexShader   = gl.createShader(GL_VERTEX_SHADER);
143         fragmentShader = gl.createShader(GL_FRAGMENT_SHADER);
144 
145         GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create shaders and program");
146 
147         gl.shaderSource(vertexShader, 1, &vertexShaderSource, DE_NULL);
148         gl.compileShader(vertexShader);
149         GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to setup vertex shader");
150 
151         gl.shaderSource(fragmentShader, 1, &fragmentShaderSource, DE_NULL);
152         gl.compileShader(fragmentShader);
153         GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to setup fragment shader");
154 
155         {
156             int32_t infoLogLength = 0;
157 
158             gl.getShaderiv(vertexShader, GL_COMPILE_STATUS, &vertexCompileStatus);
159             gl.getShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &infoLogLength);
160 
161             vertexInfoLog.resize(infoLogLength, '\0');
162 
163             gl.getShaderInfoLog(vertexShader, (glw::GLsizei)vertexInfoLog.length(), &infoLogLength,
164                                 &(vertexInfoLog[0]));
165             GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to get vertex shader compile info");
166 
167             vertexInfoLog.resize(infoLogLength);
168         }
169 
170         {
171             int32_t infoLogLength = 0;
172 
173             gl.getShaderiv(fragmentShader, GL_COMPILE_STATUS, &fragmentCompileStatus);
174             gl.getShaderiv(fragmentShader, GL_INFO_LOG_LENGTH, &infoLogLength);
175 
176             fragmentInfoLog.resize(infoLogLength, '\0');
177 
178             gl.getShaderInfoLog(fragmentShader, (glw::GLsizei)fragmentInfoLog.length(), &infoLogLength,
179                                 &(fragmentInfoLog[0]));
180             GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to get fragment shader compile info");
181 
182             fragmentInfoLog.resize(infoLogLength);
183         }
184 
185         gl.attachShader(program, vertexShader);
186         gl.attachShader(program, fragmentShader);
187         gl.linkProgram(program);
188         GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to setup program");
189 
190         {
191             int32_t infoLogLength = 0;
192 
193             gl.getProgramiv(program, GL_LINK_STATUS, &linkStatus);
194             gl.getProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength);
195 
196             programInfoLog.resize(infoLogLength, '\0');
197 
198             gl.getProgramInfoLog(program, (glw::GLsizei)programInfoLog.length(), &infoLogLength, &(programInfoLog[0]));
199             GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to get program link info");
200 
201             programInfoLog.resize(infoLogLength);
202         }
203 
204         if (linkStatus == 0 || vertexCompileStatus == 0 || fragmentCompileStatus == 0)
205         {
206 
207             log.startShaderProgram(linkStatus != 0, programInfoLog.c_str());
208 
209             log << TestLog::Shader(QP_SHADER_TYPE_VERTEX, vertexShaderSource, vertexCompileStatus != 0, vertexInfoLog);
210             log << TestLog::Shader(QP_SHADER_TYPE_FRAGMENT, fragmentShaderSource, fragmentCompileStatus != 0,
211                                    fragmentInfoLog);
212 
213             log.endShaderProgram();
214         }
215 
216         gl.deleteShader(vertexShader);
217         gl.deleteShader(fragmentShader);
218         GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to delete shaders");
219 
220         TCU_CHECK(linkStatus != 0 && vertexCompileStatus != 0 && fragmentCompileStatus != 0);
221     }
222     catch (...)
223     {
224         if (program)
225             gl.deleteProgram(program);
226 
227         if (vertexShader)
228             gl.deleteShader(vertexShader);
229 
230         if (fragmentShader)
231             gl.deleteShader(fragmentShader);
232 
233         throw;
234     }
235 
236     return program;
237 }
238 
checkColor(tcu::TestLog & log,const tcu::TextureLevel & screen,const tcu::Vec4 & color)239 bool checkColor(tcu::TestLog &log, const tcu::TextureLevel &screen, const tcu::Vec4 &color)
240 {
241     const tcu::Vec4 threshold(0.01f, 0.01f, 0.01f, 1.00f);
242 
243     for (int y = 0; y < screen.getHeight(); y++)
244     {
245         for (int x = 0; x < screen.getWidth(); x++)
246         {
247             const tcu::Vec4 pixel(screen.getAccess().getPixel(x, y));
248             const tcu::Vec4 diff(abs(pixel - color));
249 
250             if (!boolAll(lessThanEqual(diff, threshold)))
251             {
252                 log << TestLog::Message << "Unexpected color values read from screen expected: " << color
253                     << TestLog::EndMessage;
254                 log << TestLog::Image("Screen", "Screen", screen.getAccess());
255                 return false;
256             }
257         }
258     }
259 
260     return true;
261 }
262 
executeForConfig(EGLDisplay display,EGLConfig config)263 void SwapBuffersTest::executeForConfig(EGLDisplay display, EGLConfig config)
264 {
265     const Library &egl = m_eglTestCtx.getLibrary();
266     const string configIdStr(getConfigIdString(egl, display, config));
267     tcu::ScopedLogSection logSection(m_testCtx.getLog(), ("Config ID " + configIdStr).c_str(),
268                                      ("Config ID " + configIdStr).c_str());
269     const int waitFrames = 5;
270     const eglu::NativeWindowFactory &factory =
271         eglu::selectNativeWindowFactory(m_eglTestCtx.getNativeDisplayFactory(), m_testCtx.getCommandLine());
272 
273     if ((factory.getCapabilities() & eglu::NativeWindow::CAPABILITY_READ_SCREEN_PIXELS) == 0)
274         TCU_THROW(NotSupportedError, "eglu::NativeWindow doesn't support readScreenPixels()");
275 
276     {
277         TestLog &log = m_testCtx.getLog();
278 
279         log << TestLog::Message << "EGL_RED_SIZE: " << eglu::getConfigAttribInt(egl, display, config, EGL_RED_SIZE)
280             << TestLog::EndMessage;
281         log << TestLog::Message << "EGL_GREEN_SIZE: " << eglu::getConfigAttribInt(egl, display, config, EGL_GREEN_SIZE)
282             << TestLog::EndMessage;
283         log << TestLog::Message << "EGL_BLUE_SIZE: " << eglu::getConfigAttribInt(egl, display, config, EGL_BLUE_SIZE)
284             << TestLog::EndMessage;
285         log << TestLog::Message << "EGL_ALPHA_SIZE: " << eglu::getConfigAttribInt(egl, display, config, EGL_ALPHA_SIZE)
286             << TestLog::EndMessage;
287         log << TestLog::Message << "EGL_DEPTH_SIZE: " << eglu::getConfigAttribInt(egl, display, config, EGL_DEPTH_SIZE)
288             << TestLog::EndMessage;
289         log << TestLog::Message
290             << "EGL_STENCIL_SIZE: " << eglu::getConfigAttribInt(egl, display, config, EGL_STENCIL_SIZE)
291             << TestLog::EndMessage;
292         log << TestLog::Message << "EGL_SAMPLES: " << eglu::getConfigAttribInt(egl, display, config, EGL_SAMPLES)
293             << TestLog::EndMessage;
294 
295         log << TestLog::Message << "Waiting " << waitFrames * 16
296             << "ms after eglSwapBuffers() and glFinish() for frame to become visible" << TestLog::EndMessage;
297     }
298 
299     de::UniquePtr<eglu::NativeWindow> window(
300         factory.createWindow(&m_eglTestCtx.getNativeDisplay(), display, config, DE_NULL,
301                              eglu::WindowParams(128, 128, eglu::WindowParams::VISIBILITY_VISIBLE)));
302 
303     eglu::UniqueSurface surface(
304         egl, display, eglu::createWindowSurface(m_eglTestCtx.getNativeDisplay(), *window, display, config, DE_NULL));
305     eglu::UniqueContext context(egl, display, createGLES2Context(egl, display, config));
306     glw::Functions gl;
307     uint32_t program = 0;
308 
309     tcu::TextureLevel whiteFrame;
310     tcu::TextureLevel blackFrame;
311     tcu::TextureLevel frameBegin;
312     tcu::TextureLevel frameEnd;
313 
314     m_eglTestCtx.initGLFunctions(&gl, glu::ApiType::es(2, 0));
315     EGLU_CHECK_CALL(egl, makeCurrent(display, *surface, *surface, *context));
316 
317     try
318     {
319         const float positions1[] = {0.00f, 0.00f, 0.75f, 0.00f, 0.75f, 0.75f,
320 
321                                     0.75f, 0.75f, 0.00f, 0.75f, 0.00f, 0.00f};
322 
323         const float positions2[] = {-0.75f, -0.75f, 0.00f,  -0.75f, 0.00f,  0.00f,
324 
325                                     0.00f,  0.00f,  -0.75f, 0.00f,  -0.75f, -0.75f};
326 
327         uint32_t posLocation;
328 
329         program = createGLES2Program(gl, m_testCtx.getLog());
330 
331         gl.useProgram(program);
332         posLocation = gl.getAttribLocation(program, "a_pos");
333         gl.enableVertexAttribArray(posLocation);
334         GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to setup shader program for rendering");
335 
336         // Clear screen to white and check that sceen is white
337         gl.clearColor(1.0f, 1.0f, 1.0f, 1.0f);
338         gl.clear(GL_COLOR_BUFFER_BIT);
339         GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to clear surface");
340 
341         EGLU_CHECK_CALL(egl, swapBuffers(display, *surface));
342         gl.finish();
343         GLU_EXPECT_NO_ERROR(gl.getError(), "glFinish() failed");
344         deSleep(waitFrames * 16);
345         window->processEvents();
346         window->readScreenPixels(&whiteFrame);
347 
348         if (!checkColor(m_testCtx.getLog(), whiteFrame, tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f)))
349         {
350             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Couldn't reliably read pixels from screen");
351             return;
352         }
353 
354         // Clear screen to black and check that sceen is black
355         gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
356         gl.clear(GL_COLOR_BUFFER_BIT);
357         GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to clear surface");
358 
359         EGLU_CHECK_CALL(egl, swapBuffers(display, *surface));
360         gl.finish();
361         GLU_EXPECT_NO_ERROR(gl.getError(), "glFinish() failed");
362         deSleep(waitFrames * 16);
363         window->processEvents();
364         window->readScreenPixels(&blackFrame);
365 
366         if (!checkColor(m_testCtx.getLog(), blackFrame, tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)))
367         {
368             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Couldn't reliably read pixels from screen");
369             return;
370         }
371 
372         gl.clearColor(0.7f, 1.0f, 0.3f, 1.0f);
373         gl.clear(GL_COLOR_BUFFER_BIT);
374         GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to clear surface");
375 
376         gl.vertexAttribPointer(posLocation, 2, GL_FLOAT, GL_FALSE, 0, positions1);
377         gl.drawArrays(GL_TRIANGLES, 0, 6);
378         GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to render");
379 
380         EGLU_CHECK_CALL(egl, swapBuffers(display, *surface));
381         gl.finish();
382         GLU_EXPECT_NO_ERROR(gl.getError(), "glFinish() failed");
383         deSleep(waitFrames * 16);
384         window->processEvents();
385         window->readScreenPixels(&frameBegin);
386 
387         gl.clearColor(0.7f, 0.7f, 1.0f, 1.0f);
388         gl.clear(GL_COLOR_BUFFER_BIT);
389         GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to clear surface");
390 
391         gl.vertexAttribPointer(posLocation, 2, GL_FLOAT, GL_FALSE, 0, positions2);
392         gl.drawArrays(GL_TRIANGLES, 0, 6);
393         GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to render");
394 
395         gl.finish();
396         GLU_EXPECT_NO_ERROR(gl.getError(), "glFinish() failed");
397         deSleep(waitFrames * 16);
398         window->readScreenPixels(&frameEnd);
399 
400         EGLU_CHECK_CALL(egl, swapBuffers(display, *surface));
401         gl.finish();
402         GLU_EXPECT_NO_ERROR(gl.getError(), "glFinish() failed");
403         deSleep(waitFrames * 16);
404         window->processEvents();
405 
406         gl.disableVertexAttribArray(posLocation);
407         gl.useProgram(0);
408         GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to release program state");
409 
410         gl.deleteProgram(program);
411         program = 0;
412         GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteProgram()");
413 
414         if (!tcu::intThresholdCompare(m_testCtx.getLog(), "Compare end of frame against beginning of frame",
415                                       "Compare end of frame against beginning of frame", frameBegin.getAccess(),
416                                       frameEnd.getAccess(), tcu::UVec4(0, 0, 0, 0), tcu::COMPARE_LOG_RESULT))
417             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Screen pixels changed during frame");
418     }
419     catch (...)
420     {
421         if (program != 0)
422             gl.deleteProgram(program);
423 
424         EGLU_CHECK_CALL(egl, makeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
425         throw;
426     }
427 
428     EGLU_CHECK_CALL(egl, makeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
429 }
430 
431 } // namespace
432 
SwapBuffersTests(EglTestContext & eglTestCtx)433 SwapBuffersTests::SwapBuffersTests(EglTestContext &eglTestCtx)
434     : TestCaseGroup(eglTestCtx, "swap_buffers", "Swap buffers tests")
435 {
436 }
437 
isWindow(const eglu::CandidateConfig & c)438 static bool isWindow(const eglu::CandidateConfig &c)
439 {
440     return (c.surfaceType() & EGL_WINDOW_BIT) != 0;
441 }
442 
init(void)443 void SwapBuffersTests::init(void)
444 {
445     eglu::FilterList baseFilters;
446     baseFilters << isWindow;
447 
448     vector<NamedFilterList> filterLists;
449     getDefaultFilterLists(filterLists, baseFilters);
450 
451     for (vector<NamedFilterList>::iterator i = filterLists.begin(); i != filterLists.end(); i++)
452         addChild(new SwapBuffersTest(m_eglTestCtx, *i));
453 }
454 
455 } // namespace egl
456 } // namespace deqp
457