| /*------------------------------------------------------------------------- |
| * 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::map; |
| using std::string; |
| using std::vector; |
| using tcu::IVec4; |
| using tcu::UVec4; |
| using tcu::Vec3; |
| using tcu::Vec4; |
| |
| void drawQuad(const glw::Functions &gl, uint32_t 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 uint16_t indices[] = {0, 1, 2, 2, 1, 3}; |
| |
| const int32_t 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, uint32_t program, const uint32_t type, const vector<float> &vertices, |
| const vector<uint16_t> &indices) |
| { |
| const int32_t 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 uint16_t 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<uint16_t> 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] = (uint16_t)(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, uint32_t 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 uint32_t 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, uint32_t 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 int32_t 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]; |
| int32_t i[4]; |
| uint32_t 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 int32_t i_[4]) : type(INT) |
| { |
| i[0] = i_[0]; |
| i[1] = i_[1]; |
| i[2] = i_[2]; |
| i[3] = i_[3]; |
| } |
| Color(const uint32_t 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<uint8_t> refData(width * height * bufferFmt.texFmt.getPixelSize()); |
| vector<uint8_t> 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 int32_t i[4] = {0, 0, 0, 0}; |
| const uint32_t 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 int32_t i[4] = {127, -127, 0, 127}; |
| const uint32_t 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; |
| } |
| |
| } // namespace |
| |
| 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, uint32_t 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); |
| } |
| |
| } // namespace ScissorTestInternal |
| } // namespace Functional |
| } // namespace gls |
| } // namespace deqp |