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