| /*------------------------------------------------------------------------- |
| * drawElements Quality Program OpenGL (ES) 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 GLES Scissor tests |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "glsScissorTests.hpp" |
| #include "glsTextureTestUtil.hpp" |
| |
| #include "deMath.h" |
| #include "deRandom.hpp" |
| #include "deUniquePtr.hpp" |
| |
| #include "tcuTestCase.hpp" |
| #include "tcuImageCompare.hpp" |
| #include "tcuVector.hpp" |
| #include "tcuVectorUtil.hpp" |
| #include "tcuTexture.hpp" |
| #include "tcuStringTemplate.hpp" |
| |
| #include "gluStrUtil.hpp" |
| #include "gluDrawUtil.hpp" |
| #include "gluPixelTransfer.hpp" |
| #include "gluObjectWrapper.hpp" |
| |
| #include "glwEnums.hpp" |
| #include "glwFunctions.hpp" |
| |
| #include <map> |
| |
| namespace deqp |
| { |
| namespace gls |
| { |
| namespace Functional |
| { |
| namespace |
| { |
| |
| using namespace ScissorTestInternal; |
| using namespace glw; // GL types |
| |
| using tcu::ConstPixelBufferAccess; |
| using tcu::PixelBufferAccess; |
| using tcu::TestLog; |
| |
| using std::vector; |
| using std::string; |
| using std::map; |
| using tcu::Vec3; |
| using tcu::Vec4; |
| using tcu::IVec4; |
| using tcu::UVec4; |
| |
| void drawQuad (const glw::Functions& gl, deUint32 program, const Vec3& p0, const Vec3& p1) |
| { |
| // Vertex data. |
| const float hz = (p0.z() + p1.z()) * 0.5f; |
| const float position[] = |
| { |
| p0.x(), p0.y(), p0.z(), 1.0f, |
| p0.x(), p1.y(), hz, 1.0f, |
| p1.x(), p0.y(), hz, 1.0f, |
| p1.x(), p1.y(), p1.z(), 1.0f |
| }; |
| |
| const deUint16 indices[] = { 0, 1, 2, 2, 1, 3 }; |
| |
| const deInt32 posLoc = gl.getAttribLocation(program, "a_position"); |
| |
| gl.useProgram(program); |
| gl.enableVertexAttribArray(posLoc); |
| gl.vertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &position[0]); |
| |
| gl.drawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_SHORT, &indices[0]); |
| |
| gl.disableVertexAttribArray(posLoc); |
| |
| } |
| |
| void drawPrimitives (const glw::Functions& gl, deUint32 program, const deUint32 type, const vector<float>& vertices, const vector<deUint16>& indices) |
| { |
| const deInt32 posLoc = gl.getAttribLocation(program, "a_position"); |
| |
| TCU_CHECK(posLoc >= 0); |
| |
| gl.useProgram(program); |
| gl.enableVertexAttribArray(posLoc); |
| gl.vertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &vertices[0]); |
| |
| gl.drawElements(type, GLsizei(indices.size()), GL_UNSIGNED_SHORT, &indices[0]); |
| |
| gl.disableVertexAttribArray(posLoc); |
| } |
| |
| template<typename T> |
| void clearEdges (const tcu::PixelBufferAccess& access, const T& color, const IVec4& scissorArea) |
| { |
| for (int y = 0; y < access.getHeight(); y++) |
| for (int x = 0; x < access.getWidth(); x++) |
| { |
| if (y < scissorArea.y() || |
| y >= scissorArea.y() + scissorArea.w() || |
| x < scissorArea.x() || |
| x >= scissorArea.x()+ scissorArea.z()) |
| access.setPixel(color, x, y); |
| } |
| } |
| |
| glu::ProgramSources genShaders(glu::GLSLVersion version, bool isPoint) |
| { |
| string vtxSource; |
| |
| if (isPoint) |
| { |
| vtxSource = "${VERSION}\n" |
| "${IN} highp vec4 a_position;\n" |
| "void main(){\n" |
| " gl_Position = a_position;\n" |
| " gl_PointSize = 1.0;\n" |
| "}\n"; |
| } |
| else |
| { |
| vtxSource = "${VERSION}\n" |
| "${IN} highp vec4 a_position;\n" |
| "void main(){\n" |
| " gl_Position = a_position;\n" |
| "}\n"; |
| } |
| |
| const string frgSource = "${VERSION}\n" |
| "${OUT_DECL}" |
| "uniform highp vec4 u_color;\n" |
| "void main(){\n" |
| " ${OUTPUT} = u_color;\n" |
| "}\n"; |
| |
| map<string, string> params; |
| |
| switch(version) |
| { |
| case glu::GLSL_VERSION_100_ES: |
| params["VERSION"] = "#version 100"; |
| params["IN"] = "attribute"; |
| params["OUT_DECL"] = ""; |
| params["OUTPUT"] = "gl_FragColor"; |
| break; |
| |
| case glu::GLSL_VERSION_300_ES: |
| case glu::GLSL_VERSION_310_ES: // Assumed to support 3.0 |
| params["VERSION"] = "#version 300 es"; |
| params["IN"] = "in"; |
| params["OUT_DECL"] = "out mediump vec4 f_color;\n"; |
| params["OUTPUT"] = "f_color"; |
| break; |
| |
| default: |
| DE_FATAL("Unsupported version"); |
| } |
| |
| return glu::makeVtxFragSources(tcu::StringTemplate(vtxSource).specialize(params), tcu::StringTemplate(frgSource).specialize(params)); |
| } |
| |
| // Wrapper class, provides iterator & reporting logic |
| class ScissorCase : public tcu::TestCase |
| { |
| public: |
| ScissorCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char *name, const char* desc, const Vec4& scissorArea); |
| virtual ~ScissorCase (void) {} |
| |
| virtual IterateResult iterate (void); |
| |
| protected: |
| virtual void render (GLuint program, const IVec4& viewport) const = 0; |
| |
| // Initialize gl_PointSize to 1.0f when drawing points, or the point size is undefined according to spec. |
| virtual bool isPoint (void) const = 0; |
| |
| glu::RenderContext& m_renderCtx; |
| const Vec4 m_scissorArea; |
| }; |
| |
| ScissorCase::ScissorCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char *name, const char* desc, const Vec4& scissorArea) |
| : TestCase (testCtx, name, desc) |
| , m_renderCtx (renderCtx) |
| , m_scissorArea (scissorArea) |
| { |
| } |
| |
| ScissorCase::IterateResult ScissorCase::iterate (void) |
| { |
| using TextureTestUtil::RandomViewport; |
| |
| const glw::Functions& gl = m_renderCtx.getFunctions(); |
| TestLog& log = m_testCtx.getLog(); |
| const tcu::PixelFormat renderFormat = m_renderCtx.getRenderTarget().getPixelFormat(); |
| const tcu::Vec4 threshold = 0.02f * UVec4(1u << de::max(0, 8 - renderFormat.redBits), |
| 1u << de::max(0, 8 - renderFormat.greenBits), |
| 1u << de::max(0, 8 - renderFormat.blueBits), |
| 1u << de::max(0, 8 - renderFormat.alphaBits)).asFloat(); |
| const glu::ShaderProgram shader (m_renderCtx, genShaders(glu::getContextTypeGLSLVersion(m_renderCtx.getType()), isPoint())); |
| |
| const RandomViewport viewport (m_renderCtx.getRenderTarget(), 256, 256, deStringHash(getName())); |
| const IVec4 relScissorArea (int(m_scissorArea.x() * (float)viewport.width), |
| int(m_scissorArea.y() * (float)viewport.height), |
| int(m_scissorArea.z() * (float)viewport.width), |
| int(m_scissorArea.w() * (float)viewport.height)); |
| const IVec4 absScissorArea (relScissorArea.x() + viewport.x, |
| relScissorArea.y() + viewport.y, |
| relScissorArea.z(), |
| relScissorArea.w()); |
| |
| tcu::Surface refImage (viewport.width, viewport.height); |
| tcu::Surface resImage (viewport.width, viewport.height); |
| |
| if (!shader.isOk()) |
| { |
| log << shader; |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Shader compile/link failed"); |
| return STOP; |
| } |
| |
| log << TestLog::Message << "Viewport area is " << IVec4(viewport.x, viewport.y, viewport.width, viewport.height) << TestLog::EndMessage; |
| log << TestLog::Message << "Scissor area is " << absScissorArea << TestLog::EndMessage; |
| |
| // Render reference (no scissors) |
| { |
| log << TestLog::Message << "Rendering reference (scissors disabled)" << TestLog::EndMessage; |
| |
| gl.useProgram(shader.getProgram()); |
| gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height); |
| |
| gl.clearColor(0.125f, 0.25f, 0.5f, 1.0f); |
| gl.clearDepthf(1.0f); |
| gl.clearStencil(0); |
| gl.disable(GL_DEPTH_TEST); |
| gl.disable(GL_STENCIL_TEST); |
| gl.disable(GL_SCISSOR_TEST); |
| gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| render(shader.getProgram(), IVec4(viewport.x, viewport.y, viewport.width, viewport.height)); |
| |
| glu::readPixels(m_renderCtx, viewport.x, viewport.y, refImage.getAccess()); |
| GLU_CHECK_ERROR(gl.getError()); |
| } |
| |
| // Render result (scissors) |
| { |
| log << TestLog::Message << "Rendering result (scissors enabled)" << TestLog::EndMessage; |
| |
| gl.useProgram(shader.getProgram()); |
| gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height); |
| |
| gl.clearColor(0.125f, 0.25f, 0.5f, 1.0f); |
| gl.clearDepthf(1.0f); |
| gl.clearStencil(0); |
| gl.disable(GL_DEPTH_TEST); |
| gl.disable(GL_STENCIL_TEST); |
| gl.disable(GL_SCISSOR_TEST); |
| gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| |
| gl.scissor(absScissorArea.x(), absScissorArea.y(), absScissorArea.z(), absScissorArea.w()); |
| gl.enable(GL_SCISSOR_TEST); |
| |
| render(shader.getProgram(), IVec4(viewport.x, viewport.y, viewport.width, viewport.height)); |
| |
| glu::readPixels(m_renderCtx, viewport.x, viewport.y, resImage.getAccess()); |
| GLU_CHECK_ERROR(gl.getError()); |
| } |
| |
| // Manual 'scissors' for reference image |
| log << TestLog::Message << "Clearing area outside scissor area from reference" << TestLog::EndMessage; |
| clearEdges(refImage.getAccess(), IVec4(32, 64, 128, 255), relScissorArea); |
| |
| if (tcu::floatThresholdCompare(log, "ComparisonResult", "Image comparison result", refImage.getAccess(), resImage.getAccess(), threshold, tcu::COMPARE_LOG_RESULT)) |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| else |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed"); |
| |
| return STOP; |
| } |
| |
| // Tests scissoring with multiple primitive types |
| class ScissorPrimitiveCase : public ScissorCase |
| { |
| public: |
| ScissorPrimitiveCase (tcu::TestContext& testCtx, |
| glu::RenderContext& renderCtx, |
| const char* name, |
| const char* desc, |
| const Vec4& scissorArea, |
| const Vec4& renderArea, |
| PrimitiveType type, |
| int primitiveCount); |
| virtual ~ScissorPrimitiveCase (void){} |
| |
| protected: |
| virtual void render (GLuint program, const IVec4& viewport) const; |
| virtual bool isPoint (void) const; |
| |
| private: |
| const Vec4 m_renderArea; |
| const PrimitiveType m_primitiveType; |
| const int m_primitiveCount; |
| }; |
| |
| ScissorPrimitiveCase::ScissorPrimitiveCase (tcu::TestContext& testCtx, |
| glu::RenderContext& renderCtx, |
| const char* name, |
| const char* desc, |
| const Vec4& scissorArea, |
| const Vec4& renderArea, |
| PrimitiveType type, |
| int primitiveCount) |
| : ScissorCase (testCtx, renderCtx, name, desc, scissorArea) |
| , m_renderArea (renderArea) |
| , m_primitiveType (type) |
| , m_primitiveCount (primitiveCount) |
| { |
| } |
| |
| bool ScissorPrimitiveCase::isPoint (void) const |
| { |
| return (m_primitiveType == POINT); |
| } |
| |
| void ScissorPrimitiveCase::render (GLuint program, const IVec4&) const |
| { |
| const glw::Functions& gl = m_renderCtx.getFunctions(); |
| const Vec4 white (1.0f, 1.0f, 1.0f, 1.0); |
| const Vec4 primitiveArea (m_renderArea.x()*2.0f-1.0f, |
| m_renderArea.x()*2.0f-1.0f, |
| m_renderArea.z()*2.0f, |
| m_renderArea.w()*2.0f); |
| |
| static const float quadPositions[] = |
| { |
| 0.0f, 1.0f, |
| 0.0f, 0.0f, |
| 1.0f, 1.0f, |
| 1.0f, 0.0f |
| }; |
| static const float triPositions[] = |
| { |
| 0.0f, 0.0f, |
| 1.0f, 0.0f, |
| 0.5f, 1.0f, |
| }; |
| static const float linePositions[] = |
| { |
| 0.0f, 0.0f, |
| 1.0f, 1.0f |
| }; |
| static const float pointPosition[] = |
| { |
| 0.5f, 0.5f |
| }; |
| |
| const float* positionSet[] = { pointPosition, linePositions, triPositions, quadPositions }; |
| const int vertexCountSet[]= { 1, 2, 3, 4 }; |
| const int indexCountSet[] = { 1, 2, 3, 6 }; |
| |
| const deUint16 baseIndices[] = { 0, 1, 2, 2, 1, 3 }; |
| const float* basePositions = positionSet[m_primitiveType]; |
| const int vertexCount = vertexCountSet[m_primitiveType]; |
| const int indexCount = indexCountSet[m_primitiveType]; |
| |
| const float scale = 1.44f/deFloatSqrt(float(m_primitiveCount)*2.0f); // Magic value to roughly fill the render area with primitives at a readable density |
| vector<float> positions (4*vertexCount*m_primitiveCount); |
| vector<deUint16> indices (indexCount*m_primitiveCount); |
| de::Random rng (1234); |
| |
| for (int primNdx = 0; primNdx < m_primitiveCount; primNdx++) |
| { |
| const float dx = m_primitiveCount>1 ? rng.getFloat() : 0.0f; |
| const float dy = m_primitiveCount>1 ? rng.getFloat() : 0.0f; |
| |
| for (int vertNdx = 0; vertNdx < vertexCount; vertNdx++) |
| { |
| const int ndx = primNdx*4*vertexCount + vertNdx*4; |
| positions[ndx+0] = (basePositions[vertNdx*2 + 0]*scale + dx)*primitiveArea.z() + primitiveArea.x(); |
| positions[ndx+1] = (basePositions[vertNdx*2 + 1]*scale + dy)*primitiveArea.w() + primitiveArea.y(); |
| positions[ndx+2] = 0.2f; |
| positions[ndx+3] = 1.0f; |
| } |
| |
| for (int ndx = 0; ndx < indexCount; ndx++) |
| indices[primNdx*indexCount + ndx] = (deUint16)(baseIndices[ndx] + primNdx*vertexCount); |
| } |
| |
| gl.uniform4fv(gl.getUniformLocation(program, "u_color"), 1, white.m_data); |
| |
| switch (m_primitiveType) |
| { |
| case TRIANGLE: drawPrimitives(gl, program, GL_TRIANGLES, positions, indices); break; |
| case LINE: drawPrimitives(gl, program, GL_LINES, positions, indices); break; |
| case POINT: drawPrimitives(gl, program, GL_POINTS, positions, indices); break; |
| default: DE_ASSERT(false); break; |
| } |
| } |
| |
| // Test effect of scissor on default framebuffer clears |
| class ScissorClearCase : public ScissorCase |
| { |
| public: |
| ScissorClearCase (tcu::TestContext& testCtx, |
| glu::RenderContext& renderCtx, |
| const char* name, |
| const char* desc, |
| const Vec4& scissorArea, |
| deUint32 clearMode); |
| virtual ~ScissorClearCase (void) {} |
| |
| virtual void init (void); |
| |
| protected: |
| virtual void render (GLuint program, const IVec4& viewport) const; |
| virtual bool isPoint (void) const; |
| |
| private: |
| const deUint32 m_clearMode; //!< Combination of the flags accepted by glClear |
| }; |
| |
| ScissorClearCase::ScissorClearCase (tcu::TestContext& testCtx, |
| glu::RenderContext& renderCtx, |
| const char* name, |
| const char* desc, |
| const Vec4& scissorArea, |
| deUint32 clearMode) |
| : ScissorCase (testCtx, renderCtx, name, desc, scissorArea) |
| , m_clearMode (clearMode) |
| { |
| } |
| |
| void ScissorClearCase::init (void) |
| { |
| if ((m_clearMode & GL_DEPTH_BUFFER_BIT) && m_renderCtx.getRenderTarget().getDepthBits() == 0) |
| throw tcu::NotSupportedError("Cannot clear depth; no depth buffer present", "", __FILE__, __LINE__); |
| else if ((m_clearMode & GL_STENCIL_BUFFER_BIT) && m_renderCtx.getRenderTarget().getStencilBits() == 0) |
| throw tcu::NotSupportedError("Cannot clear stencil; no stencil buffer present", "", __FILE__, __LINE__); |
| } |
| |
| bool ScissorClearCase::isPoint (void) const |
| { |
| return false; |
| } |
| |
| void ScissorClearCase::render (GLuint program, const IVec4&) const |
| { |
| const glw::Functions& gl = m_renderCtx.getFunctions(); |
| const Vec4 white (1.0f, 1.0f, 1.0f, 1.0); |
| |
| gl.clearColor(0.6f, 0.1f, 0.1f, 1.0); |
| gl.clearDepthf(0.0f); |
| |
| if (m_clearMode & GL_DEPTH_BUFFER_BIT) |
| { |
| gl.enable(GL_DEPTH_TEST); |
| gl.depthFunc(GL_GREATER); |
| } |
| |
| if (m_clearMode & GL_STENCIL_BUFFER_BIT) |
| { |
| gl.clearStencil(123); |
| gl.enable(GL_STENCIL_TEST); |
| gl.stencilFunc(GL_EQUAL, 123, ~0u); |
| } |
| |
| if (m_clearMode & GL_COLOR_BUFFER_BIT) |
| gl.clearColor(0.1f, 0.6f, 0.1f, 1.0); |
| |
| gl.clear(m_clearMode); |
| gl.disable(GL_SCISSOR_TEST); |
| |
| gl.uniform4fv(gl.getUniformLocation(program, "u_color"), 1, white.getPtr()); |
| |
| if (!(m_clearMode & GL_COLOR_BUFFER_BIT)) |
| drawQuad(gl, program, Vec3(-1.0f, -1.0f, 0.5f), Vec3(1.0f, 1.0f, 0.5f)); |
| |
| gl.disable(GL_DEPTH_TEST); |
| gl.disable(GL_STENCIL_TEST); |
| } |
| |
| class FramebufferBlitCase : public ScissorCase |
| { |
| public: |
| FramebufferBlitCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, const Vec4& scissorArea); |
| virtual ~FramebufferBlitCase (void) {} |
| |
| virtual void init (void); |
| virtual void deinit (void); |
| |
| protected: |
| typedef de::MovePtr<glu::Framebuffer> FramebufferP; |
| |
| enum {SIZE = 64}; |
| |
| virtual void render (GLuint program, const IVec4& viewport) const; |
| virtual bool isPoint (void) const; |
| |
| FramebufferP m_fbo; |
| }; |
| |
| FramebufferBlitCase::FramebufferBlitCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, const Vec4& scissorArea) |
| : ScissorCase(testCtx, renderCtx, name, desc, scissorArea) |
| { |
| } |
| |
| void FramebufferBlitCase::init (void) |
| { |
| if (m_renderCtx.getRenderTarget().getNumSamples()) |
| throw tcu::NotSupportedError("Cannot blit to multisampled framebuffer", "", __FILE__, __LINE__); |
| |
| const glw::Functions& gl = m_renderCtx.getFunctions(); |
| const glu::Renderbuffer colorbuf (gl); |
| const tcu::Vec4 clearColor (1.0f, 0.5, 0.125f, 1.0f); |
| |
| m_fbo = FramebufferP(new glu::Framebuffer(gl)); |
| |
| gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, **m_fbo); |
| |
| gl.bindRenderbuffer(GL_RENDERBUFFER, *colorbuf); |
| gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, SIZE, SIZE); |
| gl.framebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, *colorbuf); |
| |
| gl.clearBufferfv(GL_COLOR, 0, clearColor.getPtr()); |
| gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, m_renderCtx.getDefaultFramebuffer()); |
| } |
| |
| void FramebufferBlitCase::deinit (void) |
| { |
| m_fbo.clear(); |
| } |
| |
| bool FramebufferBlitCase::isPoint (void) const |
| { |
| return false; |
| } |
| |
| void FramebufferBlitCase::render(GLuint program, const IVec4& viewport) const |
| { |
| const glw::Functions& gl = m_renderCtx.getFunctions(); |
| |
| const int width = viewport.z(); |
| const int height = viewport.w(); |
| const deInt32 defaultFramebuffer = m_renderCtx.getDefaultFramebuffer(); |
| |
| DE_UNREF(program); |
| |
| // blit to default framebuffer |
| gl.bindFramebuffer(GL_READ_FRAMEBUFFER, **m_fbo); |
| gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, defaultFramebuffer); |
| |
| gl.blitFramebuffer(0, 0, SIZE, SIZE, viewport.x(), viewport.y(), viewport.x() + width, viewport.y() + height, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| |
| gl.bindFramebuffer(GL_READ_FRAMEBUFFER, defaultFramebuffer); |
| } |
| |
| struct BufferFmtDesc |
| { |
| tcu::TextureFormat texFmt; |
| GLenum colorFmt; |
| }; |
| |
| struct Color |
| { |
| enum Type {FLOAT, INT, UINT}; |
| |
| Type type; |
| |
| union |
| { |
| float f[4]; |
| deInt32 i[4]; |
| deUint32 u[4]; |
| }; |
| |
| Color(const float f_[4]) : type(FLOAT) { f[0] = f_[0]; f[1] = f_[1]; f[2] = f_[2]; f[3] = f_[3]; } |
| Color(const deInt32 i_[4]) : type(INT) { i[0] = i_[0]; i[1] = i_[1]; i[2] = i_[2]; i[3] = i_[3]; } |
| Color(const deUint32 u_[4]) : type(UINT) { u[0] = u_[0]; u[1] = u_[1]; u[2] = u_[2]; u[3] = u_[3]; } |
| }; |
| |
| class FramebufferClearCase : public tcu::TestCase |
| { |
| public: |
| FramebufferClearCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, ClearType clearType); |
| virtual ~FramebufferClearCase (void) {} |
| |
| virtual IterateResult iterate (void); |
| |
| private: |
| static void clearBuffers (const glw::Functions& gl, Color color, float depth, int stencil); |
| static Color getBaseColor (const BufferFmtDesc& bufferFmt); |
| static Color getMainColor (const BufferFmtDesc& bufferFmt); |
| static BufferFmtDesc getBufferFormat (ClearType type); |
| |
| virtual void render (GLuint program) const; |
| virtual bool isPoint (void) const; |
| |
| glu::RenderContext& m_renderCtx; |
| const ClearType m_clearType; |
| }; |
| |
| FramebufferClearCase::FramebufferClearCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc, ClearType clearType) |
| : tcu::TestCase (testCtx, name, desc) |
| , m_renderCtx (renderCtx) |
| , m_clearType (clearType) |
| { |
| } |
| |
| void FramebufferClearCase::clearBuffers (const glw::Functions& gl, Color color, float depth, int stencil) |
| { |
| switch(color.type) |
| { |
| case Color::FLOAT: gl.clearBufferfv (GL_COLOR, 0, color.f); break; |
| case Color::INT: gl.clearBufferiv (GL_COLOR, 0, color.i); break; |
| case Color::UINT: gl.clearBufferuiv(GL_COLOR, 0, color.u); break; |
| default: |
| DE_ASSERT(false); |
| } |
| |
| gl.clearBufferfv(GL_DEPTH, 0, &depth); |
| gl.clearBufferiv(GL_STENCIL, 0, &stencil); |
| } |
| |
| FramebufferClearCase::IterateResult FramebufferClearCase::iterate (void) |
| { |
| TestLog& log = m_testCtx.getLog(); |
| const glw::Functions& gl = m_renderCtx.getFunctions(); |
| const glu::ShaderProgram shader (m_renderCtx, genShaders(glu::getContextTypeGLSLVersion(m_renderCtx.getType()), isPoint())); |
| |
| const glu::Framebuffer fbo (gl); |
| const glu::Renderbuffer colorbuf (gl); |
| const glu::Renderbuffer depthbuf (gl); |
| |
| const BufferFmtDesc bufferFmt = getBufferFormat(m_clearType); |
| const Color baseColor = getBaseColor(bufferFmt); |
| |
| const int width = 64; |
| const int height = 64; |
| |
| const IVec4 scissorArea (8, 8, 48, 48); |
| |
| vector<deUint8> refData (width*height*bufferFmt.texFmt.getPixelSize()); |
| vector<deUint8> resData (width*height*bufferFmt.texFmt.getPixelSize()); |
| |
| tcu::PixelBufferAccess refAccess (bufferFmt.texFmt, width, height, 1, &refData[0]); |
| tcu::PixelBufferAccess resAccess (bufferFmt.texFmt, width, height, 1, &resData[0]); |
| |
| if (!shader.isOk()) |
| { |
| log << shader; |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Shader compile/link failed"); |
| return STOP; |
| } |
| |
| gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, *fbo); |
| gl.bindFramebuffer(GL_READ_FRAMEBUFFER, *fbo); |
| |
| // Color |
| gl.bindRenderbuffer(GL_RENDERBUFFER, *colorbuf); |
| gl.renderbufferStorage(GL_RENDERBUFFER, bufferFmt.colorFmt, width, height); |
| gl.framebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, *colorbuf); |
| |
| // Depth/stencil |
| gl.bindRenderbuffer(GL_RENDERBUFFER, *depthbuf); |
| gl.renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); |
| gl.framebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, *depthbuf); |
| |
| log << TestLog::Message << "Scissor area is " << scissorArea << TestLog::EndMessage; |
| |
| // Render reference |
| { |
| log << TestLog::Message << "Rendering reference (scissors disabled)" << TestLog::EndMessage; |
| |
| gl.useProgram(shader.getProgram()); |
| gl.viewport(0, 0, width, height); |
| |
| gl.disable(GL_DEPTH_TEST); |
| gl.disable(GL_STENCIL_TEST); |
| gl.disable(GL_SCISSOR_TEST); |
| |
| clearBuffers(gl, baseColor, 1.0f, 0); |
| |
| render(shader.getProgram()); |
| |
| glu::readPixels(m_renderCtx, 0, 0, refAccess); |
| GLU_CHECK_ERROR(gl.getError()); |
| } |
| |
| // Render result |
| { |
| log << TestLog::Message << "Rendering result (scissors enabled)" << TestLog::EndMessage; |
| |
| gl.useProgram(shader.getProgram()); |
| gl.viewport(0, 0, width, height); |
| |
| gl.disable(GL_DEPTH_TEST); |
| gl.disable(GL_STENCIL_TEST); |
| gl.disable(GL_SCISSOR_TEST); |
| |
| clearBuffers(gl, baseColor, 1.0f, 0); |
| |
| gl.enable(GL_SCISSOR_TEST); |
| gl.scissor(scissorArea.x(), scissorArea.y(), scissorArea.z(), scissorArea.w()); |
| |
| render(shader.getProgram()); |
| |
| glu::readPixels(m_renderCtx, 0, 0, resAccess); |
| GLU_CHECK_ERROR(gl.getError()); |
| } |
| |
| { |
| bool resultOk = false; |
| |
| switch (baseColor.type) |
| { |
| case Color::FLOAT: |
| clearEdges(refAccess, Vec4(baseColor.f[0], baseColor.f[1], baseColor.f[2], baseColor.f[3]), scissorArea); |
| resultOk = tcu::floatThresholdCompare(log, "ComparisonResult", "Image comparison result", refAccess, resAccess, Vec4(0.02f, 0.02f, 0.02f, 0.02f), tcu::COMPARE_LOG_RESULT); |
| break; |
| |
| case Color::INT: |
| clearEdges(refAccess, IVec4(baseColor.i[0], baseColor.i[1], baseColor.i[2], baseColor.i[3]), scissorArea); |
| resultOk = tcu::intThresholdCompare(log, "ComparisonResult", "Image comparison result", refAccess, resAccess, UVec4(2, 2, 2, 2), tcu::COMPARE_LOG_RESULT); |
| break; |
| |
| case Color::UINT: |
| clearEdges(refAccess, UVec4(baseColor.u[0], baseColor.u[1], baseColor.u[2], baseColor.u[3]), scissorArea); |
| resultOk = tcu::intThresholdCompare(log, "ComparisonResult", "Image comparison result", refAccess, resAccess, UVec4(2, 2, 2, 2), tcu::COMPARE_LOG_RESULT); |
| break; |
| } |
| |
| if (resultOk) |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| else |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed"); |
| } |
| |
| return STOP; |
| } |
| |
| Color FramebufferClearCase::getBaseColor (const BufferFmtDesc& bufferFmt) |
| { |
| const float f[4] = {0.125f, 0.25f, 0.5f, 1.0f}; |
| const deInt32 i[4] = {0, 0, 0, 0}; |
| const deUint32 u[4] = {0, 0, 0, 0}; |
| |
| switch(bufferFmt.colorFmt) |
| { |
| case GL_RGBA8: return Color(f); |
| case GL_RGBA8I: return Color(i); |
| case GL_RGBA8UI: return Color(u); |
| default: |
| DE_ASSERT(false); |
| } |
| |
| return Color(f); |
| } |
| |
| Color FramebufferClearCase::getMainColor (const BufferFmtDesc& bufferFmt) |
| { |
| const float f[4] = {1.0f, 1.0f, 0.5f, 1.0f}; |
| const deInt32 i[4] = {127, -127, 0, 127}; |
| const deUint32 u[4] = {255, 255, 0, 255}; |
| |
| switch(bufferFmt.colorFmt) |
| { |
| case GL_RGBA8: return Color(f); |
| case GL_RGBA8I: return Color(i); |
| case GL_RGBA8UI: return Color(u); |
| default: |
| DE_ASSERT(false); |
| } |
| |
| return Color(f); |
| } |
| |
| BufferFmtDesc FramebufferClearCase::getBufferFormat (ClearType type) |
| { |
| BufferFmtDesc retval; |
| |
| switch (type) |
| { |
| case CLEAR_COLOR_FLOAT: |
| retval.colorFmt = GL_RGBA16F; |
| retval.texFmt = tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::HALF_FLOAT); |
| DE_FATAL("Floating point clear not implemented");// \todo [2014-1-23 otto] pixel read format & type, nothing guaranteed, need extension... |
| break; |
| |
| case CLEAR_COLOR_INT: |
| retval.colorFmt = GL_RGBA8I; |
| retval.texFmt = tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT32); |
| break; |
| |
| case CLEAR_COLOR_UINT: |
| retval.colorFmt = GL_RGBA8UI; |
| retval.texFmt = tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT32); |
| break; |
| |
| default: |
| retval.colorFmt = GL_RGBA8; |
| retval.texFmt = tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8); |
| break; |
| } |
| |
| return retval; |
| } |
| |
| void FramebufferClearCase::render (GLuint program) const |
| { |
| const glw::Functions& gl = m_renderCtx.getFunctions(); |
| |
| const BufferFmtDesc bufferFmt = getBufferFormat(m_clearType); |
| const Color clearColor = getMainColor(bufferFmt); |
| |
| const int clearStencil = 123; |
| const float clearDepth = 0.5f; |
| |
| switch (m_clearType) |
| { |
| case CLEAR_COLOR_FIXED: gl.clearBufferfv (GL_COLOR, 0, clearColor.f); break; |
| case CLEAR_COLOR_FLOAT: gl.clearBufferfv (GL_COLOR, 0, clearColor.f); break; |
| case CLEAR_COLOR_INT: gl.clearBufferiv (GL_COLOR, 0, clearColor.i); break; |
| case CLEAR_COLOR_UINT: gl.clearBufferuiv(GL_COLOR, 0, clearColor.u); break; |
| case CLEAR_DEPTH: gl.clearBufferfv (GL_DEPTH, 0, &clearDepth); break; |
| case CLEAR_STENCIL: gl.clearBufferiv (GL_STENCIL, 0, &clearStencil); break; |
| case CLEAR_DEPTH_STENCIL: gl.clearBufferfi (GL_DEPTH_STENCIL, 0, clearDepth, clearStencil); break; |
| |
| default: |
| DE_ASSERT(false); |
| } |
| |
| const bool useDepth = (m_clearType == CLEAR_DEPTH || m_clearType == CLEAR_DEPTH_STENCIL); |
| const bool useStencil = (m_clearType == CLEAR_STENCIL || m_clearType == CLEAR_DEPTH_STENCIL); |
| |
| // Render something to expose changes to depth/stencil buffer |
| if (useDepth || useStencil) |
| { |
| if (useDepth) |
| gl.enable(GL_DEPTH_TEST); |
| |
| if (useStencil) |
| gl.enable(GL_STENCIL_TEST); |
| |
| gl.stencilFunc(GL_EQUAL, clearStencil, ~0u); |
| gl.depthFunc(GL_GREATER); |
| gl.disable(GL_SCISSOR_TEST); |
| |
| gl.uniform4fv(gl.getUniformLocation(program, "u_color"), 1, clearColor.f); |
| drawQuad(gl, program, tcu::Vec3(-1.0f, -1.0f, 0.6f), tcu::Vec3(1.0f, 1.0f, 0.6f)); |
| } |
| } |
| |
| bool FramebufferClearCase::isPoint (void) const |
| { |
| return false; |
| } |
| |
| } // Anonymous |
| |
| namespace ScissorTestInternal |
| { |
| |
| tcu::TestNode* createPrimitiveTest (tcu::TestContext& testCtx, |
| glu::RenderContext& renderCtx, |
| const char* name, |
| const char* desc, |
| const Vec4& scissorArea, |
| const Vec4& renderArea, |
| PrimitiveType type, |
| int primitiveCount) |
| { |
| return new ScissorPrimitiveCase(testCtx, renderCtx, name, desc, scissorArea, renderArea, type, primitiveCount); |
| } |
| |
| tcu::TestNode* createClearTest (tcu::TestContext& testCtx, |
| glu::RenderContext& renderCtx, |
| const char* name, |
| const char* desc, |
| const Vec4& scissorArea, |
| deUint32 clearMode) |
| { |
| return new ScissorClearCase(testCtx, renderCtx, name, desc, scissorArea, clearMode); |
| } |
| |
| tcu::TestNode* createFramebufferClearTest (tcu::TestContext& testCtx, |
| glu::RenderContext& renderCtx, |
| const char* name, |
| const char* desc, |
| ClearType clearType) |
| { |
| return new FramebufferClearCase(testCtx, renderCtx, name, desc, clearType); |
| } |
| |
| tcu::TestNode* createFramebufferBlitTest (tcu::TestContext& testCtx, |
| glu::RenderContext& renderCtx, |
| const char* name, |
| const char* desc, |
| const Vec4& scissorArea) |
| { |
| return new FramebufferBlitCase(testCtx, renderCtx, name, desc, scissorArea); |
| } |
| |
| } // ScissorTestInternal |
| } // Functional |
| } // gls |
| } // deqp |