xref: /aosp_15_r20/external/deqp/modules/egl/teglMutableRenderBufferTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program EGL Module
3  * ---------------------------------------
4  *
5  * Copyright 2016 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 KHR_mutable_render_buffer
22  *//*--------------------------------------------------------------------*/
23 
24 #include "teglMutableRenderBufferTests.hpp"
25 
26 #include "egluUtil.hpp"
27 
28 #include "eglwLibrary.hpp"
29 #include "eglwEnums.hpp"
30 
31 #include "gluDefs.hpp"
32 #include "gluRenderContext.hpp"
33 
34 #include "glwFunctions.hpp"
35 #include "glwEnums.hpp"
36 
37 using namespace eglw;
38 
39 using std::vector;
40 
41 namespace deqp
42 {
43 namespace egl
44 {
45 namespace
46 {
47 
48 class MutableRenderBufferTest : public TestCase
49 {
50 public:
51     MutableRenderBufferTest(EglTestContext &eglTestCtx, const char *name, const char *description,
52                             bool enableConfigBit);
53     ~MutableRenderBufferTest(void);
54     void init(void);
55     void deinit(void);
56     IterateResult iterate(void);
57 
58 protected:
59     uint32_t drawAndSwap(const Library &egl, uint32_t color, bool flush);
60     bool m_enableConfigBit;
61     EGLDisplay m_eglDisplay;
62     EGLSurface m_eglSurface;
63     EGLConfig m_eglConfig;
64     eglu::NativeWindow *m_window;
65     EGLContext m_eglContext;
66     glw::Functions m_gl;
67 };
68 
MutableRenderBufferTest(EglTestContext & eglTestCtx,const char * name,const char * description,bool enableConfigBit)69 MutableRenderBufferTest::MutableRenderBufferTest(EglTestContext &eglTestCtx, const char *name, const char *description,
70                                                  bool enableConfigBit)
71     : TestCase(eglTestCtx, name, description)
72     , m_enableConfigBit(enableConfigBit)
73     , m_eglDisplay(EGL_NO_DISPLAY)
74     , m_eglSurface(EGL_NO_SURFACE)
75     , m_eglConfig(DE_NULL)
76     , m_window(DE_NULL)
77     , m_eglContext(EGL_NO_CONTEXT)
78 {
79 }
80 
~MutableRenderBufferTest(void)81 MutableRenderBufferTest::~MutableRenderBufferTest(void)
82 {
83     deinit();
84 }
85 
init(void)86 void MutableRenderBufferTest::init(void)
87 {
88     const Library &egl = m_eglTestCtx.getLibrary();
89 
90     // create display
91     m_eglDisplay = eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay());
92 
93     if (!eglu::hasExtension(egl, m_eglDisplay, "EGL_KHR_mutable_render_buffer"))
94     {
95         TCU_THROW(NotSupportedError, "EGL_KHR_mutable_render_buffer is not supported");
96     }
97 
98     // get mutable render buffer config
99     const EGLint attribs[]      = {EGL_RED_SIZE,
100                                    8,
101                                    EGL_GREEN_SIZE,
102                                    8,
103                                    EGL_BLUE_SIZE,
104                                    8,
105                                    EGL_ALPHA_SIZE,
106                                    8,
107                                    EGL_SURFACE_TYPE,
108                                    EGL_WINDOW_BIT | EGL_MUTABLE_RENDER_BUFFER_BIT_KHR,
109                                    EGL_RENDERABLE_TYPE,
110                                    EGL_OPENGL_ES2_BIT,
111                                    EGL_NONE};
112     const EGLint attribsNoBit[] = {EGL_RED_SIZE,
113                                    8,
114                                    EGL_GREEN_SIZE,
115                                    8,
116                                    EGL_BLUE_SIZE,
117                                    8,
118                                    EGL_ALPHA_SIZE,
119                                    8,
120                                    EGL_SURFACE_TYPE,
121                                    EGL_WINDOW_BIT,
122                                    EGL_RENDERABLE_TYPE,
123                                    EGL_OPENGL_ES2_BIT,
124                                    EGL_NONE};
125 
126     if (m_enableConfigBit)
127     {
128         m_eglConfig = eglu::chooseSingleConfig(egl, m_eglDisplay, attribs);
129     }
130     else
131     {
132         const vector<EGLConfig> configs = eglu::chooseConfigs(egl, m_eglDisplay, attribsNoBit);
133 
134         for (vector<EGLConfig>::const_iterator config = configs.begin(); config != configs.end(); ++config)
135         {
136             EGLint surfaceType = -1;
137             EGLU_CHECK_CALL(egl, getConfigAttrib(m_eglDisplay, *config, EGL_SURFACE_TYPE, &surfaceType));
138 
139             if (!(surfaceType & EGL_MUTABLE_RENDER_BUFFER_BIT_KHR))
140             {
141                 m_eglConfig = *config;
142                 break;
143             }
144         }
145 
146         if (m_eglConfig == DE_NULL)
147             TCU_THROW(NotSupportedError, "No config without support for mutable_render_buffer found");
148     }
149 
150     // create surface
151     const eglu::NativeWindowFactory &factory =
152         eglu::selectNativeWindowFactory(m_eglTestCtx.getNativeDisplayFactory(), m_testCtx.getCommandLine());
153     m_window =
154         factory.createWindow(&m_eglTestCtx.getNativeDisplay(), m_eglDisplay, m_eglConfig, DE_NULL,
155                              eglu::WindowParams(480, 480, eglu::parseWindowVisibility(m_testCtx.getCommandLine())));
156     m_eglSurface =
157         eglu::createWindowSurface(m_eglTestCtx.getNativeDisplay(), *m_window, m_eglDisplay, m_eglConfig, DE_NULL);
158 
159     // create context and make current
160     const EGLint contextAttribList[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
161 
162     egl.bindAPI(EGL_OPENGL_ES_API);
163     m_eglContext = egl.createContext(m_eglDisplay, m_eglConfig, EGL_NO_CONTEXT, contextAttribList);
164     EGLU_CHECK_MSG(egl, "eglCreateContext");
165     TCU_CHECK(m_eglSurface != EGL_NO_SURFACE);
166     egl.makeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);
167     EGLU_CHECK_MSG(egl, "eglMakeCurrent");
168 
169     m_eglTestCtx.initGLFunctions(&m_gl, glu::ApiType::es(2, 0));
170 }
171 
deinit(void)172 void MutableRenderBufferTest::deinit(void)
173 {
174     const Library &egl = m_eglTestCtx.getLibrary();
175 
176     if (m_eglContext != EGL_NO_CONTEXT)
177     {
178         egl.makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
179         egl.destroyContext(m_eglDisplay, m_eglContext);
180         m_eglContext = EGL_NO_CONTEXT;
181     }
182 
183     if (m_eglSurface != EGL_NO_SURFACE)
184     {
185         egl.destroySurface(m_eglDisplay, m_eglSurface);
186         m_eglSurface = EGL_NO_SURFACE;
187     }
188 
189     if (m_eglDisplay != EGL_NO_DISPLAY)
190     {
191         egl.terminate(m_eglDisplay);
192         m_eglDisplay = EGL_NO_DISPLAY;
193     }
194 
195     if (m_window != DE_NULL)
196     {
197         delete m_window;
198         m_window = DE_NULL;
199     }
200 }
201 
drawAndSwap(const Library & egl,uint32_t color,bool flush)202 uint32_t MutableRenderBufferTest::drawAndSwap(const Library &egl, uint32_t color, bool flush)
203 {
204     DE_ASSERT(color < 256);
205     m_gl.clearColor((float)color / 255.f, (float)color / 255.f, (float)color / 255.f, (float)color / 255.f);
206     m_gl.clear(GL_COLOR_BUFFER_BIT);
207     if (flush)
208     {
209         m_gl.flush();
210     }
211     else
212     {
213         EGLU_CHECK_CALL(egl, swapBuffers(m_eglDisplay, m_eglSurface));
214     }
215     return (color | color << 8 | color << 16 | color << 24);
216 }
217 
iterate(void)218 TestCase::IterateResult MutableRenderBufferTest::iterate(void)
219 {
220     const Library &egl = m_eglTestCtx.getLibrary();
221 
222     int frameNumber = 1;
223 
224     // run a few back-buffered frames even if we can't verify their contents
225     for (; frameNumber < 5; frameNumber++)
226     {
227         drawAndSwap(egl, frameNumber, false);
228     }
229 
230     // switch to single-buffer rendering
231     EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER));
232 
233     // Use eglSwapBuffers for the first frame
234     drawAndSwap(egl, frameNumber, false);
235     frameNumber++;
236 
237     // test a few single-buffered frames
238     for (; frameNumber < 10; frameNumber++)
239     {
240         uint32_t backBufferPixel  = 0xFFFFFFFF;
241         uint32_t frontBufferPixel = drawAndSwap(egl, frameNumber, true);
242         m_gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &backBufferPixel);
243 
244         // when single buffered, front-buffer == back-buffer
245         if (backBufferPixel != frontBufferPixel)
246         {
247             m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Surface isn't single-buffered");
248             return STOP;
249         }
250     }
251 
252     // switch back to back-buffer rendering
253     EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, EGL_BACK_BUFFER));
254 
255     // run a few back-buffered frames even if we can't verify their contents
256     for (; frameNumber < 14; frameNumber++)
257     {
258         drawAndSwap(egl, frameNumber, false);
259     }
260 
261     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
262     return STOP;
263 }
264 
265 class MutableRenderBufferQueryTest : public MutableRenderBufferTest
266 {
267 public:
268     MutableRenderBufferQueryTest(EglTestContext &eglTestCtx, const char *name, const char *description);
269     ~MutableRenderBufferQueryTest(void);
270     IterateResult iterate(void);
271 };
272 
MutableRenderBufferQueryTest(EglTestContext & eglTestCtx,const char * name,const char * description)273 MutableRenderBufferQueryTest::MutableRenderBufferQueryTest(EglTestContext &eglTestCtx, const char *name,
274                                                            const char *description)
275     : MutableRenderBufferTest(eglTestCtx, name, description, true)
276 {
277 }
278 
~MutableRenderBufferQueryTest(void)279 MutableRenderBufferQueryTest::~MutableRenderBufferQueryTest(void)
280 {
281     deinit();
282 }
283 
iterate(void)284 TestCase::IterateResult MutableRenderBufferQueryTest::iterate(void)
285 {
286     const Library &egl = m_eglTestCtx.getLibrary();
287 
288     // check that by default the query returns back buffered
289     EGLint curRenderBuffer = -1;
290     EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, &curRenderBuffer));
291     if (curRenderBuffer != EGL_BACK_BUFFER)
292     {
293         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Surface didn't default to back-buffered rendering");
294         return STOP;
295     }
296 
297     // switch to single-buffer rendering and check that the query output changed
298     EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER));
299     EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, &curRenderBuffer));
300     if (curRenderBuffer != EGL_SINGLE_BUFFER)
301     {
302         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Surface didn't switch to single-buffer rendering");
303         return STOP;
304     }
305 
306     // switch back to back-buffer rendering and check the query again
307     EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, EGL_BACK_BUFFER));
308     EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, &curRenderBuffer));
309     if (curRenderBuffer != EGL_BACK_BUFFER)
310     {
311         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Surface didn't switch back to back-buffer rendering");
312         return STOP;
313     }
314     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
315     return STOP;
316 }
317 
318 class MutableRenderBufferQueryNegativeTest : public MutableRenderBufferTest
319 {
320 public:
321     MutableRenderBufferQueryNegativeTest(EglTestContext &eglTestCtx, const char *name, const char *description);
322     ~MutableRenderBufferQueryNegativeTest(void);
323     IterateResult iterate(void);
324 };
325 
MutableRenderBufferQueryNegativeTest(EglTestContext & eglTestCtx,const char * name,const char * description)326 MutableRenderBufferQueryNegativeTest::MutableRenderBufferQueryNegativeTest(EglTestContext &eglTestCtx, const char *name,
327                                                                            const char *description)
328     : MutableRenderBufferTest(eglTestCtx, name, description, false)
329 {
330 }
331 
~MutableRenderBufferQueryNegativeTest(void)332 MutableRenderBufferQueryNegativeTest::~MutableRenderBufferQueryNegativeTest(void)
333 {
334     deinit();
335 }
336 
iterate(void)337 TestCase::IterateResult MutableRenderBufferQueryNegativeTest::iterate(void)
338 {
339     const Library &egl = m_eglTestCtx.getLibrary();
340 
341     // check that by default the query returns back buffered
342     EGLint curRenderBuffer = -1;
343     EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, &curRenderBuffer));
344     if (curRenderBuffer != EGL_BACK_BUFFER)
345     {
346         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Surface didn't default to back-buffered rendering");
347         return STOP;
348     }
349 
350     // check that trying to switch to single-buffer rendering fails when the config bit is not set
351     EGLBoolean ret = egl.surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER);
352     EGLint err     = egl.getError();
353     if (ret != EGL_FALSE)
354     {
355         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL,
356                                 "eglSurfaceAttrib didn't return false when trying to enable single-buffering on a "
357                                 "context without the mutable render buffer bit set");
358         return STOP;
359     }
360     if (err != EGL_BAD_MATCH)
361     {
362         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL,
363                                 "eglSurfaceAttrib didn't set the EGL_BAD_MATCH error when trying to enable "
364                                 "single-buffering on a context without the mutable render buffer bit set");
365         return STOP;
366     }
367 
368     EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, &curRenderBuffer));
369     if (curRenderBuffer != EGL_BACK_BUFFER)
370     {
371         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Surface didn't stay in back-buffered rendering after error");
372         return STOP;
373     }
374 
375     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
376     return STOP;
377 }
378 
379 } // namespace
380 
MutableRenderBufferTests(EglTestContext & eglTestCtx)381 MutableRenderBufferTests::MutableRenderBufferTests(EglTestContext &eglTestCtx)
382     : TestCaseGroup(eglTestCtx, "mutable_render_buffer", "Mutable render buffer tests")
383 {
384 }
385 
init(void)386 void MutableRenderBufferTests::init(void)
387 {
388     addChild(new MutableRenderBufferQueryTest(
389         m_eglTestCtx, "querySurface", "Tests if querySurface returns the correct value after surfaceAttrib is called"));
390     addChild(new MutableRenderBufferQueryNegativeTest(
391         m_eglTestCtx, "negativeConfigBit",
392         "Tests trying to enable single-buffering on a context without the mutable render buffer bit set"));
393     addChild(new MutableRenderBufferTest(
394         m_eglTestCtx, "basic", "Tests enabling/disabling single-buffer rendering and checks the buffering behavior",
395         true));
396 }
397 
398 } // namespace egl
399 } // namespace deqp
400