| /*------------------------------------------------------------------------- |
| * drawElements Quality Program OpenGL ES 2.0 Module |
| * ------------------------------------------------- |
| * |
| * Copyright 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| *//*! |
| * \file |
| * \brief glDepthRangef() tests. |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "es2fDepthRangeTests.hpp" |
| #include "tcuVector.hpp" |
| #include "tcuTestLog.hpp" |
| #include "tcuSurface.hpp" |
| #include "tcuImageCompare.hpp" |
| #include "tcuRenderTarget.hpp" |
| #include "gluPixelTransfer.hpp" |
| #include "gluShaderProgram.hpp" |
| #include "gluRenderContext.hpp" |
| #include "deRandom.hpp" |
| #include "deMath.h" |
| #include "deString.h" |
| |
| #include "glw.h" |
| |
| namespace deqp |
| { |
| namespace gles2 |
| { |
| namespace Functional |
| { |
| |
| enum |
| { |
| VISUALIZE_DEPTH_STEPS = 32 //!< Number of depth steps in visualization |
| }; |
| |
| using tcu::Vec2; |
| using tcu::Vec3; |
| using tcu::Vec4; |
| using tcu::TestLog; |
| using std::string; |
| using std::vector; |
| |
| static const char* s_vertexShaderSrc = |
| "attribute highp vec4 a_position;\n" |
| "attribute highp vec2 a_coord;\n" |
| "void main (void)\n" |
| "{\n" |
| " gl_Position = a_position;\n" |
| "}\n"; |
| static const char* s_fragmentShaderSrc = |
| "uniform mediump vec4 u_color;\n" |
| "void main (void)\n" |
| "{\n" |
| " gl_FragColor = u_color;\n" |
| "}\n"; |
| |
| template <typename T> |
| static inline bool compare (deUint32 func, T a, T b) |
| { |
| switch (func) |
| { |
| case GL_NEVER: return false; |
| case GL_ALWAYS: return true; |
| case GL_LESS: return a < b; |
| case GL_LEQUAL: return a <= b; |
| case GL_EQUAL: return a == b; |
| case GL_NOTEQUAL: return a != b; |
| case GL_GEQUAL: return a >= b; |
| case GL_GREATER: return a > b; |
| default: |
| DE_ASSERT(DE_FALSE); |
| return false; |
| } |
| } |
| |
| inline float triangleInterpolate (const float v0, const float v1, const float v2, const float x, const float y) |
| { |
| return v0 + (v2-v0)*x + (v1-v0)*y; |
| } |
| |
| inline float triQuadInterpolate (const float x, const float y, const tcu::Vec4& quad) |
| { |
| // \note Top left fill rule. |
| if (x + y < 1.0f) |
| return triangleInterpolate(quad.x(), quad.y(), quad.z(), x, y); |
| else |
| return triangleInterpolate(quad.w(), quad.z(), quad.y(), 1.0f-x, 1.0f-y); |
| } |
| |
| inline float depthRangeTransform (const float zd, const float zNear, const float zFar) |
| { |
| const float cNear = de::clamp(zNear, 0.0f, 1.0f); |
| const float cFar = de::clamp(zFar, 0.0f, 1.0f); |
| return ((cFar - cNear)/2.0f) * zd + (cNear + cFar)/2.0f; |
| } |
| |
| class DepthRangeCompareCase : public TestCase |
| { |
| public: |
| DepthRangeCompareCase (Context& context, const char* name, const char* desc, const tcu::Vec4& depthCoord, const float zNear, const float zFar, const deUint32 compareFunc); |
| ~DepthRangeCompareCase (void); |
| |
| IterateResult iterate (void); |
| |
| private: |
| const tcu::Vec4 m_depthCoord; |
| const float m_zNear; |
| const float m_zFar; |
| const deUint32 m_compareFunc; |
| }; |
| |
| DepthRangeCompareCase::DepthRangeCompareCase (Context& context, const char* name, const char* desc, const tcu::Vec4& depthCoord, const float zNear, const float zFar, const deUint32 compareFunc) |
| : TestCase (context, name, desc) |
| , m_depthCoord (depthCoord) |
| , m_zNear (zNear) |
| , m_zFar (zFar) |
| , m_compareFunc (compareFunc) |
| { |
| } |
| |
| DepthRangeCompareCase::~DepthRangeCompareCase (void) |
| { |
| } |
| |
| DepthRangeCompareCase::IterateResult DepthRangeCompareCase::iterate (void) |
| { |
| TestLog& log = m_testCtx.getLog(); |
| de::Random rnd (deStringHash(getName())); |
| const tcu::RenderTarget& renderTarget = m_context.getRenderContext().getRenderTarget(); |
| const int viewportW = de::min(128, renderTarget.getWidth()); |
| const int viewportH = de::min(128, renderTarget.getHeight()); |
| const int viewportX = rnd.getInt(0, renderTarget.getWidth()-viewportW); |
| const int viewportY = rnd.getInt(0, renderTarget.getHeight()-viewportH); |
| tcu::Surface renderedFrame (viewportW, viewportH); |
| tcu::Surface referenceFrame (viewportW, viewportH); |
| const float constDepth = 0.1f; |
| |
| if (renderTarget.getDepthBits() == 0) |
| throw tcu::NotSupportedError("Depth buffer is required", "", __FILE__, __LINE__); |
| |
| const glu::ShaderProgram program (m_context.getRenderContext(), glu::makeVtxFragSources(s_vertexShaderSrc, s_fragmentShaderSrc)); |
| |
| if (!program.isOk()) |
| { |
| log << program; |
| TCU_FAIL("Compile failed"); |
| } |
| |
| const int colorLoc = glGetUniformLocation(program.getProgram(), "u_color"); |
| const int posLoc = glGetAttribLocation(program.getProgram(), "a_position"); |
| |
| m_testCtx.getLog() << TestLog::Message << "glDepthRangef(" << m_zNear << ", " << m_zFar << ")" << TestLog::EndMessage; |
| |
| glViewport(viewportX, viewportY, viewportW, viewportH); |
| glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); |
| glEnable(GL_DEPTH_TEST); |
| glUseProgram(program.getProgram()); |
| glEnableVertexAttribArray(posLoc); |
| |
| static const deUint16 quadIndices[] = { 0, 1, 2, 2, 1, 3 }; |
| |
| // Fill viewport with 2 quads - one with constant depth and another with d = [-1..1] |
| { |
| static const float constDepthCoord[] = |
| { |
| -1.0f, -1.0f, constDepth, 1.0f, |
| -1.0f, +1.0f, constDepth, 1.0f, |
| 0.0f, -1.0f, constDepth, 1.0f, |
| 0.0f, +1.0f, constDepth, 1.0f |
| }; |
| static const float varyingDepthCoord[] = |
| { |
| 0.0f, -1.0f, +1.0f, 1.0f, |
| 0.0f, +1.0f, 0.0f, 1.0f, |
| +1.0f, -1.0f, 0.0f, 1.0f, |
| +1.0f, +1.0f, -1.0f, 1.0f |
| }; |
| |
| glUniform4f(colorLoc, 0.0f, 0.0f, 1.0f, 1.0f); |
| glDepthFunc(GL_ALWAYS); |
| |
| glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &constDepthCoord); |
| glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(quadIndices), GL_UNSIGNED_SHORT, &quadIndices[0]); |
| |
| glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &varyingDepthCoord); |
| glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(quadIndices), GL_UNSIGNED_SHORT, &quadIndices[0]); |
| |
| GLU_CHECK(); |
| } |
| |
| // Render with depth test. |
| { |
| const float position[] = |
| { |
| -1.0f, -1.0f, m_depthCoord[0], 1.0f, |
| -1.0f, +1.0f, m_depthCoord[1], 1.0f, |
| +1.0f, -1.0f, m_depthCoord[2], 1.0f, |
| +1.0f, +1.0f, m_depthCoord[3], 1.0f |
| }; |
| |
| glDepthRangef(m_zNear, m_zFar); |
| glDepthFunc(m_compareFunc); |
| glUniform4f(colorLoc, 0.0f, 1.0f, 0.0f, 1.0f); |
| |
| glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &position[0]); |
| glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(quadIndices), GL_UNSIGNED_SHORT, &quadIndices[0]); |
| |
| GLU_CHECK(); |
| } |
| |
| glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, renderedFrame.getAccess()); |
| |
| // Render reference. |
| for (int y = 0; y < referenceFrame.getHeight(); y++) |
| { |
| float yf = ((float)y + 0.5f) / (float)referenceFrame.getHeight(); |
| int half = de::clamp((int)((float)referenceFrame.getWidth()*0.5f + 0.5f), 0, referenceFrame.getWidth()); |
| |
| // Fill left half - comparison to constant 0.5 |
| for (int x = 0; x < half; x++) |
| { |
| float xf = ((float)x + 0.5f) / (float)referenceFrame.getWidth(); |
| float d = depthRangeTransform(triQuadInterpolate(xf, yf, m_depthCoord), m_zNear, m_zFar); |
| bool dpass = compare(m_compareFunc, d, constDepth*0.5f + 0.5f); |
| |
| referenceFrame.setPixel(x, y, dpass ? tcu::RGBA::green() : tcu::RGBA::blue()); |
| } |
| |
| // Fill right half - comparison to interpolated depth |
| for (int x = half; x < referenceFrame.getWidth(); x++) |
| { |
| float xf = ((float)x + 0.5f) / (float)referenceFrame.getWidth(); |
| float xh = ((float)(x - half) + 0.5f) / (float)(referenceFrame.getWidth()-half); |
| float rd = 1.0f - (xh + yf) * 0.5f; |
| float d = depthRangeTransform(triQuadInterpolate(xf, yf, m_depthCoord), m_zNear, m_zFar); |
| bool dpass = compare(m_compareFunc, d, rd); |
| |
| referenceFrame.setPixel(x, y, dpass ? tcu::RGBA::green() : tcu::RGBA::blue()); |
| } |
| } |
| |
| bool isOk = tcu::fuzzyCompare(log, "Result", "Image comparison result", referenceFrame, renderedFrame, 0.05f, tcu::COMPARE_LOG_RESULT); |
| m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, |
| isOk ? "Pass" : "Fail"); |
| return STOP; |
| } |
| |
| class DepthRangeWriteCase : public TestCase |
| { |
| public: |
| DepthRangeWriteCase (Context& context, const char* name, const char* desc, const tcu::Vec4& depthCoord, const float zNear, const float zFar); |
| ~DepthRangeWriteCase (void); |
| |
| IterateResult iterate (void); |
| |
| private: |
| const tcu::Vec4& m_depthCoord; |
| const float m_zNear; |
| const float m_zFar; |
| }; |
| |
| DepthRangeWriteCase::DepthRangeWriteCase (Context& context, const char* name, const char* desc, const tcu::Vec4& depthCoord, const float zNear, const float zFar) |
| : TestCase (context, name, desc) |
| , m_depthCoord (depthCoord) |
| , m_zNear (zNear) |
| , m_zFar (zFar) |
| { |
| } |
| |
| DepthRangeWriteCase::~DepthRangeWriteCase (void) |
| { |
| } |
| |
| DepthRangeWriteCase::IterateResult DepthRangeWriteCase::iterate (void) |
| { |
| TestLog& log = m_testCtx.getLog(); |
| de::Random rnd (deStringHash(getName())); |
| const tcu::RenderTarget& renderTarget = m_context.getRenderContext().getRenderTarget(); |
| const int viewportW = de::min(128, renderTarget.getWidth()); |
| const int viewportH = de::min(128, renderTarget.getHeight()); |
| const int viewportX = rnd.getInt(0, renderTarget.getWidth()-viewportW); |
| const int viewportY = rnd.getInt(0, renderTarget.getHeight()-viewportH); |
| tcu::Surface renderedFrame (viewportW, viewportH); |
| tcu::Surface referenceFrame (viewportW, viewportH); |
| const int numDepthSteps = VISUALIZE_DEPTH_STEPS; |
| const float depthStep = 1.0f/(float)(numDepthSteps-1); |
| |
| if (renderTarget.getDepthBits() == 0) |
| throw tcu::NotSupportedError("Depth buffer is required", "", __FILE__, __LINE__); |
| |
| const glu::ShaderProgram program (m_context.getRenderContext(), glu::makeVtxFragSources(s_vertexShaderSrc, s_fragmentShaderSrc)); |
| |
| if (!program.isOk()) |
| { |
| log << program; |
| TCU_FAIL("Compile failed"); |
| } |
| |
| const int colorLoc = glGetUniformLocation(program.getProgram(), "u_color"); |
| const int posLoc = glGetAttribLocation(program.getProgram(), "a_position"); |
| |
| m_testCtx.getLog() << TestLog::Message << "glDepthRangef(" << m_zNear << ", " << m_zFar << ")" << TestLog::EndMessage; |
| |
| glViewport(viewportX, viewportY, viewportW, viewportH); |
| glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); |
| glEnable(GL_DEPTH_TEST); |
| glUseProgram(program.getProgram()); |
| glEnableVertexAttribArray(posLoc); |
| |
| static const deUint16 quadIndices[] = { 0, 1, 2, 2, 1, 3 }; |
| |
| // Render with depth range. |
| { |
| const float position[] = |
| { |
| -1.0f, -1.0f, m_depthCoord[0], 1.0f, |
| -1.0f, +1.0f, m_depthCoord[1], 1.0f, |
| +1.0f, -1.0f, m_depthCoord[2], 1.0f, |
| +1.0f, +1.0f, m_depthCoord[3], 1.0f |
| }; |
| |
| glDepthFunc(GL_ALWAYS); |
| glDepthRangef(m_zNear, m_zFar); |
| glUniform4f(colorLoc, 0.0f, 1.0f, 0.0f, 1.0f); |
| glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &position[0]); |
| glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(quadIndices), GL_UNSIGNED_SHORT, &quadIndices[0]); |
| GLU_CHECK(); |
| } |
| |
| // Visualize by rendering full-screen quads with increasing depth and color. |
| { |
| glDepthFunc(GL_LEQUAL); |
| glDepthMask(GL_FALSE); |
| glDepthRangef(0.0f, 1.0f); |
| |
| for (int stepNdx = 0; stepNdx < numDepthSteps; stepNdx++) |
| { |
| float f = (float)stepNdx*depthStep; |
| float depth = f*2.0f - 1.0f; |
| Vec4 color = Vec4(f, f, f, 1.0f); |
| |
| float position[] = |
| { |
| -1.0f, -1.0f, depth, 1.0f, |
| -1.0f, +1.0f, depth, 1.0f, |
| +1.0f, -1.0f, depth, 1.0f, |
| +1.0f, +1.0f, depth, 1.0f |
| }; |
| |
| glUniform4fv(colorLoc, 1, color.getPtr()); |
| glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &position[0]); |
| glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(quadIndices), GL_UNSIGNED_SHORT, &quadIndices[0]); |
| } |
| |
| GLU_CHECK(); |
| } |
| |
| glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, renderedFrame.getAccess()); |
| |
| // Render reference. |
| for (int y = 0; y < referenceFrame.getHeight(); y++) |
| { |
| for (int x = 0; x < referenceFrame.getWidth(); x++) |
| { |
| float xf = ((float)x + 0.5f) / (float)referenceFrame.getWidth(); |
| float yf = ((float)y + 0.5f) / (float)referenceFrame.getHeight(); |
| float d = depthRangeTransform(triQuadInterpolate(xf, yf, m_depthCoord), m_zNear, m_zFar); |
| int step = (int)deFloatFloor(d / depthStep); |
| int col = de::clamp(deRoundFloatToInt32((float)step*depthStep*255.0f), 0, 255); |
| |
| referenceFrame.setPixel(x, y, tcu::RGBA(col, col, col, 0xff)); |
| } |
| } |
| |
| bool isOk = tcu::fuzzyCompare(log, "Result", "Image comparison result", referenceFrame, renderedFrame, 0.05f, tcu::COMPARE_LOG_RESULT); |
| m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, |
| isOk ? "Pass" : "Fail"); |
| return STOP; |
| } |
| |
| DepthRangeTests::DepthRangeTests (Context& context) |
| : TestCaseGroup(context, "depth_range", "glDepthRangef() tests") |
| { |
| } |
| |
| DepthRangeTests::~DepthRangeTests (void) |
| { |
| } |
| |
| void DepthRangeTests::init (void) |
| { |
| static const struct |
| { |
| const char* name; |
| const char* desc; |
| const tcu::Vec4 depthCoord; |
| const float zNear; |
| const float zFar; |
| } cases[] = |
| { |
| { "default", "Default depth range", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), 0.0f, 1.0f }, |
| { "reverse", "Reversed default range", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), 1.0f, 0.0f }, |
| { "zero_to_half", "From 0 to 0.5", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), 0.0f, 0.5f }, |
| { "half_to_one", "From 0.5 to 1", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), 0.5f, 1.0f }, |
| { "half_to_zero", "From 0.5 to 0", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), 0.5f, 0.0f }, |
| { "one_to_half", "From 1 to 0.5", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), 1.0f, 0.5f }, |
| { "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 }, |
| { "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 }, |
| { "zero_to_zero", "From 0 to 0", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), 0.0f, 0.0f }, |
| { "half_to_half", "From 0.5 to 0.5", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), 0.5f, 0.5f }, |
| { "one_to_one", "From 1 to 1", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), 1.0f, 1.0f }, |
| { "clamp_near", "From -1 to 1", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), -1.0f, 1.0f }, |
| { "clamp_far", "From 0 to 2", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), 0.0f, 2.0 }, |
| { "clamp_both", "From -1 to 2", tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f), -1.0, 2.0 } |
| }; |
| |
| // .write |
| tcu::TestCaseGroup* writeGroup = new tcu::TestCaseGroup(m_testCtx, "write", "gl_FragDepth write tests"); |
| addChild(writeGroup); |
| for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(cases); ndx++) |
| writeGroup->addChild(new DepthRangeWriteCase(m_context, cases[ndx].name, cases[ndx].desc, cases[ndx].depthCoord, cases[ndx].zNear, cases[ndx].zFar)); |
| |
| // .compare |
| tcu::TestCaseGroup* compareGroup = new tcu::TestCaseGroup(m_testCtx, "compare", "gl_FragDepth used with depth comparison"); |
| addChild(compareGroup); |
| for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(cases); ndx++) |
| compareGroup->addChild(new DepthRangeCompareCase(m_context, cases[ndx].name, cases[ndx].desc, cases[ndx].depthCoord, cases[ndx].zNear, cases[ndx].zFar, GL_LESS)); |
| } |
| |
| } // Functional |
| } // gles3 |
| } // deqp |