/*------------------------------------------------------------------------ * Vulkan Conformance Tests * ------------------------ * * Copyright (c) 2016 The Khronos Group Inc. * Copyright (c) 2016 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 Input Geometry Shader Tests *//*--------------------------------------------------------------------*/ #include "vktGeometryInputGeometryShaderTests.hpp" #include "vktGeometryBasicClass.hpp" #include "vktGeometryTestsUtil.hpp" #include "vkDefs.hpp" #include "vktTestCase.hpp" #include "vktTestCaseUtil.hpp" #include "vkImageUtil.hpp" #include "vkTypeUtil.hpp" #include "vkPrograms.hpp" #include "vkBuilderUtil.hpp" #include "vkRefUtil.hpp" #include "vkQueryUtil.hpp" #include "vkMemUtil.hpp" #include using namespace vk; namespace vkt { namespace geometry { namespace { using tcu::Vec4; using tcu::TestStatus; using tcu::TestContext; using tcu::TestCaseGroup; using de::MovePtr; using std::string; using std::vector; class GeometryInputTestInstance : public GeometryExpanderRenderTestInstance { public: GeometryInputTestInstance (Context& context, const VkPrimitiveTopology primitiveType, const char* name); GeometryInputTestInstance (Context& context, const VkPrimitiveTopology primitiveType, const char* name, const int numDrawVertices); void genVertexAttribData (void); }; GeometryInputTestInstance::GeometryInputTestInstance (Context& context, const VkPrimitiveTopology primitiveType, const char* name) : GeometryExpanderRenderTestInstance (context, primitiveType, name) { genVertexAttribData(); } GeometryInputTestInstance::GeometryInputTestInstance (Context& context, const VkPrimitiveTopology primitiveType, const char* name, const int numDrawVertices) : GeometryExpanderRenderTestInstance (context, primitiveType, name) { genVertexAttribData(); m_numDrawVertices = numDrawVertices; } void GeometryInputTestInstance::genVertexAttribData (void) { // Create 1 X 2 grid in triangle strip adjacent - order const float scale = 0.3f; const Vec4 offset (-0.5f, -0.2f, 0.0f, 1.0f); m_numDrawVertices = 12; m_vertexPosData.resize(m_numDrawVertices); m_vertexPosData[ 0] = Vec4( 0, 0, 0.0f, 0.0f) * scale + offset; m_vertexPosData[ 1] = Vec4(-1, -1, 0.0f, 0.0f) * scale + offset; m_vertexPosData[ 2] = Vec4( 0, -1, 0.0f, 0.0f) * scale + offset; m_vertexPosData[ 3] = Vec4( 1, 1, 0.0f, 0.0f) * scale + offset; m_vertexPosData[ 4] = Vec4( 1, 0, 0.0f, 0.0f) * scale + offset; m_vertexPosData[ 5] = Vec4( 0, -2, 0.0f, 0.0f) * scale + offset; m_vertexPosData[ 6] = Vec4( 1, -1, 0.0f, 0.0f) * scale + offset; m_vertexPosData[ 7] = Vec4( 2, 1, 0.0f, 0.0f) * scale + offset; m_vertexPosData[ 8] = Vec4( 2, 0, 0.0f, 0.0f) * scale + offset; m_vertexPosData[ 9] = Vec4( 1, -2, 0.0f, 0.0f) * scale + offset; m_vertexPosData[10] = Vec4( 2, -1, 0.0f, 0.0f) * scale + offset; m_vertexPosData[11] = Vec4( 3, 0, 0.0f, 0.0f) * scale + offset; // Red and white m_vertexAttrData.resize(m_numDrawVertices); for (int i = 0; i < m_numDrawVertices; ++i) m_vertexAttrData[i] = (i % 2 == 0) ? Vec4(1, 1, 1, 1) : Vec4(1, 0, 0, 1); } class GeometryExpanderRenderTest : public TestCase { public: GeometryExpanderRenderTest (TestContext& testCtx, const PrimitiveTestSpec& inputPrimitives); void initPrograms (SourceCollections& sourceCollections) const; virtual TestInstance* createInstance (Context& context) const; virtual void checkSupport (Context& context) const; protected: string shaderGeometry (bool pointSize) const; const VkPrimitiveTopology m_primitiveType; const VkPrimitiveTopology m_outputType; }; GeometryExpanderRenderTest::GeometryExpanderRenderTest (TestContext& testCtx, const PrimitiveTestSpec& inputPrimitives) : TestCase (testCtx, inputPrimitives.name, inputPrimitives.name) , m_primitiveType (inputPrimitives.primitiveType) , m_outputType (inputPrimitives.outputType) { } void GeometryExpanderRenderTest::checkSupport (Context& context) const { context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER); if (m_primitiveType == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN && context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") && !context.getPortabilitySubsetFeatures().triangleFans) { TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Triangle fans are not supported by this implementation"); } } void GeometryExpanderRenderTest::initPrograms (SourceCollections& sourceCollections) const { { std::ostringstream src; src << "#version 310 es\n" <<"layout(location = 0) in highp vec4 a_position;\n" <<"layout(location = 1) in highp vec4 a_color;\n" <<"layout(location = 0) out highp vec4 v_geom_FragColor;\n" <<"void main (void)\n" <<"{\n" <<" gl_Position = a_position;\n" <<" v_geom_FragColor = a_color;\n" <<"}\n"; sourceCollections.glslSources.add("vertex") << glu::VertexSource(src.str()); } { sourceCollections.glslSources.add("geometry") << glu::GeometrySource(shaderGeometry(false)); if (m_outputType == VK_PRIMITIVE_TOPOLOGY_POINT_LIST) sourceCollections.glslSources.add("geometry_pointsize") << glu::GeometrySource(shaderGeometry(true)); } { std::ostringstream src; src << "#version 310 es\n" <<"layout(location = 0) out highp vec4 fragColor;\n" <<"layout(location = 0) in highp vec4 v_frag_FragColor;\n" <<"void main (void)\n" <<"{\n" <<" fragColor = v_frag_FragColor;\n" <<"}\n"; sourceCollections.glslSources.add("fragment") << glu::FragmentSource(src.str()); } } TestInstance* GeometryExpanderRenderTest::createInstance (Context& context) const { return new GeometryInputTestInstance(context, m_primitiveType, getName()); } string GeometryExpanderRenderTest::shaderGeometry (bool pointSize) const { std::ostringstream src; src << "#version 310 es\n" << "#extension GL_EXT_geometry_shader : require\n"; if (pointSize) src <<"#extension GL_EXT_geometry_point_size : require\n"; src << "layout(" << inputTypeToGLString(m_primitiveType) << ") in;\n" << "layout(" << outputTypeToGLString(m_outputType) << ", max_vertices = " << calcOutputVertices(m_primitiveType) << ") out;\n" << "layout(location = 0) in highp vec4 v_geom_FragColor[];\n" << "layout(location = 0) out highp vec4 v_frag_FragColor;\n" << "\n" << "void main (void)\n" << "{\n" << " const highp vec4 offset0 = vec4(-0.07, -0.01, 0.0, 0.0);\n" << " const highp vec4 offset1 = vec4( 0.03, -0.03, 0.0, 0.0);\n" << " const highp vec4 offset2 = vec4(-0.01, 0.08, 0.0, 0.0);\n" << " highp vec4 yoffset = float(gl_PrimitiveIDIn) * vec4(0.02, 0.1, 0.0, 0.0);\n" << "\n" << " for (highp int ndx = 0; ndx < gl_in.length(); ndx++)\n" << " {\n"; if (pointSize) src << " gl_PointSize = 1.0;\n"; src << " gl_Position = gl_in[ndx].gl_Position + offset0 + yoffset;\n" << " v_frag_FragColor = v_geom_FragColor[ndx];\n" << " EmitVertex();\n" << "\n"; if (pointSize) src << " gl_PointSize = 1.0;\n"; src << " gl_Position = gl_in[ndx].gl_Position + offset1 + yoffset;\n" << " v_frag_FragColor = v_geom_FragColor[ndx];\n" << " EmitVertex();\n" << "\n"; if (pointSize) src << " gl_PointSize = 1.0;\n"; src << " gl_Position = gl_in[ndx].gl_Position + offset2 + yoffset;\n" << " v_frag_FragColor = v_geom_FragColor[ndx];\n" << " EmitVertex();\n" << " EndPrimitive();\n" << " }\n" << "}\n"; return src.str(); } class TriangleStripAdjacencyVertexCountTest : public GeometryExpanderRenderTest { public: TriangleStripAdjacencyVertexCountTest (TestContext& testCtx, const PrimitiveTestSpec& inputPrimitives, const int numInputVertices); virtual TestInstance* createInstance (Context& context) const; private: const int m_numInputVertices; }; TriangleStripAdjacencyVertexCountTest::TriangleStripAdjacencyVertexCountTest (TestContext& testCtx, const PrimitiveTestSpec& inputPrimitives, const int numInputVertices) : GeometryExpanderRenderTest (testCtx, inputPrimitives) , m_numInputVertices (numInputVertices) { } TestInstance* TriangleStripAdjacencyVertexCountTest::createInstance (Context& context) const { return new GeometryInputTestInstance(context, m_primitiveType, getName(), m_numInputVertices); } } // anonymous TestCaseGroup* createInputGeometryShaderTests (TestContext& testCtx) { MovePtr inputPrimitiveGroup (new TestCaseGroup(testCtx, "input", "Different input primitives.")); MovePtr basicPrimitiveGroup (new TestCaseGroup(testCtx, "basic_primitive", "Basic Primitive geometry tests")); MovePtr triStripAdjacencyGroup (new TestCaseGroup(testCtx, "triangle_strip_adjacency", "Different triangle_strip_adjacency vertex counts.")); MovePtr conversionPrimitiveGroup (new TestCaseGroup(testCtx, "conversion", "Different input and output primitives.")); const PrimitiveTestSpec inputPrimitives[] = { { VK_PRIMITIVE_TOPOLOGY_POINT_LIST, "points", VK_PRIMITIVE_TOPOLOGY_POINT_LIST }, { VK_PRIMITIVE_TOPOLOGY_LINE_LIST, "lines", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP }, { VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, "line_strip", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP }, { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, "triangles", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP }, { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, "triangle_strip", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP }, { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, "triangle_fan", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP }, { VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY, "lines_adjacency", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP }, { VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY, "line_strip_adjacency", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP }, { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY, "triangles_adjacency", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP } }; // more basic types for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(inputPrimitives); ++ndx) basicPrimitiveGroup->addChild(new GeometryExpanderRenderTest(testCtx, inputPrimitives[ndx])); // triangle strip adjacency with different vertex counts for (int vertexCount = 0; vertexCount <= 12; ++vertexCount) { const string name = "vertex_count_" + de::toString(vertexCount); const PrimitiveTestSpec primitives = { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY, name.c_str(), VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP }; triStripAdjacencyGroup->addChild(new TriangleStripAdjacencyVertexCountTest(testCtx, primitives, vertexCount)); } // different type conversions { static const PrimitiveTestSpec conversionPrimitives[] = { { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, "triangles_to_points", VK_PRIMITIVE_TOPOLOGY_POINT_LIST }, { VK_PRIMITIVE_TOPOLOGY_LINE_LIST, "lines_to_points", VK_PRIMITIVE_TOPOLOGY_POINT_LIST }, { VK_PRIMITIVE_TOPOLOGY_POINT_LIST, "points_to_lines", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP }, { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, "triangles_to_lines", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP }, { VK_PRIMITIVE_TOPOLOGY_POINT_LIST, "points_to_triangles", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP}, { VK_PRIMITIVE_TOPOLOGY_LINE_LIST, "lines_to_triangles", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP} }; for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(conversionPrimitives); ++ndx) conversionPrimitiveGroup->addChild(new GeometryExpanderRenderTest(testCtx, conversionPrimitives[ndx])); } inputPrimitiveGroup->addChild(basicPrimitiveGroup.release()); inputPrimitiveGroup->addChild(triStripAdjacencyGroup.release()); inputPrimitiveGroup->addChild(conversionPrimitiveGroup.release()); return inputPrimitiveGroup.release(); } } // geometry } // vkt