1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 3.0 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 Depth and stencil clear tests. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "es3fDepthStencilClearTests.hpp" 25 26 #include "gluShaderProgram.hpp" 27 #include "gluPixelTransfer.hpp" 28 #include "gluRenderContext.hpp" 29 30 #include "tcuTestLog.hpp" 31 #include "tcuTexture.hpp" 32 #include "tcuTextureUtil.hpp" 33 #include "tcuImageCompare.hpp" 34 #include "tcuSurface.hpp" 35 #include "tcuRenderTarget.hpp" 36 37 #include "deRandom.hpp" 38 #include "deMath.h" 39 #include "deString.h" 40 41 #include "glwFunctions.hpp" 42 #include "glwEnums.hpp" 43 44 namespace deqp 45 { 46 namespace gles3 47 { 48 namespace Functional 49 { 50 51 using tcu::Vec3; 52 using tcu::Vec4; 53 using tcu::TestLog; 54 using std::string; 55 using std::vector; 56 57 namespace 58 { 59 60 enum 61 { 62 STENCIL_STEPS = 32, 63 DEPTH_STEPS = 32 64 }; 65 66 struct Clear 67 { 68 Clear (void) 69 : clearMask (0) 70 , clearDepth (0.0f) 71 , clearStencil (0) 72 , useScissor (false) 73 , scissor (0, 0, 0, 0) 74 , depthMask (false) 75 , stencilMask (0) 76 { 77 } 78 79 deUint32 clearMask; 80 float clearDepth; 81 int clearStencil; 82 83 bool useScissor; 84 tcu::IVec4 scissor; 85 86 bool depthMask; 87 deUint32 stencilMask; 88 }; 89 90 tcu::TextureFormat getDepthFormat (int depthBits) 91 { 92 switch (depthBits) 93 { 94 case 8: return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT8); 95 case 16: return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT16); 96 case 24: return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT24); 97 case 32: return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::FLOAT); 98 default: 99 TCU_FAIL("Can't map depth buffer format"); 100 } 101 } 102 103 tcu::TextureFormat getStencilFormat (int stencilBits) 104 { 105 switch (stencilBits) 106 { 107 case 8: return tcu::TextureFormat(tcu::TextureFormat::S, tcu::TextureFormat::UNSIGNED_INT8); 108 case 16: return tcu::TextureFormat(tcu::TextureFormat::S, tcu::TextureFormat::UNSIGNED_INT16); 109 case 24: return tcu::TextureFormat(tcu::TextureFormat::S, tcu::TextureFormat::UNSIGNED_INT24); 110 case 32: return tcu::TextureFormat(tcu::TextureFormat::S, tcu::TextureFormat::UNSIGNED_INT32); 111 default: 112 TCU_FAIL("Can't map depth buffer format"); 113 } 114 } 115 116 } // anonymous. 117 118 class DepthStencilClearCase : public TestCase 119 { 120 public: 121 DepthStencilClearCase (Context& context, const char* name, const char* description, int numIters, int numClears, bool depth, bool stencil, bool scissor, bool masked); 122 ~DepthStencilClearCase (void); 123 124 void init (void); 125 void deinit (void); 126 127 IterateResult iterate (void); 128 129 private: 130 void generateClears (vector<Clear>& dst, deUint32 seed); 131 void renderGL (tcu::Surface& dst, const vector<Clear>& clears); 132 void renderReference (tcu::Surface& dst, const vector<Clear>& clears); 133 134 bool m_testDepth; 135 bool m_testStencil; 136 bool m_testScissor; 137 bool m_masked; 138 int m_numIters; 139 int m_numClears; 140 int m_curIter; 141 142 glu::ShaderProgram* m_visProgram; 143 }; 144 145 DepthStencilClearCase::DepthStencilClearCase (Context& context, const char* name, const char* description, int numIters, int numClears, bool depth, bool stencil, bool scissor, bool masked) 146 : TestCase (context, name, description) 147 , m_testDepth (depth) 148 , m_testStencil (stencil) 149 , m_testScissor (scissor) 150 , m_masked (masked) 151 , m_numIters (numIters) 152 , m_numClears (numClears) 153 , m_curIter (0) 154 , m_visProgram (DE_NULL) 155 { 156 } 157 158 DepthStencilClearCase::~DepthStencilClearCase (void) 159 { 160 DepthStencilClearCase::deinit(); 161 } 162 163 void DepthStencilClearCase::init (void) 164 { 165 TestLog& log = m_testCtx.getLog(); 166 167 m_visProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources( 168 // Vertex shader. 169 "#version 300 es\n" 170 "in highp vec4 a_position;\n" 171 "void main (void)\n" 172 "{\n" 173 " gl_Position = a_position;\n" 174 "}\n", 175 176 // Fragment shader. 177 "#version 300 es\n" 178 "uniform mediump vec4 u_color;\n" 179 "layout(location = 0) out mediump vec4 o_color;\n" 180 "void main (void)\n" 181 "{\n" 182 " o_color = u_color;\n" 183 "}\n")); 184 185 if (!m_visProgram->isOk()) 186 { 187 log << *m_visProgram; 188 delete m_visProgram; 189 m_visProgram = DE_NULL; 190 TCU_FAIL("Compile failed"); 191 } 192 193 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 194 } 195 196 void DepthStencilClearCase::deinit (void) 197 { 198 delete m_visProgram; 199 m_visProgram = DE_NULL; 200 } 201 202 DepthStencilClearCase::IterateResult DepthStencilClearCase::iterate (void) 203 { 204 const tcu::RenderTarget& renderTarget = m_context.getRenderTarget(); 205 int width = renderTarget.getWidth(); 206 int height = renderTarget.getHeight(); 207 tcu::Surface result (width, height); 208 tcu::Surface reference (width, height); 209 tcu::RGBA threshold = renderTarget.getPixelFormat().getColorThreshold() + tcu::RGBA(1,1,1,1); 210 vector<Clear> clears; 211 212 if ((m_testDepth && renderTarget.getDepthBits() == 0) || 213 (m_testStencil && renderTarget.getStencilBits() == 0)) 214 throw tcu::NotSupportedError("No depth/stencil buffers", "", __FILE__, __LINE__); 215 216 generateClears(clears, deStringHash(getName())^deInt32Hash(m_curIter)); 217 renderGL(result, clears); 218 renderReference(reference, clears); 219 220 bool isLastIter = m_curIter+1 == m_numIters; 221 bool isOk = tcu::pixelThresholdCompare(m_testCtx.getLog(), "Result", "Image comparison result", reference, result, threshold, isLastIter ? tcu::COMPARE_LOG_RESULT : tcu::COMPARE_LOG_ON_ERROR); 222 223 if (!isOk) 224 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed"); 225 226 m_curIter += 1; 227 return isLastIter || !isOk ? STOP : CONTINUE; 228 } 229 230 void DepthStencilClearCase::generateClears (vector<Clear>& clears, deUint32 seed) 231 { 232 const tcu::RenderTarget& renderTarget = m_context.getRenderContext().getRenderTarget(); 233 int width = renderTarget.getWidth(); 234 int height = renderTarget.getHeight(); 235 de::Random rnd (seed); 236 237 clears.resize(m_numClears); 238 239 for (vector<Clear>::iterator clear = clears.begin(); clear != clears.end(); clear++) 240 { 241 if (m_testScissor) 242 { 243 int w = rnd.getInt(1, width); 244 int h = rnd.getInt(1, height); 245 int x = rnd.getInt(0, width-w); 246 int y = rnd.getInt(0, height-h); 247 248 clear->useScissor = true; // \todo [pyry] Should we randomize? 249 clear->scissor = tcu::IVec4(x, y, w, h); 250 } 251 else 252 clear->useScissor = false; 253 254 clear->clearDepth = rnd.getFloat(-0.2f, 1.2f); 255 clear->clearStencil = rnd.getUint32(); 256 257 clear->depthMask = m_masked ? rnd.getBool() : true; 258 clear->stencilMask = m_masked ? rnd.getUint32() : 0xffffffffu; 259 260 if (m_testDepth && m_testStencil) 261 { 262 switch (rnd.getInt(0, 2)) 263 { 264 case 0: clear->clearMask = GL_DEPTH_BUFFER_BIT; break; 265 case 1: clear->clearMask = GL_STENCIL_BUFFER_BIT; break; 266 case 2: clear->clearMask = GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT; break; 267 } 268 } 269 else if (m_testDepth) 270 clear->clearMask = GL_DEPTH_BUFFER_BIT; 271 else 272 { 273 DE_ASSERT(m_testStencil); 274 clear->clearMask = GL_STENCIL_BUFFER_BIT; 275 } 276 } 277 } 278 279 void DepthStencilClearCase::renderGL (tcu::Surface& dst, const vector<Clear>& clears) 280 { 281 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 282 int colorLoc = gl.getUniformLocation(m_visProgram->getProgram(), "u_color"); 283 int positionLoc = gl.getAttribLocation(m_visProgram->getProgram(), "a_position"); 284 static const deUint8 indices[] = { 0, 1, 2, 2, 1, 3 }; 285 286 // Clear with default values. 287 gl.clearDepthf (1.0f); 288 gl.clearStencil (0); 289 gl.clearColor (1.0f, 0.0f, 0.0f, 1.0f); 290 gl.clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 291 292 GLU_EXPECT_NO_ERROR(gl.getError(), "Before clears"); 293 294 for (vector<Clear>::const_iterator clear = clears.begin(); clear != clears.end(); clear++) 295 { 296 if (clear->useScissor) 297 { 298 gl.enable(GL_SCISSOR_TEST); 299 gl.scissor(clear->scissor.x(), clear->scissor.y(), clear->scissor.z(), clear->scissor.w()); 300 } 301 302 // Clear values. 303 gl.clearDepthf (clear->clearDepth); 304 gl.clearStencil (clear->clearStencil); 305 306 // Masks. 307 gl.depthMask (clear->depthMask ? GL_TRUE : GL_FALSE); 308 gl.stencilMask (clear->stencilMask); 309 310 // Execute clear. 311 gl.clear (clear->clearMask); 312 313 if (clear->useScissor) 314 gl.disable(GL_SCISSOR_TEST); 315 } 316 317 // Restore default masks. 318 gl.depthMask (GL_TRUE); 319 gl.stencilMask (0xffffffffu); 320 321 GLU_EXPECT_NO_ERROR(gl.getError(), "After clears"); 322 323 gl.useProgram (m_visProgram->getProgram()); 324 gl.enableVertexAttribArray (positionLoc); 325 326 // Visualize depth / stencil buffers. 327 if (m_testDepth) 328 { 329 int numSteps = DEPTH_STEPS; 330 float step = 2.0f / numSteps; 331 332 gl.enable (GL_DEPTH_TEST); 333 gl.depthFunc(GL_LESS); 334 gl.depthMask(GL_FALSE); 335 gl.colorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_FALSE); 336 337 for (int ndx = 0; ndx < numSteps; ndx++) 338 { 339 float d = -1.0f + step*ndx; 340 float c = (float)ndx / (float)(numSteps-1); 341 float pos[] = 342 { 343 -1.0f, -1.0f, d, 344 -1.0f, 1.0f, d, 345 1.0f, -1.0f, d, 346 1.0f, 1.0f, d 347 }; 348 349 gl.uniform4f (colorLoc, 0.0f, 0.0f, c, 1.0f); 350 gl.vertexAttribPointer (positionLoc, 3, GL_FLOAT, GL_FALSE, 0, &pos[0]); 351 gl.drawElements (GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_BYTE, &indices[0]); 352 } 353 354 gl.disable (GL_DEPTH_TEST); 355 gl.depthMask(GL_TRUE); 356 357 GLU_EXPECT_NO_ERROR(gl.getError(), "After depth visualization"); 358 } 359 360 if (m_testStencil) 361 { 362 int numSteps = STENCIL_STEPS; 363 int numValues = (1 << TestCase::m_context.getRenderContext().getRenderTarget().getStencilBits()); // 2^bits 364 int step = numValues / numSteps; 365 366 gl.enable (GL_STENCIL_TEST); 367 gl.stencilOp (GL_KEEP, GL_KEEP, GL_KEEP); 368 gl.colorMask (GL_FALSE, GL_TRUE, GL_FALSE, GL_FALSE); 369 370 static const float pos[] = 371 { 372 -1.0f, -1.0f, 373 -1.0f, 1.0f, 374 1.0f, -1.0f, 375 1.0f, 1.0f 376 }; 377 gl.vertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, &pos[0]); 378 379 for (int ndx = 0; ndx < numSteps; ndx++) 380 { 381 int s = step*ndx; 382 float c = (float)ndx / (float)(numSteps-1); 383 384 gl.stencilFunc (GL_LEQUAL, s, 0xffu); 385 gl.uniform4f (colorLoc, 0.0f, c, 0.0f, 1.0f); 386 gl.drawElements (GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_BYTE, &indices[0]); 387 } 388 389 gl.disable(GL_STENCIL_TEST); 390 391 GLU_EXPECT_NO_ERROR(gl.getError(), "After stencil visualization"); 392 } 393 394 // Restore color mask (changed by visualization). 395 gl.colorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 396 397 glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess()); 398 } 399 400 void DepthStencilClearCase::renderReference (tcu::Surface& dst, const vector<Clear>& clears) 401 { 402 glu::RenderContext& renderCtx = TestCase::m_context.getRenderContext(); 403 const tcu::RenderTarget& renderTarget = renderCtx.getRenderTarget(); 404 405 // Clear surface to red. 406 tcu::clear(dst.getAccess(), tcu::RGBA::red.toVec()); 407 408 if (m_testDepth) 409 { 410 // Simulated depth buffer span. 411 tcu::TextureLevel depthBufRow (getDepthFormat(renderTarget.getDepthBits()), dst.getWidth(), 1, 1); 412 tcu::PixelBufferAccess rowAccess = depthBufRow.getAccess(); 413 414 for (int y = 0; y < dst.getHeight(); y++) 415 { 416 // Clear to default value. 417 for (int x = 0; x < rowAccess.getWidth(); x++) 418 rowAccess.setPixel(Vec4(1.0f), x, 0); 419 420 // Execute clears. 421 for (vector<Clear>::const_iterator clear = clears.begin(); clear != clears.end(); clear++) 422 { 423 // Clear / mask test. 424 if ((clear->clearMask & GL_DEPTH_BUFFER_BIT) == 0 || !clear->depthMask) 425 continue; 426 427 tcu::IVec4 clearRect = clear->useScissor ? clear->scissor : tcu::IVec4(0, 0, dst.getWidth(), dst.getHeight()); 428 429 // Intersection test. 430 if (!de::inBounds(y, clearRect.y(), clearRect.y()+clearRect.w())) 431 continue; 432 433 for (int x = clearRect.x(); x < clearRect.x()+clearRect.z(); x++) 434 rowAccess.setPixDepth(de::clamp(clear->clearDepth, 0.0f, 1.0f), x, 0); 435 } 436 437 // Map to colors. 438 for (int x = 0; x < dst.getWidth(); x++) 439 { 440 float depth = rowAccess.getPixDepth(x, 0); 441 float step = deFloatFloor(depth * (float)DEPTH_STEPS) / (float)(DEPTH_STEPS-1); 442 tcu::RGBA oldColor = dst.getPixel(x, y); 443 tcu::RGBA newColor = tcu::RGBA(oldColor.getRed(), oldColor.getGreen(), deClamp32(deRoundFloatToInt32(step * 255.0f), 0, 255), oldColor.getAlpha()); 444 445 dst.setPixel(x, y, newColor); 446 } 447 } 448 } 449 450 if (m_testStencil) 451 { 452 // Simulated stencil buffer span. 453 int stencilBits = renderTarget.getStencilBits(); 454 tcu::TextureLevel depthBufRow (getStencilFormat(stencilBits), dst.getWidth(), 1, 1); 455 tcu::PixelBufferAccess rowAccess = depthBufRow.getAccess(); 456 deUint32 bufMask = (1u<<stencilBits)-1; 457 458 for (int y = 0; y < dst.getHeight(); y++) 459 { 460 // Clear to default value. 461 for (int x = 0; x < rowAccess.getWidth(); x++) 462 rowAccess.setPixel(tcu::UVec4(0), x, 0); 463 464 // Execute clears. 465 for (vector<Clear>::const_iterator clear = clears.begin(); clear != clears.end(); clear++) 466 { 467 // Clear / mask test. 468 if ((clear->clearMask & GL_STENCIL_BUFFER_BIT) == 0 || clear->stencilMask == 0) 469 continue; 470 471 tcu::IVec4 clearRect = clear->useScissor ? clear->scissor : tcu::IVec4(0, 0, dst.getWidth(), dst.getHeight()); 472 473 // Intersection test. 474 if (!de::inBounds(y, clearRect.y(), clearRect.y()+clearRect.w())) 475 continue; 476 477 for (int x = clearRect.x(); x < clearRect.x()+clearRect.z(); x++) 478 { 479 deUint32 oldVal = rowAccess.getPixStencil(x, 0); 480 deUint32 newVal = ((oldVal & ~clear->stencilMask) | (clear->clearStencil & clear->stencilMask)) & bufMask; 481 rowAccess.setPixStencil(newVal, x, 0); 482 } 483 } 484 485 // Map to colors. 486 for (int x = 0; x < dst.getWidth(); x++) 487 { 488 deUint32 stencil = rowAccess.getPixStencil(x, 0); 489 float step = (float)(stencil / ((1u<<stencilBits) / (deUint32)STENCIL_STEPS)) / (float)(STENCIL_STEPS-1); 490 tcu::RGBA oldColor = dst.getPixel(x, y); 491 tcu::RGBA newColor = tcu::RGBA(oldColor.getRed(), deClamp32(deRoundFloatToInt32(step * 255.0f), 0, 255), oldColor.getBlue(), oldColor.getAlpha()); 492 493 dst.setPixel(x, y, newColor); 494 } 495 } 496 } 497 } 498 499 DepthStencilClearTests::DepthStencilClearTests (Context& context) 500 : TestCaseGroup(context, "depth_stencil_clear", "Depth and stencil clear tests") 501 { 502 } 503 504 void DepthStencilClearTests::init (void) 505 { 506 // iters clears depth stencil scissor masked 507 addChild(new DepthStencilClearCase(m_context, "depth", "", 4, 2, true, false, false, false)); 508 addChild(new DepthStencilClearCase(m_context, "depth_scissored", "", 4, 16, true, false, true, false)); 509 addChild(new DepthStencilClearCase(m_context, "depth_scissored_masked", "", 4, 16, true, false, true, true)); 510 511 addChild(new DepthStencilClearCase(m_context, "stencil", "", 4, 2, false, true, false, false)); 512 addChild(new DepthStencilClearCase(m_context, "stencil_masked", "", 4, 8, false, true, false, true)); 513 addChild(new DepthStencilClearCase(m_context, "stencil_scissored", "", 4, 16, false, true, true, false)); 514 addChild(new DepthStencilClearCase(m_context, "stencil_scissored_masked", "", 4, 16, false, true, true, true)); 515 516 addChild(new DepthStencilClearCase(m_context, "depth_stencil", "", 4, 2, true, true, false, false)); 517 addChild(new DepthStencilClearCase(m_context, "depth_stencil_masked", "", 4, 8, true, true, false, true)); 518 addChild(new DepthStencilClearCase(m_context, "depth_stencil_scissored", "", 4, 16, true, true, true, false)); 519 addChild(new DepthStencilClearCase(m_context, "depth_stencil_scissored_masked", "", 4, 16, true, true, true, true)); 520 } 521 522 } // Functional 523 } // gles3 524 } // deqp 525