| /*------------------------------------------------------------------------- |
| * 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 Fragment operation test utilities. |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "glsFragmentOpUtil.hpp" |
| #include "gluRenderContext.hpp" |
| #include "gluShaderProgram.hpp" |
| #include "gluDrawUtil.hpp" |
| #include "glwFunctions.hpp" |
| #include "glwEnums.hpp" |
| |
| namespace deqp |
| { |
| namespace gls |
| { |
| namespace FragmentOpUtil |
| { |
| |
| template <typename T> |
| inline T triQuadInterpolate(const T values[4], float xFactor, float yFactor) |
| { |
| if (xFactor + yFactor < 1.0f) |
| return values[0] + (values[2] - values[0]) * xFactor + (values[1] - values[0]) * yFactor; |
| else |
| return values[3] + (values[1] - values[3]) * (1.0f - xFactor) + (values[2] - values[3]) * (1.0f - yFactor); |
| } |
| |
| // GLSL ES 1.0 shaders |
| static const char *s_glsl1VertSrc = "attribute highp vec4 a_position;\n" |
| "attribute mediump vec4 a_color;\n" |
| "varying mediump vec4 v_color;\n" |
| "void main()\n" |
| "{\n" |
| " gl_Position = a_position;\n" |
| " v_color = a_color;\n" |
| "}\n"; |
| static const char *s_glsl1FragSrc = "varying mediump vec4 v_color;\n" |
| "void main()\n" |
| "{\n" |
| " gl_FragColor = v_color;\n" |
| "}\n"; |
| |
| // GLSL ES 3.0 shaders |
| static const char *s_glsl3VertSrc = "#version 300 es\n" |
| "in highp vec4 a_position;\n" |
| "in mediump vec4 a_color;\n" |
| "out mediump vec4 v_color;\n" |
| "void main()\n" |
| "{\n" |
| " gl_Position = a_position;\n" |
| " v_color = a_color;\n" |
| "}\n"; |
| static const char *s_glsl3FragSrc = "#version 300 es\n" |
| "in mediump vec4 v_color;\n" |
| "layout(location = 0) out mediump vec4 o_color;\n" |
| "void main()\n" |
| "{\n" |
| " o_color = v_color;\n" |
| "}\n"; |
| |
| // GLSL 3.3 shaders |
| static const char *s_glsl33VertSrc = "#version 330 core\n" |
| "in vec4 a_position;\n" |
| "in vec4 a_color;\n" |
| "in vec4 a_color1;\n" |
| "out vec4 v_color;\n" |
| "out vec4 v_color1;\n" |
| "void main()\n" |
| "{\n" |
| " gl_Position = a_position;\n" |
| " v_color = a_color;\n" |
| " v_color1 = a_color1;\n" |
| "}\n"; |
| static const char *s_glsl33FragSrc = "#version 330 core\n" |
| "in vec4 v_color;\n" |
| "in vec4 v_color1;\n" |
| "layout(location = 0, index = 0) out vec4 o_color;\n" |
| "layout(location = 0, index = 1) out vec4 o_color1;\n" |
| "void main()\n" |
| "{\n" |
| " o_color = v_color;\n" |
| " o_color1 = v_color1;\n" |
| "}\n"; |
| |
| static const char *getVertSrc(glu::GLSLVersion glslVersion) |
| { |
| if (glslVersion == glu::GLSL_VERSION_100_ES) |
| return s_glsl1VertSrc; |
| else if (glslVersion == glu::GLSL_VERSION_300_ES) |
| return s_glsl3VertSrc; |
| else if (glslVersion == glu::GLSL_VERSION_330) |
| return s_glsl33VertSrc; |
| |
| DE_ASSERT(false); |
| return 0; |
| } |
| |
| static const char *getFragSrc(glu::GLSLVersion glslVersion) |
| { |
| if (glslVersion == glu::GLSL_VERSION_100_ES) |
| return s_glsl1FragSrc; |
| else if (glslVersion == glu::GLSL_VERSION_300_ES) |
| return s_glsl3FragSrc; |
| else if (glslVersion == glu::GLSL_VERSION_330) |
| return s_glsl33FragSrc; |
| |
| DE_ASSERT(false); |
| return 0; |
| } |
| |
| QuadRenderer::QuadRenderer(const glu::RenderContext &context, glu::GLSLVersion glslVersion) |
| : m_context(context) |
| , m_program(DE_NULL) |
| , m_positionLoc(0) |
| , m_colorLoc(-1) |
| , m_color1Loc(-1) |
| , m_blendFuncExt(!glu::glslVersionIsES(glslVersion) && (glslVersion >= glu::GLSL_VERSION_330)) |
| { |
| DE_ASSERT(glslVersion == glu::GLSL_VERSION_100_ES || glslVersion == glu::GLSL_VERSION_300_ES || |
| glslVersion == glu::GLSL_VERSION_330); |
| |
| const glw::Functions &gl = context.getFunctions(); |
| const char *vertSrc = getVertSrc(glslVersion); |
| const char *fragSrc = getFragSrc(glslVersion); |
| |
| m_program = new glu::ShaderProgram(m_context, glu::makeVtxFragSources(vertSrc, fragSrc)); |
| if (!m_program->isOk()) |
| { |
| delete m_program; |
| throw tcu::TestError("Failed to compile program", DE_NULL, __FILE__, __LINE__); |
| } |
| |
| m_positionLoc = gl.getAttribLocation(m_program->getProgram(), "a_position"); |
| m_colorLoc = gl.getAttribLocation(m_program->getProgram(), "a_color"); |
| |
| if (m_blendFuncExt) |
| m_color1Loc = gl.getAttribLocation(m_program->getProgram(), "a_color1"); |
| |
| if (m_positionLoc < 0 || m_colorLoc < 0 || (m_blendFuncExt && m_color1Loc < 0)) |
| { |
| delete m_program; |
| throw tcu::TestError("Invalid attribute locations", DE_NULL, __FILE__, __LINE__); |
| } |
| } |
| |
| QuadRenderer::~QuadRenderer(void) |
| { |
| delete m_program; |
| } |
| |
| void QuadRenderer::render(const Quad &quad) const |
| { |
| const float position[] = {quad.posA.x(), quad.posA.y(), quad.depth[0], 1.0f, quad.posA.x(), quad.posB.y(), |
| quad.depth[1], 1.0f, quad.posB.x(), quad.posA.y(), quad.depth[2], 1.0f, |
| quad.posB.x(), quad.posB.y(), quad.depth[3], 1.0f}; |
| const uint8_t indices[] = {0, 2, 1, 1, 2, 3}; |
| |
| DE_STATIC_ASSERT(sizeof(tcu::Vec4) == sizeof(float) * 4); |
| DE_STATIC_ASSERT(sizeof(quad.color) == sizeof(float) * 4 * 4); |
| DE_STATIC_ASSERT(sizeof(quad.color1) == sizeof(float) * 4 * 4); |
| |
| std::vector<glu::VertexArrayBinding> vertexArrays; |
| |
| vertexArrays.push_back(glu::va::Float(m_positionLoc, 4, 4, 0, &position[0])); |
| vertexArrays.push_back(glu::va::Float(m_colorLoc, 4, 4, 0, (const float *)&quad.color[0])); |
| |
| if (m_blendFuncExt) |
| vertexArrays.push_back(glu::va::Float(m_color1Loc, 4, 4, 0, (const float *)&quad.color1[0])); |
| |
| m_context.getFunctions().useProgram(m_program->getProgram()); |
| glu::draw(m_context, m_program->getProgram(), (int)vertexArrays.size(), &vertexArrays[0], |
| glu::pr::Triangles(DE_LENGTH_OF_ARRAY(indices), &indices[0])); |
| } |
| |
| ReferenceQuadRenderer::ReferenceQuadRenderer(void) : m_fragmentBufferSize(0) |
| { |
| for (int i = 0; i < DE_LENGTH_OF_ARRAY(m_fragmentDepths); i++) |
| m_fragmentDepths[i] = 0.0f; |
| } |
| |
| void ReferenceQuadRenderer::flushFragmentBuffer(const rr::MultisamplePixelBufferAccess &colorBuffer, |
| const rr::MultisamplePixelBufferAccess &depthBuffer, |
| const rr::MultisamplePixelBufferAccess &stencilBuffer, |
| rr::FaceType faceType, const rr::FragmentOperationState &state) |
| { |
| m_fragmentProcessor.render(colorBuffer, depthBuffer, stencilBuffer, &m_fragmentBuffer[0], m_fragmentBufferSize, |
| faceType, state); |
| m_fragmentBufferSize = 0; |
| } |
| |
| void ReferenceQuadRenderer::render(const tcu::PixelBufferAccess &colorBuffer, const tcu::PixelBufferAccess &depthBuffer, |
| const tcu::PixelBufferAccess &stencilBuffer, const IntegerQuad &quad, |
| const rr::FragmentOperationState &state) |
| { |
| bool flipX = quad.posA.x() > quad.posB.x(); |
| bool flipY = quad.posA.y() > quad.posB.y(); |
| rr::FaceType faceType = flipX == flipY ? rr::FACETYPE_FRONT : rr::FACETYPE_BACK; |
| int xFirst = flipX ? quad.posB.x() : quad.posA.x(); |
| int xLast = flipX ? quad.posA.x() : quad.posB.x(); |
| int yFirst = flipY ? quad.posB.y() : quad.posA.y(); |
| int yLast = flipY ? quad.posA.y() : quad.posB.y(); |
| float width = (float)(xLast - xFirst + 1); |
| float height = (float)(yLast - yFirst + 1); |
| |
| for (int y = yFirst; y <= yLast; y++) |
| { |
| // Interpolation factor for y. |
| float yRatio = (0.5f + (float)(y - yFirst)) / height; |
| if (flipY) |
| yRatio = 1.0f - yRatio; |
| |
| for (int x = xFirst; x <= xLast; x++) |
| { |
| // Interpolation factor for x. |
| float xRatio = (0.5f + (float)(x - xFirst)) / width; |
| if (flipX) |
| xRatio = 1.0f - xRatio; |
| |
| tcu::Vec4 color = triQuadInterpolate(quad.color, xRatio, yRatio); |
| tcu::Vec4 color1 = triQuadInterpolate(quad.color1, xRatio, yRatio); |
| float depth = triQuadInterpolate(quad.depth, xRatio, yRatio); |
| |
| // Interpolated color and depth. |
| |
| DE_STATIC_ASSERT(MAX_FRAGMENT_BUFFER_SIZE == DE_LENGTH_OF_ARRAY(m_fragmentBuffer)); |
| |
| if (m_fragmentBufferSize >= MAX_FRAGMENT_BUFFER_SIZE) |
| flushFragmentBuffer(rr::MultisamplePixelBufferAccess::fromMultisampleAccess(colorBuffer), |
| rr::MultisamplePixelBufferAccess::fromMultisampleAccess(depthBuffer), |
| rr::MultisamplePixelBufferAccess::fromMultisampleAccess(stencilBuffer), faceType, |
| state); |
| |
| m_fragmentDepths[m_fragmentBufferSize] = depth; |
| m_fragmentBuffer[m_fragmentBufferSize] = |
| rr::Fragment(tcu::IVec2(x, y), rr::GenericVec4(color), rr::GenericVec4(color1), 1u /* coverage mask */, |
| &m_fragmentDepths[m_fragmentBufferSize]); |
| m_fragmentBufferSize++; |
| } |
| } |
| |
| flushFragmentBuffer(rr::MultisamplePixelBufferAccess::fromMultisampleAccess(colorBuffer), |
| rr::MultisamplePixelBufferAccess::fromMultisampleAccess(depthBuffer), |
| rr::MultisamplePixelBufferAccess::fromMultisampleAccess(stencilBuffer), faceType, state); |
| } |
| |
| tcu::PixelBufferAccess getMultisampleAccess(const tcu::PixelBufferAccess &original) |
| { |
| return tcu::PixelBufferAccess(original.getFormat(), 1, original.getWidth(), original.getHeight(), |
| original.getFormat().getPixelSize(), original.getRowPitch(), original.getDataPtr()); |
| } |
| |
| tcu::ConstPixelBufferAccess getMultisampleAccess(const tcu::ConstPixelBufferAccess &original) |
| { |
| return tcu::ConstPixelBufferAccess(original.getFormat(), 1, original.getWidth(), original.getHeight(), |
| original.getFormat().getPixelSize(), original.getRowPitch(), |
| original.getDataPtr()); |
| } |
| |
| } // namespace FragmentOpUtil |
| } // namespace gls |
| } // namespace deqp |