/*------------------------------------------------------------------------- * 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 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 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