/*------------------------------------------------------------------------- * 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 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& vertices, const vector& 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 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 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 positions (4*vertexCount*m_primitiveCount); vector 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 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 refData (width*height*bufferFmt.texFmt.getPixelSize()); vector 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