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