| /*------------------------------------------------------------------------ |
| * Vulkan Conformance Tests |
| * ------------------------ |
| * |
| * Copyright (c) 2015 The Khronos Group Inc. |
| * Copyright (c) 2015 Samsung Electronics Co., Ltd. |
| * 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 Vulkan ShaderExecutor |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "vktShaderExecutor.hpp" |
| |
| #include "vkMemUtil.hpp" |
| #include "vkRef.hpp" |
| #include "vkPrograms.hpp" |
| #include "vkRefUtil.hpp" |
| #include "vkTypeUtil.hpp" |
| #include "vkQueryUtil.hpp" |
| #include "vkBuilderUtil.hpp" |
| |
| #include "gluShaderUtil.hpp" |
| |
| #include "tcuVector.hpp" |
| #include "tcuTestLog.hpp" |
| #include "tcuTextureUtil.hpp" |
| |
| #include "deUniquePtr.hpp" |
| #include "deStringUtil.hpp" |
| #include "deSharedPtr.hpp" |
| |
| #include <map> |
| #include <sstream> |
| #include <iostream> |
| |
| using std::vector; |
| using namespace vk; |
| |
| namespace vkt |
| { |
| namespace shaderexecutor |
| { |
| namespace |
| { |
| |
| enum |
| { |
| DEFAULT_RENDER_WIDTH = 100, |
| DEFAULT_RENDER_HEIGHT = 100, |
| }; |
| |
| // Common typedefs |
| |
| typedef de::SharedPtr<Unique<VkImage> > VkImageSp; |
| typedef de::SharedPtr<Unique<VkImageView> > VkImageViewSp; |
| typedef de::SharedPtr<Unique<VkBuffer> > VkBufferSp; |
| typedef de::SharedPtr<Allocation> AllocationSp; |
| |
| // Shader utilities |
| |
| static VkClearValue getDefaultClearColor (void) |
| { |
| return makeClearValueColorF32(0.125f, 0.25f, 0.5f, 1.0f); |
| } |
| |
| static std::string generateEmptyFragmentSource (void) |
| { |
| std::ostringstream src; |
| |
| src << "#version 310 es\n" |
| "layout(location=0) out highp vec4 o_color;\n"; |
| |
| src << "void main (void)\n{\n"; |
| src << " o_color = vec4(0.0);\n"; |
| src << "}\n"; |
| |
| return src.str(); |
| } |
| |
| static std::string generatePassthroughVertexShader (const std::vector<Symbol>& inputs, const char* inputPrefix, const char* outputPrefix) |
| { |
| |
| std::ostringstream src; |
| int location = 0; |
| |
| src << "#version 310 es\n" |
| "layout(location = " << location << ") in highp vec4 a_position;\n"; |
| |
| for (vector<Symbol>::const_iterator input = inputs.begin(); input != inputs.end(); ++input) |
| { |
| location++; |
| src << "layout(location = "<< location << ") in " << glu::declare(input->varType, inputPrefix + input->name) << ";\n" |
| << "layout(location = " << location - 1 << ") flat out " << glu::declare(input->varType, outputPrefix + input->name) << ";\n"; |
| } |
| |
| src << "\nvoid main (void)\n{\n" |
| << " gl_Position = a_position;\n" |
| << " gl_PointSize = 1.0;\n"; |
| |
| for (vector<Symbol>::const_iterator input = inputs.begin(); input != inputs.end(); ++input) |
| src << "\t" << outputPrefix << input->name << " = " << inputPrefix << input->name << ";\n"; |
| |
| src << "}\n"; |
| |
| return src.str(); |
| } |
| |
| static std::string generateVertexShader (const ShaderSpec& shaderSpec, const std::string& inputPrefix, const std::string& outputPrefix) |
| { |
| DE_ASSERT(!inputPrefix.empty() && !outputPrefix.empty()); |
| |
| std::ostringstream src; |
| |
| src << "#version 310 es\n"; |
| |
| if (!shaderSpec.globalDeclarations.empty()) |
| src << shaderSpec.globalDeclarations << "\n"; |
| |
| src << "layout(location = 0) in highp vec4 a_position;\n"; |
| |
| int locationNumber = 1; |
| for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input, ++locationNumber) |
| src << "layout(location = " << locationNumber << ") in " << glu::declare(input->varType, inputPrefix + input->name) << ";\n"; |
| |
| locationNumber = 0; |
| for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output, ++locationNumber) |
| { |
| DE_ASSERT(output->varType.isBasicType()); |
| |
| if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType())) |
| { |
| const int vecSize = glu::getDataTypeScalarSize(output->varType.getBasicType()); |
| const glu::DataType intBaseType = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT; |
| const glu::VarType intType (intBaseType, glu::PRECISION_HIGHP); |
| |
| src << "layout(location = " << locationNumber << ") flat out " << glu::declare(intType, outputPrefix + output->name) << ";\n"; |
| } |
| else |
| src << "layout(location = " << locationNumber << ") flat out " << glu::declare(output->varType, outputPrefix + output->name) << ";\n"; |
| } |
| |
| src << "\n" |
| << "void main (void)\n" |
| << "{\n" |
| << " gl_Position = a_position;\n" |
| << " gl_PointSize = 1.0;\n"; |
| |
| // Declare & fetch local input variables |
| for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input) |
| src << "\t" << glu::declare(input->varType, input->name) << " = " << inputPrefix << input->name << ";\n"; |
| |
| // Declare local output variables |
| for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output) |
| src << "\t" << glu::declare(output->varType, output->name) << ";\n"; |
| |
| // Operation - indented to correct level. |
| { |
| std::istringstream opSrc (shaderSpec.source); |
| std::string line; |
| |
| while (std::getline(opSrc, line)) |
| src << "\t" << line << "\n"; |
| } |
| |
| // Assignments to outputs. |
| for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output) |
| { |
| if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType())) |
| { |
| const int vecSize = glu::getDataTypeScalarSize(output->varType.getBasicType()); |
| const glu::DataType intBaseType = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT; |
| |
| src << "\t" << outputPrefix << output->name << " = " << glu::getDataTypeName(intBaseType) << "(" << output->name << ");\n"; |
| } |
| else |
| src << "\t" << outputPrefix << output->name << " = " << output->name << ";\n"; |
| } |
| |
| src << "}\n"; |
| |
| return src.str(); |
| } |
| |
| struct FragmentOutputLayout |
| { |
| std::vector<const Symbol*> locationSymbols; //! Symbols by location |
| std::map<std::string, int> locationMap; //! Map from symbol name to start location |
| }; |
| |
| static void generateFragShaderOutputDecl (std::ostream& src, const ShaderSpec& shaderSpec, bool useIntOutputs, const std::map<std::string, int>& outLocationMap, const std::string& outputPrefix) |
| { |
| for (int outNdx = 0; outNdx < (int)shaderSpec.outputs.size(); ++outNdx) |
| { |
| const Symbol& output = shaderSpec.outputs[outNdx]; |
| const int location = de::lookup(outLocationMap, output.name); |
| const std::string outVarName = outputPrefix + output.name; |
| glu::VariableDeclaration decl (output.varType, outVarName, glu::STORAGE_OUT, glu::INTERPOLATION_LAST, glu::Layout(location)); |
| |
| TCU_CHECK_INTERNAL(output.varType.isBasicType()); |
| |
| if (useIntOutputs && glu::isDataTypeFloatOrVec(output.varType.getBasicType())) |
| { |
| const int vecSize = glu::getDataTypeScalarSize(output.varType.getBasicType()); |
| const glu::DataType uintBasicType = vecSize > 1 ? glu::getDataTypeUintVec(vecSize) : glu::TYPE_UINT; |
| const glu::VarType uintType (uintBasicType, glu::PRECISION_HIGHP); |
| |
| decl.varType = uintType; |
| src << decl << ";\n"; |
| } |
| else if (glu::isDataTypeBoolOrBVec(output.varType.getBasicType())) |
| { |
| const int vecSize = glu::getDataTypeScalarSize(output.varType.getBasicType()); |
| const glu::DataType intBasicType = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT; |
| const glu::VarType intType (intBasicType, glu::PRECISION_HIGHP); |
| |
| decl.varType = intType; |
| src << decl << ";\n"; |
| } |
| else if (glu::isDataTypeMatrix(output.varType.getBasicType())) |
| { |
| const int vecSize = glu::getDataTypeMatrixNumRows(output.varType.getBasicType()); |
| const int numVecs = glu::getDataTypeMatrixNumColumns(output.varType.getBasicType()); |
| const glu::DataType uintBasicType = glu::getDataTypeUintVec(vecSize); |
| const glu::VarType uintType (uintBasicType, glu::PRECISION_HIGHP); |
| |
| decl.varType = uintType; |
| for (int vecNdx = 0; vecNdx < numVecs; ++vecNdx) |
| { |
| decl.name = outVarName + "_" + de::toString(vecNdx); |
| decl.layout.location = location + vecNdx; |
| src << decl << ";\n"; |
| } |
| } |
| else |
| src << decl << ";\n"; |
| } |
| } |
| |
| static void generateFragShaderOutAssign (std::ostream& src, const ShaderSpec& shaderSpec, bool useIntOutputs, const std::string& valuePrefix, const std::string& outputPrefix) |
| { |
| for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output) |
| { |
| if (useIntOutputs && glu::isDataTypeFloatOrVec(output->varType.getBasicType())) |
| src << " o_" << output->name << " = floatBitsToUint(" << valuePrefix << output->name << ");\n"; |
| else if (glu::isDataTypeMatrix(output->varType.getBasicType())) |
| { |
| const int numVecs = glu::getDataTypeMatrixNumColumns(output->varType.getBasicType()); |
| |
| for (int vecNdx = 0; vecNdx < numVecs; ++vecNdx) |
| if (useIntOutputs) |
| src << "\t" << outputPrefix << output->name << "_" << vecNdx << " = floatBitsToUint(" << valuePrefix << output->name << "[" << vecNdx << "]);\n"; |
| else |
| src << "\t" << outputPrefix << output->name << "_" << vecNdx << " = " << valuePrefix << output->name << "[" << vecNdx << "];\n"; |
| } |
| else if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType())) |
| { |
| const int vecSize = glu::getDataTypeScalarSize(output->varType.getBasicType()); |
| const glu::DataType intBaseType = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT; |
| |
| src << "\t" << outputPrefix << output->name << " = " << glu::getDataTypeName(intBaseType) << "(" << valuePrefix << output->name << ");\n"; |
| } |
| else |
| src << "\t" << outputPrefix << output->name << " = " << valuePrefix << output->name << ";\n"; |
| } |
| } |
| |
| static std::string generatePassthroughFragmentShader (const ShaderSpec& shaderSpec, bool useIntOutputs, const std::map<std::string, int>& outLocationMap, const std::string& inputPrefix, const std::string& outputPrefix) |
| { |
| std::ostringstream src; |
| |
| src << "#version 310 es\n"; |
| |
| if (!shaderSpec.globalDeclarations.empty()) |
| src << shaderSpec.globalDeclarations << "\n"; |
| |
| int locationNumber = 0; |
| for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output, ++locationNumber) |
| { |
| if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType())) |
| { |
| const int vecSize = glu::getDataTypeScalarSize(output->varType.getBasicType()); |
| const glu::DataType intBaseType = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT; |
| const glu::VarType intType (intBaseType, glu::PRECISION_HIGHP); |
| |
| src << "layout(location = " << locationNumber << ") flat in " << glu::declare(intType, inputPrefix + output->name) << ";\n"; |
| } |
| else |
| src << "layout(location = " << locationNumber << ") flat in " << glu::declare(output->varType, inputPrefix + output->name) << ";\n"; |
| } |
| |
| generateFragShaderOutputDecl(src, shaderSpec, useIntOutputs, outLocationMap, outputPrefix); |
| |
| src << "\nvoid main (void)\n{\n"; |
| |
| generateFragShaderOutAssign(src, shaderSpec, useIntOutputs, inputPrefix, outputPrefix); |
| |
| src << "}\n"; |
| |
| return src.str(); |
| } |
| |
| static std::string generateGeometryShader (const ShaderSpec& shaderSpec, const std::string& inputPrefix, const std::string& outputPrefix) |
| { |
| DE_ASSERT(!inputPrefix.empty() && !outputPrefix.empty()); |
| |
| std::ostringstream src; |
| |
| src << "#version 310 es\n" |
| "#extension GL_EXT_geometry_shader : require\n"; |
| |
| if (!shaderSpec.globalDeclarations.empty()) |
| src << shaderSpec.globalDeclarations << "\n"; |
| |
| src << "layout(points) in;\n" |
| << "layout(points, max_vertices = 1) out;\n"; |
| |
| int locationNumber = 0; |
| for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input, ++locationNumber) |
| src << "layout(location = " << locationNumber << ") flat in " << glu::declare(input->varType, inputPrefix + input->name) << "[];\n"; |
| |
| locationNumber = 0; |
| for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output, ++locationNumber) |
| { |
| DE_ASSERT(output->varType.isBasicType()); |
| |
| if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType())) |
| { |
| const int vecSize = glu::getDataTypeScalarSize(output->varType.getBasicType()); |
| const glu::DataType intBaseType = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT; |
| const glu::VarType intType (intBaseType, glu::PRECISION_HIGHP); |
| |
| src << "layout(location = " << locationNumber << ") flat out " << glu::declare(intType, outputPrefix + output->name) << ";\n"; |
| } |
| else |
| src << "layout(location = " << locationNumber << ") flat out " << glu::declare(output->varType, outputPrefix + output->name) << ";\n"; |
| } |
| |
| src << "\n" |
| << "void main (void)\n" |
| << "{\n" |
| << " gl_Position = gl_in[0].gl_Position;\n\n"; |
| |
| // Fetch input variables |
| for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input) |
| src << "\t" << glu::declare(input->varType, input->name) << " = " << inputPrefix << input->name << "[0];\n"; |
| |
| // Declare local output variables. |
| for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output) |
| src << "\t" << glu::declare(output->varType, output->name) << ";\n"; |
| |
| src << "\n"; |
| |
| // Operation - indented to correct level. |
| { |
| std::istringstream opSrc (shaderSpec.source); |
| std::string line; |
| |
| while (std::getline(opSrc, line)) |
| src << "\t" << line << "\n"; |
| } |
| |
| // Assignments to outputs. |
| for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output) |
| { |
| if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType())) |
| { |
| const int vecSize = glu::getDataTypeScalarSize(output->varType.getBasicType()); |
| const glu::DataType intBaseType = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT; |
| |
| src << "\t" << outputPrefix << output->name << " = " << glu::getDataTypeName(intBaseType) << "(" << output->name << ");\n"; |
| } |
| else |
| src << "\t" << outputPrefix << output->name << " = " << output->name << ";\n"; |
| } |
| |
| src << " EmitVertex();\n" |
| << " EndPrimitive();\n" |
| << "}\n"; |
| |
| return src.str(); |
| } |
| |
| static std::string generateFragmentShader (const ShaderSpec& shaderSpec, bool useIntOutputs, const std::map<std::string, int>& outLocationMap, const std::string& inputPrefix, const std::string& outputPrefix) |
| { |
| std::ostringstream src; |
| src << "#version 310 es\n"; |
| if (!shaderSpec.globalDeclarations.empty()) |
| src << shaderSpec.globalDeclarations << "\n"; |
| |
| int locationNumber = 0; |
| for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input, ++locationNumber) |
| src << "layout(location = " << locationNumber << ") flat in " << glu::declare(input->varType, inputPrefix + input->name) << ";\n"; |
| |
| generateFragShaderOutputDecl(src, shaderSpec, useIntOutputs, outLocationMap, outputPrefix); |
| |
| src << "\nvoid main (void)\n{\n"; |
| |
| // Declare & fetch local input variables |
| for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input) |
| src << "\t" << glu::declare(input->varType, input->name) << " = " << inputPrefix << input->name << ";\n"; |
| |
| // Declare output variables |
| for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output) |
| src << "\t" << glu::declare(output->varType, output->name) << ";\n"; |
| |
| // Operation - indented to correct level. |
| { |
| std::istringstream opSrc (shaderSpec.source); |
| std::string line; |
| |
| while (std::getline(opSrc, line)) |
| src << "\t" << line << "\n"; |
| } |
| |
| generateFragShaderOutAssign(src, shaderSpec, useIntOutputs, "", outputPrefix); |
| |
| src << "}\n"; |
| |
| return src.str(); |
| } |
| |
| // FragmentOutExecutor |
| |
| class FragmentOutExecutor : public ShaderExecutor |
| { |
| public: |
| FragmentOutExecutor (Context& context, glu::ShaderType shaderType, const ShaderSpec& shaderSpec, VkDescriptorSetLayout extraResourcesLayout); |
| virtual ~FragmentOutExecutor (void); |
| |
| virtual void execute (int numValues, |
| const void* const* inputs, |
| void* const* outputs, |
| VkDescriptorSet extraResources); |
| |
| protected: |
| const glu::ShaderType m_shaderType; |
| const FragmentOutputLayout m_outputLayout; |
| |
| private: |
| void bindAttributes (int numValues, |
| const void* const* inputs); |
| |
| void addAttribute (deUint32 bindingLocation, |
| VkFormat format, |
| deUint32 sizePerElement, |
| deUint32 count, |
| const void* dataPtr); |
| // reinit render data members |
| virtual void clearRenderData (void); |
| |
| const VkDescriptorSetLayout m_extraResourcesLayout; |
| |
| std::vector<VkVertexInputBindingDescription> m_vertexBindingDescriptions; |
| std::vector<VkVertexInputAttributeDescription> m_vertexAttributeDescriptions; |
| std::vector<VkBufferSp> m_vertexBuffers; |
| std::vector<AllocationSp> m_vertexBufferAllocs; |
| }; |
| |
| static FragmentOutputLayout computeFragmentOutputLayout (const std::vector<Symbol>& symbols) |
| { |
| FragmentOutputLayout ret; |
| int location = 0; |
| |
| for (std::vector<Symbol>::const_iterator it = symbols.begin(); it != symbols.end(); ++it) |
| { |
| const int numLocations = glu::getDataTypeNumLocations(it->varType.getBasicType()); |
| |
| TCU_CHECK_INTERNAL(!de::contains(ret.locationMap, it->name)); |
| de::insert(ret.locationMap, it->name, location); |
| location += numLocations; |
| |
| for (int ndx = 0; ndx < numLocations; ++ndx) |
| ret.locationSymbols.push_back(&*it); |
| } |
| |
| return ret; |
| } |
| |
| FragmentOutExecutor::FragmentOutExecutor (Context& context, glu::ShaderType shaderType, const ShaderSpec& shaderSpec, VkDescriptorSetLayout extraResourcesLayout) |
| : ShaderExecutor (context, shaderSpec) |
| , m_shaderType (shaderType) |
| , m_outputLayout (computeFragmentOutputLayout(m_shaderSpec.outputs)) |
| , m_extraResourcesLayout (extraResourcesLayout) |
| { |
| } |
| |
| FragmentOutExecutor::~FragmentOutExecutor (void) |
| { |
| } |
| |
| static std::vector<tcu::Vec2> computeVertexPositions (int numValues, const tcu::IVec2& renderSize) |
| { |
| std::vector<tcu::Vec2> positions(numValues); |
| for (int valNdx = 0; valNdx < numValues; valNdx++) |
| { |
| const int ix = valNdx % renderSize.x(); |
| const int iy = valNdx / renderSize.x(); |
| const float fx = -1.0f + 2.0f*((float(ix) + 0.5f) / float(renderSize.x())); |
| const float fy = -1.0f + 2.0f*((float(iy) + 0.5f) / float(renderSize.y())); |
| |
| positions[valNdx] = tcu::Vec2(fx, fy); |
| } |
| |
| return positions; |
| } |
| |
| static tcu::TextureFormat getRenderbufferFormatForOutput (const glu::VarType& outputType, bool useIntOutputs) |
| { |
| const tcu::TextureFormat::ChannelOrder channelOrderMap[] = |
| { |
| tcu::TextureFormat::R, |
| tcu::TextureFormat::RG, |
| tcu::TextureFormat::RGBA, // No RGB variants available. |
| tcu::TextureFormat::RGBA |
| }; |
| |
| const glu::DataType basicType = outputType.getBasicType(); |
| const int numComps = glu::getDataTypeNumComponents(basicType); |
| tcu::TextureFormat::ChannelType channelType; |
| |
| switch (glu::getDataTypeScalarType(basicType)) |
| { |
| case glu::TYPE_UINT: channelType = tcu::TextureFormat::UNSIGNED_INT32; break; |
| case glu::TYPE_INT: channelType = tcu::TextureFormat::SIGNED_INT32; break; |
| case glu::TYPE_BOOL: channelType = tcu::TextureFormat::SIGNED_INT32; break; |
| case glu::TYPE_FLOAT: channelType = useIntOutputs ? tcu::TextureFormat::UNSIGNED_INT32 : tcu::TextureFormat::FLOAT; break; |
| default: |
| throw tcu::InternalError("Invalid output type"); |
| } |
| |
| DE_ASSERT(de::inRange<int>(numComps, 1, DE_LENGTH_OF_ARRAY(channelOrderMap))); |
| |
| return tcu::TextureFormat(channelOrderMap[numComps-1], channelType); |
| } |
| |
| static VkFormat getAttributeFormat (const glu::DataType dataType) |
| { |
| switch (dataType) |
| { |
| case glu::TYPE_FLOAT: return VK_FORMAT_R32_SFLOAT; |
| case glu::TYPE_FLOAT_VEC2: return VK_FORMAT_R32G32_SFLOAT; |
| case glu::TYPE_FLOAT_VEC3: return VK_FORMAT_R32G32B32_SFLOAT; |
| case glu::TYPE_FLOAT_VEC4: return VK_FORMAT_R32G32B32A32_SFLOAT; |
| |
| case glu::TYPE_INT: return VK_FORMAT_R32_SINT; |
| case glu::TYPE_INT_VEC2: return VK_FORMAT_R32G32_SINT; |
| case glu::TYPE_INT_VEC3: return VK_FORMAT_R32G32B32_SINT; |
| case glu::TYPE_INT_VEC4: return VK_FORMAT_R32G32B32A32_SINT; |
| |
| case glu::TYPE_UINT: return VK_FORMAT_R32_UINT; |
| case glu::TYPE_UINT_VEC2: return VK_FORMAT_R32G32_UINT; |
| case glu::TYPE_UINT_VEC3: return VK_FORMAT_R32G32B32_UINT; |
| case glu::TYPE_UINT_VEC4: return VK_FORMAT_R32G32B32A32_UINT; |
| |
| case glu::TYPE_FLOAT_MAT2: return VK_FORMAT_R32G32_SFLOAT; |
| case glu::TYPE_FLOAT_MAT2X3: return VK_FORMAT_R32G32B32_SFLOAT; |
| case glu::TYPE_FLOAT_MAT2X4: return VK_FORMAT_R32G32B32A32_SFLOAT; |
| case glu::TYPE_FLOAT_MAT3X2: return VK_FORMAT_R32G32_SFLOAT; |
| case glu::TYPE_FLOAT_MAT3: return VK_FORMAT_R32G32B32_SFLOAT; |
| case glu::TYPE_FLOAT_MAT3X4: return VK_FORMAT_R32G32B32A32_SFLOAT; |
| case glu::TYPE_FLOAT_MAT4X2: return VK_FORMAT_R32G32_SFLOAT; |
| case glu::TYPE_FLOAT_MAT4X3: return VK_FORMAT_R32G32B32_SFLOAT; |
| case glu::TYPE_FLOAT_MAT4: return VK_FORMAT_R32G32B32A32_SFLOAT; |
| default: |
| DE_ASSERT(false); |
| return VK_FORMAT_UNDEFINED; |
| } |
| } |
| |
| void FragmentOutExecutor::addAttribute (deUint32 bindingLocation, VkFormat format, deUint32 sizePerElement, deUint32 count, const void* dataPtr) |
| { |
| // Add binding specification |
| const deUint32 binding = (deUint32)m_vertexBindingDescriptions.size(); |
| const VkVertexInputBindingDescription bindingDescription = |
| { |
| binding, |
| sizePerElement, |
| VK_VERTEX_INPUT_RATE_VERTEX |
| }; |
| |
| m_vertexBindingDescriptions.push_back(bindingDescription); |
| |
| // Add location and format specification |
| const VkVertexInputAttributeDescription attributeDescription = |
| { |
| bindingLocation, // deUint32 location; |
| binding, // deUint32 binding; |
| format, // VkFormat format; |
| 0u, // deUint32 offsetInBytes; |
| }; |
| |
| m_vertexAttributeDescriptions.push_back(attributeDescription); |
| |
| // Upload data to buffer |
| const VkDevice vkDevice = m_context.getDevice(); |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); |
| |
| const VkDeviceSize inputSize = sizePerElement * count; |
| const VkBufferCreateInfo vertexBufferParams = |
| { |
| VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkBufferCreateFlags flags; |
| inputSize, // VkDeviceSize size; |
| VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, // VkBufferUsageFlags usage; |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; |
| 1u, // deUint32 queueFamilyCount; |
| &queueFamilyIndex // const deUint32* pQueueFamilyIndices; |
| }; |
| |
| Move<VkBuffer> buffer = createBuffer(vk, vkDevice, &vertexBufferParams); |
| de::MovePtr<Allocation> alloc = m_context.getDefaultAllocator().allocate(getBufferMemoryRequirements(vk, vkDevice, *buffer), MemoryRequirement::HostVisible); |
| |
| VK_CHECK(vk.bindBufferMemory(vkDevice, *buffer, alloc->getMemory(), alloc->getOffset())); |
| |
| deMemcpy(alloc->getHostPtr(), dataPtr, (size_t)inputSize); |
| flushMappedMemoryRange(vk, vkDevice, alloc->getMemory(), alloc->getOffset(), inputSize); |
| |
| m_vertexBuffers.push_back(de::SharedPtr<Unique<VkBuffer> >(new Unique<VkBuffer>(buffer))); |
| m_vertexBufferAllocs.push_back(AllocationSp(alloc.release())); |
| } |
| |
| void FragmentOutExecutor::bindAttributes (int numValues, const void* const* inputs) |
| { |
| // Input attributes |
| for (int inputNdx = 0; inputNdx < (int)m_shaderSpec.inputs.size(); inputNdx++) |
| { |
| const Symbol& symbol = m_shaderSpec.inputs[inputNdx]; |
| const void* ptr = inputs[inputNdx]; |
| const glu::DataType basicType = symbol.varType.getBasicType(); |
| const int vecSize = glu::getDataTypeScalarSize(basicType); |
| const VkFormat format = getAttributeFormat(basicType); |
| int elementSize = 0; |
| int numAttrsToAdd = 1; |
| |
| if (glu::isDataTypeFloatOrVec(basicType)) |
| elementSize = sizeof(float); |
| else if (glu::isDataTypeIntOrIVec(basicType)) |
| elementSize = sizeof(int); |
| else if (glu::isDataTypeUintOrUVec(basicType)) |
| elementSize = sizeof(deUint32); |
| else if (glu::isDataTypeMatrix(basicType)) |
| { |
| int numRows = glu::getDataTypeMatrixNumRows(basicType); |
| int numCols = glu::getDataTypeMatrixNumColumns(basicType); |
| |
| elementSize = numRows * numCols * (int)sizeof(float); |
| numAttrsToAdd = numCols; |
| } |
| else |
| DE_ASSERT(false); |
| |
| // add attributes, in case of matrix every column is binded as an attribute |
| for (int attrNdx = 0; attrNdx < numAttrsToAdd; attrNdx++) |
| { |
| addAttribute((deUint32)m_vertexBindingDescriptions.size(), format, elementSize * vecSize, numValues, ptr); |
| } |
| } |
| } |
| |
| void FragmentOutExecutor::clearRenderData (void) |
| { |
| m_vertexBindingDescriptions.clear(); |
| m_vertexAttributeDescriptions.clear(); |
| m_vertexBuffers.clear(); |
| m_vertexBufferAllocs.clear(); |
| } |
| |
| static Move<VkDescriptorSetLayout> createEmptyDescriptorSetLayout (const DeviceInterface& vkd, VkDevice device) |
| { |
| const VkDescriptorSetLayoutCreateInfo createInfo = |
| { |
| VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, |
| DE_NULL, |
| (VkDescriptorSetLayoutCreateFlags)0, |
| 0u, |
| DE_NULL, |
| }; |
| return createDescriptorSetLayout(vkd, device, &createInfo); |
| } |
| |
| static Move<VkDescriptorPool> createDummyDescriptorPool (const DeviceInterface& vkd, VkDevice device) |
| { |
| const VkDescriptorPoolSize dummySize = |
| { |
| VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, |
| 1u, |
| }; |
| const VkDescriptorPoolCreateInfo createInfo = |
| { |
| VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, |
| DE_NULL, |
| (VkDescriptorPoolCreateFlags)VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, |
| 1u, |
| 1u, |
| &dummySize |
| }; |
| return createDescriptorPool(vkd, device, &createInfo); |
| } |
| |
| static Move<VkDescriptorSet> allocateSingleDescriptorSet (const DeviceInterface& vkd, VkDevice device, VkDescriptorPool pool, VkDescriptorSetLayout layout) |
| { |
| const VkDescriptorSetAllocateInfo allocInfo = |
| { |
| VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, |
| DE_NULL, |
| pool, |
| 1u, |
| &layout, |
| }; |
| return allocateDescriptorSet(vkd, device, &allocInfo); |
| } |
| |
| void FragmentOutExecutor::execute (int numValues, const void* const* inputs, void* const* outputs, VkDescriptorSet extraResources) |
| { |
| const VkDevice vkDevice = m_context.getDevice(); |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| const VkQueue queue = m_context.getUniversalQueue(); |
| const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); |
| Allocator& memAlloc = m_context.getDefaultAllocator(); |
| |
| const deUint32 renderSizeX = de::min(static_cast<deUint32>(DEFAULT_RENDER_WIDTH), (deUint32)numValues); |
| const deUint32 renderSizeY = ((deUint32)numValues / renderSizeX) + (((deUint32)numValues % renderSizeX != 0) ? 1u : 0u); |
| const tcu::UVec2 renderSize (renderSizeX, renderSizeY); |
| std::vector<tcu::Vec2> positions; |
| |
| const bool useGeometryShader = m_shaderType == glu::SHADERTYPE_GEOMETRY; |
| |
| std::vector<VkImageSp> colorImages; |
| std::vector<VkImageMemoryBarrier> colorImagePreRenderBarriers; |
| std::vector<VkImageMemoryBarrier> colorImagePostRenderBarriers; |
| std::vector<AllocationSp> colorImageAllocs; |
| std::vector<VkAttachmentDescription> attachments; |
| std::vector<VkClearValue> attachmentClearValues; |
| std::vector<VkImageViewSp> colorImageViews; |
| |
| std::vector<VkPipelineColorBlendAttachmentState> colorBlendAttachmentStates; |
| std::vector<VkAttachmentReference> colorAttachmentReferences; |
| |
| Move<VkRenderPass> renderPass; |
| Move<VkFramebuffer> framebuffer; |
| Move<VkPipelineLayout> pipelineLayout; |
| Move<VkPipeline> graphicsPipeline; |
| |
| Move<VkShaderModule> vertexShaderModule; |
| Move<VkShaderModule> geometryShaderModule; |
| Move<VkShaderModule> fragmentShaderModule; |
| |
| Move<VkCommandPool> cmdPool; |
| Move<VkCommandBuffer> cmdBuffer; |
| |
| Move<VkFence> fence; |
| |
| Unique<VkDescriptorSetLayout> emptyDescriptorSetLayout (createEmptyDescriptorSetLayout(vk, vkDevice)); |
| Unique<VkDescriptorPool> dummyDescriptorPool (createDummyDescriptorPool(vk, vkDevice)); |
| Unique<VkDescriptorSet> emptyDescriptorSet (allocateSingleDescriptorSet(vk, vkDevice, *dummyDescriptorPool, *emptyDescriptorSetLayout)); |
| |
| clearRenderData(); |
| |
| // Compute positions - 1px points are used to drive fragment shading. |
| positions = computeVertexPositions(numValues, renderSize.cast<int>()); |
| |
| // Bind attributes |
| addAttribute(0u, VK_FORMAT_R32G32_SFLOAT, sizeof(tcu::Vec2), (deUint32)positions.size(), &positions[0]); |
| bindAttributes(numValues, inputs); |
| |
| // Create color images |
| { |
| const VkPipelineColorBlendAttachmentState colorBlendAttachmentState = |
| { |
| VK_FALSE, // VkBool32 blendEnable; |
| VK_BLEND_FACTOR_ONE, // VkBlendFactor srcColorBlendFactor; |
| VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor; |
| VK_BLEND_OP_ADD, // VkBlendOp blendOpColor; |
| VK_BLEND_FACTOR_ONE, // VkBlendFactor srcAlphaBlendFactor; |
| VK_BLEND_FACTOR_ZERO, // VkBlendFactor destAlphaBlendFactor; |
| VK_BLEND_OP_ADD, // VkBlendOp blendOpAlpha; |
| (VK_COLOR_COMPONENT_R_BIT | |
| VK_COLOR_COMPONENT_G_BIT | |
| VK_COLOR_COMPONENT_B_BIT | |
| VK_COLOR_COMPONENT_A_BIT) // VkColorComponentFlags colorWriteMask; |
| }; |
| |
| for (int outNdx = 0; outNdx < (int)m_outputLayout.locationSymbols.size(); ++outNdx) |
| { |
| const bool isFloat = isDataTypeFloatOrVec(m_shaderSpec.outputs[outNdx].varType.getBasicType()); |
| const bool isSigned = isDataTypeIntOrIVec (m_shaderSpec.outputs[outNdx].varType.getBasicType()); |
| const bool isBool = isDataTypeBoolOrBVec(m_shaderSpec.outputs[outNdx].varType.getBasicType()); |
| const VkFormat colorFormat = isFloat ? VK_FORMAT_R32G32B32A32_SFLOAT : (isSigned || isBool ? VK_FORMAT_R32G32B32A32_SINT : VK_FORMAT_R32G32B32A32_UINT); |
| |
| 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; |
| colorFormat, // VkFormat format; |
| { renderSize.x(), renderSize.y(), 1u }, // VkExtent3D extent; |
| 1u, // deUint32 mipLevels; |
| 1u, // deUint32 arraySize; |
| 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 queueFamilyCount; |
| &queueFamilyIndex, // const deUint32* pQueueFamilyIndices; |
| VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; |
| }; |
| |
| const VkAttachmentDescription colorAttachmentDescription = |
| { |
| 0u, // VkAttachmentDescriptorFlags flags; |
| colorFormat, // VkFormat format; |
| VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; |
| VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp; |
| VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp; |
| VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp; |
| VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp; |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout initialLayout; |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout; |
| }; |
| |
| Move<VkImage> colorImage = createImage(vk, vkDevice, &colorImageParams); |
| colorImages.push_back(de::SharedPtr<Unique<VkImage> >(new Unique<VkImage>(colorImage))); |
| attachmentClearValues.push_back(getDefaultClearColor()); |
| |
| // Allocate and bind color image memory |
| { |
| de::MovePtr<Allocation> colorImageAlloc = memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *((const VkImage*) colorImages.back().get())), MemoryRequirement::Any); |
| VK_CHECK(vk.bindImageMemory(vkDevice, colorImages.back().get()->get(), colorImageAlloc->getMemory(), colorImageAlloc->getOffset())); |
| colorImageAllocs.push_back(de::SharedPtr<Allocation>(colorImageAlloc.release())); |
| |
| attachments.push_back(colorAttachmentDescription); |
| colorBlendAttachmentStates.push_back(colorBlendAttachmentState); |
| |
| const VkAttachmentReference colorAttachmentReference = |
| { |
| (deUint32) (colorImages.size() - 1), // deUint32 attachment; |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout; |
| }; |
| |
| colorAttachmentReferences.push_back(colorAttachmentReference); |
| } |
| |
| // Create color attachment view |
| { |
| const VkImageViewCreateInfo colorImageViewParams = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkImageViewCreateFlags flags; |
| colorImages.back().get()->get(), // VkImage image; |
| VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType; |
| colorFormat, // VkFormat format; |
| { |
| VK_COMPONENT_SWIZZLE_R, // VkComponentSwizzle r; |
| VK_COMPONENT_SWIZZLE_G, // VkComponentSwizzle g; |
| VK_COMPONENT_SWIZZLE_B, // VkComponentSwizzle b; |
| VK_COMPONENT_SWIZZLE_A // VkComponentSwizzle a; |
| }, // VkComponentMapping components; |
| { |
| VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask; |
| 0u, // deUint32 baseMipLevel; |
| 1u, // deUint32 mipLevels; |
| 0u, // deUint32 baseArraySlice; |
| 1u // deUint32 arraySize; |
| } // VkImageSubresourceRange subresourceRange; |
| }; |
| |
| Move<VkImageView> colorImageView = createImageView(vk, vkDevice, &colorImageViewParams); |
| colorImageViews.push_back(de::SharedPtr<Unique<VkImageView> >(new Unique<VkImageView>(colorImageView))); |
| |
| const VkImageMemoryBarrier colorImagePreRenderBarrier = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType |
| DE_NULL, // pNext |
| 0u, // srcAccessMask |
| (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | |
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT), // dstAccessMask |
| VK_IMAGE_LAYOUT_UNDEFINED, // oldLayout |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // newLayout |
| VK_QUEUE_FAMILY_IGNORED, // srcQueueFamilyIndex |
| VK_QUEUE_FAMILY_IGNORED, // dstQueueFamilyIndex |
| colorImages.back().get()->get(), // image |
| { |
| VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask |
| 0u, // baseMipLevel |
| 1u, // levelCount |
| 0u, // baseArrayLayer |
| 1u, // layerCount |
| } // subresourceRange |
| }; |
| colorImagePreRenderBarriers.push_back(colorImagePreRenderBarrier); |
| |
| const VkImageMemoryBarrier colorImagePostRenderBarrier = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType |
| DE_NULL, // pNext |
| (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | |
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT), // srcAccessMask |
| VK_ACCESS_TRANSFER_READ_BIT, // dstAccessMask |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // oldLayout |
| VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // newLayout |
| VK_QUEUE_FAMILY_IGNORED, // srcQueueFamilyIndex |
| VK_QUEUE_FAMILY_IGNORED, // dstQueueFamilyIndex |
| colorImages.back().get()->get(), // image |
| { |
| VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask |
| 0u, // baseMipLevel |
| 1u, // levelCount |
| 0u, // baseArrayLayer |
| 1u, // layerCount |
| } // subresourceRange |
| }; |
| colorImagePostRenderBarriers.push_back(colorImagePostRenderBarrier); |
| } |
| } |
| } |
| |
| // Create render pass |
| { |
| const VkSubpassDescription subpassDescription = |
| { |
| 0u, // VkSubpassDescriptionFlags flags; |
| VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint; |
| 0u, // deUint32 inputCount; |
| DE_NULL, // const VkAttachmentReference* pInputAttachments; |
| (deUint32)colorImages.size(), // deUint32 colorCount; |
| &colorAttachmentReferences[0], // const VkAttachmentReference* colorAttachments; |
| DE_NULL, // const VkAttachmentReference* resolveAttachments; |
| DE_NULL, // VkAttachmentReference depthStencilAttachment; |
| 0u, // deUint32 preserveCount; |
| DE_NULL // const VkAttachmentReference* pPreserveAttachments; |
| }; |
| |
| const VkRenderPassCreateInfo renderPassParams = |
| { |
| VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags; |
| (deUint32)attachments.size(), // deUint32 attachmentCount; |
| &attachments[0], // const VkAttachmentDescription* pAttachments; |
| 1u, // deUint32 subpassCount; |
| &subpassDescription, // const VkSubpassDescription* pSubpasses; |
| 0u, // deUint32 dependencyCount; |
| DE_NULL // const VkSubpassDependency* pDependencies; |
| }; |
| |
| renderPass = createRenderPass(vk, vkDevice, &renderPassParams); |
| } |
| |
| // Create framebuffer |
| { |
| std::vector<VkImageView> views(colorImageViews.size()); |
| for (size_t i = 0; i < colorImageViews.size(); i++) |
| { |
| views[i] = colorImageViews[i].get()->get(); |
| } |
| |
| const VkFramebufferCreateInfo framebufferParams = |
| { |
| VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkFramebufferCreateFlags flags; |
| *renderPass, // VkRenderPass renderPass; |
| (deUint32)views.size(), // deUint32 attachmentCount; |
| &views[0], // const VkImageView* pAttachments; |
| (deUint32)renderSize.x(), // deUint32 width; |
| (deUint32)renderSize.y(), // deUint32 height; |
| 1u // deUint32 layers; |
| }; |
| |
| framebuffer = createFramebuffer(vk, vkDevice, &framebufferParams); |
| } |
| |
| // Create pipeline layout |
| { |
| const VkDescriptorSetLayout setLayouts[] = |
| { |
| *emptyDescriptorSetLayout, |
| m_extraResourcesLayout |
| }; |
| const VkPipelineLayoutCreateInfo pipelineLayoutParams = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineLayoutCreateFlags)0, // VkPipelineLayoutCreateFlags flags; |
| (m_extraResourcesLayout != 0 ? 2u : 0u), // deUint32 descriptorSetCount; |
| setLayouts, // const VkDescriptorSetLayout* pSetLayouts; |
| 0u, // deUint32 pushConstantRangeCount; |
| DE_NULL // const VkPushConstantRange* pPushConstantRanges; |
| }; |
| |
| pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams); |
| } |
| |
| // Create shaders |
| { |
| vertexShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("vert"), 0); |
| fragmentShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("frag"), 0); |
| |
| if (useGeometryShader) |
| { |
| geometryShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("geom"), 0); |
| } |
| } |
| |
| // Create pipeline |
| { |
| std::vector<VkPipelineShaderStageCreateInfo> shaderStageParams; |
| |
| const VkPipelineShaderStageCreateInfo vertexShaderStageParams = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags; |
| VK_SHADER_STAGE_VERTEX_BIT, // VkShaderStageFlagBits stage; |
| *vertexShaderModule, // VkShaderModule module; |
| "main", // const char* pName; |
| DE_NULL // const VkSpecializationInfo* pSpecializationInfo; |
| }; |
| |
| const VkPipelineShaderStageCreateInfo fragmentShaderStageParams = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags; |
| VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlagBits stage; |
| *fragmentShaderModule, // VkShaderModule module; |
| "main", // const char* pName; |
| DE_NULL // const VkSpecializationInfo* pSpecializationInfo; |
| }; |
| |
| shaderStageParams.push_back(vertexShaderStageParams); |
| shaderStageParams.push_back(fragmentShaderStageParams); |
| |
| if (useGeometryShader) |
| { |
| const VkPipelineShaderStageCreateInfo geometryShaderStageParams = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags; |
| VK_SHADER_STAGE_GEOMETRY_BIT, // VkShaderStageFlagBits stage; |
| *geometryShaderModule, // VkShaderModule module; |
| "main", // VkShader shader; |
| DE_NULL // const VkSpecializationInfo* pSpecializationInfo; |
| }; |
| |
| shaderStageParams.push_back(geometryShaderStageParams); |
| } |
| |
| const VkPipelineVertexInputStateCreateInfo vertexInputStateParams = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineVertexInputStateCreateFlags)0, // VkPipelineVertexInputStateCreateFlags flags; |
| (deUint32)m_vertexBindingDescriptions.size(), // deUint32 bindingCount; |
| &m_vertexBindingDescriptions[0], // const VkVertexInputBindingDescription* pVertexBindingDescriptions; |
| (deUint32)m_vertexAttributeDescriptions.size(), // deUint32 attributeCount; |
| &m_vertexAttributeDescriptions[0], // const VkVertexInputAttributeDescription* pvertexAttributeDescriptions; |
| }; |
| |
| const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateParams = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineInputAssemblyStateCreateFlags)0, // VkPipelineInputAssemblyStateCreateFlags flags; |
| VK_PRIMITIVE_TOPOLOGY_POINT_LIST, // VkPrimitiveTopology topology; |
| DE_FALSE // VkBool32 primitiveRestartEnable; |
| }; |
| |
| const VkViewport viewport = |
| { |
| 0.0f, // float originX; |
| 0.0f, // float originY; |
| (float)renderSize.x(), // float width; |
| (float)renderSize.y(), // float height; |
| 0.0f, // float minDepth; |
| 1.0f // float maxDepth; |
| }; |
| |
| const VkRect2D scissor = |
| { |
| { |
| 0u, // deUint32 x; |
| 0u, // deUint32 y; |
| }, // VkOffset2D offset; |
| { |
| renderSize.x(), // deUint32 width; |
| renderSize.y(), // deUint32 height; |
| }, // VkExtent2D extent; |
| }; |
| |
| 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 scissorsCount; |
| &scissor // const VkRect2D* pScissors; |
| }; |
| |
| const VkPipelineRasterizationStateCreateInfo rasterStateParams = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineRasterizationStateCreateFlags)0u, //VkPipelineRasterizationStateCreateFlags flags; |
| VK_FALSE, // VkBool32 depthClipEnable; |
| VK_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 depthBias; |
| 0.0f, // float depthBiasClamp; |
| 0.0f, // float slopeScaledDepthBias; |
| 1.0f // float lineWidth; |
| }; |
| |
| 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; |
| VK_FALSE, // VkBool32 sampleShadingEnable; |
| 0.0f, // float minSampleShading; |
| DE_NULL, // const VkSampleMask* pSampleMask; |
| VK_FALSE, // VkBool32 alphaToCoverageEnable; |
| VK_FALSE // VkBool32 alphaToOneEnable; |
| }; |
| |
| const VkPipelineColorBlendStateCreateInfo colorBlendStateParams = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineColorBlendStateCreateFlags)0, // VkPipelineColorBlendStateCreateFlags flags; |
| VK_FALSE, // VkBool32 logicOpEnable; |
| VK_LOGIC_OP_COPY, // VkLogicOp logicOp; |
| (deUint32)colorBlendAttachmentStates.size(), // deUint32 attachmentCount; |
| &colorBlendAttachmentStates[0], // const VkPipelineColorBlendAttachmentState* pAttachments; |
| { 0.0f, 0.0f, 0.0f, 0.0f } // float blendConst[4]; |
| }; |
| |
| const VkGraphicsPipelineCreateInfo graphicsPipelineParams = |
| { |
| VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineCreateFlags)0, // VkPipelineCreateFlags flags; |
| (deUint32)shaderStageParams.size(), // deUint32 stageCount; |
| &shaderStageParams[0], // const VkPipelineShaderStageCreateInfo* pStages; |
| &vertexInputStateParams, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState; |
| &inputAssemblyStateParams, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState; |
| DE_NULL, // const VkPipelineTessellationStateCreateInfo* pTessellationState; |
| &viewportStateParams, // const VkPipelineViewportStateCreateInfo* pViewportState; |
| &rasterStateParams, // const VkPipelineRasterStateCreateInfo* pRasterState; |
| &multisampleStateParams, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState; |
| DE_NULL, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState; |
| &colorBlendStateParams, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState; |
| (const VkPipelineDynamicStateCreateInfo*)DE_NULL, // const VkPipelineDynamicStateCreateInfo* pDynamicState; |
| *pipelineLayout, // VkPipelineLayout layout; |
| *renderPass, // VkRenderPass renderPass; |
| 0u, // deUint32 subpass; |
| 0u, // VkPipeline basePipelineHandle; |
| 0u // deInt32 basePipelineIndex; |
| }; |
| |
| graphicsPipeline = createGraphicsPipeline(vk, vkDevice, DE_NULL, &graphicsPipelineParams); |
| } |
| |
| // Create command pool |
| { |
| const VkCommandPoolCreateInfo cmdPoolParams = |
| { |
| VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, // VkCmdPoolCreateFlags flags; |
| queueFamilyIndex, // deUint32 queueFamilyIndex; |
| }; |
| |
| cmdPool = createCommandPool(vk, vkDevice, &cmdPoolParams); |
| } |
| |
| // Create command buffer |
| { |
| const VkCommandBufferAllocateInfo cmdBufferParams = |
| { |
| VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| *cmdPool, // VkCmdPool cmdPool; |
| VK_COMMAND_BUFFER_LEVEL_PRIMARY, // VkCmdBufferLevel level; |
| 1 // deUint32 bufferCount; |
| }; |
| |
| const VkCommandBufferBeginInfo cmdBufferBeginInfo = |
| { |
| VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkCmdBufferOptimizeFlags flags; |
| (const VkCommandBufferInheritanceInfo*)DE_NULL, |
| }; |
| |
| const VkRenderPassBeginInfo renderPassBeginInfo = |
| { |
| VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| *renderPass, // VkRenderPass renderPass; |
| *framebuffer, // VkFramebuffer framebuffer; |
| { { 0, 0 }, { renderSize.x(), renderSize.y() } }, // VkRect2D renderArea; |
| (deUint32)attachmentClearValues.size(), // deUint32 attachmentCount; |
| &attachmentClearValues[0] // const VkClearValue* pAttachmentClearValues; |
| }; |
| |
| cmdBuffer = allocateCommandBuffer(vk, vkDevice, &cmdBufferParams); |
| |
| VK_CHECK(vk.beginCommandBuffer(*cmdBuffer, &cmdBufferBeginInfo)); |
| |
| vk.cmdPipelineBarrier(*cmdBuffer, vk::VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, (VkDependencyFlags)0, |
| 0, (const VkMemoryBarrier*)DE_NULL, |
| 0, (const VkBufferMemoryBarrier*)DE_NULL, |
| (deUint32)colorImagePreRenderBarriers.size(), colorImagePreRenderBarriers.empty() ? DE_NULL : &colorImagePreRenderBarriers[0]); |
| vk.cmdBeginRenderPass(*cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); |
| |
| vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline); |
| |
| if (m_extraResourcesLayout != 0) |
| { |
| DE_ASSERT(extraResources != 0); |
| const VkDescriptorSet descriptorSets[] = { *emptyDescriptorSet, extraResources }; |
| vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, DE_LENGTH_OF_ARRAY(descriptorSets), descriptorSets, 0u, DE_NULL); |
| } |
| else |
| DE_ASSERT(extraResources == 0); |
| |
| const deUint32 numberOfVertexAttributes = (deUint32)m_vertexBuffers.size(); |
| |
| std::vector<VkDeviceSize> offsets(numberOfVertexAttributes, 0); |
| |
| std::vector<VkBuffer> buffers(numberOfVertexAttributes); |
| for (size_t i = 0; i < numberOfVertexAttributes; i++) |
| { |
| buffers[i] = m_vertexBuffers[i].get()->get(); |
| } |
| |
| vk.cmdBindVertexBuffers(*cmdBuffer, 0, numberOfVertexAttributes, &buffers[0], &offsets[0]); |
| vk.cmdDraw(*cmdBuffer, (deUint32)positions.size(), 1u, 0u, 0u); |
| |
| vk.cmdEndRenderPass(*cmdBuffer); |
| vk.cmdPipelineBarrier(*cmdBuffer, vk::VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, (VkDependencyFlags)0, |
| 0, (const VkMemoryBarrier*)DE_NULL, |
| 0, (const VkBufferMemoryBarrier*)DE_NULL, |
| (deUint32)colorImagePostRenderBarriers.size(), colorImagePostRenderBarriers.empty() ? DE_NULL : &colorImagePostRenderBarriers[0]); |
| |
| VK_CHECK(vk.endCommandBuffer(*cmdBuffer)); |
| } |
| |
| // Create fence |
| { |
| const VkFenceCreateInfo fenceParams = |
| { |
| VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u // VkFenceCreateFlags flags; |
| }; |
| |
| fence = createFence(vk, vkDevice, &fenceParams); |
| } |
| |
| // Execute Draw |
| { |
| |
| const VkSubmitInfo submitInfo = |
| { |
| VK_STRUCTURE_TYPE_SUBMIT_INFO, // sType |
| DE_NULL, // pNext |
| 0u, // waitSemaphoreCount |
| DE_NULL, // pWaitSemaphores |
| (const VkPipelineStageFlags*)DE_NULL, |
| 1u, // commandBufferCount |
| &cmdBuffer.get(), // pCommandBuffers |
| 0u, // signalSemaphoreCount |
| DE_NULL // pSignalSemaphores |
| }; |
| |
| VK_CHECK(vk.resetFences(vkDevice, 1, &fence.get())); |
| VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, *fence)); |
| VK_CHECK(vk.waitForFences(vkDevice, 1, &fence.get(), DE_TRUE, ~(0ull) /* infinity*/)); |
| } |
| |
| // Read back result and output |
| { |
| const VkDeviceSize imageSizeBytes = (VkDeviceSize)(4 * sizeof(deUint32) * renderSize.x() * renderSize.y()); |
| const VkBufferCreateInfo readImageBufferParams = |
| { |
| VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkBufferCreateFlags flags; |
| imageSizeBytes, // VkDeviceSize size; |
| VK_BUFFER_USAGE_TRANSFER_DST_BIT, // VkBufferUsageFlags usage; |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; |
| 1u, // deUint32 queueFamilyCount; |
| &queueFamilyIndex, // const deUint32* pQueueFamilyIndices; |
| }; |
| |
| // constants for image copy |
| |
| const VkCommandPoolCreateInfo cmdPoolParams = |
| { |
| VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, // VkCmdPoolCreateFlags flags; |
| queueFamilyIndex // deUint32 queueFamilyIndex; |
| }; |
| |
| Move<VkCommandPool> copyCmdPool = createCommandPool(vk, vkDevice, &cmdPoolParams); |
| |
| const VkCommandBufferAllocateInfo cmdBufferParams = |
| { |
| VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| *copyCmdPool, // VkCmdPool cmdPool; |
| VK_COMMAND_BUFFER_LEVEL_PRIMARY, // VkCmdBufferLevel level; |
| 1u // deUint32 bufferCount; |
| }; |
| |
| const VkCommandBufferBeginInfo cmdBufferBeginInfo = |
| { |
| VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkCmdBufferOptimizeFlags flags; |
| (const VkCommandBufferInheritanceInfo*)DE_NULL, |
| }; |
| |
| const VkBufferImageCopy copyParams = |
| { |
| 0u, // VkDeviceSize bufferOffset; |
| (deUint32)renderSize.x(), // deUint32 bufferRowLength; |
| (deUint32)renderSize.y(), // deUint32 bufferImageHeight; |
| { |
| VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspect aspect; |
| 0u, // deUint32 mipLevel; |
| 0u, // deUint32 arraySlice; |
| 1u, // deUint32 arraySize; |
| }, // VkImageSubresource imageSubresource; |
| { 0u, 0u, 0u }, // VkOffset3D imageOffset; |
| { renderSize.x(), renderSize.y(), 1u } // VkExtent3D imageExtent; |
| }; |
| |
| // Read back pixels. |
| for (int outNdx = 0; outNdx < (int)m_shaderSpec.outputs.size(); ++outNdx) |
| { |
| const Symbol& output = m_shaderSpec.outputs[outNdx]; |
| const int outSize = output.varType.getScalarSize(); |
| const int outVecSize = glu::getDataTypeNumComponents(output.varType.getBasicType()); |
| const int outNumLocs = glu::getDataTypeNumLocations(output.varType.getBasicType()); |
| deUint32* dstPtrBase = static_cast<deUint32*>(outputs[outNdx]); |
| const int outLocation = de::lookup(m_outputLayout.locationMap, output.name); |
| |
| for (int locNdx = 0; locNdx < outNumLocs; ++locNdx) |
| { |
| tcu::TextureLevel tmpBuf; |
| const tcu::TextureFormat format = getRenderbufferFormatForOutput(output.varType, false); |
| const tcu::TextureFormat readFormat (tcu::TextureFormat::RGBA, format.type); |
| const Unique<VkBuffer> readImageBuffer(createBuffer(vk, vkDevice, &readImageBufferParams)); |
| const de::UniquePtr<Allocation> readImageBufferMemory(memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *readImageBuffer), MemoryRequirement::HostVisible)); |
| |
| VK_CHECK(vk.bindBufferMemory(vkDevice, *readImageBuffer, readImageBufferMemory->getMemory(), readImageBufferMemory->getOffset())); |
| |
| // Copy image to buffer |
| { |
| |
| Move<VkCommandBuffer> copyCmdBuffer = allocateCommandBuffer(vk, vkDevice, &cmdBufferParams); |
| |
| const VkSubmitInfo submitInfo = |
| { |
| VK_STRUCTURE_TYPE_SUBMIT_INFO, |
| DE_NULL, |
| 0u, |
| (const VkSemaphore*)DE_NULL, |
| (const VkPipelineStageFlags*)DE_NULL, |
| 1u, |
| ©CmdBuffer.get(), |
| 0u, |
| (const VkSemaphore*)DE_NULL, |
| }; |
| |
| VK_CHECK(vk.beginCommandBuffer(*copyCmdBuffer, &cmdBufferBeginInfo)); |
| vk.cmdCopyImageToBuffer(*copyCmdBuffer, colorImages[outLocation + locNdx].get()->get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *readImageBuffer, 1u, ©Params); |
| VK_CHECK(vk.endCommandBuffer(*copyCmdBuffer)); |
| |
| VK_CHECK(vk.resetFences(vkDevice, 1, &fence.get())); |
| VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, *fence)); |
| VK_CHECK(vk.waitForFences(vkDevice, 1, &fence.get(), true, ~(0ull) /* infinity */)); |
| } |
| |
| const VkMappedMemoryRange range = |
| { |
| VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| readImageBufferMemory->getMemory(), // VkDeviceMemory mem; |
| 0, // VkDeviceSize offset; |
| imageSizeBytes, // VkDeviceSize size; |
| }; |
| |
| VK_CHECK(vk.invalidateMappedMemoryRanges(vkDevice, 1u, &range)); |
| |
| tmpBuf.setStorage(readFormat, renderSize.x(), renderSize.y()); |
| |
| const tcu::TextureFormat resultFormat(tcu::TextureFormat::RGBA, format.type); |
| const tcu::ConstPixelBufferAccess resultAccess(resultFormat, renderSize.x(), renderSize.y(), 1, readImageBufferMemory->getHostPtr()); |
| |
| tcu::copy(tmpBuf.getAccess(), resultAccess); |
| |
| if (outSize == 4 && outNumLocs == 1) |
| deMemcpy(dstPtrBase, tmpBuf.getAccess().getDataPtr(), numValues * outVecSize * sizeof(deUint32)); |
| else |
| { |
| for (int valNdx = 0; valNdx < numValues; valNdx++) |
| { |
| const deUint32* srcPtr = (const deUint32*)tmpBuf.getAccess().getDataPtr() + valNdx * 4; |
| deUint32* dstPtr = &dstPtrBase[outSize * valNdx + outVecSize * locNdx]; |
| deMemcpy(dstPtr, srcPtr, outVecSize * sizeof(deUint32)); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| // VertexShaderExecutor |
| |
| class VertexShaderExecutor : public FragmentOutExecutor |
| { |
| public: |
| VertexShaderExecutor (Context& context, const ShaderSpec& shaderSpec, VkDescriptorSetLayout extraResourcesLayout); |
| virtual ~VertexShaderExecutor (void); |
| |
| static void generateSources (const ShaderSpec& shaderSpec, SourceCollections& dst); |
| }; |
| |
| VertexShaderExecutor::VertexShaderExecutor (Context& context, const ShaderSpec& shaderSpec, VkDescriptorSetLayout extraResourcesLayout) |
| : FragmentOutExecutor(context, glu::SHADERTYPE_VERTEX, shaderSpec, extraResourcesLayout) |
| { |
| } |
| |
| VertexShaderExecutor::~VertexShaderExecutor (void) |
| { |
| } |
| |
| void VertexShaderExecutor::generateSources (const ShaderSpec& shaderSpec, SourceCollections& programCollection) |
| { |
| const FragmentOutputLayout outputLayout (computeFragmentOutputLayout(shaderSpec.outputs)); |
| |
| programCollection.glslSources.add("vert") << glu::VertexSource(generateVertexShader(shaderSpec, "a_", "vtx_out_")); |
| /* \todo [2015-09-11 hegedusd] set useIntOutputs parameter if needed. */ |
| programCollection.glslSources.add("frag") << glu::FragmentSource(generatePassthroughFragmentShader(shaderSpec, false, outputLayout.locationMap, "vtx_out_", "o_")); |
| } |
| |
| // GeometryShaderExecutor |
| |
| class GeometryShaderExecutor : public FragmentOutExecutor |
| { |
| public: |
| GeometryShaderExecutor (Context& context, const ShaderSpec& shaderSpec, VkDescriptorSetLayout extraResourcesLayout); |
| virtual ~GeometryShaderExecutor (void); |
| |
| static void generateSources (const ShaderSpec& shaderSpec, SourceCollections& programCollection); |
| |
| }; |
| |
| GeometryShaderExecutor::GeometryShaderExecutor (Context& context, const ShaderSpec& shaderSpec, VkDescriptorSetLayout extraResourcesLayout) |
| : FragmentOutExecutor(context, glu::SHADERTYPE_GEOMETRY, shaderSpec, extraResourcesLayout) |
| { |
| const VkPhysicalDeviceFeatures& features = context.getDeviceFeatures(); |
| |
| if (!features.geometryShader) |
| TCU_THROW(NotSupportedError, "Geometry shader type not supported by device"); |
| } |
| |
| GeometryShaderExecutor::~GeometryShaderExecutor (void) |
| { |
| } |
| |
| void GeometryShaderExecutor::generateSources (const ShaderSpec& shaderSpec, SourceCollections& programCollection) |
| { |
| const FragmentOutputLayout outputLayout (computeFragmentOutputLayout(shaderSpec.outputs)); |
| |
| programCollection.glslSources.add("vert") << glu::VertexSource(generatePassthroughVertexShader(shaderSpec.inputs, "a_", "vtx_out_")); |
| |
| programCollection.glslSources.add("geom") << glu::GeometrySource(generateGeometryShader(shaderSpec, "vtx_out_", "geom_out_")); |
| |
| /* \todo [2015-09-18 rsipka] set useIntOutputs parameter if needed. */ |
| programCollection.glslSources.add("frag") << glu::FragmentSource(generatePassthroughFragmentShader(shaderSpec, false, outputLayout.locationMap, "geom_out_", "o_")); |
| |
| } |
| |
| // FragmentShaderExecutor |
| |
| class FragmentShaderExecutor : public FragmentOutExecutor |
| { |
| public: |
| FragmentShaderExecutor (Context& context, const ShaderSpec& shaderSpec, VkDescriptorSetLayout extraResourcesLayout); |
| virtual ~FragmentShaderExecutor (void); |
| |
| static void generateSources (const ShaderSpec& shaderSpec, SourceCollections& programCollection); |
| |
| }; |
| |
| FragmentShaderExecutor::FragmentShaderExecutor (Context& context, const ShaderSpec& shaderSpec, VkDescriptorSetLayout extraResourcesLayout) |
| : FragmentOutExecutor(context, glu::SHADERTYPE_FRAGMENT, shaderSpec, extraResourcesLayout) |
| { |
| } |
| |
| FragmentShaderExecutor::~FragmentShaderExecutor (void) |
| { |
| } |
| |
| void FragmentShaderExecutor::generateSources (const ShaderSpec& shaderSpec, SourceCollections& programCollection) |
| { |
| const FragmentOutputLayout outputLayout (computeFragmentOutputLayout(shaderSpec.outputs)); |
| |
| programCollection.glslSources.add("vert") << glu::VertexSource(generatePassthroughVertexShader(shaderSpec.inputs, "a_", "vtx_out_")); |
| /* \todo [2015-09-11 hegedusd] set useIntOutputs parameter if needed. */ |
| programCollection.glslSources.add("frag") << glu::FragmentSource(generateFragmentShader(shaderSpec, false, outputLayout.locationMap, "vtx_out_", "o_")); |
| } |
| |
| // Shared utilities for compute and tess executors |
| |
| static deUint32 getVecStd430ByteAlignment (glu::DataType type) |
| { |
| switch (glu::getDataTypeScalarSize(type)) |
| { |
| case 1: return 4u; |
| case 2: return 8u; |
| case 3: return 16u; |
| case 4: return 16u; |
| default: |
| DE_ASSERT(false); |
| return 0u; |
| } |
| } |
| |
| class BufferIoExecutor : public ShaderExecutor |
| { |
| public: |
| BufferIoExecutor (Context& context, const ShaderSpec& shaderSpec); |
| virtual ~BufferIoExecutor (void); |
| |
| protected: |
| enum |
| { |
| INPUT_BUFFER_BINDING = 0, |
| OUTPUT_BUFFER_BINDING = 1, |
| }; |
| |
| void initBuffers (int numValues); |
| VkBuffer getInputBuffer (void) const { return *m_inputBuffer; } |
| VkBuffer getOutputBuffer (void) const { return *m_outputBuffer; } |
| deUint32 getInputStride (void) const { return getLayoutStride(m_inputLayout); } |
| deUint32 getOutputStride (void) const { return getLayoutStride(m_outputLayout); } |
| |
| void uploadInputBuffer (const void* const* inputPtrs, int numValues); |
| void readOutputBuffer (void* const* outputPtrs, int numValues); |
| |
| static void declareBufferBlocks (std::ostream& src, const ShaderSpec& spec); |
| static void generateExecBufferIo(std::ostream& src, const ShaderSpec& spec, const char* invocationNdxName); |
| |
| protected: |
| Move<VkBuffer> m_inputBuffer; |
| Move<VkBuffer> m_outputBuffer; |
| |
| private: |
| struct VarLayout |
| { |
| deUint32 offset; |
| deUint32 stride; |
| deUint32 matrixStride; |
| |
| VarLayout (void) : offset(0), stride(0), matrixStride(0) {} |
| }; |
| |
| static void computeVarLayout (const std::vector<Symbol>& symbols, std::vector<VarLayout>* layout); |
| static deUint32 getLayoutStride (const vector<VarLayout>& layout); |
| |
| static void copyToBuffer (const glu::VarType& varType, const VarLayout& layout, int numValues, const void* srcBasePtr, void* dstBasePtr); |
| static void copyFromBuffer (const glu::VarType& varType, const VarLayout& layout, int numValues, const void* srcBasePtr, void* dstBasePtr); |
| |
| de::MovePtr<Allocation> m_inputAlloc; |
| de::MovePtr<Allocation> m_outputAlloc; |
| |
| vector<VarLayout> m_inputLayout; |
| vector<VarLayout> m_outputLayout; |
| }; |
| |
| BufferIoExecutor::BufferIoExecutor (Context& context, const ShaderSpec& shaderSpec) |
| : ShaderExecutor(context, shaderSpec) |
| { |
| computeVarLayout(m_shaderSpec.inputs, &m_inputLayout); |
| computeVarLayout(m_shaderSpec.outputs, &m_outputLayout); |
| } |
| |
| BufferIoExecutor::~BufferIoExecutor (void) |
| { |
| } |
| |
| inline deUint32 BufferIoExecutor::getLayoutStride (const vector<VarLayout>& layout) |
| { |
| return layout.empty() ? 0 : layout[0].stride; |
| } |
| |
| void BufferIoExecutor::computeVarLayout (const std::vector<Symbol>& symbols, std::vector<VarLayout>* layout) |
| { |
| deUint32 maxAlignment = 0; |
| deUint32 curOffset = 0; |
| |
| DE_ASSERT(layout != DE_NULL); |
| DE_ASSERT(layout->empty()); |
| layout->resize(symbols.size()); |
| |
| for (size_t varNdx = 0; varNdx < symbols.size(); varNdx++) |
| { |
| const Symbol& symbol = symbols[varNdx]; |
| const glu::DataType basicType = symbol.varType.getBasicType(); |
| VarLayout& layoutEntry = (*layout)[varNdx]; |
| |
| if (glu::isDataTypeScalarOrVector(basicType)) |
| { |
| const deUint32 alignment = getVecStd430ByteAlignment(basicType); |
| const deUint32 size = (deUint32)glu::getDataTypeScalarSize(basicType) * (int)sizeof(deUint32); |
| |
| curOffset = (deUint32)deAlign32((int)curOffset, (int)alignment); |
| maxAlignment = de::max(maxAlignment, alignment); |
| |
| layoutEntry.offset = curOffset; |
| layoutEntry.matrixStride = 0; |
| |
| curOffset += size; |
| } |
| else if (glu::isDataTypeMatrix(basicType)) |
| { |
| const int numVecs = glu::getDataTypeMatrixNumColumns(basicType); |
| const glu::DataType vecType = glu::getDataTypeFloatVec(glu::getDataTypeMatrixNumRows(basicType)); |
| const deUint32 vecAlignment = getVecStd430ByteAlignment(vecType); |
| |
| curOffset = (deUint32)deAlign32((int)curOffset, (int)vecAlignment); |
| maxAlignment = de::max(maxAlignment, vecAlignment); |
| |
| layoutEntry.offset = curOffset; |
| layoutEntry.matrixStride = vecAlignment; |
| |
| curOffset += vecAlignment*numVecs; |
| } |
| else |
| DE_ASSERT(false); |
| } |
| |
| { |
| const deUint32 totalSize = (deUint32)deAlign32(curOffset, maxAlignment); |
| |
| for (vector<VarLayout>::iterator varIter = layout->begin(); varIter != layout->end(); ++varIter) |
| varIter->stride = totalSize; |
| } |
| } |
| |
| void BufferIoExecutor::declareBufferBlocks (std::ostream& src, const ShaderSpec& spec) |
| { |
| // Input struct |
| if (!spec.inputs.empty()) |
| { |
| glu::StructType inputStruct("Inputs"); |
| for (vector<Symbol>::const_iterator symIter = spec.inputs.begin(); symIter != spec.inputs.end(); ++symIter) |
| inputStruct.addMember(symIter->name.c_str(), symIter->varType); |
| src << glu::declare(&inputStruct) << ";\n"; |
| } |
| |
| // Output struct |
| { |
| glu::StructType outputStruct("Outputs"); |
| for (vector<Symbol>::const_iterator symIter = spec.outputs.begin(); symIter != spec.outputs.end(); ++symIter) |
| outputStruct.addMember(symIter->name.c_str(), symIter->varType); |
| src << glu::declare(&outputStruct) << ";\n"; |
| } |
| |
| src << "\n"; |
| |
| if (!spec.inputs.empty()) |
| { |
| src << "layout(set = 0, binding = " << int(INPUT_BUFFER_BINDING) << ", std430) buffer InBuffer\n" |
| << "{\n" |
| << " Inputs inputs[];\n" |
| << "};\n"; |
| } |
| |
| src << "layout(set = 0, binding = " << int(OUTPUT_BUFFER_BINDING) << ", std430) buffer OutBuffer\n" |
| << "{\n" |
| << " Outputs outputs[];\n" |
| << "};\n" |
| << "\n"; |
| } |
| |
| void BufferIoExecutor::generateExecBufferIo (std::ostream& src, const ShaderSpec& spec, const char* invocationNdxName) |
| { |
| for (vector<Symbol>::const_iterator symIter = spec.inputs.begin(); symIter != spec.inputs.end(); ++symIter) |
| src << "\t" << glu::declare(symIter->varType, symIter->name) << " = inputs[" << invocationNdxName << "]." << symIter->name << ";\n"; |
| |
| for (vector<Symbol>::const_iterator symIter = spec.outputs.begin(); symIter != spec.outputs.end(); ++symIter) |
| src << "\t" << glu::declare(symIter->varType, symIter->name) << ";\n"; |
| |
| src << "\n"; |
| |
| { |
| std::istringstream opSrc (spec.source); |
| std::string line; |
| |
| while (std::getline(opSrc, line)) |
| src << "\t" << line << "\n"; |
| } |
| |
| src << "\n"; |
| for (vector<Symbol>::const_iterator symIter = spec.outputs.begin(); symIter != spec.outputs.end(); ++symIter) |
| src << "\toutputs[" << invocationNdxName << "]." << symIter->name << " = " << symIter->name << ";\n"; |
| } |
| |
| void BufferIoExecutor::copyToBuffer (const glu::VarType& varType, const VarLayout& layout, int numValues, const void* srcBasePtr, void* dstBasePtr) |
| { |
| if (varType.isBasicType()) |
| { |
| const glu::DataType basicType = varType.getBasicType(); |
| const bool isMatrix = glu::isDataTypeMatrix(basicType); |
| const int scalarSize = glu::getDataTypeScalarSize(basicType); |
| const int numVecs = isMatrix ? glu::getDataTypeMatrixNumColumns(basicType) : 1; |
| const int numComps = scalarSize / numVecs; |
| |
| for (int elemNdx = 0; elemNdx < numValues; elemNdx++) |
| { |
| for (int vecNdx = 0; vecNdx < numVecs; vecNdx++) |
| { |
| const int srcOffset = (int)sizeof(deUint32) * (elemNdx * scalarSize + vecNdx * numComps); |
| const int dstOffset = layout.offset + layout.stride * elemNdx + (isMatrix ? layout.matrixStride * vecNdx : 0); |
| const deUint8* srcPtr = (const deUint8*)srcBasePtr + srcOffset; |
| deUint8* dstPtr = (deUint8*)dstBasePtr + dstOffset; |
| |
| deMemcpy(dstPtr, srcPtr, sizeof(deUint32) * numComps); |
| } |
| } |
| } |
| else |
| throw tcu::InternalError("Unsupported type"); |
| } |
| |
| void BufferIoExecutor::copyFromBuffer (const glu::VarType& varType, const VarLayout& layout, int numValues, const void* srcBasePtr, void* dstBasePtr) |
| { |
| if (varType.isBasicType()) |
| { |
| const glu::DataType basicType = varType.getBasicType(); |
| const bool isMatrix = glu::isDataTypeMatrix(basicType); |
| const int scalarSize = glu::getDataTypeScalarSize(basicType); |
| const int numVecs = isMatrix ? glu::getDataTypeMatrixNumColumns(basicType) : 1; |
| const int numComps = scalarSize / numVecs; |
| |
| for (int elemNdx = 0; elemNdx < numValues; elemNdx++) |
| { |
| for (int vecNdx = 0; vecNdx < numVecs; vecNdx++) |
| { |
| const int srcOffset = layout.offset + layout.stride * elemNdx + (isMatrix ? layout.matrixStride * vecNdx : 0); |
| const int dstOffset = (int)sizeof(deUint32) * (elemNdx * scalarSize + vecNdx * numComps); |
| const deUint8* srcPtr = (const deUint8*)srcBasePtr + srcOffset; |
| deUint8* dstPtr = (deUint8*)dstBasePtr + dstOffset; |
| |
| deMemcpy(dstPtr, srcPtr, sizeof(deUint32) * numComps); |
| } |
| } |
| } |
| else |
| throw tcu::InternalError("Unsupported type"); |
| } |
| |
| void BufferIoExecutor::uploadInputBuffer (const void* const* inputPtrs, int numValues) |
| { |
| const VkDevice vkDevice = m_context.getDevice(); |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| |
| const deUint32 inputStride = getLayoutStride(m_inputLayout); |
| const int inputBufferSize = inputStride * numValues; |
| |
| if (inputBufferSize == 0) |
| return; // No inputs |
| |
| DE_ASSERT(m_shaderSpec.inputs.size() == m_inputLayout.size()); |
| for (size_t inputNdx = 0; inputNdx < m_shaderSpec.inputs.size(); ++inputNdx) |
| { |
| const glu::VarType& varType = m_shaderSpec.inputs[inputNdx].varType; |
| const VarLayout& layout = m_inputLayout[inputNdx]; |
| |
| copyToBuffer(varType, layout, numValues, inputPtrs[inputNdx], m_inputAlloc->getHostPtr()); |
| } |
| |
| flushMappedMemoryRange(vk, vkDevice, m_inputAlloc->getMemory(), m_inputAlloc->getOffset(), inputBufferSize); |
| } |
| |
| void BufferIoExecutor::readOutputBuffer (void* const* outputPtrs, int numValues) |
| { |
| const VkDevice vkDevice = m_context.getDevice(); |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| |
| const deUint32 outputStride = getLayoutStride(m_outputLayout); |
| const int outputBufferSize = numValues * outputStride; |
| |
| DE_ASSERT(outputBufferSize > 0); // At least some outputs are required. |
| |
| invalidateMappedMemoryRange(vk, vkDevice, m_outputAlloc->getMemory(), m_outputAlloc->getOffset(), outputBufferSize); |
| |
| DE_ASSERT(m_shaderSpec.outputs.size() == m_outputLayout.size()); |
| for (size_t outputNdx = 0; outputNdx < m_shaderSpec.outputs.size(); ++outputNdx) |
| { |
| const glu::VarType& varType = m_shaderSpec.outputs[outputNdx].varType; |
| const VarLayout& layout = m_outputLayout[outputNdx]; |
| |
| copyFromBuffer(varType, layout, numValues, m_outputAlloc->getHostPtr(), outputPtrs[outputNdx]); |
| } |
| } |
| |
| void BufferIoExecutor::initBuffers (int numValues) |
| { |
| const deUint32 inputStride = getLayoutStride(m_inputLayout); |
| const deUint32 outputStride = getLayoutStride(m_outputLayout); |
| // Avoid creating zero-sized buffer/memory |
| const size_t inputBufferSize = numValues * inputStride ? (numValues * inputStride) : 1; |
| const size_t outputBufferSize = numValues * outputStride; |
| |
| // Upload data to buffer |
| const VkDevice vkDevice = m_context.getDevice(); |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); |
| Allocator& memAlloc = m_context.getDefaultAllocator(); |
| |
| const VkBufferCreateInfo inputBufferParams = |
| { |
| VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkBufferCreateFlags flags; |
| inputBufferSize, // VkDeviceSize size; |
| VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, // VkBufferUsageFlags usage; |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; |
| 1u, // deUint32 queueFamilyCount; |
| &queueFamilyIndex // const deUint32* pQueueFamilyIndices; |
| }; |
| |
| m_inputBuffer = createBuffer(vk, vkDevice, &inputBufferParams); |
| m_inputAlloc = memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_inputBuffer), MemoryRequirement::HostVisible); |
| |
| VK_CHECK(vk.bindBufferMemory(vkDevice, *m_inputBuffer, m_inputAlloc->getMemory(), m_inputAlloc->getOffset())); |
| |
| const VkBufferCreateInfo outputBufferParams = |
| { |
| VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkBufferCreateFlags flags; |
| outputBufferSize, // VkDeviceSize size; |
| VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, // VkBufferUsageFlags usage; |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; |
| 1u, // deUint32 queueFamilyCount; |
| &queueFamilyIndex // const deUint32* pQueueFamilyIndices; |
| }; |
| |
| m_outputBuffer = createBuffer(vk, vkDevice, &outputBufferParams); |
| m_outputAlloc = memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_outputBuffer), MemoryRequirement::HostVisible); |
| |
| VK_CHECK(vk.bindBufferMemory(vkDevice, *m_outputBuffer, m_outputAlloc->getMemory(), m_outputAlloc->getOffset())); |
| } |
| |
| // ComputeShaderExecutor |
| |
| class ComputeShaderExecutor : public BufferIoExecutor |
| { |
| public: |
| ComputeShaderExecutor (Context& context, const ShaderSpec& shaderSpec, VkDescriptorSetLayout extraResourcesLayout); |
| virtual ~ComputeShaderExecutor (void); |
| |
| static void generateSources (const ShaderSpec& shaderSpec, SourceCollections& programCollection); |
| |
| virtual void execute (int numValues, const void* const* inputs, void* const* outputs, VkDescriptorSet extraResources); |
| |
| protected: |
| static std::string generateComputeShader (const ShaderSpec& spec); |
| |
| private: |
| const VkDescriptorSetLayout m_extraResourcesLayout; |
| }; |
| |
| ComputeShaderExecutor::ComputeShaderExecutor(Context& context, const ShaderSpec& shaderSpec, VkDescriptorSetLayout extraResourcesLayout) |
| : BufferIoExecutor (context, shaderSpec) |
| , m_extraResourcesLayout (extraResourcesLayout) |
| { |
| } |
| |
| ComputeShaderExecutor::~ComputeShaderExecutor (void) |
| { |
| } |
| |
| std::string ComputeShaderExecutor::generateComputeShader (const ShaderSpec& spec) |
| { |
| std::ostringstream src; |
| src << "#version 310 es\n"; |
| |
| if (!spec.globalDeclarations.empty()) |
| src << spec.globalDeclarations << "\n"; |
| |
| src << "layout(local_size_x = 1) in;\n" |
| << "\n"; |
| |
| declareBufferBlocks(src, spec); |
| |
| src << "void main (void)\n" |
| << "{\n" |
| << " uint invocationNdx = gl_NumWorkGroups.x*gl_NumWorkGroups.y*gl_WorkGroupID.z\n" |
| << " + gl_NumWorkGroups.x*gl_WorkGroupID.y + gl_WorkGroupID.x;\n"; |
| |
| generateExecBufferIo(src, spec, "invocationNdx"); |
| |
| src << "}\n"; |
| |
| return src.str(); |
| } |
| |
| void ComputeShaderExecutor::generateSources (const ShaderSpec& shaderSpec, SourceCollections& programCollection) |
| { |
| programCollection.glslSources.add("compute") << glu::ComputeSource(generateComputeShader(shaderSpec)); |
| } |
| |
| void ComputeShaderExecutor::execute (int numValues, const void* const* inputs, void* const* outputs, VkDescriptorSet extraResources) |
| { |
| const VkDevice vkDevice = m_context.getDevice(); |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| const VkQueue queue = m_context.getUniversalQueue(); |
| const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); |
| |
| DescriptorPoolBuilder descriptorPoolBuilder; |
| DescriptorSetLayoutBuilder descriptorSetLayoutBuilder; |
| |
| Move<VkShaderModule> computeShaderModule; |
| Move<VkPipeline> computePipeline; |
| Move<VkPipelineLayout> pipelineLayout; |
| Move<VkCommandPool> cmdPool; |
| Move<VkDescriptorPool> descriptorPool; |
| Move<VkDescriptorSetLayout> descriptorSetLayout; |
| Move<VkDescriptorSet> descriptorSet; |
| const deUint32 numDescriptorSets = (m_extraResourcesLayout != 0) ? 2u : 1u; |
| Move<VkFence> fence; |
| |
| DE_ASSERT((m_extraResourcesLayout != 0) == (extraResources != 0)); |
| |
| initBuffers(numValues); |
| |
| // Setup input buffer & copy data |
| uploadInputBuffer(inputs, numValues); |
| |
| // Create command pool |
| { |
| const VkCommandPoolCreateInfo cmdPoolParams = |
| { |
| VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, // VkCmdPoolCreateFlags flags; |
| queueFamilyIndex // deUint32 queueFamilyIndex; |
| }; |
| |
| cmdPool = createCommandPool(vk, vkDevice, &cmdPoolParams); |
| } |
| |
| // Create command buffer |
| const VkCommandBufferAllocateInfo cmdBufferParams = |
| { |
| VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| *cmdPool, // VkCmdPool cmdPool; |
| VK_COMMAND_BUFFER_LEVEL_PRIMARY, // VkCmdBufferLevel level; |
| 1u // deUint32 bufferCount; |
| }; |
| |
| const VkCommandBufferBeginInfo cmdBufferBeginInfo = |
| { |
| VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkCmdBufferOptimizeFlags flags; |
| (const VkCommandBufferInheritanceInfo*)DE_NULL, |
| }; |
| |
| descriptorSetLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT); |
| descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| descriptorSetLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT); |
| descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| |
| descriptorSetLayout = descriptorSetLayoutBuilder.build(vk, vkDevice); |
| descriptorPool = descriptorPoolBuilder.build(vk, vkDevice, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u); |
| |
| const VkDescriptorSetAllocateInfo allocInfo = |
| { |
| VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, |
| DE_NULL, |
| *descriptorPool, |
| 1u, |
| &*descriptorSetLayout |
| }; |
| |
| descriptorSet = allocateDescriptorSet(vk, vkDevice, &allocInfo); |
| |
| // Create pipeline layout |
| { |
| const VkDescriptorSetLayout descriptorSetLayouts[] = |
| { |
| *descriptorSetLayout, |
| m_extraResourcesLayout |
| }; |
| const VkPipelineLayoutCreateInfo pipelineLayoutParams = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineLayoutCreateFlags)0, // VkPipelineLayoutCreateFlags flags; |
| numDescriptorSets, // deUint32 CdescriptorSetCount; |
| descriptorSetLayouts, // const VkDescriptorSetLayout* pSetLayouts; |
| 0u, // deUint32 pushConstantRangeCount; |
| DE_NULL // const VkPushConstantRange* pPushConstantRanges; |
| }; |
| |
| pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams); |
| } |
| |
| // Create shaders |
| { |
| computeShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("compute"), 0); |
| } |
| |
| // create pipeline |
| { |
| const VkPipelineShaderStageCreateInfo shaderStageParams[1] = |
| { |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineShaderStageCreateFlags)0u, // VkPipelineShaderStageCreateFlags flags; |
| VK_SHADER_STAGE_COMPUTE_BIT, // VkShaderStageFlagsBit stage; |
| *computeShaderModule, // VkShaderModule shader; |
| "main", // const char* pName; |
| DE_NULL // const VkSpecializationInfo* pSpecializationInfo; |
| } |
| }; |
| |
| const VkComputePipelineCreateInfo computePipelineParams = |
| { |
| VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineCreateFlags)0, // VkPipelineCreateFlags flags; |
| *shaderStageParams, // VkPipelineShaderStageCreateInfo cs; |
| *pipelineLayout, // VkPipelineLayout layout; |
| 0u, // VkPipeline basePipelineHandle; |
| 0u, // int32_t basePipelineIndex; |
| }; |
| |
| computePipeline = createComputePipeline(vk, vkDevice, DE_NULL, &computePipelineParams); |
| } |
| |
| // Create fence |
| { |
| const VkFenceCreateInfo fenceParams = |
| { |
| VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u // VkFenceCreateFlags flags; |
| }; |
| fence = createFence(vk, vkDevice, &fenceParams); |
| } |
| |
| const int maxValuesPerInvocation = m_context.getDeviceProperties().limits.maxComputeWorkGroupSize[0]; |
| int curOffset = 0; |
| const deUint32 inputStride = getInputStride(); |
| const deUint32 outputStride = getOutputStride(); |
| |
| while (curOffset < numValues) |
| { |
| Move<VkCommandBuffer> cmdBuffer; |
| const int numToExec = de::min(maxValuesPerInvocation, numValues-curOffset); |
| |
| // Update descriptors |
| { |
| DescriptorSetUpdateBuilder descriptorSetUpdateBuilder; |
| |
| const VkDescriptorBufferInfo outputDescriptorBufferInfo = |
| { |
| *m_outputBuffer, // VkBuffer buffer; |
| curOffset * outputStride, // VkDeviceSize offset; |
| numToExec * outputStride // VkDeviceSize range; |
| }; |
| |
| descriptorSetUpdateBuilder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding((deUint32)OUTPUT_BUFFER_BINDING), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &outputDescriptorBufferInfo); |
| |
| if (inputStride) |
| { |
| const VkDescriptorBufferInfo inputDescriptorBufferInfo = |
| { |
| *m_inputBuffer, // VkBuffer buffer; |
| curOffset * inputStride, // VkDeviceSize offset; |
| numToExec * inputStride // VkDeviceSize range; |
| }; |
| |
| descriptorSetUpdateBuilder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding((deUint32)INPUT_BUFFER_BINDING), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &inputDescriptorBufferInfo); |
| } |
| |
| descriptorSetUpdateBuilder.update(vk, vkDevice); |
| } |
| |
| cmdBuffer = allocateCommandBuffer(vk, vkDevice, &cmdBufferParams); |
| VK_CHECK(vk.beginCommandBuffer(*cmdBuffer, &cmdBufferBeginInfo)); |
| vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *computePipeline); |
| |
| { |
| const VkDescriptorSet descriptorSets[] = { *descriptorSet, extraResources }; |
| vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, numDescriptorSets, descriptorSets, 0u, DE_NULL); |
| } |
| |
| vk.cmdDispatch(*cmdBuffer, numToExec, 1, 1); |
| |
| VK_CHECK(vk.endCommandBuffer(*cmdBuffer)); |
| |
| curOffset += numToExec; |
| |
| // Execute |
| { |
| VK_CHECK(vk.resetFences(vkDevice, 1, &fence.get())); |
| |
| const VkSubmitInfo submitInfo = |
| { |
| VK_STRUCTURE_TYPE_SUBMIT_INFO, |
| DE_NULL, |
| 0u, |
| (const VkSemaphore*)DE_NULL, |
| (const VkPipelineStageFlags*)DE_NULL, |
| 1u, |
| &cmdBuffer.get(), |
| 0u, |
| (const VkSemaphore*)DE_NULL, |
| }; |
| |
| VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, *fence)); |
| VK_CHECK(vk.waitForFences(vkDevice, 1, &fence.get(), true, ~(0ull) /* infinity*/)); |
| } |
| } |
| |
| // Read back data |
| readOutputBuffer(outputs, numValues); |
| } |
| |
| // Tessellation utils |
| |
| static std::string generateVertexShaderForTess (void) |
| { |
| std::ostringstream src; |
| src << "#version 310 es\n" |
| << "void main (void)\n{\n" |
| << " gl_Position = vec4(gl_VertexIndex/2, gl_VertexIndex%2, 0.0, 1.0);\n" |
| << "}\n"; |
| |
| return src.str(); |
| } |
| |
| class TessellationExecutor : public BufferIoExecutor |
| { |
| public: |
| TessellationExecutor (Context& context, const ShaderSpec& shaderSpec, VkDescriptorSetLayout extraResourcesLayout); |
| virtual ~TessellationExecutor (void); |
| |
| void renderTess (deUint32 numValues, deUint32 vertexCount, deUint32 patchControlPoints, VkDescriptorSet extraResources); |
| |
| private: |
| const VkDescriptorSetLayout m_extraResourcesLayout; |
| }; |
| |
| TessellationExecutor::TessellationExecutor (Context& context, const ShaderSpec& shaderSpec, VkDescriptorSetLayout extraResourcesLayout) |
| : BufferIoExecutor (context, shaderSpec) |
| , m_extraResourcesLayout (extraResourcesLayout) |
| { |
| const VkPhysicalDeviceFeatures& features = context.getDeviceFeatures(); |
| |
| if (!features.tessellationShader) |
| TCU_THROW(NotSupportedError, "Tessellation shader is not supported by device"); |
| } |
| |
| TessellationExecutor::~TessellationExecutor (void) |
| { |
| } |
| |
| void TessellationExecutor::renderTess (deUint32 numValues, deUint32 vertexCount, deUint32 patchControlPoints, VkDescriptorSet extraResources) |
| { |
| const size_t inputBufferSize = numValues * getInputStride(); |
| const VkDevice vkDevice = m_context.getDevice(); |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| const VkQueue queue = m_context.getUniversalQueue(); |
| const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); |
| Allocator& memAlloc = m_context.getDefaultAllocator(); |
| |
| const tcu::UVec2 renderSize (DEFAULT_RENDER_WIDTH, DEFAULT_RENDER_HEIGHT); |
| |
| Move<VkImage> colorImage; |
| de::MovePtr<Allocation> colorImageAlloc; |
| VkFormat colorFormat = VK_FORMAT_R8G8B8A8_UNORM; |
| Move<VkImageView> colorImageView; |
| |
| Move<VkRenderPass> renderPass; |
| Move<VkFramebuffer> framebuffer; |
| Move<VkPipelineLayout> pipelineLayout; |
| Move<VkPipeline> graphicsPipeline; |
| |
| Move<VkShaderModule> vertexShaderModule; |
| Move<VkShaderModule> tessControlShaderModule; |
| Move<VkShaderModule> tessEvalShaderModule; |
| Move<VkShaderModule> fragmentShaderModule; |
| |
| Move<VkCommandPool> cmdPool; |
| Move<VkCommandBuffer> cmdBuffer; |
| |
| Move<VkFence> fence; |
| |
| Move<VkDescriptorPool> descriptorPool; |
| Move<VkDescriptorSetLayout> descriptorSetLayout; |
| Move<VkDescriptorSet> descriptorSet; |
| const deUint32 numDescriptorSets = (m_extraResourcesLayout != 0) ? 2u : 1u; |
| |
| DE_ASSERT((m_extraResourcesLayout != 0) == (extraResources != 0)); |
| |
| // 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; |
| colorFormat, // VkFormat format; |
| { renderSize.x(), renderSize.y(), 1u }, // VkExtent3D extent; |
| 1u, // deUint32 mipLevels; |
| 1u, // deUint32 arraySize; |
| 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 queueFamilyCount; |
| &queueFamilyIndex, // const deUint32* pQueueFamilyIndices; |
| VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout; |
| }; |
| |
| colorImage = createImage(vk, vkDevice, &colorImageParams); |
| |
| // Allocate and bind color image memory |
| colorImageAlloc = memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *colorImage), MemoryRequirement::Any); |
| VK_CHECK(vk.bindImageMemory(vkDevice, *colorImage, colorImageAlloc->getMemory(), colorImageAlloc->getOffset())); |
| } |
| |
| // Create color attachment view |
| { |
| const VkImageViewCreateInfo colorImageViewParams = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkImageViewCreateFlags flags; |
| *colorImage, // VkImage image; |
| VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType; |
| colorFormat, // VkFormat format; |
| { |
| VK_COMPONENT_SWIZZLE_R, // VkComponentSwizzle r; |
| VK_COMPONENT_SWIZZLE_G, // VkComponentSwizzle g; |
| VK_COMPONENT_SWIZZLE_B, // VkComponentSwizzle b; |
| VK_COMPONENT_SWIZZLE_A // VkComponentSwizzle a; |
| }, // VkComponentsMapping components; |
| { |
| VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask; |
| 0u, // deUint32 baseMipLevel; |
| 1u, // deUint32 mipLevels; |
| 0u, // deUint32 baseArraylayer; |
| 1u // deUint32 layerCount; |
| } // VkImageSubresourceRange subresourceRange; |
| }; |
| |
| colorImageView = createImageView(vk, vkDevice, &colorImageViewParams); |
| } |
| |
| // Create render pass |
| { |
| const VkAttachmentDescription colorAttachmentDescription = |
| { |
| 0u, // VkAttachmentDescriptorFlags flags; |
| colorFormat, // VkFormat format; |
| VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; |
| VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp; |
| VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp; |
| VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp; |
| VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp; |
| VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout |
| }; |
| |
| const VkAttachmentDescription attachments[1] = |
| { |
| colorAttachmentDescription |
| }; |
| |
| const VkAttachmentReference colorAttachmentReference = |
| { |
| 0u, // deUint32 attachment; |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout; |
| }; |
| |
| const VkSubpassDescription subpassDescription = |
| { |
| 0u, // VkSubpassDescriptionFlags flags; |
| VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint; |
| 0u, // deUint32 inputCount; |
| DE_NULL, // const VkAttachmentReference* pInputAttachments; |
| 1u, // deUint32 colorCount; |
| &colorAttachmentReference, // const VkAttachmentReference* pColorAttachments; |
| DE_NULL, // const VkAttachmentReference* pResolveAttachments; |
| DE_NULL, // VkAttachmentReference depthStencilAttachment; |
| 0u, // deUint32 preserveCount; |
| DE_NULL // const VkAttachmentReference* pPreserveAttachments; |
| }; |
| |
| const VkRenderPassCreateInfo renderPassParams = |
| { |
| VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkRenderPassCreateFlags flags; |
| 1u, // deUint32 attachmentCount; |
| attachments, // const VkAttachmentDescription* pAttachments; |
| 1u, // deUint32 subpassCount; |
| &subpassDescription, // const VkSubpassDescription* pSubpasses; |
| 0u, // deUint32 dependencyCount; |
| DE_NULL // const VkSubpassDependency* pDependencies; |
| }; |
| |
| renderPass = createRenderPass(vk, vkDevice, &renderPassParams); |
| } |
| |
| // Create framebuffer |
| { |
| const VkFramebufferCreateInfo framebufferParams = |
| { |
| VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkFramebufferCreateFlags flags; |
| *renderPass, // VkRenderPass renderPass; |
| 1u, // deUint32 attachmentCount; |
| &*colorImageView, // const VkAttachmentBindInfo* pAttachments; |
| (deUint32)renderSize.x(), // deUint32 width; |
| (deUint32)renderSize.y(), // deUint32 height; |
| 1u // deUint32 layers; |
| }; |
| |
| framebuffer = createFramebuffer(vk, vkDevice, &framebufferParams); |
| } |
| |
| // Create descriptors |
| { |
| DescriptorPoolBuilder descriptorPoolBuilder; |
| DescriptorSetLayoutBuilder descriptorSetLayoutBuilder; |
| |
| descriptorSetLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_ALL); |
| descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| descriptorSetLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_ALL); |
| descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| |
| descriptorSetLayout = descriptorSetLayoutBuilder.build(vk, vkDevice); |
| descriptorPool = descriptorPoolBuilder.build(vk, vkDevice, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u); |
| |
| const VkDescriptorSetAllocateInfo allocInfo = |
| { |
| VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, |
| DE_NULL, |
| *descriptorPool, |
| 1u, |
| &*descriptorSetLayout |
| }; |
| |
| descriptorSet = allocateDescriptorSet(vk, vkDevice, &allocInfo); |
| // Update descriptors |
| { |
| DescriptorSetUpdateBuilder descriptorSetUpdateBuilder; |
| const VkDescriptorBufferInfo outputDescriptorBufferInfo = |
| { |
| *m_outputBuffer, // VkBuffer buffer; |
| 0u, // VkDeviceSize offset; |
| VK_WHOLE_SIZE // VkDeviceSize range; |
| }; |
| |
| descriptorSetUpdateBuilder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding((deUint32)OUTPUT_BUFFER_BINDING), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &outputDescriptorBufferInfo); |
| |
| VkDescriptorBufferInfo inputDescriptorBufferInfo = |
| { |
| 0, // VkBuffer buffer; |
| 0u, // VkDeviceSize offset; |
| VK_WHOLE_SIZE // VkDeviceSize range; |
| }; |
| |
| if (inputBufferSize > 0) |
| { |
| inputDescriptorBufferInfo.buffer = *m_inputBuffer; |
| |
| descriptorSetUpdateBuilder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding((deUint32)INPUT_BUFFER_BINDING), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &inputDescriptorBufferInfo); |
| } |
| |
| descriptorSetUpdateBuilder.update(vk, vkDevice); |
| } |
| } |
| |
| // Create pipeline layout |
| { |
| const VkDescriptorSetLayout descriptorSetLayouts[] = |
| { |
| *descriptorSetLayout, |
| m_extraResourcesLayout |
| }; |
| const VkPipelineLayoutCreateInfo pipelineLayoutParams = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineLayoutCreateFlags)0, // VkPipelineLayoutCreateFlags flags; |
| numDescriptorSets, // deUint32 descriptorSetCount; |
| descriptorSetLayouts, // const VkDescriptorSetLayout* pSetLayouts; |
| 0u, // deUint32 pushConstantRangeCount; |
| DE_NULL // const VkPushConstantRange* pPushConstantRanges; |
| }; |
| |
| pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams); |
| } |
| |
| // Create shader modules |
| { |
| vertexShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("vert"), 0); |
| tessControlShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("tess_control"), 0); |
| tessEvalShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("tess_eval"), 0); |
| fragmentShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("frag"), 0); |
| } |
| |
| // Create pipeline |
| { |
| const VkPipelineShaderStageCreateInfo shaderStageParams[4] = |
| { |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags; |
| VK_SHADER_STAGE_VERTEX_BIT, // VkShaderStageFlagBit stage; |
| *vertexShaderModule, // VkShaderModule shader; |
| "main", // const char* pName; |
| DE_NULL // const VkSpecializationInfo* pSpecializationInfo; |
| }, |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags; |
| VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, // VkShaderStageFlagBit stage; |
| *tessControlShaderModule, // VkShaderModule shader; |
| "main", // const char* pName; |
| DE_NULL // const VkSpecializationInfo* pSpecializationInfo; |
| }, |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags; |
| VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, // VkShaderStageFlagBit stage; |
| *tessEvalShaderModule, // VkShaderModule shader; |
| "main", // const char* pName; |
| DE_NULL // const VkSpecializationInfo* pSpecializationInfo; |
| }, |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags; |
| VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlagBit stage; |
| *fragmentShaderModule, // VkShaderModule shader; |
| "main", // const char* pName; |
| DE_NULL // const VkSpecializationInfo* pSpecializationInfo; |
| } |
| }; |
| |
| const VkPipelineVertexInputStateCreateInfo vertexInputStateParams = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineVertexInputStateCreateFlags)0, // VkPipelineVertexInputStateCreateFlags flags; |
| 0u, // deUint32 bindingCount; |
| DE_NULL, // const VkVertexInputBindingDescription* pVertexBindingDescriptions; |
| 0u, // deUint32 attributeCount; |
| DE_NULL, // const VkVertexInputAttributeDescription* pvertexAttributeDescriptions; |
| }; |
| |
| const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateParams = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags; |
| VK_PRIMITIVE_TOPOLOGY_PATCH_LIST, // VkPrimitiveTopology topology; |
| DE_FALSE // VkBool32 primitiveRestartEnable; |
| }; |
| |
| struct VkPipelineTessellationStateCreateInfo tessellationStateParams = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineTessellationStateCreateFlags)0, // VkPipelineTessellationStateCreateFlags flags; |
| patchControlPoints // uint32_t patchControlPoints; |
| }; |
| |
| const VkViewport viewport = |
| { |
| 0.0f, // float originX; |
| 0.0f, // float originY; |
| (float)renderSize.x(), // float width; |
| (float)renderSize.y(), // float height; |
| 0.0f, // float minDepth; |
| 1.0f // float maxDepth; |
| }; |
| |
| const VkRect2D scissor = |
| { |
| { |
| 0u, // deUint32 x; |
| 0u, // deUint32 y; |
| }, // VkOffset2D offset; |
| { |
| renderSize.x(), // deUint32 width; |
| renderSize.y(), // deUint32 height; |
| }, // VkExtent2D extent; |
| }; |
| |
| const VkPipelineViewportStateCreateInfo viewportStateParams = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineViewportStateCreateFlags)0, // VkPipelineViewPortStateCreateFlags flags; |
| 1u, // deUint32 viewportCount; |
| &viewport, // const VkViewport* pViewports; |
| 1u, // deUint32 scissorsCount; |
| &scissor // const VkRect2D* pScissors; |
| }; |
| |
| const VkPipelineRasterizationStateCreateInfo rasterStateParams = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineRasterizationStateCreateFlags)0, // VkPipelineRasterizationStageCreateFlags flags; |
| VK_FALSE, // VkBool32 depthClipEnable; |
| VK_FALSE, // VkBool32 rasterizerDiscardEnable; |
| VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode; |
| VK_CULL_MODE_NONE, // VkCullMode cullMode; |
| VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace; |
| VK_FALSE, // VkBool32 depthBiasEnable; |
| 0.0f, // float depthBias; |
| 0.0f, // float depthBiasClamp; |
| 0.0f, // float slopeScaledDepthBias; |
| 1.0f // float lineWidth; |
| }; |
| |
| 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; |
| VK_FALSE, // VkBool32 sampleShadingEnable; |
| 0.0f, // float minSampleShading; |
| DE_NULL, // const VkSampleMask* pSampleMask; |
| VK_FALSE, // VkBool32 alphaToCoverageEnable; |
| VK_FALSE // VkBool32 alphaToOneEnable; |
| }; |
| |
| const VkPipelineColorBlendAttachmentState colorBlendAttachmentState = |
| { |
| VK_FALSE, // VkBool32 blendEnable; |
| VK_BLEND_FACTOR_ONE, // VkBlendFactor srcBlendColor; |
| VK_BLEND_FACTOR_ZERO, // VkBlendFactor destBlendColor; |
| VK_BLEND_OP_ADD, // VkBlendOp blendOpColor; |
| VK_BLEND_FACTOR_ONE, // VkBlendFactor srcBlendAlpha; |
| VK_BLEND_FACTOR_ZERO, // VkBlendFactor destBlendAlpha; |
| VK_BLEND_OP_ADD, // VkBlendOp blendOpAlpha; |
| (VK_COLOR_COMPONENT_R_BIT | |
| VK_COLOR_COMPONENT_G_BIT | |
| VK_COLOR_COMPONENT_B_BIT | |
| VK_COLOR_COMPONENT_A_BIT) // VkColorComponentFlags colorWriteMask; |
| }; |
| |
| const VkPipelineColorBlendStateCreateInfo colorBlendStateParams = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| (VkPipelineColorBlendStateCreateFlags)0, // VkPipelineColorBlendStateCreateFlags flags |
| VK_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 blendConst[4]; |
| }; |
| |
| const VkGraphicsPipelineCreateInfo graphicsPipelineParams = |
| { |
| VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkPipelineCreateFlags flags; |
| 4u, // deUint32 stageCount; |
| shaderStageParams, // const VkPipelineShaderStageCreateInfo* pStages; |
| &vertexInputStateParams, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState; |
| &inputAssemblyStateParams, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState; |
| &tessellationStateParams, // const VkPipelineTessellationStateCreateInfo* pTessellationState; |
| &viewportStateParams, // const VkPipelineViewportStateCreateInfo* pViewportState; |
| &rasterStateParams, // const VkPipelineRasterStateCreateInfo* pRasterState; |
| &multisampleStateParams, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState; |
| DE_NULL, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState; |
| &colorBlendStateParams, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState; |
| (const VkPipelineDynamicStateCreateInfo*)DE_NULL, // const VkPipelineDynamicStateCreateInfo* pDynamicState; |
| *pipelineLayout, // VkPipelineLayout layout; |
| *renderPass, // VkRenderPass renderPass; |
| 0u, // deUint32 subpass; |
| 0u, // VkPipeline basePipelineHandle; |
| 0u // deInt32 basePipelineIndex; |
| }; |
| |
| graphicsPipeline = createGraphicsPipeline(vk, vkDevice, DE_NULL, &graphicsPipelineParams); |
| } |
| |
| // Create command pool |
| { |
| const VkCommandPoolCreateInfo cmdPoolParams = |
| { |
| VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, // VkCmdPoolCreateFlags flags; |
| queueFamilyIndex, // deUint32 queueFamilyIndex; |
| }; |
| |
| cmdPool = createCommandPool(vk, vkDevice, &cmdPoolParams); |
| } |
| |
| // Create command buffer |
| { |
| const VkCommandBufferAllocateInfo cmdBufferParams = |
| { |
| VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| *cmdPool, // VkCmdPool cmdPool; |
| VK_COMMAND_BUFFER_LEVEL_PRIMARY, // VkCmdBufferLevel level; |
| 1u // uint32_t bufferCount; |
| }; |
| |
| const VkCommandBufferBeginInfo cmdBufferBeginInfo = |
| { |
| VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkCmdBufferOptimizeFlags flags; |
| (const VkCommandBufferInheritanceInfo*)DE_NULL, |
| }; |
| |
| const VkClearValue clearValues[1] = |
| { |
| getDefaultClearColor() |
| }; |
| |
| const VkRenderPassBeginInfo renderPassBeginInfo = |
| { |
| VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| *renderPass, // VkRenderPass renderPass; |
| *framebuffer, // VkFramebuffer framebuffer; |
| { { 0, 0 }, { renderSize.x(), renderSize.y() } }, // VkRect2D renderArea; |
| 1, // deUint32 attachmentCount; |
| clearValues // const VkClearValue* pClearValues; |
| }; |
| |
| cmdBuffer = allocateCommandBuffer(vk, vkDevice, &cmdBufferParams); |
| |
| VK_CHECK(vk.beginCommandBuffer(*cmdBuffer, &cmdBufferBeginInfo)); |
| |
| vk.cmdBeginRenderPass(*cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); |
| |
| vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline); |
| |
| { |
| const VkDescriptorSet descriptorSets[] = { *descriptorSet, extraResources }; |
| vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, numDescriptorSets, descriptorSets, 0u, DE_NULL); |
| } |
| |
| vk.cmdDraw(*cmdBuffer, vertexCount, 1, 0, 0); |
| |
| vk.cmdEndRenderPass(*cmdBuffer); |
| VK_CHECK(vk.endCommandBuffer(*cmdBuffer)); |
| } |
| |
| // Create fence |
| { |
| const VkFenceCreateInfo fenceParams = |
| { |
| VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u // VkFenceCreateFlags flags; |
| }; |
| fence = createFence(vk, vkDevice, &fenceParams); |
| } |
| |
| // Execute Draw |
| { |
| VK_CHECK(vk.resetFences(vkDevice, 1, &fence.get())); |
| const VkSubmitInfo submitInfo = |
| { |
| VK_STRUCTURE_TYPE_SUBMIT_INFO, |
| DE_NULL, |
| 0u, |
| (const VkSemaphore*)0, |
| (const VkPipelineStageFlags*)DE_NULL, |
| 1u, |
| &cmdBuffer.get(), |
| 0u, |
| (const VkSemaphore*)0, |
| }; |
| VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, *fence)); |
| VK_CHECK(vk.waitForFences(vkDevice, 1, &fence.get(), true, ~(0ull) /* infinity*/)); |
| } |
| } |
| |
| // TessControlExecutor |
| |
| class TessControlExecutor : public TessellationExecutor |
| { |
| public: |
| TessControlExecutor (Context& context, const ShaderSpec& shaderSpec, VkDescriptorSetLayout extraResourcesLayout); |
| virtual ~TessControlExecutor (void); |
| |
| static void generateSources (const ShaderSpec& shaderSpec, SourceCollections& programCollection); |
| |
| virtual void execute (int numValues, const void* const* inputs, void* const* outputs, VkDescriptorSet extraResources); |
| |
| protected: |
| static std::string generateTessControlShader (const ShaderSpec& shaderSpec); |
| }; |
| |
| TessControlExecutor::TessControlExecutor (Context& context, const ShaderSpec& shaderSpec, VkDescriptorSetLayout extraResourcesLayout) |
| : TessellationExecutor(context, shaderSpec, extraResourcesLayout) |
|