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 glDepthRangef() tests. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "es2fDepthRangeTests.hpp" 25 #include "tcuVector.hpp" 26 #include "tcuTestLog.hpp" 27 #include "tcuSurface.hpp" 28 #include "tcuImageCompare.hpp" 29 #include "tcuRenderTarget.hpp" 30 #include "gluPixelTransfer.hpp" 31 #include "gluShaderProgram.hpp" 32 #include "gluRenderContext.hpp" 33 #include "deRandom.hpp" 34 #include "deMath.h" 35 #include "deString.h" 36 37 #include "glw.h" 38 39 namespace deqp 40 { 41 namespace gles2 42 { 43 namespace Functional 44 { 45 46 enum 47 { 48 VISUALIZE_DEPTH_STEPS = 32 //!< Number of depth steps in visualization 49 }; 50 51 using tcu::Vec2; 52 using tcu::Vec3; 53 using tcu::Vec4; 54 using tcu::TestLog; 55 using std::string; 56 using std::vector; 57 58 static const char* s_vertexShaderSrc = 59 "attribute highp vec4 a_position;\n" 60 "attribute highp vec2 a_coord;\n" 61 "void main (void)\n" 62 "{\n" 63 " gl_Position = a_position;\n" 64 "}\n"; 65 static const char* s_fragmentShaderSrc = 66 "uniform mediump vec4 u_color;\n" 67 "void main (void)\n" 68 "{\n" 69 " gl_FragColor = u_color;\n" 70 "}\n"; 71 72 template <typename T> 73 static inline bool compare (deUint32 func, T a, T b) 74 { 75 switch (func) 76 { 77 case GL_NEVER: return false; 78 case GL_ALWAYS: return true; 79 case GL_LESS: return a < b; 80 case GL_LEQUAL: return a <= b; 81 case GL_EQUAL: return a == b; 82 case GL_NOTEQUAL: return a != b; 83 case GL_GEQUAL: return a >= b; 84 case GL_GREATER: return a > b; 85 default: 86 DE_ASSERT(DE_FALSE); 87 return false; 88 } 89 } 90 91 inline float triangleInterpolate (const float v0, const float v1, const float v2, const float x, const float y) 92 { 93 return v0 + (v2-v0)*x + (v1-v0)*y; 94 } 95 96 inline float triQuadInterpolate (const float x, const float y, const tcu::Vec4& quad) 97 { 98 // \note Top left fill rule. 99 if (x + y < 1.0f) 100 return triangleInterpolate(quad.x(), quad.y(), quad.z(), x, y); 101 else 102 return triangleInterpolate(quad.w(), quad.z(), quad.y(), 1.0f-x, 1.0f-y); 103 } 104 105 inline float depthRangeTransform (const float zd, const float zNear, const float zFar) 106 { 107 const float cNear = de::clamp(zNear, 0.0f, 1.0f); 108 const float cFar = de::clamp(zFar, 0.0f, 1.0f); 109 return ((cFar - cNear)/2.0f) * zd + (cNear + cFar)/2.0f; 110 } 111 112 class DepthRangeCompareCase : public TestCase 113 { 114 public: 115 DepthRangeCompareCase (Context& context, const char* name, const char* desc, const tcu::Vec4& depthCoord, const float zNear, const float zFar, const deUint32 compareFunc); 116 ~DepthRangeCompareCase (void); 117 118 IterateResult iterate (void); 119 120 private: 121 const tcu::Vec4 m_depthCoord; 122 const float m_zNear; 123 const float m_zFar; 124 const deUint32 m_compareFunc; 125 }; 126 127 DepthRangeCompareCase::DepthRangeCompareCase (Context& context, const char* name, const char* desc, const tcu::Vec4& depthCoord, const float zNear, const float zFar, const deUint32 compareFunc) 128 : TestCase (context, name, desc) 129 , m_depthCoord (depthCoord) 130 , m_zNear (zNear) 131 , m_zFar (zFar) 132 , m_compareFunc (compareFunc) 133 { 134 } 135 136 DepthRangeCompareCase::~DepthRangeCompareCase (void) 137 { 138 } 139 140 DepthRangeCompareCase::IterateResult DepthRangeCompareCase::iterate (void) 141 { 142 TestLog& log = m_testCtx.getLog(); 143 de::Random rnd (deStringHash(getName())); 144 const tcu::RenderTarget& renderTarget = m_context.getRenderContext().getRenderTarget(); 145 const int viewportW = de::min(128, renderTarget.getWidth()); 146 const int viewportH = de::min(128, renderTarget.getHeight()); 147 const int viewportX = rnd.getInt(0, renderTarget.getWidth()-viewportW); 148 const int viewportY = rnd.getInt(0, renderTarget.getHeight()-viewportH); 149 tcu::Surface renderedFrame (viewportW, viewportH); 150 tcu::Surface referenceFrame (viewportW, viewportH); 151 const float constDepth = 0.1f; 152 153 if (renderTarget.getDepthBits() == 0) 154 throw tcu::NotSupportedError("Depth buffer is required", "", __FILE__, __LINE__); 155 156 const glu::ShaderProgram program (m_context.getRenderContext(), glu::makeVtxFragSources(s_vertexShaderSrc, s_fragmentShaderSrc)); 157 158 if (!program.isOk()) 159 { 160 log << program; 161 TCU_FAIL("Compile failed"); 162 } 163 164 const int colorLoc = glGetUniformLocation(program.getProgram(), "u_color"); 165 const int posLoc = glGetAttribLocation(program.getProgram(), "a_position"); 166 167 m_testCtx.getLog() << TestLog::Message << "glDepthRangef(" << m_zNear << ", " << m_zFar << ")" << TestLog::EndMessage; 168 169 glViewport(viewportX, viewportY, viewportW, viewportH); 170 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); 171 glEnable(GL_DEPTH_TEST); 172 glUseProgram(program.getProgram()); 173 glEnableVertexAttribArray(posLoc); 174 175 static const deUint16 quadIndices[] = { 0, 1, 2, 2, 1, 3 }; 176 177 // Fill viewport with 2 quads - one with constant depth and another with d = [-1..1] 178 { 179 static const float constDepthCoord[] = 180 { 181 -1.0f, -1.0f, constDepth, 1.0f, 182 -1.0f, +1.0f, constDepth, 1.0f, 183 0.0f, -1.0f, constDepth, 1.0f, 184 0.0f, +1.0f, constDepth, 1.0f 185 }; 186 static const float varyingDepthCoord[] = 187 { 188 0.0f, -1.0f, +1.0f, 1.0f, 189 0.0f, +1.0f, 0.0f, 1.0f, 190 +1.0f, -1.0f, 0.0f, 1.0f, 191 +1.0f, +1.0f, -1.0f, 1.0f 192 }; 193 194 glUniform4f(colorLoc, 0.0f, 0.0f, 1.0f, 1.0f); 195 glDepthFunc(GL_ALWAYS); 196 197 glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &constDepthCoord); 198 glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(quadIndices), GL_UNSIGNED_SHORT, &quadIndices[0]); 199 200 glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &varyingDepthCoord); 201 glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(quadIndices), GL_UNSIGNED_SHORT, &quadIndices[0]); 202 203 GLU_CHECK(); 204 } 205 206 // Render with depth test. 207 { 208 const float position[] = 209 { 210 -1.0f, -1.0f, m_depthCoord[0], 1.0f, 211 -1.0f, +1.0f, m_depthCoord[1], 1.0f, 212 +1.0f, -1.0f, m_depthCoord[2], 1.0f, 213 +1.0f, +1.0f, m_depthCoord[3], 1.0f 214 }; 215 216 glDepthRangef(m_zNear, m_zFar); 217 glDepthFunc(m_compareFunc); 218 glUniform4f(colorLoc, 0.0f, 1.0f, 0.0f, 1.0f); 219 220 glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &position[0]); 221 glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(quadIndices), GL_UNSIGNED_SHORT, &quadIndices[0]); 222 223 GLU_CHECK(); 224 } 225 226 glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, renderedFrame.getAccess()); 227 228 // Render reference. 229 for (int y = 0; y < referenceFrame.getHeight(); y++) 230 { 231 float yf = ((float)y + 0.5f) / referenceFrame.getHeight(); 232 int half = de::clamp((int)((float)referenceFrame.getWidth()*0.5f + 0.5f), 0, referenceFrame.getWidth()); 233 234 // Fill left half - comparison to constant 0.5 235 for (int x = 0; x < half; x++) 236 { 237 float xf = ((float)x + 0.5f) / (float)referenceFrame.getWidth(); 238 float d = depthRangeTransform(triQuadInterpolate(xf, yf, m_depthCoord), m_zNear, m_zFar); 239 bool dpass = compare(m_compareFunc, d, constDepth*0.5f + 0.5f); 240 241 referenceFrame.setPixel(x, y, dpass ? tcu::RGBA::green : tcu::RGBA::blue); 242 } 243 244 // Fill right half - comparison to interpolated depth 245 for (int x = half; x < referenceFrame.getWidth(); x++) 246 { 247 float xf = ((float)x + 0.5f) / (float)referenceFrame.getWidth(); 248 float xh = ((float)x - half + 0.5f) / (float)(referenceFrame.getWidth()-half); 249 float rd = 1.0f - (xh + yf) * 0.5f; 250 float d = depthRangeTransform(triQuadInterpolate(xf, yf, m_depthCoord), m_zNear, m_zFar); 251 bool dpass = compare(m_compareFunc, d, rd); 252 253 referenceFrame.setPixel(x, y, dpass ? tcu::RGBA::green : tcu::RGBA::blue); 254 } 255 } 256 257 bool isOk = tcu::fuzzyCompare(log, "Result", "Image comparison result", referenceFrame, renderedFrame, 0.05f, tcu::COMPARE_LOG_RESULT); 258 m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 259 isOk ? "Pass" : "Fail"); 260 return STOP; 261 } 262 263 class DepthRangeWriteCase : public TestCase 264 { 265 public: 266 DepthRangeWriteCase (Context& context, const char* name, const char* desc, const tcu::Vec4& depthCoord, const float zNear, const float zFar); 267 ~DepthRangeWriteCase (void); 268 269 IterateResult iterate (void); 270 271 private: 272 const tcu::Vec4& m_depthCoord; 273 const float m_zNear; 274 const float m_zFar; 275 }; 276 277 DepthRangeWriteCase::DepthRangeWriteCase (Context& context, const char* name, const char* desc, const tcu::Vec4& depthCoord, const float zNear, const float zFar) 278 : TestCase (context, name, desc) 279 , m_depthCoord (depthCoord) 280 , m_zNear (zNear) 281 , m_zFar (zFar) 282 { 283 } 284 285 DepthRangeWriteCase::~DepthRangeWriteCase (void) 286 { 287 } 288 289 DepthRangeWriteCase::IterateResult DepthRangeWriteCase::iterate (void) 290 { 291 TestLog& log = m_testCtx.getLog(); 292 de::Random rnd (deStringHash(getName())); 293 const tcu::RenderTarget& renderTarget = m_context.getRenderContext().getRenderTarget(); 294 const int viewportW = de::min(128, renderTarget.getWidth()); 295 const int viewportH = de::min(128, renderTarget.getHeight()); 296 const int viewportX = rnd.getInt(0, renderTarget.getWidth()-viewportW); 297 const int viewportY = rnd.getInt(0, renderTarget.getHeight()-viewportH); 298 tcu::Surface renderedFrame (viewportW, viewportH); 299 tcu::Surface referenceFrame (viewportW, viewportH); 300 const int numDepthSteps = VISUALIZE_DEPTH_STEPS; 301 const float depthStep = 1.0f/(float)(numDepthSteps-1); 302 303 if (renderTarget.getDepthBits() == 0) 304 throw tcu::NotSupportedError("Depth buffer is required", "", __FILE__, __LINE__); 305 306 const glu::ShaderProgram program (m_context.getRenderContext(), glu::makeVtxFragSources(s_vertexShaderSrc, s_fragmentShaderSrc)); 307 308 if (!program.isOk()) 309 { 310 log << program; 311 TCU_FAIL("Compile failed"); 312 } 313 314 const int colorLoc = glGetUniformLocation(program.getProgram(), "u_color"); 315 const int posLoc = glGetAttribLocation(program.getProgram(), "a_position"); 316 317 m_testCtx.getLog() << TestLog::Message << "glDepthRangef(" << m_zNear << ", " << m_zFar << ")" << TestLog::EndMessage; 318 319 glViewport(viewportX, viewportY, viewportW, viewportH); 320 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); 321 glEnable(GL_DEPTH_TEST); 322 glUseProgram(program.getProgram()); 323 glEnableVertexAttribArray(posLoc); 324 325 static const deUint16 quadIndices[] = { 0, 1, 2, 2, 1, 3 }; 326 327 // Render with depth range. 328 { 329 const float position[] = 330 { 331 -1.0f, -1.0f, m_depthCoord[0], 1.0f, 332 -1.0f, +1.0f, m_depthCoord[1], 1.0f, 333 +1.0f, -1.0f, m_depthCoord[2], 1.0f, 334 +1.0f, +1.0f, m_depthCoord[3], 1.0f 335 }; 336 337 glDepthFunc(GL_ALWAYS); 338 glDepthRangef(m_zNear, m_zFar); 339 glUniform4f(colorLoc, 0.0f, 1.0f, 0.0f, 1.0f); 340 glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &position[0]); 341 glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(quadIndices), GL_UNSIGNED_SHORT, &quadIndices[0]); 342 GLU_CHECK(); 343 } 344 345 // Visualize by rendering full-screen quads with increasing depth and color. 346 { 347 glDepthFunc(GL_LEQUAL); 348 glDepthMask(GL_FALSE); 349 glDepthRangef(0.0f, 1.0f); 350 351 for (int stepNdx = 0; stepNdx < numDepthSteps; stepNdx++) 352 { 353 float f = (float)stepNdx*depthStep; 354 float depth = f*2.0f - 1.0f; 355 Vec4 color = Vec4(f, f, f, 1.0f); 356 357 float position[] = 358 { 359 -1.0f, -1.0f, depth, 1.0f, 360 -1.0f, +1.0f, depth, 1.0f, 361 +1.0f, -1.0f, depth, 1.0f, 362 +1.0f, +1.0f, depth, 1.0f 363 }; 364 365 glUniform4fv(colorLoc, 1, color.getPtr()); 366 glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &position[0]); 367 glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(quadIndices), GL_UNSIGNED_SHORT, &quadIndices[0]); 368 } 369 370 GLU_CHECK(); 371 } 372 373 glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, renderedFrame.getAccess()); 374 375 // Render reference. 376 for (int y = 0; y < referenceFrame.getHeight(); y++) 377 { 378 for (int x = 0; x < referenceFrame.getWidth(); x++) 379 { 380 float xf = ((float)x + 0.5f) / (float)referenceFrame.getWidth(); 381 float yf = ((float)y + 0.5f) / (float)referenceFrame.getHeight(); 382 float d = depthRangeTransform(triQuadInterpolate(xf, yf, m_depthCoord), m_zNear, m_zFar); 383 int step = (int)deFloatFloor(d / depthStep); 384 int col = de::clamp(deRoundFloatToInt32((float)step*depthStep*255.0f), 0, 255); 385 386 referenceFrame.setPixel(x, y, tcu::RGBA(col, col, col, 0xff)); 387 } 388 } 389 390 bool isOk = tcu::fuzzyCompare(log, "Result", "Image comparison result", referenceFrame, renderedFrame, 0.05f, tcu::COMPARE_LOG_RESULT); 391 m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 392 isOk ? "Pass" : "Fail"); 393 return STOP; 394 } 395 396 DepthRangeTests::DepthRangeTests (Context& context) 397 : TestCaseGroup(context, "depth_range", "glDepthRangef() tests") 398 { 399 } 400 401 DepthRangeTests::~DepthRangeTests (void) 402 { 403 } 404 405 void DepthRangeTests::init (void) 406 { 407 static const struct 408 { 409 const char* name; 410 const char* desc; 411 const tcu::Vec4 depthCoord; 412 const float zNear; 413 const float zFar; 414 } cases[] = 415 { 416 { "default", "Default depth range", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), 0.0f, 1.0f }, 417 { "reverse", "Reversed default range", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), 1.0f, 0.0f }, 418 { "zero_to_half", "From 0 to 0.5", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), 0.0f, 0.5f }, 419 { "half_to_one", "From 0.5 to 1", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), 0.5f, 1.0f }, 420 { "half_to_zero", "From 0.5 to 0", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), 0.5f, 0.0f }, 421 { "one_to_half", "From 1 to 0.5", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), 1.0f, 0.5f }, 422 { "third_to_0_8", "From 1/3 to 0.8", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), 1.0f/3.0f, 0.8f }, 423 { "0_8_to_third", "From 0.8 to 1/3", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), 0.8f, 1.0f/3.0f }, 424 { "zero_to_zero", "From 0 to 0", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), 0.0f, 0.0f }, 425 { "half_to_half", "From 0.5 to 0.5", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), 0.5f, 0.5f }, 426 { "one_to_one", "From 1 to 1", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), 1.0f, 1.0f }, 427 { "clamp_near", "From -1 to 1", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), -1.0f, 1.0f }, 428 { "clamp_far", "From 0 to 2", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), 0.0f, 2.0 }, 429 { "clamp_both", "From -1 to 2", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), -1.0, 2.0 } 430 }; 431 432 // .write 433 tcu::TestCaseGroup* writeGroup = new tcu::TestCaseGroup(m_testCtx, "write", "gl_FragDepth write tests"); 434 addChild(writeGroup); 435 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(cases); ndx++) 436 writeGroup->addChild(new DepthRangeWriteCase(m_context, cases[ndx].name, cases[ndx].desc, cases[ndx].depthCoord, cases[ndx].zNear, cases[ndx].zFar)); 437 438 // .compare 439 tcu::TestCaseGroup* compareGroup = new tcu::TestCaseGroup(m_testCtx, "compare", "gl_FragDepth used with depth comparison"); 440 addChild(compareGroup); 441 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(cases); ndx++) 442 compareGroup->addChild(new DepthRangeCompareCase(m_context, cases[ndx].name, cases[ndx].desc, cases[ndx].depthCoord, cases[ndx].zNear, cases[ndx].zFar, GL_LESS)); 443 } 444 445 } // Functional 446 } // gles3 447 } // deqp 448