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, 52 const char* name, 53 const char* description, 54 bool enableConfigBit); 55 ~MutableRenderBufferTest (void); 56 void init (void); 57 void deinit (void); 58 IterateResult iterate (void); 59 60 protected: 61 deUint32 drawAndSwap (const Library& egl, 62 deUint32 color, 63 bool flush); 64 bool m_enableConfigBit; 65 EGLDisplay m_eglDisplay; 66 EGLSurface m_eglSurface; 67 EGLConfig m_eglConfig; 68 eglu::NativeWindow* m_window; 69 EGLContext m_eglContext; 70 glw::Functions m_gl; 71 }; 72 73 MutableRenderBufferTest::MutableRenderBufferTest (EglTestContext& eglTestCtx, 74 const char* name, const char* description, 75 bool enableConfigBit) 76 : TestCase (eglTestCtx, name, description) 77 , m_enableConfigBit (enableConfigBit) 78 , m_eglDisplay (EGL_NO_DISPLAY) 79 , m_eglSurface (EGL_NO_SURFACE) 80 , m_eglConfig (DE_NULL) 81 , m_window (DE_NULL) 82 , m_eglContext (EGL_NO_CONTEXT) 83 { 84 } 85 86 MutableRenderBufferTest::~MutableRenderBufferTest (void) 87 { 88 deinit(); 89 } 90 91 void MutableRenderBufferTest::init (void) 92 { 93 const Library& egl = m_eglTestCtx.getLibrary(); 94 95 // create display 96 m_eglDisplay = eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay()); 97 98 if (!eglu::hasExtension(egl, m_eglDisplay, "EGL_KHR_mutable_render_buffer")) 99 { 100 TCU_THROW(NotSupportedError, "EGL_KHR_mutable_render_buffer is not supported"); 101 } 102 103 // get mutable render buffer config 104 const EGLint attribs[] = 105 { 106 EGL_RED_SIZE, 8, 107 EGL_GREEN_SIZE, 8, 108 EGL_BLUE_SIZE, 8, 109 EGL_ALPHA_SIZE, 8, 110 EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_MUTABLE_RENDER_BUFFER_BIT_KHR, 111 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 112 EGL_NONE 113 }; 114 const EGLint attribsNoBit[] = 115 { 116 EGL_RED_SIZE, 8, 117 EGL_GREEN_SIZE, 8, 118 EGL_BLUE_SIZE, 8, 119 EGL_ALPHA_SIZE, 8, 120 EGL_SURFACE_TYPE, EGL_WINDOW_BIT, 121 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 122 EGL_NONE 123 }; 124 125 if (m_enableConfigBit) 126 { 127 m_eglConfig = eglu::chooseSingleConfig(egl, m_eglDisplay, attribs); 128 } 129 else 130 { 131 const vector<EGLConfig> configs = eglu::chooseConfigs(egl, m_eglDisplay, attribsNoBit); 132 133 for (vector<EGLConfig>::const_iterator config = configs.begin(); config != configs.end(); ++config) 134 { 135 EGLint surfaceType = -1; 136 EGLU_CHECK_CALL(egl, getConfigAttrib(m_eglDisplay, *config, EGL_SURFACE_TYPE, &surfaceType)); 137 138 if (!(surfaceType & EGL_MUTABLE_RENDER_BUFFER_BIT_KHR)) 139 { 140 m_eglConfig = *config; 141 break; 142 } 143 } 144 145 if (m_eglConfig == DE_NULL) 146 TCU_THROW(NotSupportedError, "No config without support for mutable_render_buffer found"); 147 } 148 149 // create surface 150 const eglu::NativeWindowFactory& factory = eglu::selectNativeWindowFactory(m_eglTestCtx.getNativeDisplayFactory(), m_testCtx.getCommandLine()); 151 m_window = factory.createWindow(&m_eglTestCtx.getNativeDisplay(), m_eglDisplay, m_eglConfig, DE_NULL, 152 eglu::WindowParams(480, 480, eglu::parseWindowVisibility(m_testCtx.getCommandLine()))); 153 m_eglSurface = eglu::createWindowSurface(m_eglTestCtx.getNativeDisplay(), *m_window, m_eglDisplay, m_eglConfig, DE_NULL); 154 155 // create context and make current 156 const EGLint contextAttribList[] = 157 { 158 EGL_CONTEXT_CLIENT_VERSION, 2, 159 EGL_NONE 160 }; 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 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 202 deUint32 MutableRenderBufferTest::drawAndSwap (const Library& egl, deUint32 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 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 deUint32 backBufferPixel = 0xFFFFFFFF; 241 deUint32 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, 269 const char* name, 270 const char* description); 271 ~MutableRenderBufferQueryTest (void); 272 IterateResult iterate (void); 273 }; 274 275 MutableRenderBufferQueryTest::MutableRenderBufferQueryTest (EglTestContext& eglTestCtx, 276 const char* name, const char* description) 277 : MutableRenderBufferTest (eglTestCtx, name, description, true) 278 { 279 } 280 281 MutableRenderBufferQueryTest::~MutableRenderBufferQueryTest (void) 282 { 283 deinit(); 284 } 285 286 TestCase::IterateResult MutableRenderBufferQueryTest::iterate (void) 287 { 288 const Library& egl = m_eglTestCtx.getLibrary(); 289 290 // check that by default the query returns back buffered 291 EGLint curRenderBuffer = -1; 292 EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, &curRenderBuffer)); 293 if (curRenderBuffer != EGL_BACK_BUFFER) 294 { 295 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Surface didn't default to back-buffered rendering"); 296 return STOP; 297 } 298 299 // switch to single-buffer rendering and check that the query output changed 300 EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER)); 301 EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, &curRenderBuffer)); 302 if (curRenderBuffer != EGL_SINGLE_BUFFER) 303 { 304 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Surface didn't switch to single-buffer rendering"); 305 return STOP; 306 } 307 308 // switch back to back-buffer rendering and check the query again 309 EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, EGL_BACK_BUFFER)); 310 EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, &curRenderBuffer)); 311 if (curRenderBuffer != EGL_BACK_BUFFER) 312 { 313 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Surface didn't switch back to back-buffer rendering"); 314 return STOP; 315 } 316 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 317 return STOP; 318 } 319 320 class MutableRenderBufferQueryNegativeTest : public MutableRenderBufferTest 321 { 322 public: 323 MutableRenderBufferQueryNegativeTest (EglTestContext& eglTestCtx, 324 const char* name, 325 const char* description); 326 ~MutableRenderBufferQueryNegativeTest (void); 327 IterateResult iterate (void); 328 }; 329 330 MutableRenderBufferQueryNegativeTest::MutableRenderBufferQueryNegativeTest (EglTestContext& eglTestCtx, 331 const char* name, const char* description) 332 : MutableRenderBufferTest (eglTestCtx, name, description, false) 333 { 334 } 335 336 MutableRenderBufferQueryNegativeTest::~MutableRenderBufferQueryNegativeTest (void) 337 { 338 deinit(); 339 } 340 341 TestCase::IterateResult MutableRenderBufferQueryNegativeTest::iterate (void) 342 { 343 const Library& egl = m_eglTestCtx.getLibrary(); 344 345 // check that by default the query returns back buffered 346 EGLint curRenderBuffer = -1; 347 EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, &curRenderBuffer)); 348 if (curRenderBuffer != EGL_BACK_BUFFER) 349 { 350 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Surface didn't default to back-buffered rendering"); 351 return STOP; 352 } 353 354 // check that trying to switch to single-buffer rendering fails when the config bit is not set 355 EGLBoolean ret = egl.surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER); 356 EGLint err = egl.getError(); 357 if (ret != EGL_FALSE) 358 { 359 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, 360 "eglSurfaceAttrib didn't return false when trying to enable single-buffering on a context without the mutable render buffer bit set"); 361 return STOP; 362 } 363 if (err != EGL_BAD_MATCH) 364 { 365 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, 366 "eglSurfaceAttrib didn't set the EGL_BAD_MATCH error when trying to enable single-buffering on a context without the mutable render buffer bit set"); 367 return STOP; 368 } 369 370 EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, &curRenderBuffer)); 371 if (curRenderBuffer != EGL_BACK_BUFFER) 372 { 373 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Surface didn't stay in back-buffered rendering after error"); 374 return STOP; 375 } 376 377 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 378 return STOP; 379 } 380 381 } // anonymous 382 383 MutableRenderBufferTests::MutableRenderBufferTests (EglTestContext& eglTestCtx) 384 : TestCaseGroup(eglTestCtx, "mutable_render_buffer", "Mutable render buffer tests") 385 { 386 } 387 388 void MutableRenderBufferTests::init (void) 389 { 390 addChild(new MutableRenderBufferQueryTest(m_eglTestCtx, "querySurface", 391 "Tests if querySurface returns the correct value after surfaceAttrib is called")); 392 addChild(new MutableRenderBufferQueryNegativeTest(m_eglTestCtx, "negativeConfigBit", 393 "Tests trying to enable single-buffering on a context without the mutable render buffer bit set")); 394 addChild(new MutableRenderBufferTest(m_eglTestCtx, "basic", 395 "Tests enabling/disabling single-buffer rendering and checks the buffering behavior", true)); 396 } 397 398 } // egl 399 } // deqp 400