1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 2.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 "es2fDepthStencilClearTests.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 gles2 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::UNSIGNED_INT_24_8); 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_INT_24_8); 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 "attribute highp vec4 a_position;\n" 170 "void main (void)\n" 171 "{\n" 172 " gl_Position = a_position;\n" 173 "}\n", 174 175 // Fragment shader. 176 "uniform mediump vec4 u_color;\n" 177 "void main (void)\n" 178 "{\n" 179 " gl_FragColor = u_color;\n" 180 "}\n")); 181 182 if (!m_visProgram->isOk()) 183 { 184 log << *m_visProgram; 185 delete m_visProgram; 186 m_visProgram = DE_NULL; 187 TCU_FAIL("Compile failed"); 188 } 189 190 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 191 } 192 193 void DepthStencilClearCase::deinit (void) 194 { 195 delete m_visProgram; 196 m_visProgram = DE_NULL; 197 } 198 199 DepthStencilClearCase::IterateResult DepthStencilClearCase::iterate (void) 200 { 201 const tcu::RenderTarget& renderTarget = m_context.getRenderTarget(); 202 int width = renderTarget.getWidth(); 203 int height = renderTarget.getHeight(); 204 tcu::Surface result (width, height); 205 tcu::Surface reference (width, height); 206 tcu::RGBA threshold = renderTarget.getPixelFormat().getColorThreshold() + tcu::RGBA(1,1,1,1); 207 vector<Clear> clears; 208 209 if ((m_testDepth && renderTarget.getDepthBits() == 0) || 210 (m_testStencil && renderTarget.getStencilBits() == 0)) 211 throw tcu::NotSupportedError("No depth/stencil buffers", "", __FILE__, __LINE__); 212 213 generateClears(clears, deStringHash(getName())^deInt32Hash(m_curIter)); 214 renderGL(result, clears); 215 renderReference(reference, clears); 216 217 bool isLastIter = m_curIter+1 == m_numIters; 218 bool isOk = tcu::pixelThresholdCompare(m_testCtx.getLog(), "Result", "Image comparison result", reference, result, threshold, isLastIter ? tcu::COMPARE_LOG_RESULT : tcu::COMPARE_LOG_ON_ERROR); 219 220 if (!isOk) 221 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed"); 222 223 m_curIter += 1; 224 return isLastIter || !isOk ? STOP : CONTINUE; 225 } 226 227 void DepthStencilClearCase::generateClears (vector<Clear>& clears, deUint32 seed) 228 { 229 const tcu::RenderTarget& renderTarget = m_context.getRenderContext().getRenderTarget(); 230 int width = renderTarget.getWidth(); 231 int height = renderTarget.getHeight(); 232 de::Random rnd (seed); 233 234 clears.resize(m_numClears); 235 236 for (vector<Clear>::iterator clear = clears.begin(); clear != clears.end(); clear++) 237 { 238 if (m_testScissor) 239 { 240 int w = rnd.getInt(1, width); 241 int h = rnd.getInt(1, height); 242 int x = rnd.getInt(0, width-w); 243 int y = rnd.getInt(0, height-h); 244 245 clear->useScissor = true; // \todo [pyry] Should we randomize? 246 clear->scissor = tcu::IVec4(x, y, w, h); 247 } 248 else 249 clear->useScissor = false; 250 251 clear->clearDepth = rnd.getFloat(-0.2f, 1.2f); 252 clear->clearStencil = rnd.getUint32(); 253 254 clear->depthMask = m_masked ? rnd.getBool() : true; 255 clear->stencilMask = m_masked ? rnd.getUint32() : 0xffffffffu; 256 257 if (m_testDepth && m_testStencil) 258 { 259 switch (rnd.getInt(0, 2)) 260 { 261 case 0: clear->clearMask = GL_DEPTH_BUFFER_BIT; break; 262 case 1: clear->clearMask = GL_STENCIL_BUFFER_BIT; break; 263 case 2: clear->clearMask = GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT; break; 264 } 265 } 266 else if (m_testDepth) 267 clear->clearMask = GL_DEPTH_BUFFER_BIT; 268 else 269 { 270 DE_ASSERT(m_testStencil); 271 clear->clearMask = GL_STENCIL_BUFFER_BIT; 272 } 273 } 274 } 275 276 void DepthStencilClearCase::renderGL (tcu::Surface& dst, const vector<Clear>& clears) 277 { 278 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 279 int colorLoc = gl.getUniformLocation(m_visProgram->getProgram(), "u_color"); 280 int positionLoc = gl.getAttribLocation(m_visProgram->getProgram(), "a_position"); 281 static const deUint8 indices[] = { 0, 1, 2, 2, 1, 3 }; 282 283 // Clear with default values. 284 gl.clearDepthf (1.0f); 285 gl.clearStencil (0); 286 gl.clearColor (1.0f, 0.0f, 0.0f, 1.0f); 287 gl.clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 288 289 GLU_EXPECT_NO_ERROR(gl.getError(), "Before clears"); 290 291 for (vector<Clear>::const_iterator clear = clears.begin(); clear != clears.end(); clear++) 292 { 293 if (clear->useScissor) 294 { 295 gl.enable(GL_SCISSOR_TEST); 296 gl.scissor(clear->scissor.x(), clear->scissor.y(), clear->scissor.z(), clear->scissor.w()); 297 } 298 299 // Clear values. 300 gl.clearDepthf (clear->clearDepth); 301 gl.clearStencil (clear->clearStencil); 302 303 // Masks. 304 gl.depthMask (clear->depthMask ? GL_TRUE : GL_FALSE); 305 gl.stencilMask (clear->stencilMask); 306 307 // Execute clear. 308 gl.clear (clear->clearMask); 309 310 if (clear->useScissor) 311 gl.disable(GL_SCISSOR_TEST); 312 } 313 314 // Restore default masks. 315 gl.depthMask (GL_TRUE); 316 gl.stencilMask (0xffffffffu); 317 318 GLU_EXPECT_NO_ERROR(gl.getError(), "After clears"); 319 320 gl.useProgram (m_visProgram->getProgram()); 321 gl.enableVertexAttribArray (positionLoc); 322 323 // Visualize depth / stencil buffers. 324 if (m_testDepth) 325 { 326 int numSteps = DEPTH_STEPS; 327 float step = 2.0f / numSteps; 328 329 gl.enable (GL_DEPTH_TEST); 330 gl.depthFunc(GL_LESS); 331 gl.depthMask(GL_FALSE); 332 gl.colorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_FALSE); 333 334 for (int ndx = 0; ndx < numSteps; ndx++) 335 { 336 float d = -1.0f + step*ndx; 337 float c = (float)ndx / (float)(numSteps-1); 338 float pos[] = 339 { 340 -1.0f, -1.0f, d, 341 -1.0f, 1.0f, d, 342 1.0f, -1.0f, d, 343 1.0f, 1.0f, d 344 }; 345 346 gl.uniform4f (colorLoc, 0.0f, 0.0f, c, 1.0f); 347 gl.vertexAttribPointer (positionLoc, 3, GL_FLOAT, GL_FALSE, 0, &pos[0]); 348 gl.drawElements (GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_BYTE, &indices[0]); 349 } 350 351 gl.disable (GL_DEPTH_TEST); 352 gl.depthMask(GL_TRUE); 353 354 GLU_EXPECT_NO_ERROR(gl.getError(), "After depth visualization"); 355 } 356 357 if (m_testStencil) 358 { 359 int numSteps = STENCIL_STEPS; 360 int numValues = (1 << TestCase::m_context.getRenderContext().getRenderTarget().getStencilBits()); // 2^bits 361 int step = numValues / numSteps; 362 363 gl.enable (GL_STENCIL_TEST); 364 gl.stencilOp (GL_KEEP, GL_KEEP, GL_KEEP); 365 gl.colorMask (GL_FALSE, GL_TRUE, GL_FALSE, GL_FALSE); 366 367 static const float pos[] = 368 { 369 -1.0f, -1.0f, 370 -1.0f, 1.0f, 371 1.0f, -1.0f, 372 1.0f, 1.0f 373 }; 374 gl.vertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, &pos[0]); 375 376 for (int ndx = 0; ndx < numSteps; ndx++) 377 { 378 int s = step*ndx; 379 float c = (float)ndx / (float)(numSteps-1); 380 381 gl.stencilFunc (GL_LEQUAL, s, 0xffu); 382 gl.uniform4f (colorLoc, 0.0f, c, 0.0f, 1.0f); 383 gl.drawElements (GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_BYTE, &indices[0]); 384 } 385 386 gl.disable(GL_STENCIL_TEST); 387 388 GLU_EXPECT_NO_ERROR(gl.getError(), "After stencil visualization"); 389 } 390 391 // Restore color mask (changed by visualization). 392 gl.colorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 393 394 glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess()); 395 } 396 397 void DepthStencilClearCase::renderReference (tcu::Surface& dst, const vector<Clear>& clears) 398 { 399 glu::RenderContext& renderCtx = TestCase::m_context.getRenderContext(); 400 const tcu::RenderTarget& renderTarget = renderCtx.getRenderTarget(); 401 402 // Clear surface to red. 403 tcu::clear(dst.getAccess(), tcu::RGBA::red.toVec()); 404 405 if (m_testDepth) 406 { 407 // Simulated depth buffer span. 408 tcu::TextureLevel depthBufRow (getDepthFormat(renderTarget.getDepthBits()), dst.getWidth(), 1, 1); 409 tcu::PixelBufferAccess rowAccess = depthBufRow.getAccess(); 410 411 for (int y = 0; y < dst.getHeight(); y++) 412 { 413 // Clear to default value. 414 for (int x = 0; x < rowAccess.getWidth(); x++) 415 rowAccess.setPixel(Vec4(1.0f), x, 0); 416 417 // Execute clears. 418 for (vector<Clear>::const_iterator clear = clears.begin(); clear != clears.end(); clear++) 419 { 420 // Clear / mask test. 421 if ((clear->clearMask & GL_DEPTH_BUFFER_BIT) == 0 || !clear->depthMask) 422 continue; 423 424 tcu::IVec4 clearRect = clear->useScissor ? clear->scissor : tcu::IVec4(0, 0, dst.getWidth(), dst.getHeight()); 425 426 // Intersection test. 427 if (!de::inBounds(y, clearRect.y(), clearRect.y()+clearRect.w())) 428 continue; 429 430 for (int x = clearRect.x(); x < clearRect.x()+clearRect.z(); x++) 431 rowAccess.setPixel(Vec4(de::clamp(clear->clearDepth, 0.0f, 1.0f)), x, 0); 432 } 433 434 // Map to colors. 435 for (int x = 0; x < dst.getWidth(); x++) 436 { 437 float depth = rowAccess.getPixel(x, 0).x(); 438 float step = deFloatFloor(depth * (float)DEPTH_STEPS) / (float)(DEPTH_STEPS-1); 439 tcu::RGBA oldColor = dst.getPixel(x, y); 440 tcu::RGBA newColor = tcu::RGBA(oldColor.getRed(), oldColor.getGreen(), deClamp32(deRoundFloatToInt32(step * 255.0f), 0, 255), oldColor.getAlpha()); 441 442 dst.setPixel(x, y, newColor); 443 } 444 } 445 } 446 447 if (m_testStencil) 448 { 449 // Simulated stencil buffer span. 450 int stencilBits = renderTarget.getStencilBits(); 451 tcu::TextureLevel depthBufRow (getStencilFormat(stencilBits), dst.getWidth(), 1, 1); 452 tcu::PixelBufferAccess rowAccess = depthBufRow.getAccess(); 453 deUint32 bufMask = (1u<<stencilBits)-1; 454 455 for (int y = 0; y < dst.getHeight(); y++) 456 { 457 // Clear to default value. 458 for (int x = 0; x < rowAccess.getWidth(); x++) 459 rowAccess.setPixel(tcu::UVec4(0), x, 0); 460 461 // Execute clears. 462 for (vector<Clear>::const_iterator clear = clears.begin(); clear != clears.end(); clear++) 463 { 464 // Clear / mask test. 465 if ((clear->clearMask & GL_STENCIL_BUFFER_BIT) == 0 || clear->stencilMask == 0) 466 continue; 467 468 tcu::IVec4 clearRect = clear->useScissor ? clear->scissor : tcu::IVec4(0, 0, dst.getWidth(), dst.getHeight()); 469 470 // Intersection test. 471 if (!de::inBounds(y, clearRect.y(), clearRect.y()+clearRect.w())) 472 continue; 473 474 for (int x = clearRect.x(); x < clearRect.x()+clearRect.z(); x++) 475 { 476 deUint32 oldVal = rowAccess.getPixelUint(x, 0).w(); 477 deUint32 newVal = ((oldVal & ~clear->stencilMask) | (clear->clearStencil & clear->stencilMask)) & bufMask; 478 rowAccess.setPixel(tcu::UVec4(newVal), x, 0); 479 } 480 } 481 482 // Map to colors. 483 for (int x = 0; x < dst.getWidth(); x++) 484 { 485 deUint32 stencil = rowAccess.getPixelUint(x, 0).w(); 486 float step = (float)(stencil / ((1u<<stencilBits) / (deUint32)STENCIL_STEPS)) / (float)(STENCIL_STEPS-1); 487 tcu::RGBA oldColor = dst.getPixel(x, y); 488 tcu::RGBA newColor = tcu::RGBA(oldColor.getRed(), deClamp32(deRoundFloatToInt32(step * 255.0f), 0, 255), oldColor.getBlue(), oldColor.getAlpha()); 489 490 dst.setPixel(x, y, newColor); 491 } 492 } 493 } 494 } 495 496 DepthStencilClearTests::DepthStencilClearTests (Context& context) 497 : TestCaseGroup(context, "depth_stencil_clear", "Depth and stencil clear tests") 498 { 499 } 500 501 void DepthStencilClearTests::init (void) 502 { 503 // iters clears depth stencil scissor masked 504 addChild(new DepthStencilClearCase(m_context, "depth", "", 4, 2, true, false, false, false)); 505 addChild(new DepthStencilClearCase(m_context, "depth_scissored", "", 4, 16, true, false, true, false)); 506 addChild(new DepthStencilClearCase(m_context, "depth_scissored_masked", "", 4, 16, true, false, true, true)); 507 508 addChild(new DepthStencilClearCase(m_context, "stencil", "", 4, 2, false, true, false, false)); 509 addChild(new DepthStencilClearCase(m_context, "stencil_masked", "", 4, 8, false, true, false, true)); 510 addChild(new DepthStencilClearCase(m_context, "stencil_scissored", "", 4, 16, false, true, true, false)); 511 addChild(new DepthStencilClearCase(m_context, "stencil_scissored_masked", "", 4, 16, false, true, true, true)); 512 513 addChild(new DepthStencilClearCase(m_context, "depth_stencil", "", 4, 2, true, true, false, false)); 514 addChild(new DepthStencilClearCase(m_context, "depth_stencil_masked", "", 4, 8, true, true, false, true)); 515 addChild(new DepthStencilClearCase(m_context, "depth_stencil_scissored", "", 4, 16, true, true, true, false)); 516 addChild(new DepthStencilClearCase(m_context, "depth_stencil_scissored_masked", "", 4, 16, true, true, true, true)); 517 } 518 519 } // Functional 520 } // gles2 521 } // deqp 522