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