1 /*------------------------------------------------------------------------- 2 * OpenGL Conformance Test Suite 3 * ----------------------------- 4 * 5 * Copyright (c) 2015-2016 The Khronos Group Inc. 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 22 */ /*-------------------------------------------------------------------*/ 23 24 /*! 25 * \file esextcDrawBuffersIndexedColorMasks.hpp 26 * \brief Draw Buffers Indexed tests 4. Color masks 27 */ /*-------------------------------------------------------------------*/ 28 29 #include "esextcDrawBuffersIndexedColorMasks.hpp" 30 #include "gluPixelTransfer.hpp" 31 #include "gluShaderProgram.hpp" 32 #include "tcuTestLog.hpp" 33 #include <cmath> 34 35 namespace glcts 36 { 37 38 /** Constructor 39 * 40 * @param context Test context 41 * @param name Test case's name 42 * @param description Test case's description 43 **/ 44 DrawBuffersIndexedColorMasks::DrawBuffersIndexedColorMasks(Context& context, const ExtParameters& extParams, 45 const char* name, const char* description) 46 : DrawBuffersIndexedBase(context, extParams, name, description) 47 { 48 /* Left blank on purpose */ 49 } 50 51 void DrawBuffersIndexedColorMasks::prepareFramebuffer() 52 { 53 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 54 55 glw::GLint maxDrawBuffers = 0; 56 gl.getIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers); 57 if (maxDrawBuffers < 4) 58 { 59 throw tcu::ResourceError("Minimum number of draw buffers too low"); 60 } 61 62 gl.genFramebuffers(1, &m_fbo); 63 gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo); 64 65 std::vector<glw::GLenum> bufs(maxDrawBuffers); 66 for (int i = 0; i < maxDrawBuffers; ++i) 67 { 68 bufs[i] = GL_COLOR_ATTACHMENT0 + i; 69 } 70 gl.drawBuffers(maxDrawBuffers, &bufs[0]); 71 72 gl.disable(GL_DITHER); 73 } 74 75 void DrawBuffersIndexedColorMasks::releaseFramebuffer() 76 { 77 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 78 79 glw::GLint maxDrawBuffers = 0; 80 gl.getIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers); 81 if (maxDrawBuffers < 4) 82 { 83 throw tcu::ResourceError("Minimum number of draw buffers too low"); 84 } 85 86 BlendMaskStateMachine state(m_context, m_testCtx.getLog(), maxDrawBuffers); 87 state.SetDefaults(); 88 gl.deleteFramebuffers(1, &m_fbo); 89 gl.bindFramebuffer(GL_FRAMEBUFFER, 0); 90 glw::GLenum bufs[1] = { GL_BACK }; 91 gl.drawBuffers(1, bufs); 92 gl.readBuffer(GL_BACK); 93 } 94 95 tcu::TestNode::IterateResult DrawBuffersIndexedColorMasks::iterate() 96 { 97 static const glw::GLenum WriteMasksFormats[] = { GL_R8, GL_RG8, GL_RGB8, GL_RGB565, GL_RGBA4, 98 GL_RGB5_A1, GL_RGBA8, GL_R8I, GL_R8UI, GL_R16I, 99 GL_R16UI, GL_R32I, GL_R32UI, GL_RG8I, GL_RG8UI, 100 GL_RG16I, GL_RG16UI, GL_RG32I, GL_RG32UI, GL_RGBA8I, 101 GL_RGBA8UI, GL_RGBA16I, GL_RGBA16UI, GL_RGBA32I, GL_RGBA32UI }; 102 static const int kSize = 32; 103 static unsigned int formatId = 0; 104 105 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 106 glw::GLenum format = WriteMasksFormats[formatId]; 107 108 prepareFramebuffer(); 109 110 // Check number of available draw buffers 111 glw::GLint maxDrawBuffers = 0; 112 gl.getIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers); 113 if (maxDrawBuffers < 4) 114 { 115 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Minimum number of draw buffers too low"); 116 return STOP; 117 } 118 119 // Prepare render targets 120 glw::GLuint tex; 121 gl.genTextures(1, &tex); 122 gl.bindTexture(GL_TEXTURE_2D_ARRAY, tex); 123 gl.texStorage3D(GL_TEXTURE_2D_ARRAY, 1, format, kSize, kSize, maxDrawBuffers); 124 for (int i = 0; i < maxDrawBuffers; ++i) 125 { 126 gl.framebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, tex, 0, i); 127 } 128 129 // Clear all buffers 130 switch (ReadableType(format)) 131 { 132 case GL_UNSIGNED_BYTE: 133 { 134 tcu::Vec4 c0(0.15f, 0.3f, 0.45f, 0.6f); 135 for (int i = 0; i < maxDrawBuffers; ++i) 136 { 137 gl.clearBufferfv(GL_COLOR, i, &c0[0]); 138 } 139 break; 140 } 141 case GL_UNSIGNED_INT: 142 { 143 tcu::UVec4 c0(2, 3, 4, 5); 144 for (int i = 0; i < maxDrawBuffers; ++i) 145 { 146 gl.clearBufferuiv(GL_COLOR, i, &c0[0]); 147 } 148 break; 149 } 150 case GL_INT: 151 { 152 tcu::IVec4 c0(2, 3, 4, 5); 153 for (int i = 0; i < maxDrawBuffers; ++i) 154 { 155 gl.clearBufferiv(GL_COLOR, i, &c0[0]); 156 } 157 break; 158 } 159 } 160 161 // Set color masks for each buffer 162 BlendMaskStateMachine state(m_context, m_testCtx.getLog(), maxDrawBuffers); 163 164 glw::GLboolean mask[] = { GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE }; 165 for (int i = 0; i < maxDrawBuffers; ++i) 166 { 167 mask[i % 4] = GL_TRUE; 168 state.SetColorMaski(i, mask[0], mask[1], mask[2], mask[3]); 169 mask[i % 4] = GL_FALSE; 170 } 171 172 // Clear all buffers 173 switch (ReadableType(format)) 174 { 175 case GL_UNSIGNED_BYTE: 176 { 177 tcu::Vec4 c1(0.85f, 0.85f, 0.85f, 0.85f); 178 for (int i = 0; i < maxDrawBuffers; ++i) 179 { 180 gl.clearBufferfv(GL_COLOR, i, &c1[0]); 181 } 182 break; 183 } 184 case GL_UNSIGNED_INT: 185 { 186 tcu::UVec4 c1(23, 23, 23, 23); 187 for (int i = 0; i < maxDrawBuffers; ++i) 188 { 189 gl.clearBufferuiv(GL_COLOR, i, &c1[0]); 190 } 191 break; 192 } 193 case GL_INT: 194 { 195 tcu::IVec4 c1(23, 23, 23, 23); 196 for (int i = 0; i < maxDrawBuffers; ++i) 197 { 198 gl.clearBufferiv(GL_COLOR, i, &c1[0]); 199 } 200 break; 201 } 202 } 203 204 // Verify color 205 int numComponents = NumComponents(format); 206 tcu::RGBA epsilon = GetEpsilon(); 207 bool success = true; 208 209 for (int i = 0; i < maxDrawBuffers; ++i) 210 { 211 gl.readBuffer(GL_COLOR_ATTACHMENT0 + i); 212 213 switch (ReadableType(format)) 214 { 215 case GL_UNSIGNED_BYTE: 216 { 217 tcu::UVec4 e(static_cast<unsigned int>(0.15f * 255), static_cast<unsigned int>(0.30f * 255), 218 static_cast<unsigned int>(0.45f * 255), static_cast<unsigned int>(0.60f * 255)); 219 e[i % 4] = static_cast<unsigned int>(0.85f * 255); 220 e = tcu::UVec4(e.x(), numComponents >= 2 ? e.y() : 0, numComponents >= 3 ? e.z() : 0, 221 numComponents == 4 ? e.w() : 255); 222 tcu::RGBA expected(e.x(), e.y(), e.z(), e.w()); 223 224 std::vector<unsigned char> rendered(kSize * kSize * 4, 45); 225 226 tcu::TextureLevel textureLevel(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), 227 kSize, kSize); 228 glu::readPixels(m_context.getRenderContext(), 0, 0, textureLevel.getAccess()); 229 230 if (!VerifyImg(textureLevel, expected, epsilon)) 231 { 232 m_testCtx.getLog() << tcu::TestLog::Message << "Write mask error in texture format " << format 233 << " occurred for buffer #" << i << "\n" 234 << tcu::TestLog::EndMessage; 235 m_testCtx.getLog() << tcu::TestLog::Image("Result", "Rendered result image", textureLevel.getAccess()); 236 success = false; 237 } 238 break; 239 } 240 case GL_UNSIGNED_INT: 241 { 242 tcu::UVec4 e(2, 3, 4, 5); 243 e[i % 4] = 23; 244 e = tcu::UVec4(e.x(), numComponents >= 2 ? e.y() : 0, numComponents >= 3 ? e.z() : 0, 245 numComponents == 4 ? e.w() : 1); 246 tcu::RGBA expected(e.x(), e.y(), e.z(), e.w()); 247 248 tcu::TextureLevel textureLevel( 249 tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT32), kSize, kSize); 250 glu::readPixels(m_context.getRenderContext(), 0, 0, textureLevel.getAccess()); 251 252 if (!VerifyImg(textureLevel, expected, epsilon)) 253 { 254 m_testCtx.getLog() << tcu::TestLog::Message << "Write mask error in texture format " << format 255 << " occurred for buffer #" << i << "\n" 256 << tcu::TestLog::EndMessage; 257 m_testCtx.getLog() << tcu::TestLog::Image("Result", "Rendered result image", textureLevel.getAccess()); 258 success = false; 259 } 260 break; 261 } 262 case GL_INT: 263 { 264 tcu::UVec4 e(2, 3, 4, 5); 265 e[i % 4] = 23; 266 e = tcu::UVec4(e.x(), numComponents >= 2 ? e.y() : 0, numComponents >= 3 ? e.z() : 0, 267 numComponents == 4 ? e.w() : 1); 268 tcu::RGBA expected(e.x(), e.y(), e.z(), e.w()); 269 270 tcu::TextureLevel textureLevel( 271 tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT32), kSize, kSize); 272 glu::readPixels(m_context.getRenderContext(), 0, 0, textureLevel.getAccess()); 273 274 if (!VerifyImg(textureLevel, expected, epsilon)) 275 { 276 m_testCtx.getLog() << tcu::TestLog::Message << "Write mask error in texture format " << format 277 << " occurred for buffer #" << i << "\n" 278 << tcu::TestLog::EndMessage; 279 m_testCtx.getLog() << tcu::TestLog::Image("Result", "Rendered result image", textureLevel.getAccess()); 280 success = false; 281 } 282 break; 283 } 284 } 285 } 286 287 gl.colorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 288 gl.bindTexture(GL_TEXTURE_2D_ARRAY, 0); 289 gl.deleteTextures(1, &tex); 290 releaseFramebuffer(); 291 292 // Check for error 293 glw::GLenum error_code = gl.getError(); 294 if (error_code != GL_NO_ERROR) 295 { 296 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Some functions generated error"); 297 formatId = 0; 298 return STOP; 299 } 300 301 if (!success) 302 { 303 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Write mask error occurred"); 304 formatId = 0; 305 return STOP; 306 } 307 else 308 { 309 ++formatId; 310 if (formatId < (sizeof(WriteMasksFormats) / sizeof(WriteMasksFormats[0]))) 311 { 312 return CONTINUE; 313 } 314 else 315 { 316 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 317 formatId = 0; 318 return STOP; 319 } 320 } 321 } 322 323 unsigned int DrawBuffersIndexedColorMasks::NumComponents(glw::GLenum format) 324 { 325 switch (format) 326 { 327 case GL_R8: 328 case GL_R8I: 329 case GL_R8UI: 330 case GL_R16I: 331 case GL_R16UI: 332 case GL_R32I: 333 case GL_R32UI: 334 return 1; 335 case GL_RG8: 336 case GL_RG8I: 337 case GL_RG8UI: 338 case GL_RG16I: 339 case GL_RG16UI: 340 case GL_RG32I: 341 case GL_RG32UI: 342 return 2; 343 case GL_RGB8: 344 case GL_RGB565: 345 return 3; 346 case GL_RGBA4: 347 case GL_RGB5_A1: 348 case GL_RGBA8: 349 case GL_RGB10_A2: 350 case GL_RGBA8I: 351 case GL_RGBA8UI: 352 case GL_RGBA16I: 353 case GL_RGBA16UI: 354 case GL_RGBA32I: 355 case GL_RGBA32UI: 356 return 4; 357 default: 358 return 0; 359 } 360 } 361 362 glw::GLenum DrawBuffersIndexedColorMasks::ReadableType(glw::GLenum format) 363 { 364 switch (format) 365 { 366 case GL_R8: 367 case GL_RG8: 368 case GL_RGB8: 369 case GL_RGB565: 370 case GL_RGBA4: 371 case GL_RGB5_A1: 372 case GL_RGBA8: 373 case GL_RGB10_A2: 374 return GL_UNSIGNED_BYTE; 375 376 case GL_R8I: 377 case GL_R16I: 378 case GL_R32I: 379 case GL_RG8I: 380 case GL_RG16I: 381 case GL_RG32I: 382 case GL_RGBA8I: 383 case GL_RGBA16I: 384 case GL_RGBA32I: 385 return GL_INT; 386 387 case GL_R8UI: 388 case GL_R16UI: 389 case GL_R32UI: 390 case GL_RG8UI: 391 case GL_RG16UI: 392 case GL_RG32UI: 393 case GL_RGB10_A2UI: 394 case GL_RGBA8UI: 395 case GL_RGBA16UI: 396 case GL_RGBA32UI: 397 return GL_UNSIGNED_INT; 398 399 default: 400 return 0; 401 } 402 } 403 404 tcu::RGBA DrawBuffersIndexedColorMasks::GetEpsilon() 405 { 406 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 407 408 tcu::IVec4 bits; 409 tcu::UVec4 epsilon; 410 411 for (int i = 0; i < 4; ++i) 412 { 413 gl.getIntegerv(GL_RED_BITS + i, &bits[i]); 414 epsilon[i] = de::min( 415 255u, static_cast<unsigned int>(ceil(1.0 + 255.0 * (1.0 / pow(2.0, static_cast<double>(bits[i])))))); 416 } 417 418 return tcu::RGBA(epsilon.x(), epsilon.y(), epsilon.z(), epsilon.w()); 419 } 420 421 bool DrawBuffersIndexedColorMasks::VerifyImg(const tcu::TextureLevel& textureLevel, tcu::RGBA expectedColor, 422 tcu::RGBA epsilon) 423 { 424 for (int y = 0; y < textureLevel.getHeight(); ++y) 425 { 426 for (int x = 0; x < textureLevel.getWidth(); ++x) 427 { 428 tcu::IVec4 color(textureLevel.getAccess().getPixelInt(x, y)); 429 tcu::RGBA pixel(color.x(), color.y(), color.z(), color.w()); 430 431 if (!tcu::compareThreshold(pixel, expectedColor, epsilon)) 432 { 433 m_testCtx.getLog() << tcu::TestLog::Message << "Expected value: " << expectedColor << "\n" 434 << "Read value: " << pixel << "\n" 435 << "Epsilon: " << epsilon << tcu::TestLog::EndMessage; 436 return false; 437 } 438 } 439 } 440 return true; 441 } 442 443 } // namespace glcts 444