1e5c31af7Sopenharmony_ci/*------------------------------------------------------------------------- 2e5c31af7Sopenharmony_ci * OpenGL Conformance Test Suite 3e5c31af7Sopenharmony_ci * ----------------------------- 4e5c31af7Sopenharmony_ci * 5e5c31af7Sopenharmony_ci * Copyright (c) 2017 The Khronos Group Inc. 6e5c31af7Sopenharmony_ci * 7e5c31af7Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 8e5c31af7Sopenharmony_ci * you may not use this file except in compliance with the License. 9e5c31af7Sopenharmony_ci * You may obtain a copy of the License at 10e5c31af7Sopenharmony_ci * 11e5c31af7Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 12e5c31af7Sopenharmony_ci * 13e5c31af7Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 14e5c31af7Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 15e5c31af7Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16e5c31af7Sopenharmony_ci * See the License for the specific language governing permissions and 17e5c31af7Sopenharmony_ci * limitations under the License. 18e5c31af7Sopenharmony_ci * 19e5c31af7Sopenharmony_ci */ /*! 20e5c31af7Sopenharmony_ci * \file esextcTessellationShaderWinding.cpp 21e5c31af7Sopenharmony_ci * \brief Test winding order with tessellation shaders 22e5c31af7Sopenharmony_ci */ /*-------------------------------------------------------------------*/ 23e5c31af7Sopenharmony_ci 24e5c31af7Sopenharmony_ci#include "esextcTessellationShaderWinding.hpp" 25e5c31af7Sopenharmony_ci#include "deSharedPtr.hpp" 26e5c31af7Sopenharmony_ci#include "esextcTessellationShaderUtils.hpp" 27e5c31af7Sopenharmony_ci#include "gluContextInfo.hpp" 28e5c31af7Sopenharmony_ci#include "gluDefs.hpp" 29e5c31af7Sopenharmony_ci#include "gluPixelTransfer.hpp" 30e5c31af7Sopenharmony_ci#include "gluShaderProgram.hpp" 31e5c31af7Sopenharmony_ci#include "glwEnums.hpp" 32e5c31af7Sopenharmony_ci#include "glwFunctions.hpp" 33e5c31af7Sopenharmony_ci#include "tcuRGBA.hpp" 34e5c31af7Sopenharmony_ci#include "tcuSurface.hpp" 35e5c31af7Sopenharmony_ci#include "tcuTestLog.hpp" 36e5c31af7Sopenharmony_ci#include <string> 37e5c31af7Sopenharmony_ci 38e5c31af7Sopenharmony_cinamespace glcts 39e5c31af7Sopenharmony_ci{ 40e5c31af7Sopenharmony_ci 41e5c31af7Sopenharmony_ciclass WindingCase : public TestCaseBase 42e5c31af7Sopenharmony_ci{ 43e5c31af7Sopenharmony_cipublic: 44e5c31af7Sopenharmony_ci WindingCase(glcts::Context& context, const ExtParameters& extParams, std::string name, std::string primitiveType, 45e5c31af7Sopenharmony_ci std::string winding); 46e5c31af7Sopenharmony_ci 47e5c31af7Sopenharmony_ci void init(void); 48e5c31af7Sopenharmony_ci void deinit(void); 49e5c31af7Sopenharmony_ci IterateResult iterate(void); 50e5c31af7Sopenharmony_ci void prepareFramebuffer(); 51e5c31af7Sopenharmony_ci 52e5c31af7Sopenharmony_ciprivate: 53e5c31af7Sopenharmony_ci static const int RENDER_SIZE = 64; 54e5c31af7Sopenharmony_ci 55e5c31af7Sopenharmony_ci de::SharedPtr<const glu::ShaderProgram> m_program; 56e5c31af7Sopenharmony_ci glw::GLuint m_rbo; 57e5c31af7Sopenharmony_ci glw::GLuint m_fbo; 58e5c31af7Sopenharmony_ci}; 59e5c31af7Sopenharmony_ci 60e5c31af7Sopenharmony_ciWindingCase::WindingCase(glcts::Context& context, const ExtParameters& extParams, std::string name, 61e5c31af7Sopenharmony_ci std::string primitiveType, std::string winding) 62e5c31af7Sopenharmony_ci : TestCaseBase(context, extParams, name.c_str(), "") 63e5c31af7Sopenharmony_ci{ 64e5c31af7Sopenharmony_ci DE_ASSERT((primitiveType.compare("triangles") == 0) || (primitiveType.compare("quads") == 0)); 65e5c31af7Sopenharmony_ci DE_ASSERT((winding.compare("cw") == 0) || (winding.compare("ccw") == 0)); 66e5c31af7Sopenharmony_ci 67e5c31af7Sopenharmony_ci m_specializationMap["PRIMITIVE_TYPE"] = primitiveType; 68e5c31af7Sopenharmony_ci m_specializationMap["WINDING"] = winding; 69e5c31af7Sopenharmony_ci m_rbo = 0; 70e5c31af7Sopenharmony_ci m_fbo = 0; 71e5c31af7Sopenharmony_ci} 72e5c31af7Sopenharmony_ci 73e5c31af7Sopenharmony_civoid WindingCase::init(void) 74e5c31af7Sopenharmony_ci{ 75e5c31af7Sopenharmony_ci TestCaseBase::init(); 76e5c31af7Sopenharmony_ci if (!m_is_tessellation_shader_supported) 77e5c31af7Sopenharmony_ci { 78e5c31af7Sopenharmony_ci TCU_THROW(NotSupportedError, TESSELLATION_SHADER_EXTENSION_NOT_SUPPORTED); 79e5c31af7Sopenharmony_ci } 80e5c31af7Sopenharmony_ci 81e5c31af7Sopenharmony_ci TestCaseBase::init(); 82e5c31af7Sopenharmony_ci 83e5c31af7Sopenharmony_ci const char* vs("${VERSION}\n" 84e5c31af7Sopenharmony_ci "void main (void)\n" 85e5c31af7Sopenharmony_ci "{\n" 86e5c31af7Sopenharmony_ci "}\n"); 87e5c31af7Sopenharmony_ci const char* tcs("${VERSION}\n" 88e5c31af7Sopenharmony_ci "${TESSELLATION_SHADER_REQUIRE}\n" 89e5c31af7Sopenharmony_ci "layout (vertices = 1) out;\n" 90e5c31af7Sopenharmony_ci "void main (void)\n" 91e5c31af7Sopenharmony_ci "{\n" 92e5c31af7Sopenharmony_ci " gl_TessLevelInner[0] = 5.0;\n" 93e5c31af7Sopenharmony_ci " gl_TessLevelInner[1] = 5.0;\n" 94e5c31af7Sopenharmony_ci "\n" 95e5c31af7Sopenharmony_ci " gl_TessLevelOuter[0] = 5.0;\n" 96e5c31af7Sopenharmony_ci " gl_TessLevelOuter[1] = 5.0;\n" 97e5c31af7Sopenharmony_ci " gl_TessLevelOuter[2] = 5.0;\n" 98e5c31af7Sopenharmony_ci " gl_TessLevelOuter[3] = 5.0;\n" 99e5c31af7Sopenharmony_ci "}\n"); 100e5c31af7Sopenharmony_ci const char* tes("${VERSION}\n" 101e5c31af7Sopenharmony_ci "${TESSELLATION_SHADER_REQUIRE}\n" 102e5c31af7Sopenharmony_ci "layout (${PRIMITIVE_TYPE}, ${WINDING}) in;\n" 103e5c31af7Sopenharmony_ci "void main (void)\n" 104e5c31af7Sopenharmony_ci "{\n" 105e5c31af7Sopenharmony_ci " gl_Position = vec4(gl_TessCoord.xy*2.0 - 1.0, 0.0, 1.0);\n" 106e5c31af7Sopenharmony_ci "}\n"); 107e5c31af7Sopenharmony_ci const char* fs("${VERSION}\n" 108e5c31af7Sopenharmony_ci "layout (location = 0) out mediump vec4 o_color;\n" 109e5c31af7Sopenharmony_ci "void main (void)\n" 110e5c31af7Sopenharmony_ci "{\n" 111e5c31af7Sopenharmony_ci " o_color = vec4(1.0);\n" 112e5c31af7Sopenharmony_ci "}\n"); 113e5c31af7Sopenharmony_ci 114e5c31af7Sopenharmony_ci m_program = de::SharedPtr<const glu::ShaderProgram>( 115e5c31af7Sopenharmony_ci new glu::ShaderProgram(m_context.getRenderContext(), 116e5c31af7Sopenharmony_ci glu::ProgramSources() << glu::VertexSource(specializeShader(1, &vs)) 117e5c31af7Sopenharmony_ci << glu::TessellationControlSource(specializeShader(1, &tcs)) 118e5c31af7Sopenharmony_ci << glu::TessellationEvaluationSource(specializeShader(1, &tes)) 119e5c31af7Sopenharmony_ci << glu::FragmentSource(specializeShader(1, &fs)))); 120e5c31af7Sopenharmony_ci 121e5c31af7Sopenharmony_ci m_testCtx.getLog() << *m_program; 122e5c31af7Sopenharmony_ci if (!m_program->isOk()) 123e5c31af7Sopenharmony_ci TCU_FAIL("Program compilation failed"); 124e5c31af7Sopenharmony_ci} 125e5c31af7Sopenharmony_ci 126e5c31af7Sopenharmony_civoid WindingCase::deinit(void) 127e5c31af7Sopenharmony_ci{ 128e5c31af7Sopenharmony_ci const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 129e5c31af7Sopenharmony_ci 130e5c31af7Sopenharmony_ci if (m_fbo) 131e5c31af7Sopenharmony_ci { 132e5c31af7Sopenharmony_ci gl.deleteFramebuffers(1, &m_fbo); 133e5c31af7Sopenharmony_ci m_fbo = 0; 134e5c31af7Sopenharmony_ci } 135e5c31af7Sopenharmony_ci 136e5c31af7Sopenharmony_ci if (m_rbo) 137e5c31af7Sopenharmony_ci { 138e5c31af7Sopenharmony_ci gl.deleteRenderbuffers(1, &m_rbo); 139e5c31af7Sopenharmony_ci m_rbo = 0; 140e5c31af7Sopenharmony_ci } 141e5c31af7Sopenharmony_ci 142e5c31af7Sopenharmony_ci m_program.clear(); 143e5c31af7Sopenharmony_ci} 144e5c31af7Sopenharmony_ci 145e5c31af7Sopenharmony_ci/** @brief Bind default framebuffer object. 146e5c31af7Sopenharmony_ci * 147e5c31af7Sopenharmony_ci * @note The function may throw if unexpected error has occured. 148e5c31af7Sopenharmony_ci */ 149e5c31af7Sopenharmony_civoid WindingCase::prepareFramebuffer() 150e5c31af7Sopenharmony_ci{ 151e5c31af7Sopenharmony_ci /* Shortcut for GL functionality */ 152e5c31af7Sopenharmony_ci const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 153e5c31af7Sopenharmony_ci 154e5c31af7Sopenharmony_ci gl.genRenderbuffers(1, &m_rbo); 155e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glGenRenderbuffers call failed."); 156e5c31af7Sopenharmony_ci 157e5c31af7Sopenharmony_ci gl.bindRenderbuffer(GL_RENDERBUFFER, m_rbo); 158e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer call failed."); 159e5c31af7Sopenharmony_ci 160e5c31af7Sopenharmony_ci gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, RENDER_SIZE, RENDER_SIZE); 161e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glRenderbufferStorage call failed."); 162e5c31af7Sopenharmony_ci 163e5c31af7Sopenharmony_ci gl.genFramebuffers(1, &m_fbo); 164e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers call failed."); 165e5c31af7Sopenharmony_ci 166e5c31af7Sopenharmony_ci gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo); 167e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer call failed."); 168e5c31af7Sopenharmony_ci 169e5c31af7Sopenharmony_ci gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_rbo); 170e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferRenderbuffer call failed."); 171e5c31af7Sopenharmony_ci} 172e5c31af7Sopenharmony_ci 173e5c31af7Sopenharmony_ciWindingCase::IterateResult WindingCase::iterate(void) 174e5c31af7Sopenharmony_ci{ 175e5c31af7Sopenharmony_ci const glu::RenderContext& renderCtx = m_context.getRenderContext(); 176e5c31af7Sopenharmony_ci const deUint32 programGL = m_program->getProgram(); 177e5c31af7Sopenharmony_ci const glw::Functions& gl = renderCtx.getFunctions(); 178e5c31af7Sopenharmony_ci 179e5c31af7Sopenharmony_ci const unsigned int windingTaken[2] = { GL_CW, GL_CCW }; 180e5c31af7Sopenharmony_ci const char* windingTakenName[2] = { "GL_CW", "GL_CCW" }; 181e5c31af7Sopenharmony_ci 182e5c31af7Sopenharmony_ci const bool testPrimitiveTypeIsTriangles = (m_specializationMap["PRIMITIVE_TYPE"].compare("triangles") == 0); 183e5c31af7Sopenharmony_ci const bool testWindingIsCW = (m_specializationMap["WINDING"].compare("cw") == 0); 184e5c31af7Sopenharmony_ci bool success = true; 185e5c31af7Sopenharmony_ci 186e5c31af7Sopenharmony_ci prepareFramebuffer(); 187e5c31af7Sopenharmony_ci gl.viewport(0, 0, RENDER_SIZE, RENDER_SIZE); 188e5c31af7Sopenharmony_ci gl.clearColor(1.0f, 0.0f, 0.0f, 1.0f); 189e5c31af7Sopenharmony_ci gl.useProgram(programGL); 190e5c31af7Sopenharmony_ci 191e5c31af7Sopenharmony_ci gl.patchParameteri(GL_PATCH_VERTICES, 1); 192e5c31af7Sopenharmony_ci 193e5c31af7Sopenharmony_ci gl.enable(GL_CULL_FACE); 194e5c31af7Sopenharmony_ci 195e5c31af7Sopenharmony_ci deUint32 vaoGL; 196e5c31af7Sopenharmony_ci gl.genVertexArrays(1, &vaoGL); 197e5c31af7Sopenharmony_ci gl.bindVertexArray(vaoGL); 198e5c31af7Sopenharmony_ci 199e5c31af7Sopenharmony_ci m_testCtx.getLog() << tcu::TestLog::Message << "Face culling enabled" << tcu::TestLog::EndMessage; 200e5c31af7Sopenharmony_ci 201e5c31af7Sopenharmony_ci for (int windingIndex = 0; windingIndex < 2; windingIndex++) 202e5c31af7Sopenharmony_ci { 203e5c31af7Sopenharmony_ci m_testCtx.getLog() << tcu::TestLog::Message << "Setting glFrontFace(" << windingTakenName[windingIndex] << ")" 204e5c31af7Sopenharmony_ci << tcu::TestLog::EndMessage; 205e5c31af7Sopenharmony_ci 206e5c31af7Sopenharmony_ci gl.frontFace(windingTaken[windingIndex]); 207e5c31af7Sopenharmony_ci 208e5c31af7Sopenharmony_ci gl.clear(GL_COLOR_BUFFER_BIT); 209e5c31af7Sopenharmony_ci gl.drawArrays(GL_PATCHES, 0, 1); 210e5c31af7Sopenharmony_ci GLU_EXPECT_NO_ERROR(gl.getError(), "Draw failed"); 211e5c31af7Sopenharmony_ci 212e5c31af7Sopenharmony_ci { 213e5c31af7Sopenharmony_ci tcu::Surface rendered(RENDER_SIZE, RENDER_SIZE); 214e5c31af7Sopenharmony_ci glu::readPixels(renderCtx, 0, 0, rendered.getAccess()); 215e5c31af7Sopenharmony_ci m_testCtx.getLog() << tcu::TestLog::Image("RenderedImage", "Rendered Image", rendered); 216e5c31af7Sopenharmony_ci 217e5c31af7Sopenharmony_ci { 218e5c31af7Sopenharmony_ci const int badPixelTolerance = 219e5c31af7Sopenharmony_ci testPrimitiveTypeIsTriangles ? 5 * de::max(rendered.getWidth(), rendered.getHeight()) : 0; 220e5c31af7Sopenharmony_ci const int totalNumPixels = rendered.getWidth() * rendered.getHeight(); 221e5c31af7Sopenharmony_ci 222e5c31af7Sopenharmony_ci int numWhitePixels = 0; 223e5c31af7Sopenharmony_ci int numRedPixels = 0; 224e5c31af7Sopenharmony_ci for (int y = 0; y < rendered.getHeight(); y++) 225e5c31af7Sopenharmony_ci for (int x = 0; x < rendered.getWidth(); x++) 226e5c31af7Sopenharmony_ci { 227e5c31af7Sopenharmony_ci numWhitePixels += rendered.getPixel(x, y) == tcu::RGBA::white() ? 1 : 0; 228e5c31af7Sopenharmony_ci numRedPixels += rendered.getPixel(x, y) == tcu::RGBA::red() ? 1 : 0; 229e5c31af7Sopenharmony_ci } 230e5c31af7Sopenharmony_ci 231e5c31af7Sopenharmony_ci DE_ASSERT(numWhitePixels + numRedPixels <= totalNumPixels); 232e5c31af7Sopenharmony_ci 233e5c31af7Sopenharmony_ci m_testCtx.getLog() << tcu::TestLog::Message << "Note: got " << numWhitePixels << " white and " 234e5c31af7Sopenharmony_ci << numRedPixels << " red pixels" << tcu::TestLog::EndMessage; 235e5c31af7Sopenharmony_ci 236e5c31af7Sopenharmony_ci if (totalNumPixels - numWhitePixels - numRedPixels > badPixelTolerance) 237e5c31af7Sopenharmony_ci { 238e5c31af7Sopenharmony_ci m_testCtx.getLog() << tcu::TestLog::Message << "Failure: Got " 239e5c31af7Sopenharmony_ci << totalNumPixels - numWhitePixels - numRedPixels 240e5c31af7Sopenharmony_ci << " other than white or red pixels (maximum tolerance " << badPixelTolerance 241e5c31af7Sopenharmony_ci << ")" << tcu::TestLog::EndMessage; 242e5c31af7Sopenharmony_ci success = false; 243e5c31af7Sopenharmony_ci break; 244e5c31af7Sopenharmony_ci } 245e5c31af7Sopenharmony_ci 246e5c31af7Sopenharmony_ci bool frontFaceWindingIsCW = (windingIndex == 0); 247e5c31af7Sopenharmony_ci if (frontFaceWindingIsCW == testWindingIsCW) 248e5c31af7Sopenharmony_ci { 249e5c31af7Sopenharmony_ci if (testPrimitiveTypeIsTriangles) 250e5c31af7Sopenharmony_ci { 251e5c31af7Sopenharmony_ci if (de::abs(numWhitePixels - totalNumPixels / 2) > badPixelTolerance) 252e5c31af7Sopenharmony_ci { 253e5c31af7Sopenharmony_ci m_testCtx.getLog() << tcu::TestLog::Message 254e5c31af7Sopenharmony_ci << "Failure: wrong number of white pixels; expected approximately " 255e5c31af7Sopenharmony_ci << totalNumPixels / 2 << tcu::TestLog::EndMessage; 256e5c31af7Sopenharmony_ci success = false; 257e5c31af7Sopenharmony_ci break; 258e5c31af7Sopenharmony_ci } 259e5c31af7Sopenharmony_ci } 260e5c31af7Sopenharmony_ci else // test primitive type is quads 261e5c31af7Sopenharmony_ci { 262e5c31af7Sopenharmony_ci if (numWhitePixels != totalNumPixels) 263e5c31af7Sopenharmony_ci { 264e5c31af7Sopenharmony_ci m_testCtx.getLog() 265e5c31af7Sopenharmony_ci << tcu::TestLog::Message << "Failure: expected only white pixels (full-viewport quad)" 266e5c31af7Sopenharmony_ci << tcu::TestLog::EndMessage; 267e5c31af7Sopenharmony_ci success = false; 268e5c31af7Sopenharmony_ci break; 269e5c31af7Sopenharmony_ci } 270e5c31af7Sopenharmony_ci } 271e5c31af7Sopenharmony_ci } 272e5c31af7Sopenharmony_ci else 273e5c31af7Sopenharmony_ci { 274e5c31af7Sopenharmony_ci if (numWhitePixels != 0) 275e5c31af7Sopenharmony_ci { 276e5c31af7Sopenharmony_ci m_testCtx.getLog() 277e5c31af7Sopenharmony_ci << tcu::TestLog::Message << "Failure: expected only red pixels (everything culled)" 278e5c31af7Sopenharmony_ci << tcu::TestLog::EndMessage; 279e5c31af7Sopenharmony_ci success = false; 280e5c31af7Sopenharmony_ci break; 281e5c31af7Sopenharmony_ci } 282e5c31af7Sopenharmony_ci } 283e5c31af7Sopenharmony_ci } 284e5c31af7Sopenharmony_ci } 285e5c31af7Sopenharmony_ci } 286e5c31af7Sopenharmony_ci 287e5c31af7Sopenharmony_ci gl.bindVertexArray(0); 288e5c31af7Sopenharmony_ci gl.deleteVertexArrays(1, &vaoGL); 289e5c31af7Sopenharmony_ci 290e5c31af7Sopenharmony_ci m_testCtx.setTestResult(success ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 291e5c31af7Sopenharmony_ci success ? "Pass" : "Image verification failed"); 292e5c31af7Sopenharmony_ci return STOP; 293e5c31af7Sopenharmony_ci} 294e5c31af7Sopenharmony_ci 295e5c31af7Sopenharmony_ci/** Constructor 296e5c31af7Sopenharmony_ci * 297e5c31af7Sopenharmony_ci * @param context Test context 298e5c31af7Sopenharmony_ci **/ 299e5c31af7Sopenharmony_ciTesselationShaderWindingTests::TesselationShaderWindingTests(glcts::Context& context, const ExtParameters& extParams) 300e5c31af7Sopenharmony_ci : TestCaseGroupBase(context, extParams, "winding", "Verifies winding order with tessellation shaders") 301e5c31af7Sopenharmony_ci{ 302e5c31af7Sopenharmony_ci} 303e5c31af7Sopenharmony_ci 304e5c31af7Sopenharmony_ci/** 305e5c31af7Sopenharmony_ci * Initializes test groups for winding tests 306e5c31af7Sopenharmony_ci **/ 307e5c31af7Sopenharmony_civoid TesselationShaderWindingTests::init(void) 308e5c31af7Sopenharmony_ci{ 309e5c31af7Sopenharmony_ci addChild(new WindingCase(m_context, m_extParams, "triangles_ccw", "triangles", "ccw")); 310e5c31af7Sopenharmony_ci addChild(new WindingCase(m_context, m_extParams, "triangles_cw", "triangles", "cw")); 311e5c31af7Sopenharmony_ci addChild(new WindingCase(m_context, m_extParams, "quads_ccw", "quads", "ccw")); 312e5c31af7Sopenharmony_ci addChild(new WindingCase(m_context, m_extParams, "quads_cw", "quads", "cw")); 313e5c31af7Sopenharmony_ci} 314e5c31af7Sopenharmony_ci 315e5c31af7Sopenharmony_ci} /* namespace glcts */ 316