/*------------------------------------------------------------------------ * Vulkan Conformance Tests * ------------------------ * * Copyright (c) 2015 The Khronos Group Inc. * Copyright (c) 2015 Imagination Technologies Ltd. * * 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 Assembly Tests *//*--------------------------------------------------------------------*/ #include "vktPipelineInputAssemblyTests.hpp" #include "vktPipelineClearUtil.hpp" #include "vktPipelineImageUtil.hpp" #include "vktPipelineVertexUtil.hpp" #include "vktPipelineReferenceRenderer.hpp" #include "vktTestCase.hpp" #include "vkImageUtil.hpp" #include "vkMemUtil.hpp" #include "vkPrograms.hpp" #include "vkQueryUtil.hpp" #include "vkRef.hpp" #include "vkRefUtil.hpp" #include "vkTypeUtil.hpp" #include "vkCmdUtil.hpp" #include "vkObjUtil.hpp" #include "tcuImageCompare.hpp" #include "deMath.h" #include "deMemory.h" #include "deRandom.hpp" #include "deStringUtil.hpp" #include "deUniquePtr.hpp" #include #include #include namespace vkt { namespace pipeline { using namespace vk; namespace { class InputAssemblyTest : public vkt::TestCase { public: const static VkPrimitiveTopology s_primitiveTopologies[]; const static deUint32 s_restartIndex32; const static deUint16 s_restartIndex16; const static deUint8 s_restartIndex8; InputAssemblyTest (tcu::TestContext& testContext, const std::string& name, const std::string& description, VkPrimitiveTopology primitiveTopology, int primitiveCount, bool testPrimitiveRestart, VkIndexType indexType); virtual ~InputAssemblyTest (void) {} virtual void initPrograms (SourceCollections& sourceCollections) const; virtual void checkSupport (Context& context) const; virtual TestInstance* createInstance (Context& context) const; static bool isRestartIndex (VkIndexType indexType, deUint32 indexValue); static deUint32 getRestartIndex (VkIndexType indexType); protected: virtual void createBufferData (VkPrimitiveTopology topology, int primitiveCount, VkIndexType indexType, std::vector& indexData, std::vector& vertexData) const = 0; VkPrimitiveTopology m_primitiveTopology; private: const int m_primitiveCount; bool m_testPrimitiveRestart; VkIndexType m_indexType; }; class PrimitiveTopologyTest : public InputAssemblyTest { public: PrimitiveTopologyTest (tcu::TestContext& testContext, const std::string& name, const std::string& description, VkPrimitiveTopology primitiveTopology, VkIndexType indexType); virtual ~PrimitiveTopologyTest (void) {} protected: virtual void createBufferData (VkPrimitiveTopology topology, int primitiveCount, VkIndexType indexType, std::vector& indexData, std::vector& vertexData) const; private: }; class PrimitiveRestartTest : public InputAssemblyTest { public: PrimitiveRestartTest (tcu::TestContext& testContext, const std::string& name, const std::string& description, VkPrimitiveTopology primitiveTopology, VkIndexType indexType); virtual ~PrimitiveRestartTest (void) {} virtual void checkSupport (Context& context) const; protected: virtual void createBufferData (VkPrimitiveTopology topology, int primitiveCount, VkIndexType indexType, std::vector& indexData, std::vector& vertexData) const; private: bool isRestartPrimitive (int primitiveIndex) const; void createListPrimitives (int primitiveCount, float originX, float originY, float primitiveSizeX, float primitiveSizeY, int verticesPerPrimitive, VkIndexType indexType, std::vector& indexData, std::vector& vertexData, std::vector adjacencies) const; std::vector m_restartPrimitives; }; class InputAssemblyInstance : public vkt::TestInstance { public: InputAssemblyInstance (Context& context, VkPrimitiveTopology primitiveTopology, bool testPrimitiveRestart, VkIndexType indexType, const std::vector& indexBufferData, const std::vector& vertexBufferData); virtual ~InputAssemblyInstance (void); virtual tcu::TestStatus iterate (void); private: tcu::TestStatus verifyImage (void); void uploadIndexBufferData16 (deUint16* destPtr, const std::vector& indexBufferData); void uploadIndexBufferData8 (deUint8* destPtr, const std::vector& indexBufferData); VkPrimitiveTopology m_primitiveTopology; bool m_primitiveRestartEnable; VkIndexType m_indexType; Move m_vertexBuffer; std::vector m_vertices; de::MovePtr m_vertexBufferAlloc; Move m_indexBuffer; std::vector m_indices; de::MovePtr m_indexBufferAlloc; const tcu::UVec2 m_renderSize; const VkFormat m_colorFormat; VkImageCreateInfo m_colorImageCreateInfo; Move m_colorImage; de::MovePtr m_colorImageAlloc; Move m_colorAttachmentView; Move m_renderPass; Move m_framebuffer; Move m_vertexShaderModule; Move m_fragmentShaderModule; Move m_tcsShaderModule; Move m_tesShaderModule; Move m_pipelineLayout; Move m_graphicsPipeline; Move m_cmdPool; Move m_cmdBuffer; }; // InputAssemblyTest const VkPrimitiveTopology InputAssemblyTest::s_primitiveTopologies[] = { VK_PRIMITIVE_TOPOLOGY_POINT_LIST, VK_PRIMITIVE_TOPOLOGY_LINE_LIST, VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY, VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY }; const deUint32 InputAssemblyTest::s_restartIndex32 = ~((deUint32)0u); const deUint16 InputAssemblyTest::s_restartIndex16 = ~((deUint16)0u); const deUint8 InputAssemblyTest::s_restartIndex8 = ~((deUint8)0u); InputAssemblyTest::InputAssemblyTest (tcu::TestContext& testContext, const std::string& name, const std::string& description, VkPrimitiveTopology primitiveTopology, int primitiveCount, bool testPrimitiveRestart, VkIndexType indexType) : vkt::TestCase (testContext, name, description) , m_primitiveTopology (primitiveTopology) , m_primitiveCount (primitiveCount) , m_testPrimitiveRestart (testPrimitiveRestart) , m_indexType (indexType) { } void InputAssemblyTest::checkSupport (Context& context) const { if (m_indexType == VK_INDEX_TYPE_UINT8_EXT) context.requireDeviceFunctionality("VK_EXT_index_type_uint8"); switch (m_primitiveTopology) { case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY: case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY: case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY: case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY: context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER); break; case VK_PRIMITIVE_TOPOLOGY_PATCH_LIST: context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_TESSELLATION_SHADER); break; default: break; } if (m_primitiveTopology == 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"); } } TestInstance* InputAssemblyTest::createInstance (Context& context) const { std::vector indexBufferData; std::vector vertexBufferData; createBufferData(m_primitiveTopology, m_primitiveCount, m_indexType, indexBufferData, vertexBufferData); return new InputAssemblyInstance(context, m_primitiveTopology, m_testPrimitiveRestart, m_indexType, indexBufferData, vertexBufferData); } void InputAssemblyTest::initPrograms (SourceCollections& sourceCollections) const { std::ostringstream vertexSource; vertexSource << "#version 310 es\n" "layout(location = 0) in vec4 position;\n" "layout(location = 1) in vec4 color;\n" "layout(location = 0) out highp vec4 vtxColor;\n" "void main (void)\n" "{\n" " gl_Position = position;\n" << (m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_POINT_LIST ? " gl_PointSize = 3.0;\n" : "" ) << " vtxColor = color;\n" "}\n"; sourceCollections.glslSources.add("color_vert") << glu::VertexSource(vertexSource.str()); sourceCollections.glslSources.add("color_frag") << glu::FragmentSource( "#version 310 es\n" "layout(location = 0) in highp vec4 vtxColor;\n" "layout(location = 0) out highp vec4 fragColor;\n" "void main (void)\n" "{\n" " fragColor = vtxColor;\n" "}\n"); sourceCollections.glslSources.add("color_tcs") << glu::TessellationControlSource( "#version 310 es\n" "#extension GL_EXT_tessellation_shader : require\n" "layout(vertices = 3) out;\n" "layout(location = 0) in highp vec4 vtxColorIn[];\n" "layout(location = 0) out highp vec4 vtxColorOut[];\n" "#define ID gl_InvocationID\n" "void main (void)\n" "{\n" " vtxColorOut[ID] = vtxColorIn[ID];\n" " gl_out[ID].gl_Position = gl_in[ID].gl_Position;\n" " if (ID == 0)\n" " {\n" " gl_TessLevelInner[0] = 5.0;\n" " gl_TessLevelOuter[0] = 4.0;\n" " gl_TessLevelOuter[1] = 5.0;\n" " gl_TessLevelOuter[2] = 6.0;\n" " }\n" "}\n"); sourceCollections.glslSources.add("color_tes") << glu::TessellationEvaluationSource( "#version 310 es\n" "#extension GL_EXT_tessellation_shader : require\n" "layout(triangles) in;\n" "layout(location = 0) in vec4 vtxColorIn[];\n" "layout(location = 0) out vec4 vtxColorOut;\n" "void main (void)\n" "{\n" " vec4 p0 = gl_TessCoord.x * gl_in[0].gl_Position;\n" " vec4 p1 = gl_TessCoord.y * gl_in[1].gl_Position;\n" " vec4 p2 = gl_TessCoord.z * gl_in[2].gl_Position;\n" " gl_Position = p0 + p1 + p2;\n" " vec4 q0 = gl_TessCoord.x * vtxColorIn[0];\n" " vec4 q1 = gl_TessCoord.y * vtxColorIn[1];\n" " vec4 q2 = gl_TessCoord.z * vtxColorIn[2];\n" " vtxColorOut = q0 + q1 + q2;\n" "}\n"); } bool InputAssemblyTest::isRestartIndex (VkIndexType indexType, deUint32 indexValue) { if (indexType == VK_INDEX_TYPE_UINT16) return indexValue == s_restartIndex16; else if (indexType == VK_INDEX_TYPE_UINT8_EXT) return indexValue == s_restartIndex8; else return indexValue == s_restartIndex32; } deUint32 InputAssemblyTest::getRestartIndex (VkIndexType indexType) { if (indexType == VK_INDEX_TYPE_UINT16) return InputAssemblyTest::s_restartIndex16; else if (indexType == VK_INDEX_TYPE_UINT8_EXT) return InputAssemblyTest::s_restartIndex8; else return InputAssemblyTest::s_restartIndex32; } // PrimitiveTopologyTest PrimitiveTopologyTest::PrimitiveTopologyTest (tcu::TestContext& testContext, const std::string& name, const std::string& description, VkPrimitiveTopology primitiveTopology, VkIndexType indexType) : InputAssemblyTest (testContext, name, description, primitiveTopology, 10, false, indexType) { } void PrimitiveTopologyTest::createBufferData (VkPrimitiveTopology topology, int primitiveCount, VkIndexType indexType, std::vector& indexData, std::vector& vertexData) const { DE_ASSERT(primitiveCount > 0); DE_UNREF(indexType); const tcu::Vec4 red (1.0f, 0.0f, 0.0f, 1.0f); const tcu::Vec4 green (0.0f, 1.0f, 0.0f, 1.0f); const float border = 0.2f; const float originX = -1.0f + border; const float originY = -1.0f + border; const Vertex4RGBA defaultVertex = { tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), green }; float primitiveSizeY = (2.0f - 2.0f * border); float primitiveSizeX; std::vector indices; std::vector vertices; // Calculate primitive size switch (topology) { case VK_PRIMITIVE_TOPOLOGY_POINT_LIST: primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount / 2 + primitiveCount % 2 - 1); break; case VK_PRIMITIVE_TOPOLOGY_LINE_LIST: case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY: primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount - 1); break; case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP: case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY: primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount / 2); break; case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY: primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount + primitiveCount / 2 + primitiveCount % 2 - 1); break; case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY: primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount / 2 + primitiveCount % 2); break; case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN: primitiveSizeX = 1.0f - border; primitiveSizeY = 1.0f - border; break; default: primitiveSizeX = 0.0f; // Garbage DE_ASSERT(false); } switch (topology) { case VK_PRIMITIVE_TOPOLOGY_POINT_LIST: for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++) { const Vertex4RGBA vertex = { tcu::Vec4(originX + float(primitiveNdx / 2) * primitiveSizeX, originY + float(primitiveNdx % 2) * primitiveSizeY, 0.0f, 1.0f), red }; vertices.push_back(vertex); indices.push_back(primitiveNdx); } break; case VK_PRIMITIVE_TOPOLOGY_LINE_LIST: for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++) { for (int vertexNdx = 0; vertexNdx < 2; vertexNdx++) { const Vertex4RGBA vertex = { tcu::Vec4(originX + float((primitiveNdx * 2 + vertexNdx) / 2) * primitiveSizeX, originY + float(vertexNdx % 2) * primitiveSizeY, 0.0f, 1.0f), red }; vertices.push_back(vertex); indices.push_back((primitiveNdx * 2 + vertexNdx)); } } break; case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP: for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++) { if (primitiveNdx == 0) { Vertex4RGBA vertex = { tcu::Vec4(originX, originY, 0.0f, 1.0f), red }; vertices.push_back(vertex); indices.push_back(0); vertex.position = tcu::Vec4(originX, originY + primitiveSizeY, 0.0f, 1.0f); vertices.push_back(vertex); indices.push_back(1); } else { const Vertex4RGBA vertex = { tcu::Vec4(originX + float((primitiveNdx + 1) / 2) * primitiveSizeX, originY + float((primitiveNdx + 1) % 2) * primitiveSizeY, 0.0f, 1.0f), red }; vertices.push_back(vertex); indices.push_back(primitiveNdx + 1); } } break; case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++) { for (int vertexNdx = 0; vertexNdx < 3; vertexNdx++) { const Vertex4RGBA vertex = { tcu::Vec4(originX + float((primitiveNdx * 3 + vertexNdx) / 2) * primitiveSizeX, originY + float((primitiveNdx * 3 + vertexNdx)% 2) * primitiveSizeY, 0.0f, 1.0f), red }; vertices.push_back(vertex); indices.push_back(primitiveNdx * 3 + vertexNdx); } } break; case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++) { if (primitiveNdx == 0) { for (int vertexNdx = 0; vertexNdx < 3; vertexNdx++) { const Vertex4RGBA vertex = { tcu::Vec4(originX + float(vertexNdx / 2) * primitiveSizeX, originY + float(vertexNdx % 2) * primitiveSizeY, 0.0f, 1.0f), red }; vertices.push_back(vertex); indices.push_back(vertexNdx); } } else { const Vertex4RGBA vertex = { tcu::Vec4(originX + float((primitiveNdx + 2) / 2) * primitiveSizeX, originY + float((primitiveNdx + 2) % 2) * primitiveSizeY, 0.0f, 1.0f), red }; vertices.push_back(vertex); indices.push_back(primitiveNdx + 2); } } break; case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN: { const float stepAngle = de::min(DE_PI * 0.5f, (2 * DE_PI) / float(primitiveCount)); for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++) { if (primitiveNdx == 0) { Vertex4RGBA vertex = { tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f), red }; vertices.push_back(vertex); indices.push_back(0); vertex.position = tcu::Vec4(primitiveSizeX, 0.0f, 0.0f, 1.0f); vertices.push_back(vertex); indices.push_back(1); vertex.position = tcu::Vec4(primitiveSizeX * deFloatCos(stepAngle), primitiveSizeY * deFloatSin(stepAngle), 0.0f, 1.0f); vertices.push_back(vertex); indices.push_back(2); } else { const Vertex4RGBA vertex = { tcu::Vec4(primitiveSizeX * deFloatCos(stepAngle * float(primitiveNdx + 1)), primitiveSizeY * deFloatSin(stepAngle * float(primitiveNdx + 1)), 0.0f, 1.0f), red }; vertices.push_back(vertex); indices.push_back(primitiveNdx + 2); } } break; } case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY: vertices.push_back(defaultVertex); for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++) { indices.push_back(0); for (int vertexNdx = 0; vertexNdx < 2; vertexNdx++) { const Vertex4RGBA vertex = { tcu::Vec4(originX + float((primitiveNdx * 2 + vertexNdx) / 2) * primitiveSizeX, originY + float(vertexNdx % 2) * primitiveSizeY, 0.0f, 1.0f), red }; vertices.push_back(vertex); indices.push_back(primitiveNdx * 2 + vertexNdx + 1); } indices.push_back(0); } break; case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY: vertices.push_back(defaultVertex); indices.push_back(0); for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++) { if (primitiveNdx == 0) { Vertex4RGBA vertex = { tcu::Vec4(originX, originY, 0.0f, 1.0f), red }; vertices.push_back(vertex); indices.push_back(1); vertex.position = tcu::Vec4(originX, originY + primitiveSizeY, 0.0f, 1.0f); vertices.push_back(vertex); indices.push_back(2); } else { const Vertex4RGBA vertex = { tcu::Vec4(originX + float((primitiveNdx + 1) / 2) * primitiveSizeX, originY + float((primitiveNdx + 1) % 2) * primitiveSizeY, 0.0f, 1.0f), red }; vertices.push_back(vertex); indices.push_back(primitiveNdx + 2); } } indices.push_back(0); break; case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY: vertices.push_back(defaultVertex); for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++) { for (int vertexNdx = 0; vertexNdx < 3; vertexNdx++) { const Vertex4RGBA vertex = { tcu::Vec4(originX + float((primitiveNdx * 3 + vertexNdx) / 2) * primitiveSizeX, originY + float((primitiveNdx * 3 + vertexNdx)% 2) * primitiveSizeY, 0.0f, 1.0f), red }; vertices.push_back(vertex); indices.push_back(primitiveNdx * 3 + vertexNdx + 1); indices.push_back(0); } } break; case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY: vertices.push_back(defaultVertex); for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++) { if (primitiveNdx == 0) { for (int vertexNdx = 0; vertexNdx < 3; vertexNdx++) { const Vertex4RGBA vertex = { tcu::Vec4(originX + float(vertexNdx / 2) * primitiveSizeX, originY + float(vertexNdx % 2) * primitiveSizeY, 0.0f, 1.0f), red }; vertices.push_back(vertex); indices.push_back(vertexNdx + 1); indices.push_back(0); } } else { const Vertex4RGBA vertex = { tcu::Vec4(originX + float((primitiveNdx + 2) / 2) * primitiveSizeX, originY + float((primitiveNdx + 2) % 2) * primitiveSizeY, 0.0f, 1.0f), red }; vertices.push_back(vertex); indices.push_back(primitiveNdx + 2 + 1); indices.push_back(0); } } break; default: DE_ASSERT(false); break; } vertexData = vertices; indexData = indices; } // PrimitiveRestartTest PrimitiveRestartTest::PrimitiveRestartTest (tcu::TestContext& testContext, const std::string& name, const std::string& description, VkPrimitiveTopology primitiveTopology, VkIndexType indexType) : InputAssemblyTest (testContext, name, description, primitiveTopology, 10, true, indexType) { deUint32 restartPrimitives[] = { 1, 5 }; m_restartPrimitives = std::vector(restartPrimitives, restartPrimitives + sizeof(restartPrimitives) / sizeof(deUint32)); } void PrimitiveRestartTest::checkSupport (Context& context) const { switch (m_primitiveTopology) { case VK_PRIMITIVE_TOPOLOGY_PATCH_LIST: case VK_PRIMITIVE_TOPOLOGY_POINT_LIST: case VK_PRIMITIVE_TOPOLOGY_LINE_LIST: case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY: case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY: { context.requireDeviceFunctionality("VK_EXT_primitive_topology_list_restart"); const auto& features = context.getPrimitiveTopologyListRestartFeaturesEXT(); if (!features.primitiveTopologyListRestart) TCU_THROW(NotSupportedError, "Primitive topology list restart feature not supported"); if (m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST && !features.primitiveTopologyPatchListRestart) TCU_THROW(NotSupportedError, "Primitive topology patch list restart feature not supported"); } break; default: break; } InputAssemblyTest::checkSupport(context); } void PrimitiveRestartTest::createBufferData (VkPrimitiveTopology topology, int primitiveCount, VkIndexType indexType, std::vector& indexData, std::vector& vertexData) const { DE_ASSERT(primitiveCount > 0); DE_UNREF(indexType); const tcu::Vec4 red (1.0f, 0.0f, 0.0f, 1.0f); const tcu::Vec4 green (0.0f, 1.0f, 0.0f, 1.0f); const float border = 0.2f; const float originX = -1.0f + border; const float originY = -1.0f + border; const Vertex4RGBA defaultVertex = { tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), green }; float primitiveSizeY = (2.0f - 2.0f * border); float primitiveSizeX; bool primitiveStart = true; std::vector indices; std::vector vertices; // Calculate primitive size switch (topology) { case VK_PRIMITIVE_TOPOLOGY_POINT_LIST: primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount / 2 + primitiveCount % 2 - 1); break; case VK_PRIMITIVE_TOPOLOGY_LINE_LIST: case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY: case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP: case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY: primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount / 2); break; case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY: case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY: case VK_PRIMITIVE_TOPOLOGY_PATCH_LIST: primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount / 2 + primitiveCount % 2); break; case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN: primitiveSizeX = 1.0f - border; primitiveSizeY = 1.0f - border; break; default: primitiveSizeX = 0.0f; // Garbage DE_ASSERT(false); } switch (topology) { case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP: for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++) { if (isRestartPrimitive(primitiveNdx)) { indices.push_back(InputAssemblyTest::getRestartIndex(indexType)); primitiveStart = true; } else { if (primitiveStart) { const Vertex4RGBA vertex = { tcu::Vec4(originX + float(primitiveNdx / 2) * primitiveSizeX, originY + float(primitiveNdx % 2) * primitiveSizeY, 0.0f, 1.0f), red }; vertices.push_back(vertex); indices.push_back((deUint32)vertices.size() - 1); primitiveStart = false; } const Vertex4RGBA vertex = { tcu::Vec4(originX + float((primitiveNdx + 1) / 2) * primitiveSizeX, originY + float((primitiveNdx + 1) % 2) * primitiveSizeY, 0.0f, 1.0f), red }; vertices.push_back(vertex); indices.push_back((deUint32)vertices.size() - 1); } } break; case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: { for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++) { if (isRestartPrimitive(primitiveNdx)) { indices.push_back(InputAssemblyTest::getRestartIndex(indexType)); primitiveStart = true; } else { if (primitiveStart) { for (int vertexNdx = 0; vertexNdx < 2; vertexNdx++) { const Vertex4RGBA vertex = { tcu::Vec4(originX + float((primitiveNdx + vertexNdx) / 2) * primitiveSizeX, originY + float((primitiveNdx + vertexNdx) % 2) * primitiveSizeY, 0.0f, 1.0f), red }; vertices.push_back(vertex); indices.push_back((deUint32)vertices.size() - 1); } primitiveStart = false; } const Vertex4RGBA vertex = { tcu::Vec4(originX + float((primitiveNdx + 2) / 2) * primitiveSizeX, originY + float((primitiveNdx + 2) % 2) * primitiveSizeY, 0.0f, 1.0f), red }; vertices.push_back(vertex); indices.push_back((deUint32)vertices.size() - 1); } } break; } case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN: { const float stepAngle = de::min(DE_PI * 0.5f, (2 * DE_PI) / float(primitiveCount)); for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++) { if (isRestartPrimitive(primitiveNdx)) { indices.push_back(InputAssemblyTest::getRestartIndex(indexType)); primitiveStart = true; } else { if (primitiveStart) { Vertex4RGBA vertex = { tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f), red }; vertices.push_back(vertex); indices.push_back((deUint32)vertices.size() - 1); vertex.position = tcu::Vec4(primitiveSizeX * deFloatCos(stepAngle * float(primitiveNdx)), primitiveSizeY * deFloatSin(stepAngle * float(primitiveNdx)), 0.0f, 1.0f); vertices.push_back(vertex); indices.push_back((deUint32)vertices.size() - 1); primitiveStart = false; } const Vertex4RGBA vertex = { tcu::Vec4(primitiveSizeX * deFloatCos(stepAngle * float(primitiveNdx + 1)), primitiveSizeY * deFloatSin(stepAngle * float(primitiveNdx + 1)), 0.0f, 1.0f), red }; vertices.push_back(vertex); indices.push_back((deUint32)vertices.size() - 1); } } break; } case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY: vertices.push_back(defaultVertex); for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++) { if (isRestartPrimitive(primitiveNdx)) { indices.push_back(0); indices.push_back(InputAssemblyTest::getRestartIndex(indexType)); primitiveStart = true; } else { if (primitiveStart) { indices.push_back(0); const Vertex4RGBA vertex = { tcu::Vec4(originX + float(primitiveNdx / 2) * primitiveSizeX, originY + float(primitiveNdx % 2) * primitiveSizeY, 0.0f, 1.0f), red }; vertices.push_back(vertex); indices.push_back((deUint32)vertices.size() - 1); primitiveStart = false; } const Vertex4RGBA vertex = { tcu::Vec4(originX + float((primitiveNdx + 1) / 2) * primitiveSizeX, originY + float((primitiveNdx + 1) % 2) * primitiveSizeY, 0.0f, 1.0f), red }; vertices.push_back(vertex); indices.push_back((deUint32)vertices.size() - 1); } } indices.push_back(0); break; case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY: vertices.push_back(defaultVertex); for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++) { if (isRestartPrimitive(primitiveNdx)) { indices.push_back(InputAssemblyTest::getRestartIndex(indexType)); primitiveStart = true; } else { if (primitiveStart) { for (int vertexNdx = 0; vertexNdx < 2; vertexNdx++) { const Vertex4RGBA vertex = { tcu::Vec4(originX + float((primitiveNdx + vertexNdx) / 2) * primitiveSizeX, originY + float((primitiveNdx + vertexNdx) % 2) * primitiveSizeY, 0.0f, 1.0f), red }; vertices.push_back(vertex); indices.push_back((deUint32)vertices.size() - 1); indices.push_back(0); } primitiveStart = false; } const Vertex4RGBA vertex = { tcu::Vec4(originX + float((primitiveNdx + 2) / 2) * primitiveSizeX, originY + float((primitiveNdx + 2) % 2) * primitiveSizeY, 0.0f, 1.0f), red }; vertices.push_back(vertex); indices.push_back((deUint32)vertices.size() - 1); indices.push_back(0); } } break; case VK_PRIMITIVE_TOPOLOGY_POINT_LIST: createListPrimitives(primitiveCount, originX, originY, primitiveSizeX, primitiveSizeY, 1, indexType, indices, vertices, std::vector()); break; case VK_PRIMITIVE_TOPOLOGY_LINE_LIST: createListPrimitives(primitiveCount, originX, originY, primitiveSizeX, primitiveSizeY, 2, indexType, indices, vertices, std::vector()); break; case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY: { std::vector adjacencies = { 0, 3 }; createListPrimitives(primitiveCount, originX, originY, primitiveSizeX, primitiveSizeY, 4, indexType, indices, vertices, adjacencies); } break; case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: case VK_PRIMITIVE_TOPOLOGY_PATCH_LIST: createListPrimitives(primitiveCount, originX, originY, primitiveSizeX, primitiveSizeY, 3, indexType, indices, vertices, std::vector()); break; case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY: { std::vector adjacencies = { 1, 3, 5 }; createListPrimitives(primitiveCount, originX, originY, primitiveSizeX, primitiveSizeY, 6, indexType, indices, vertices, adjacencies); } break; default: DE_ASSERT(false); break; } vertexData = vertices; indexData = indices; } void PrimitiveRestartTest::createListPrimitives (int primitiveCount, float originX, float originY, float primitiveSizeX, float primitiveSizeY, int verticesPerPrimitive, VkIndexType indexType, std::vector& indexData, std::vector& vertexData, std::vector adjacencies) const { const tcu::Vec4 red (1.0f, 0.0f, 0.0f, 1.0f); const tcu::Vec4 green (0.0f, 1.0f, 0.0f, 1.0f); // Tells which vertex of a primitive is used as a restart index. // This is decreased each time a restart primitive is used. int restartVertexIndex = verticesPerPrimitive - 1; for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++) { deUint32 nonAdjacentVertexNdx = 0; for (int vertexNdx = 0; vertexNdx < verticesPerPrimitive; vertexNdx++) { if (isRestartPrimitive(primitiveNdx) && vertexNdx == restartVertexIndex) { indexData.push_back(InputAssemblyTest::getRestartIndex(indexType)); restartVertexIndex--; if (restartVertexIndex < 0) restartVertexIndex = verticesPerPrimitive - 1; break; } if (std::find(adjacencies.begin(), adjacencies.end(), vertexNdx) != adjacencies.end()) { // This is an adjacency vertex index. Add a green vertex that should never end up to the framebuffer. const Vertex4RGBA vertex = { tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f), green }; vertexData.push_back(vertex); indexData.push_back((deUint32) vertexData.size() - 1); continue; } const Vertex4RGBA vertex = { tcu::Vec4(originX + float((primitiveNdx + nonAdjacentVertexNdx) / 2) * primitiveSizeX, originY + float((primitiveNdx + nonAdjacentVertexNdx) % 2) * primitiveSizeY, 0.0f, 1.0f), red }; vertexData.push_back(vertex); indexData.push_back((deUint32) vertexData.size() - 1); nonAdjacentVertexNdx++; } } } bool PrimitiveRestartTest::isRestartPrimitive (int primitiveIndex) const { return std::find(m_restartPrimitives.begin(), m_restartPrimitives.end(), primitiveIndex) != m_restartPrimitives.end(); } // InputAssemblyInstance InputAssemblyInstance::InputAssemblyInstance (Context& context, VkPrimitiveTopology primitiveTopology, bool testPrimitiveRestart, VkIndexType indexType, const std::vector& indexBufferData, const std::vector& vertexBufferData) : vkt::TestInstance (context) , m_primitiveTopology (primitiveTopology) , m_primitiveRestartEnable (testPrimitiveRestart) , m_indexType (indexType) , m_vertices (vertexBufferData) , m_indices (indexBufferData) , m_renderSize ((primitiveTopology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN) ? tcu::UVec2(32, 32) : tcu::UVec2(64, 16)) , m_colorFormat (VK_FORMAT_R8G8B8A8_UNORM) { const DeviceInterface& vk = context.getDeviceInterface(); const VkDevice vkDevice = context.getDevice(); const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex(); SimpleAllocator memAlloc (vk, vkDevice, getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice())); const VkComponentMapping componentMappingRGBA = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }; const bool patchList = m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST; // Create color image { const VkImageCreateInfo colorImageParams = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkImageCreateFlags flags; VK_IMAGE_TYPE_2D, // VkImageType imageType; m_colorFormat, // VkFormat format; { m_renderSize.x(), m_renderSize.y(), 1u }, // VkExtent3D extent; 1u, // deUint32 mipLevels; 1u, // deUint32 arrayLayers; VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling; VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, // VkImageUsageFlags usage; VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; 1u, // deUint32 queueFamilyIndexCount; &queueFamilyIndex, // const deUint32* pQueueFamilyIndices; VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout; }; m_colorImageCreateInfo = colorImageParams; m_colorImage = createImage(vk, vkDevice, &m_colorImageCreateInfo); // Allocate and bind color image memory m_colorImageAlloc = memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *m_colorImage), MemoryRequirement::Any); VK_CHECK(vk.bindImageMemory(vkDevice, *m_colorImage, m_colorImageAlloc->getMemory(), m_colorImageAlloc->getOffset())); } // Create color attachment view { const VkImageViewCreateInfo colorAttachmentViewParams = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkImageViewCreateFlags flags; *m_colorImage, // VkImage image; VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType; m_colorFormat, // VkFormat format; componentMappingRGBA, // VkComponentMapping components; { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }, // VkImageSubresourceRange subresourceRange; }; m_colorAttachmentView = createImageView(vk, vkDevice, &colorAttachmentViewParams); } // Create render pass m_renderPass = makeRenderPass(vk, vkDevice, m_colorFormat); // Create framebuffer { const VkFramebufferCreateInfo framebufferParams = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkFramebufferCreateFlags flags; *m_renderPass, // VkRenderPass renderPass; 1u, // deUint32 attachmentCount; &m_colorAttachmentView.get(), // const VkImageView* pAttachments; (deUint32)m_renderSize.x(), // deUint32 width; (deUint32)m_renderSize.y(), // deUint32 height; 1u // deUint32 layers; }; m_framebuffer = createFramebuffer(vk, vkDevice, &framebufferParams); } // Create pipeline layout { const VkPipelineLayoutCreateInfo pipelineLayoutParams = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkPipelineLayoutCreateFlags flags; 0u, // deUint32 setLayoutCount; DE_NULL, // const VkDescriptorSetLayout* pSetLayouts; 0u, // deUint32 pushConstantRangeCount; DE_NULL // const VkPushConstantRange* pPushConstantRanges; }; m_pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams); } m_vertexShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("color_vert"), 0); m_fragmentShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("color_frag"), 0); if (patchList) { m_tcsShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("color_tcs"), 0); m_tesShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("color_tes"), 0); } // Create pipeline { std::vector shaderStages; // Vertex shaderStages.push_back({ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkPipelineShaderStageCreateFlags flags; VK_SHADER_STAGE_VERTEX_BIT, // VkShaderStageFlagBits stage; *m_vertexShaderModule, // VkShaderModule module; "main", // const char* pName; DE_NULL // const VkSpecializationInfo* pSpecializationInfo; }); // Fragment shaderStages.push_back({ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkPipelineShaderStageCreateFlags flags; VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlagBits stage; *m_fragmentShaderModule, // VkShaderModule module; "main", // const char* pName; DE_NULL // const VkSpecializationInfo* pSpecializationInfo; }); if (patchList) { // Tessellation Control Shader shaderStages.push_back({ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkPipelineShaderStageCreateFlags flags; VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, // VkShaderStageFlagBits stage; *m_tcsShaderModule, // VkShaderModule module; "main", // const char* pName; DE_NULL // const VkSpecializationInfo* pSpecializationInfo; }); // Tessellation Evaluation Shader shaderStages.push_back({ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkPipelineShaderStageCreateFlags flags; VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, // VkShaderStageFlagBits stage; *m_tesShaderModule, // VkShaderModule module; "main", // const char* pName; DE_NULL // const VkSpecializationInfo* pSpecializationInfo; }); } const VkVertexInputBindingDescription vertexInputBindingDescription = { 0u, // deUint32 binding; sizeof(Vertex4RGBA), // deUint32 stride; VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputRate inputRate; }; const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] = { { 0u, // deUint32 location; 0u, // deUint32 binding; VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format; 0u // deUint32 offset; }, { 1u, // deUint32 location; 0u, // deUint32 binding; VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format; DE_OFFSET_OF(Vertex4RGBA, color), // deUint32 offset; } }; const VkPipelineVertexInputStateCreateInfo vertexInputStateParams = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkPipelineVertexInputStateCreateFlags flags; 1u, // deUint32 vertexBindingDescriptionCount; &vertexInputBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions; 2u, // deUint32 vertexAttributeDescriptionCount; vertexInputAttributeDescriptions // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions; }; const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateParams = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkPipelineInputAssemblyStateCreateFlags flags; m_primitiveTopology, // VkPrimitiveTopology topology; m_primitiveRestartEnable // VkBool32 primitiveRestartEnable; }; const VkViewport viewport = makeViewport(m_renderSize); const VkRect2D scissor = makeRect2D(m_renderSize); const VkPipelineViewportStateCreateInfo viewportStateParams = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkPipelineViewportStateCreateFlags flags; 1u, // deUint32 viewportCount; &viewport, // const VkViewport* pViewports; 1u, // deUint32 scissorCount; &scissor, // const VkRect2D* pScissors; }; const VkPipelineRasterizationStateCreateInfo rasterStateParams = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkPipelineRasterizationStateCreateFlags flags; false, // VkBool32 depthClampEnable; false, // VkBool32 rasterizerDiscardEnable; VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode; VK_CULL_MODE_NONE, // VkCullModeFlags cullMode; VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace; VK_FALSE, // VkBool32 depthBiasEnable; 0.0f, // float depthBiasConstantFactor; 0.0f, // float depthBiasClamp; 0.0f, // float depthBiasSlopeFactor; 1.0f // float lineWidth; }; const VkPipelineColorBlendAttachmentState colorBlendAttachmentState = { false, // VkBool32 blendEnable; VK_BLEND_FACTOR_ONE, // VkBlendFactor srcColorBlendFactor; VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor; VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp; VK_BLEND_FACTOR_ONE, // VkBlendFactor srcAlphaBlendFactor; VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor; VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp; VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | // VkColorComponentFlags colorWriteMask; VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT }; const VkPipelineColorBlendStateCreateInfo colorBlendStateParams = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkPipelineColorBlendStateCreateFlags flags; false, // VkBool32 logicOpEnable; VK_LOGIC_OP_COPY, // VkLogicOp logicOp; 1u, // deUint32 attachmentCount; &colorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments; { 0.0f, 0.0f, 0.0f, 0.0f } // float blendConstants[4]; }; const VkPipelineMultisampleStateCreateInfo multisampleStateParams = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkPipelineMultisampleStateCreateFlags flags; VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples; false, // VkBool32 sampleShadingEnable; 0.0f, // float minSampleShading; DE_NULL, // const VkSampleMask* pSampleMask; false, // VkBool32 alphaToCoverageEnable; false // VkBool32 alphaToOneEnable; }; VkPipelineDepthStencilStateCreateInfo depthStencilStateParams = { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkPipelineDepthStencilStateCreateFlags flags; false, // VkBool32 depthTestEnable; false, // VkBool32 depthWriteEnable; VK_COMPARE_OP_LESS, // VkCompareOp depthCompareOp; false, // VkBool32 depthBoundsTestEnable; false, // VkBool32 stencilTestEnable; // VkStencilOpState front; { VK_STENCIL_OP_KEEP, // VkStencilOp failOp; VK_STENCIL_OP_KEEP, // VkStencilOp passOp; VK_STENCIL_OP_KEEP, // VkStencilOp depthFailOp; VK_COMPARE_OP_NEVER, // VkCompareOp compareOp; 0u, // deUint32 compareMask; 0u, // deUint32 writeMask; 0u, // deUint32 reference; }, // VkStencilOpState back; { VK_STENCIL_OP_KEEP, // VkStencilOp failOp; VK_STENCIL_OP_KEEP, // VkStencilOp passOp; VK_STENCIL_OP_KEEP, // VkStencilOp depthFailOp; VK_COMPARE_OP_NEVER, // VkCompareOp compareOp; 0u, // deUint32 compareMask; 0u, // deUint32 writeMask; 0u, // deUint32 reference; }, 0.0f, // float minDepthBounds; 1.0f // float maxDepthBounds; }; const VkPipelineTessellationStateCreateInfo tessellationParams = { VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkPipelineTessellationStateCreateFlags flags; 3u, // uint32_t patchControlPoints; }; const VkGraphicsPipelineCreateInfo graphicsPipelineParams = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkPipelineCreateFlags flags; (deUint32)shaderStages.size(), // deUint32 stageCount; shaderStages.data(), // const VkPipelineShaderStageCreateInfo* pStages; &vertexInputStateParams, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState; &inputAssemblyStateParams, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState; patchList ? &tessellationParams : DE_NULL, // const VkPipelineTessellationStateCreateInfo* pTessellationState; &viewportStateParams, // const VkPipelineViewportStateCreateInfo* pViewportState; &rasterStateParams, // const VkPipelineRasterizationStateCreateInfo* pRasterizationState; &multisampleStateParams, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState; &depthStencilStateParams, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState; &colorBlendStateParams, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState; (const VkPipelineDynamicStateCreateInfo*)DE_NULL, // const VkPipelineDynamicStateCreateInfo* pDynamicState; *m_pipelineLayout, // VkPipelineLayout layout; *m_renderPass, // VkRenderPass renderPass; 0u, // deUint32 subpass; 0u, // VkPipeline basePipelineHandle; 0u // deInt32 basePipelineIndex; }; m_graphicsPipeline = createGraphicsPipeline(vk, vkDevice, DE_NULL, &graphicsPipelineParams); } // Create vertex and index buffer { const VkBufferCreateInfo indexBufferParams = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkBufferCreateFlags flags; m_indices.size() * sizeof(deUint32), // VkDeviceSize size; VK_BUFFER_USAGE_INDEX_BUFFER_BIT, // VkBufferUsageFlags usage; VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; 1u, // deUint32 queueFamilyIndexCount; &queueFamilyIndex // const deUint32* pQueueFamilyIndices; }; const VkBufferCreateInfo vertexBufferParams = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkBufferCreateFlags flags; m_vertices.size() * sizeof(Vertex4RGBA), // VkDeviceSize size; VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, // VkBufferUsageFlags usage; VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; 1u, // deUint32 queueFamilyIndexCount; &queueFamilyIndex // const deUint32* pQueueFamilyIndices; }; m_indexBuffer = createBuffer(vk, vkDevice, &indexBufferParams); m_indexBufferAlloc = memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_indexBuffer), MemoryRequirement::HostVisible); VK_CHECK(vk.bindBufferMemory(vkDevice, *m_indexBuffer, m_indexBufferAlloc->getMemory(), m_indexBufferAlloc->getOffset())); m_vertexBuffer = createBuffer(vk, vkDevice, &vertexBufferParams); m_vertexBufferAlloc = memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_vertexBuffer), MemoryRequirement::HostVisible); VK_CHECK(vk.bindBufferMemory(vkDevice, *m_vertexBuffer, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset())); // Load vertices into index buffer if (m_indexType == VK_INDEX_TYPE_UINT32) { deMemcpy(m_indexBufferAlloc->getHostPtr(), m_indices.data(), m_indices.size() * sizeof(deUint32)); } else if (m_indexType == VK_INDEX_TYPE_UINT8_EXT) { uploadIndexBufferData8((deUint8*)m_indexBufferAlloc->getHostPtr(), m_indices); } else // m_indexType == VK_INDEX_TYPE_UINT16 { uploadIndexBufferData16((deUint16*)m_indexBufferAlloc->getHostPtr(), m_indices); } // Load vertices into vertex buffer deMemcpy(m_vertexBufferAlloc->getHostPtr(), m_vertices.data(), m_vertices.size() * sizeof(Vertex4RGBA)); flushAlloc(vk, vkDevice, *m_indexBufferAlloc); flushAlloc(vk, vkDevice, *m_vertexBufferAlloc); } // Create command pool m_cmdPool = createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex); // Create command buffer { const VkClearValue attachmentClearValue = defaultClearValue(m_colorFormat); const VkImageMemoryBarrier attachmentLayoutBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkAccessFlags srcAccessMask; VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags dstAccessMask; VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout; VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout newLayout; VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex; VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex; *m_colorImage, // VkImage image; { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }, // VkImageSubresourceRange subresourceRange; }; m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY); beginCommandBuffer(vk, *m_cmdBuffer, 0u); vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, (VkDependencyFlags)0, 0u, DE_NULL, 0u, DE_NULL, 1u, &attachmentLayoutBarrier); beginRenderPass(vk, *m_cmdBuffer, *m_renderPass, *m_framebuffer, makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()), attachmentClearValue); const VkDeviceSize vertexBufferOffset = 0; vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_graphicsPipeline); vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &m_vertexBuffer.get(), &vertexBufferOffset); vk.cmdBindIndexBuffer(*m_cmdBuffer, *m_indexBuffer, 0, m_indexType); vk.cmdDrawIndexed(*m_cmdBuffer, (deUint32)m_indices.size(), 1, 0, 0, 0); endRenderPass(vk, *m_cmdBuffer); endCommandBuffer(vk, *m_cmdBuffer); } } InputAssemblyInstance::~InputAssemblyInstance (void) { } tcu::TestStatus InputAssemblyInstance::iterate (void) { const DeviceInterface& vk = m_context.getDeviceInterface(); const VkDevice vkDevice = m_context.getDevice(); const VkQueue queue = m_context.getUniversalQueue(); submitCommandsAndWait(vk, vkDevice, queue, m_cmdBuffer.get()); return verifyImage(); } tcu::TestStatus InputAssemblyInstance::verifyImage (void) { const tcu::TextureFormat tcuColorFormat = mapVkFormat(m_colorFormat); const tcu::TextureFormat tcuStencilFormat = tcu::TextureFormat(); const ColorVertexShader vertexShader; const ColorFragmentShader fragmentShader (tcuColorFormat, tcuStencilFormat); const rr::Program program (&vertexShader, &fragmentShader); ReferenceRenderer refRenderer (m_renderSize.x(), m_renderSize.y(), 1, tcuColorFormat, tcuStencilFormat, &program); bool compareOk = false; // Render reference image { // The reference for tessellated patches are drawn using ordinary triangles. const rr::PrimitiveType topology = m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST ? rr::PrimitiveType::PRIMITIVETYPE_TRIANGLES : mapVkPrimitiveTopology(m_primitiveTopology); rr::RenderState renderState (refRenderer.getViewportState(), m_context.getDeviceProperties().limits.subPixelPrecisionBits); if (m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_POINT_LIST) renderState.point.pointSize = 3.0f; if (m_primitiveRestartEnable) { std::vector indicesRange; for (size_t indexNdx = 0; indexNdx < m_indices.size(); indexNdx++) { const bool isRestart = InputAssemblyTest::isRestartIndex(m_indexType, m_indices[indexNdx]); if (!isRestart) indicesRange.push_back(m_indices[indexNdx]); if (isRestart || indexNdx == (m_indices.size() - 1)) { // Draw the range of indices found so far std::vector nonIndexedVertices; for (size_t i = 0; i < indicesRange.size(); i++) nonIndexedVertices.push_back(m_vertices[indicesRange[i]]); refRenderer.draw(renderState, topology, nonIndexedVertices); indicesRange.clear(); } } } else { std::vector nonIndexedVertices; for (size_t i = 0; i < m_indices.size(); i++) nonIndexedVertices.push_back(m_vertices[m_indices[i]]); refRenderer.draw(renderState, topology, nonIndexedVertices); } } // Compare result with reference image { const DeviceInterface& vk = m_context.getDeviceInterface(); const VkDevice vkDevice = m_context.getDevice(); const VkQueue queue = m_context.getUniversalQueue(); const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); SimpleAllocator allocator (vk, vkDevice, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice())); de::UniquePtr result (readColorAttachment(vk, vkDevice, queue, queueFamilyIndex, allocator, *m_colorImage, m_colorFormat, m_renderSize).release()); compareOk = tcu::intThresholdPositionDeviationCompare(m_context.getTestContext().getLog(), "IntImageCompare", "Image comparison", refRenderer.getAccess(), result->getAccess(), tcu::UVec4(2, 2, 2, 2), tcu::IVec3(1, 1, 0), true, tcu::COMPARE_LOG_RESULT); } if (compareOk) return tcu::TestStatus::pass("Result image matches reference"); else return tcu::TestStatus::fail("Image mismatch"); } void InputAssemblyInstance::uploadIndexBufferData16 (deUint16* destPtr, const std::vector& indexBufferData) { for (size_t i = 0; i < indexBufferData.size(); i++) { DE_ASSERT(indexBufferData[i] <= 0xFFFF); destPtr[i] = (deUint16)indexBufferData[i]; } } void InputAssemblyInstance::uploadIndexBufferData8 (deUint8* destPtr, const std::vector& indexBufferData) { for (size_t i = 0; i < indexBufferData.size(); i++) { DE_ASSERT(indexBufferData[i] <= 0xFF); destPtr[i] = (deUint8)indexBufferData[i]; } } // Utilities for test names std::string getPrimitiveTopologyCaseName (VkPrimitiveTopology topology) { const std::string fullName = getPrimitiveTopologyName(topology); DE_ASSERT(de::beginsWith(fullName, "VK_PRIMITIVE_TOPOLOGY_")); return de::toLower(fullName.substr(22)); } de::MovePtr createPrimitiveTopologyTests (tcu::TestContext& testCtx) { de::MovePtr primitiveTopologyTests (new tcu::TestCaseGroup(testCtx, "primitive_topology", "")); de::MovePtr indexUint16Tests (new tcu::TestCaseGroup(testCtx, "index_type_uint16", "")); de::MovePtr indexUint32Tests (new tcu::TestCaseGroup(testCtx, "index_type_uint32", "")); de::MovePtr indexUint8Tests (new tcu::TestCaseGroup(testCtx, "index_type_uint8", "")); for (int topologyNdx = 0; topologyNdx < DE_LENGTH_OF_ARRAY(InputAssemblyTest::s_primitiveTopologies); topologyNdx++) { const VkPrimitiveTopology topology = InputAssemblyTest::s_primitiveTopologies[topologyNdx]; indexUint16Tests->addChild(new PrimitiveTopologyTest(testCtx, getPrimitiveTopologyCaseName(topology), "", topology, VK_INDEX_TYPE_UINT16)); indexUint32Tests->addChild(new PrimitiveTopologyTest(testCtx, getPrimitiveTopologyCaseName(topology), "", topology, VK_INDEX_TYPE_UINT32)); indexUint8Tests->addChild(new PrimitiveTopologyTest(testCtx, getPrimitiveTopologyCaseName(topology), "", topology, VK_INDEX_TYPE_UINT8_EXT)); } primitiveTopologyTests->addChild(indexUint16Tests.release()); primitiveTopologyTests->addChild(indexUint32Tests.release()); primitiveTopologyTests->addChild(indexUint8Tests.release()); return primitiveTopologyTests; } de::MovePtr createPrimitiveRestartTests (tcu::TestContext& testCtx) { const VkPrimitiveTopology primitiveRestartTopologies[] = { VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY, // Supported with VK_EXT_primitive_topology_list_restart VK_PRIMITIVE_TOPOLOGY_POINT_LIST, VK_PRIMITIVE_TOPOLOGY_LINE_LIST, VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY, VK_PRIMITIVE_TOPOLOGY_PATCH_LIST }; de::MovePtr primitiveRestartTests (new tcu::TestCaseGroup(testCtx, "primitive_restart", "Restarts indices of ")); de::MovePtr indexUint16Tests (new tcu::TestCaseGroup(testCtx, "index_type_uint16", "")); de::MovePtr indexUint32Tests (new tcu::TestCaseGroup(testCtx, "index_type_uint32", "")); de::MovePtr indexUint8Tests (new tcu::TestCaseGroup(testCtx, "index_type_uint8", "")); for (int topologyNdx = 0; topologyNdx < DE_LENGTH_OF_ARRAY(primitiveRestartTopologies); topologyNdx++) { const VkPrimitiveTopology topology = primitiveRestartTopologies[topologyNdx]; indexUint16Tests->addChild(new PrimitiveRestartTest(testCtx, getPrimitiveTopologyCaseName(topology), "", topology, VK_INDEX_TYPE_UINT16)); indexUint32Tests->addChild(new PrimitiveRestartTest(testCtx, getPrimitiveTopologyCaseName(topology), "", topology, VK_INDEX_TYPE_UINT32)); indexUint8Tests->addChild(new PrimitiveRestartTest(testCtx, getPrimitiveTopologyCaseName(topology), "", topology, VK_INDEX_TYPE_UINT8_EXT)); } primitiveRestartTests->addChild(indexUint16Tests.release()); primitiveRestartTests->addChild(indexUint32Tests.release()); primitiveRestartTests->addChild(indexUint8Tests.release()); return primitiveRestartTests; } } // anonymous tcu::TestCaseGroup* createInputAssemblyTests (tcu::TestContext& testCtx) { de::MovePtr inputAssemblyTests (new tcu::TestCaseGroup(testCtx, "input_assembly", "Input assembly tests")); inputAssemblyTests->addChild(createPrimitiveTopologyTests(testCtx).release()); inputAssemblyTests->addChild(createPrimitiveRestartTests(testCtx).release()); return inputAssemblyTests.release(); } } // pipeline } // vkt