/*------------------------------------------------------------------------- * 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(DE_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(DE_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 deUint8 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()); } } // FragmentOpUtil } // gls } // deqp