/**
         * Create a buffer on the device
         *
         * @param usageFlags Usage flag bitmask for the buffer (i.e. index, vertex, uniform buffer)
         * @param memoryPropertyFlags Memory properties for this buffer (i.e. device local, host visible, coherent)
         * @param buffer Pointer to a vk::Vulkan buffer object
         * @param size Size of the buffer in byes
         * @param data Pointer to the data that should be copied to the buffer after creation (optional, if not set, no data is copied over)
         *
         * @return Success if buffer handle and memory have been created and (optionally passed) data has been copied
         */
        public VkResult createBuffer(VkBufferUsageFlagBits usageFlags, VkMemoryPropertyFlagBits memoryPropertyFlags, vksBuffer buffer, ulong size, void *data = null)
        {
            buffer.device = _logicalDevice;

            // Create the buffer handle
            VkBufferCreateInfo bufferCreateInfo = new VkBufferCreateInfo();

            bufferCreateInfo.sType = BufferCreateInfo;
            bufferCreateInfo.usage = usageFlags;
            bufferCreateInfo.size  = size;
            {
                VkBuffer vkBuffer;
                vkCreateBuffer(_logicalDevice, &bufferCreateInfo, null, &vkBuffer);
                buffer.buffer = vkBuffer;
            }

            // Create the memory backing up the buffer handle
            VkMemoryRequirements memReqs;
            VkMemoryAllocateInfo memAlloc = new VkMemoryAllocateInfo();

            memAlloc.sType = MemoryAllocateInfo;
            vkGetBufferMemoryRequirements(_logicalDevice, buffer.buffer, &memReqs);
            memAlloc.allocationSize = memReqs.size;
            // Find a memory type index that fits the properties of the buffer
            memAlloc.memoryTypeIndex = getMemoryType(memReqs.memoryTypeBits, memoryPropertyFlags);
            {
                VkDeviceMemory memory;
                vkAllocateMemory(_logicalDevice, &memAlloc, null, &memory);
                buffer.memory = memory;
            }

            buffer.alignment           = memReqs.alignment;
            buffer.size                = memAlloc.allocationSize;
            buffer.usageFlags          = usageFlags;
            buffer.memoryPropertyFlags = memoryPropertyFlags;

            // If a pointer to the buffer data has been passed, map the buffer and copy over the data
            if (data != null)
            {
                buffer.map();
                Unsafe.CopyBlock(buffer.mapped, data, (uint)size);
                buffer.unmap();
            }

            // Initialize a default descriptor that covers the whole buffer size
            buffer.setupDescriptor();

            // Attach the memory to the buffer object
            return(buffer.bind());
        }
 public VkResult createBuffer(VkBufferUsageFlagBits usageFlags, VkMemoryPropertyFlagBits memoryPropertyFlags, vksBuffer buffer, ulong size, IntPtr data)
 => createBuffer(usageFlags, memoryPropertyFlags, buffer, size, data.ToPointer());
Exemple #3
0
        /**
         * Loads a 3D model from a file into Vulkan buffers
         *
         * @param device Pointer to the Vulkan device used to generated the vertex and index buffers on
         * @param filename File to load (must be a model format supported by ASSIMP)
         * @param layout Vertex layout components (position, normals, tangents, etc.)
         * @param createInfo MeshCreateInfo structure for load time settings like scale, center, etc.
         * @param copyQueue Queue used for the memory staging copy commands (must support transfer)
         * @param (Optional) flags ASSIMP model loading flags
         */
        //public bool loadFromFile(string filename, vksVertexLayout layout, vksModelCreateInfo* createInfo, vksVulkanDevice device, VkQueue copyQueue, int flags)
        //{
        //    this.device = device.LogicalDevice;

        //    ObjFile objFile;
        //    using (var fs = File.OpenRead(filename))
        //    {
        //        objFile = new ObjParser().Parse(fs);
        //    }
        //    string mtlFilename = Path.ChangeExtension(filename, "mtl");
        //    MtlFile mtlFile;
        //    using (var fs = File.OpenRead(mtlFilename))
        //    {
        //        mtlFile = new MtlParser().Parse(fs);
        //    }

        //    if (objFile != null)
        //    {
        //        parts.Clear();
        //        parts.Resize((uint)objFile.MeshGroups.Length);

        //        Vector3 scale = new Vector3(1.0f);
        //        Vector2 uvscale = new Vector2(1.0f);
        //        Vector3 center = new Vector3(0.0f);
        //        if (createInfo != null)
        //        {
        //            scale = createInfo->Scale;
        //            uvscale = createInfo->UVScale;
        //            center = createInfo->Center;
        //        }

        //        NativeList<float> vertexBuffer = new NativeList<float>();
        //        NativeList<uint> indexBuffer = new NativeList<uint>();

        //        vertexCount = 0;
        //        indexCount = 0;

        //        // Load meshes
        //        parts.Count = (uint)objFile.MeshGroups.Length;
        //        for (uint i = 0; i < objFile.MeshGroups.Length; i++)
        //        {
        //            ConstructedMeshInfo mesh = objFile.GetMesh(objFile.MeshGroups[i]);

        //            parts[i] = new ModelPart();
        //            parts[i].vertexBase = vertexCount;
        //            parts[i].indexBase = indexCount;

        //            vertexCount += (uint)mesh.Vertices.Length;

        //            var material = mtlFile.Definitions[objFile.MeshGroups[i].Material];
        //            Vector3 pColor = material.DiffuseReflectivity;

        //            Vector3 Zero3D = Vector3.Zero;

        //            for (uint j = 0; j < mesh.Vertices.Length; j++)
        //            {
        //                VertexPositionNormalTexture vertex = mesh.Vertices[j];
        //                Vector3* pPos = &vertex.Position;
        //                Vector3* pNormal = &vertex.Normal;
        //                Vector2* pTexCoord = &vertex.TextureCoordinates;
        //                Vector3* pTangent = &Zero3D;
        //                Vector3* pBiTangent = &Zero3D;

        //                /*
        //                const aiVector3D* pPos = &(paiMesh->mVertices[j]);
        //                const aiVector3D* pNormal = &(paiMesh->mNormals[j]);
        //                const aiVector3D* pTexCoord = (paiMesh->HasTextureCoords(0)) ? &(paiMesh->mTextureCoords[0][j]) : &Zero3D;
        //                const aiVector3D* pTangent = (paiMesh->HasTangentsAndBitangents()) ? &(paiMesh->mTangents[j]) : &Zero3D;
        //                const aiVector3D* pBiTangent = (paiMesh->HasTangentsAndBitangents()) ? &(paiMesh->mBitangents[j]) : &Zero3D;
        //                */

        //                foreach (var component in layout.Components)
        //                {
        //                    switch (component)
        //                    {
        //                        case VertexComponent.VERTEX_COMPONENT_POSITION:
        //                            vertexBuffer.Add(pPos.X * scale.X + center.X);
        //                            vertexBuffer.Add(-pPos.Y * scale.Y + center.Y);
        //                            vertexBuffer.Add(pPos.Z * scale.Z + center.Z);
        //                            break;
        //                        case VertexComponent.VERTEX_COMPONENT_NORMAL:
        //                            vertexBuffer.Add(pNormal.X);
        //                            vertexBuffer.Add(-pNormal.Y);
        //                            vertexBuffer.Add(pNormal.Z);
        //                            break;
        //                        case VertexComponent.VERTEX_COMPONENT_UV:
        //                            vertexBuffer.Add(pTexCoord.X * uvscale.X);
        //                            vertexBuffer.Add(pTexCoord.Y * uvscale.Y);
        //                            break;
        //                        case VertexComponent.VERTEX_COMPONENT_COLOR:
        //                            vertexBuffer.Add(pColor.X);
        //                            vertexBuffer.Add(pColor.Y);
        //                            vertexBuffer.Add(pColor.Z);
        //                            break;
        //                        case VertexComponent.VERTEX_COMPONENT_TANGENT:
        //                            vertexBuffer.Add(pTangent.X);
        //                            vertexBuffer.Add(pTangent.Y);
        //                            vertexBuffer.Add(pTangent.Z);
        //                            break;
        //                        case VertexComponent.VERTEX_COMPONENT_BITANGENT:
        //                            vertexBuffer.Add(pBiTangent.X);
        //                            vertexBuffer.Add(pBiTangent.Y);
        //                            vertexBuffer.Add(pBiTangent.Z);
        //                            break;
        //                        // Dummy components for padding
        //                        case VertexComponent.VERTEX_COMPONENT_DUMMY_FLOAT:
        //                            vertexBuffer.Add(0.0f);
        //                            break;
        //                        case VertexComponent.VERTEX_COMPONENT_DUMMY_VEC4:
        //                            vertexBuffer.Add(0.0f);
        //                            vertexBuffer.Add(0.0f);
        //                            vertexBuffer.Add(0.0f);
        //                            vertexBuffer.Add(0.0f);
        //                            break;
        //                    };
        //                }

        //                dim.Max.X = Math.Max(pPos.X, dim.Max.X);
        //                dim.Max.Y = Math.Max(pPos.Y, dim.Max.Y);
        //                dim.Max.Z = Math.Max(pPos.Z, dim.Max.Z);

        //                dim.Min.X = Math.Min(pPos.X, dim.Min.X);
        //                dim.Min.Y = Math.Min(pPos.Y, dim.Min.Y);
        //                dim.Min.Z = Math.Min(pPos.Z, dim.Min.Z);
        //            }

        //            dim.Size = dim.Max - dim.Min;

        //            parts[i].vertexCount = (uint)mesh.Vertices.Length;

        //            uint indexBase = indexBuffer.Count;

        //            foreach (var index in mesh.Indices)
        //            {
        //                indexBuffer.Add(index);
        //            }
        //            indexCount += (uint)mesh.Indices.Length;
        //            parts[i].indexCount += (uint)mesh.Indices.Length;

        //            /*
        //            for (uint j = 0; j < paiMesh->mNumFaces; j++)
        //            {
        //                const aiFace&Face = paiMesh->mFaces[j];
        //                if (Face.mNumIndices != 3)
        //                    continue;
        //                indexBuffer.Add(indexBase + Face.mIndices[0]);
        //                indexBuffer.Add(indexBase + Face.mIndices[1]);
        //                indexBuffer.Add(indexBase + Face.mIndices[2]);
        //                parts[i].indexCount += 3;
        //                indexCount += 3;
        //            }
        //            */
        //        }


        //        uint vBufferSize = vertexBuffer.Count * sizeof(float);
        //        uint iBufferSize = indexBuffer.Count * sizeof(uint);

        //        // Use staging buffer to move vertex and index buffer to device local memory
        //        // Create staging buffers
        //        vksBuffer vertexStaging = new vksBuffer();
        //        vksBuffer indexStaging = new vksBuffer();

        //        // Vertex buffer
        //        Util.CheckResult(device.createBuffer(
        //            VkBufferUsageFlags.TransferSrc,
        //            VkMemoryPropertyFlags.HostVisible,
        //            vertexStaging,
        //            vBufferSize,
        //            vertexBuffer.Data.ToPointer()));

        //        // Index buffer
        //        Util.CheckResult(device.createBuffer(
        //            VkBufferUsageFlags.TransferSrc,
        //            VkMemoryPropertyFlags.HostVisible,
        //            indexStaging,
        //            iBufferSize,
        //            indexBuffer.Data.ToPointer()));

        //        // Create device local target buffers
        //        // Vertex buffer
        //        Util.CheckResult(device.createBuffer(
        //            VkBufferUsageFlags.VertexBuffer | VkBufferUsageFlags.TransferDst,
        //            VkMemoryPropertyFlags.DeviceLocal,
        //            vertices,
        //            vBufferSize));

        //        // Index buffer
        //        Util.CheckResult(device.createBuffer(
        //            VkBufferUsageFlags.IndexBuffer | VkBufferUsageFlags.TransferDst,
        //            VkMemoryPropertyFlags.DeviceLocal,
        //            indices,
        //            iBufferSize));

        //        // Copy from staging buffers
        //        VkCommandBuffer copyCmd = device.createCommandBuffer(VkCommandBufferLevel.Primary, true);

        //        VkBufferCopy copyRegion = new VkBufferCopy();

        //        copyRegion.size = vertices.size;

        //        vkCmdCopyBuffer(copyCmd, vertexStaging.buffer, vertices.buffer, 1, &copyRegion);

        //        copyRegion.size = indices.size;

        //        vkCmdCopyBuffer(copyCmd, indexStaging.buffer, indices.buffer, 1, &copyRegion);

        //        device.flushCommandBuffer(copyCmd, copyQueue);

        //        // Destroy staging resources
        //        vkDestroyBuffer(device.LogicalDevice, vertexStaging.buffer, null);

        //        vkFreeMemory(device.LogicalDevice, vertexStaging.memory, null);

        //        vkDestroyBuffer(device.LogicalDevice, indexStaging.buffer, null);

        //        vkFreeMemory(device.LogicalDevice, indexStaging.memory, null);

        //        return true;
        //    }
        //    else
        //    {
        //        Console.WriteLine("Error loading file.");
        //        return false;
        //    }
        //}


        /**
         * Loads a 3D model from a file into Vulkan buffers
         *
         * @param device Pointer to the Vulkan device used to generated the vertex and index buffers on
         * @param filename File to load (must be a model format supported by ASSIMP)
         * @param layout Vertex layout components (position, normals, tangents, etc.)
         * @param createInfo MeshCreateInfo structure for load time settings like scale, center, etc.
         * @param copyQueue Queue used for the memory staging copy commands (must support transfer)
         * @param (Optional) flags ASSIMP model loading flags
         */
        bool loadFromFile(string filename, vksVertexLayout layout, vksModelCreateInfo *createInfo, vksVulkanDevice device, VkQueue copyQueue, PostProcessSteps flags = DefaultPostProcessSteps)
        {
            this.device = device.LogicalDevice;

            // Load file
            var assimpContext = new AssimpContext();
            var pScene        = assimpContext.ImportFile(filename, flags);

            parts = new ModelPart[pScene.Meshes.Count];

            Vector3 scale   = new Vector3(1.0f);
            Vector2 uvscale = new Vector2(1.0f);
            Vector3 center  = new Vector3(0.0f);

            if (createInfo != null)
            {
                scale   = createInfo->Scale;
                uvscale = createInfo->UVScale;
                center  = createInfo->Center;
            }

            var vertexBuffer = new List <float>();
            var indexBuffer  = new List <uint>();

            vertexCount = 0;
            indexCount  = 0;

            // Load meshes
            for (int i = 0; i < pScene.Meshes.Count; i++)
            {
                var paiMesh = pScene.Meshes[i];

                parts[i]            = new ModelPart();
                parts[i].vertexBase = vertexCount;
                parts[i].indexBase  = indexCount;

                vertexCount += (uint)paiMesh.VertexCount;

                var pColor = pScene.Materials[paiMesh.MaterialIndex].ColorDiffuse;

                Vector3D Zero3D = new Vector3D(0.0f, 0.0f, 0.0f);

                for (int j = 0; j < paiMesh.VertexCount; j++)
                {
                    Vector3D pPos       = paiMesh.Vertices[j];
                    Vector3D pNormal    = paiMesh.Normals[j];
                    Vector3D pTexCoord  = paiMesh.HasTextureCoords(0) ? paiMesh.TextureCoordinateChannels[0][j] : Zero3D;
                    Vector3D pTangent   = paiMesh.HasTangentBasis ? paiMesh.Tangents[j] : Zero3D;
                    Vector3D pBiTangent = paiMesh.HasTangentBasis ? paiMesh.BiTangents[j] : Zero3D;

                    foreach (var component in layout.Components)
                    {
                        switch (component)
                        {
                        case VertexComponent.VERTEX_COMPONENT_POSITION:
                            vertexBuffer.Add(pPos.X * scale.X + center.X);
                            vertexBuffer.Add(-pPos.Y * scale.Y + center.Y);
                            vertexBuffer.Add(pPos.Z * scale.Z + center.Z);
                            break;

                        case VertexComponent.VERTEX_COMPONENT_NORMAL:
                            vertexBuffer.Add(pNormal.X);
                            vertexBuffer.Add(-pNormal.Y);
                            vertexBuffer.Add(pNormal.Z);
                            break;

                        case VertexComponent.VERTEX_COMPONENT_UV:
                            vertexBuffer.Add(pTexCoord.X * uvscale.X);
                            vertexBuffer.Add(pTexCoord.Y * uvscale.Y);
                            break;

                        case VertexComponent.VERTEX_COMPONENT_COLOR:
                            vertexBuffer.Add(pColor.R);
                            vertexBuffer.Add(pColor.G);
                            vertexBuffer.Add(pColor.B);
                            break;

                        case VertexComponent.VERTEX_COMPONENT_TANGENT:
                            vertexBuffer.Add(pTangent.X);
                            vertexBuffer.Add(pTangent.Y);
                            vertexBuffer.Add(pTangent.Z);
                            break;

                        case VertexComponent.VERTEX_COMPONENT_BITANGENT:
                            vertexBuffer.Add(pBiTangent.X);
                            vertexBuffer.Add(pBiTangent.Y);
                            vertexBuffer.Add(pBiTangent.Z);
                            break;

                        // Dummy components for padding
                        case VertexComponent.VERTEX_COMPONENT_DUMMY_FLOAT:
                            vertexBuffer.Add(0.0f);
                            break;

                        case VertexComponent.VERTEX_COMPONENT_DUMMY_VEC4:
                            vertexBuffer.Add(0.0f);
                            vertexBuffer.Add(0.0f);
                            vertexBuffer.Add(0.0f);
                            vertexBuffer.Add(0.0f);
                            break;
                        }
                        ;
                    }

                    dim.Max.X = (float)Math.Max(pPos.X, dim.Max.X);
                    dim.Max.Y = (float)Math.Max(pPos.Y, dim.Max.Y);
                    dim.Max.Z = (float)Math.Max(pPos.Z, dim.Max.Z);

                    dim.Min.X = (float)Math.Min(pPos.X, dim.Min.X);
                    dim.Min.Y = (float)Math.Min(pPos.Y, dim.Min.Y);
                    dim.Min.Z = (float)Math.Min(pPos.Z, dim.Min.Z);
                }

                dim.Size = dim.Max - dim.Min;

                parts[i].vertexCount = (uint)paiMesh.VertexCount;

                uint indexBase = (uint)indexBuffer.Count;
                for (uint j = 0; j < paiMesh.FaceCount; j++)
                {
                    var Face = paiMesh.Faces[(int)j];
                    if (Face.IndexCount != 3)
                    {
                        continue;
                    }
                    indexBuffer.Add(indexBase + (uint)Face.Indices[0]);
                    indexBuffer.Add(indexBase + (uint)Face.Indices[1]);
                    indexBuffer.Add(indexBase + (uint)Face.Indices[2]);
                    parts[i].indexCount += 3;
                    indexCount          += 3;
                }
            }


            uint vBufferSize = (uint)(vertexBuffer.Count * sizeof(float));
            uint iBufferSize = (uint)(indexBuffer.Count * sizeof(uint));

            // Use staging buffer to move vertex and index buffer to device local memory
            // Create staging buffers
            vksBuffer vertexStaging = new vksBuffer();
            vksBuffer indexStaging  = new vksBuffer();

            // Vertex buffer
            fixed(float *data = vertexBuffer.ToArray())
            {
                device.createBuffer(
                    VkBufferUsageFlagBits.TransferSrc,
                    VkMemoryPropertyFlagBits.HostVisible,
                    vertexStaging,
                    vBufferSize,
                    data);
            }

            // Index buffer
            fixed(uint *data = indexBuffer.ToArray())
            {
                device.createBuffer(
                    VkBufferUsageFlagBits.TransferSrc,
                    VkMemoryPropertyFlagBits.HostVisible,
                    indexStaging,
                    iBufferSize,
                    data);
            }

            // Create device local target buffers
            // Vertex buffer
            device.createBuffer(
                VkBufferUsageFlagBits.VertexBuffer | VkBufferUsageFlagBits.TransferDst,
                VkMemoryPropertyFlagBits.DeviceLocal,
                vertices,
                vBufferSize);

            // Index buffer
            device.createBuffer(
                VkBufferUsageFlagBits.IndexBuffer | VkBufferUsageFlagBits.TransferDst,
                VkMemoryPropertyFlagBits.DeviceLocal,
                indices,
                iBufferSize);

            // Copy from staging buffers
            VkCommandBuffer copyCmd = device.createCommandBuffer(VkCommandBufferLevel.Primary, true);

            VkBufferCopy copyRegion = new VkBufferCopy();

            copyRegion.size = vertices.size;
            vkCmdCopyBuffer(copyCmd, vertexStaging.buffer, vertices.buffer, 1, &copyRegion);

            copyRegion.size = indices.size;
            vkCmdCopyBuffer(copyCmd, indexStaging.buffer, indices.buffer, 1, &copyRegion);

            device.flushCommandBuffer(copyCmd, copyQueue);

            // Destroy staging resources
            vkDestroyBuffer(device.LogicalDevice, vertexStaging.buffer, null);
            vkFreeMemory(device.LogicalDevice, vertexStaging.memory, null);
            vkDestroyBuffer(device.LogicalDevice, indexStaging.buffer, null);
            vkFreeMemory(device.LogicalDevice, indexStaging.memory, null);

            return(true);
        }