Ejemplo n.º 1
0
        void loadCubemap(string filename, VkFormat format, bool forceLinearTiling)
        {
            KtxFile texCube;

            using (var fs = File.OpenRead(filename))
            {
                texCube = KtxFile.Load(fs, readKeyValuePairs: false);
            }

            cubeMap.width     = texCube.Header.PixelWidth;
            cubeMap.height    = texCube.Header.PixelHeight;
            cubeMap.mipLevels = texCube.Header.NumberOfMipmapLevels;

            VkMemoryAllocateInfo memAllocInfo = Initializers.memoryAllocateInfo();
            VkMemoryRequirements memReqs;

            // Create a host-visible staging buffer that contains the raw image data
            VkBuffer       stagingBuffer;
            VkDeviceMemory stagingMemory;

            VkBufferCreateInfo bufferCreateInfo = Initializers.bufferCreateInfo();

            bufferCreateInfo.size = texCube.GetTotalSize();
            // This buffer is used as a transfer source for the buffer copy
            bufferCreateInfo.usage       = VkBufferUsageFlags.TransferSrc;
            bufferCreateInfo.sharingMode = VkSharingMode.Exclusive;

            Util.CheckResult(vkCreateBuffer(device, &bufferCreateInfo, null, &stagingBuffer));

            // Get memory requirements for the staging buffer (alignment, memory type bits)
            vkGetBufferMemoryRequirements(device, stagingBuffer, &memReqs);
            memAllocInfo.allocationSize = memReqs.size;
            // Get memory type index for a host visible buffer
            memAllocInfo.memoryTypeIndex = vulkanDevice.getMemoryType(memReqs.memoryTypeBits, VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent);
            Util.CheckResult(vkAllocateMemory(device, &memAllocInfo, null, &stagingMemory));
            Util.CheckResult(vkBindBufferMemory(device, stagingBuffer, stagingMemory, 0));

            // Copy texture data into staging buffer
            byte *data;

            Util.CheckResult(vkMapMemory(device, stagingMemory, 0, memReqs.size, 0, (void **)&data));
            byte[] allTextureData = texCube.GetAllTextureData();
            fixed(byte *texCubeDataPtr = &allTextureData[0])
            {
                Unsafe.CopyBlock(data, texCubeDataPtr, (uint)allTextureData.Length);
            }

            vkUnmapMemory(device, stagingMemory);

            // Create optimal tiled target image
            VkImageCreateInfo imageCreateInfo = Initializers.imageCreateInfo();

            imageCreateInfo.imageType     = VkImageType.Image2D;
            imageCreateInfo.format        = format;
            imageCreateInfo.mipLevels     = cubeMap.mipLevels;
            imageCreateInfo.samples       = VkSampleCountFlags.Count1;
            imageCreateInfo.tiling        = VkImageTiling.Optimal;
            imageCreateInfo.usage         = VkImageUsageFlags.Sampled;
            imageCreateInfo.sharingMode   = VkSharingMode.Exclusive;
            imageCreateInfo.initialLayout = VkImageLayout.Undefined;
            imageCreateInfo.extent        = new VkExtent3D {
                width = cubeMap.width, height = cubeMap.height, depth = 1
            };
            imageCreateInfo.usage = VkImageUsageFlags.TransferDst | VkImageUsageFlags.Sampled;
            // Cube faces count as array layers in Vulkan
            imageCreateInfo.arrayLayers = 6;
            // This flag is required for cube map images
            imageCreateInfo.flags = VkImageCreateFlags.CubeCompatible;

            Util.CheckResult(vkCreateImage(device, &imageCreateInfo, null, out cubeMap.image));

            vkGetImageMemoryRequirements(device, cubeMap.image, &memReqs);

            memAllocInfo.allocationSize  = memReqs.size;
            memAllocInfo.memoryTypeIndex = vulkanDevice.getMemoryType(memReqs.memoryTypeBits, VkMemoryPropertyFlags.DeviceLocal);

            Util.CheckResult(vkAllocateMemory(device, &memAllocInfo, null, out cubeMap.deviceMemory));
            Util.CheckResult(vkBindImageMemory(device, cubeMap.image, cubeMap.deviceMemory, 0));

            VkCommandBuffer copyCmd = createCommandBuffer(VkCommandBufferLevel.Primary, true);

            // Setup buffer copy regions for each face including all of it's miplevels
            NativeList <VkBufferImageCopy> bufferCopyRegions = new NativeList <VkBufferImageCopy>();
            uint offset = 0;

            for (uint face = 0; face < 6; face++)
            {
                for (uint level = 0; level < cubeMap.mipLevels; level++)
                {
                    VkBufferImageCopy bufferCopyRegion = new VkBufferImageCopy();
                    bufferCopyRegion.imageSubresource.aspectMask     = VkImageAspectFlags.Color;
                    bufferCopyRegion.imageSubresource.mipLevel       = level;
                    bufferCopyRegion.imageSubresource.baseArrayLayer = face;
                    bufferCopyRegion.imageSubresource.layerCount     = 1;
                    bufferCopyRegion.imageExtent.width  = texCube.Faces[face].Mipmaps[level].Width;
                    bufferCopyRegion.imageExtent.height = texCube.Faces[face].Mipmaps[level].Height;
                    bufferCopyRegion.imageExtent.depth  = 1;
                    bufferCopyRegion.bufferOffset       = offset;

                    bufferCopyRegions.Add(bufferCopyRegion);

                    // Increase offset into staging buffer for next level / face
                    offset += texCube.Faces[face].Mipmaps[level].SizeInBytes;
                }
            }

            // Image barrier for optimal image (target)
            // Set initial layout for all array layers (faces) of the optimal (target) tiled texture
            VkImageSubresourceRange subresourceRange = new VkImageSubresourceRange();

            subresourceRange.aspectMask   = VkImageAspectFlags.Color;
            subresourceRange.baseMipLevel = 0;
            subresourceRange.levelCount   = cubeMap.mipLevels;
            subresourceRange.layerCount   = 6;

            Tools.setImageLayout(
                copyCmd,
                cubeMap.image,
                VkImageAspectFlags.Color,
                VkImageLayout.Undefined,
                VkImageLayout.TransferDstOptimal,
                subresourceRange);

            // Copy the cube map faces from the staging buffer to the optimal tiled image
            vkCmdCopyBufferToImage(
                copyCmd,
                stagingBuffer,
                cubeMap.image,
                VkImageLayout.TransferDstOptimal,
                bufferCopyRegions.Count,
                bufferCopyRegions.Data);

            // Change texture image layout to shader read after all faces have been copied
            cubeMap.imageLayout = VkImageLayout.ShaderReadOnlyOptimal;
            Tools.setImageLayout(
                copyCmd,
                cubeMap.image,
                VkImageAspectFlags.Color,
                VkImageLayout.TransferDstOptimal,
                cubeMap.imageLayout,
                subresourceRange);

            flushCommandBuffer(copyCmd, queue, true);

            // Create sampler
            VkSamplerCreateInfo sampler = Initializers.samplerCreateInfo();

            sampler.magFilter     = VkFilter.Linear;
            sampler.minFilter     = VkFilter.Linear;
            sampler.mipmapMode    = VkSamplerMipmapMode.Linear;
            sampler.addressModeU  = VkSamplerAddressMode.ClampToEdge;
            sampler.addressModeV  = sampler.addressModeU;
            sampler.addressModeW  = sampler.addressModeU;
            sampler.mipLodBias    = 0.0f;
            sampler.compareOp     = VkCompareOp.Never;
            sampler.minLod        = 0.0f;
            sampler.maxLod        = cubeMap.mipLevels;
            sampler.borderColor   = VkBorderColor.FloatOpaqueWhite;
            sampler.maxAnisotropy = 1.0f;
            if (vulkanDevice.features.samplerAnisotropy == 1)
            {
                sampler.maxAnisotropy    = vulkanDevice.properties.limits.maxSamplerAnisotropy;
                sampler.anisotropyEnable = True;
            }
            Util.CheckResult(vkCreateSampler(device, &sampler, null, out cubeMap.sampler));

            // Create image view
            VkImageViewCreateInfo view = Initializers.imageViewCreateInfo();

            // Cube map view type
            view.viewType   = VkImageViewType.ImageCube;
            view.format     = format;
            view.components = new VkComponentMapping {
                r = VkComponentSwizzle.R, g = VkComponentSwizzle.G, b = VkComponentSwizzle.B, a = VkComponentSwizzle.A
            };
            view.subresourceRange = new VkImageSubresourceRange {
                aspectMask = VkImageAspectFlags.Color, baseMipLevel = 0, layerCount = 1, baseArrayLayer = 0, levelCount = 1
            };
            // 6 array layers (faces)
            view.subresourceRange.layerCount = 6;
            // Set number of mip levels
            view.subresourceRange.levelCount = cubeMap.mipLevels;
            view.image = cubeMap.image;
            Util.CheckResult(vkCreateImageView(device, &view, null, out cubeMap.view));

            // Clean up staging resources
            vkFreeMemory(device, stagingMemory, null);
            vkDestroyBuffer(device, stagingBuffer, null);
        }
Ejemplo n.º 2
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.Clear();
            parts.Count = (uint)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;
            }

            NativeList <float> vertexBuffer = new NativeList <float>();
            NativeList <uint>  indexBuffer  = new NativeList <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 = 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 = (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);
        }
Ejemplo n.º 3
0
        void loadTexture(string fileName, VkFormat format, bool forceLinearTiling)
        {
            KtxFile tex2D;

            using (var fs = File.OpenRead(fileName))
            {
                tex2D = KtxFile.Load(fs, false);
            }

            VkFormatProperties formatProperties;

            texture.width     = tex2D.Header.PixelWidth;
            texture.height    = tex2D.Header.PixelHeight;
            texture.mipLevels = tex2D.Header.NumberOfMipmapLevels;

            // Get Device properites for the requested texture format
            vkGetPhysicalDeviceFormatProperties(PhysicalDevice, format, &formatProperties);

            // Only use linear tiling if requested (and supported by the Device)
            // Support for linear tiling is mostly limited, so prefer to use
            // optimal tiling instead
            // On most implementations linear tiling will only support a very
            // limited amount of formats and features (mip maps, cubemaps, arrays, etc.)
            uint useStaging = 1;

            // Only use linear tiling if forced
            if (forceLinearTiling)
            {
                // Don't use linear if format is not supported for (linear) shader sampling
                useStaging = ((formatProperties.linearTilingFeatures & VkFormatFeatureFlags.SampledImage) != VkFormatFeatureFlags.SampledImage) ? 1u : 0u;
            }

            VkMemoryAllocateInfo memAllocInfo = Initializers.memoryAllocateInfo();
            VkMemoryRequirements memReqs      = new VkMemoryRequirements();

            if (useStaging == 1)
            {
                // Create a host-visible staging buffer that contains the raw image data
                VkBuffer       stagingBuffer;
                VkDeviceMemory stagingMemory;

                VkBufferCreateInfo bufferCreateInfo = Initializers.bufferCreateInfo();
                bufferCreateInfo.size = tex2D.GetTotalSize();
                // This buffer is used as a transfer source for the buffer copy
                bufferCreateInfo.usage       = VkBufferUsageFlags.TransferSrc;
                bufferCreateInfo.sharingMode = VkSharingMode.Exclusive;

                Util.CheckResult(vkCreateBuffer(Device, &bufferCreateInfo, null, &stagingBuffer));

                // Get memory requirements for the staging buffer (alignment, memory type bits)
                vkGetBufferMemoryRequirements(Device, stagingBuffer, &memReqs);

                memAllocInfo.allocationSize = memReqs.size;
                // Get memory type index for a host visible buffer
                memAllocInfo.memoryTypeIndex = VulkanDevice.GetMemoryType(memReqs.memoryTypeBits, VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent);

                Util.CheckResult(vkAllocateMemory(Device, &memAllocInfo, null, &stagingMemory));
                Util.CheckResult(vkBindBufferMemory(Device, stagingBuffer, stagingMemory, 0));

                // Copy texture data into staging buffer
                byte *data;
                Util.CheckResult(vkMapMemory(Device, stagingMemory, 0, memReqs.size, 0, (void **)&data));
                byte[] allData = tex2D.GetAllTextureData();
                fixed(byte *tex2DDataPtr = &allData[0])
                {
                    Unsafe.CopyBlock(data, tex2DDataPtr, (uint)allData.Length);
                }

                vkUnmapMemory(Device, stagingMemory);

                // Setup buffer copy regions for each mip level
                NativeList <VkBufferImageCopy> bufferCopyRegions = new NativeList <VkBufferImageCopy>();
                uint offset = 0;

                for (uint i = 0; i < texture.mipLevels; i++)
                {
                    VkBufferImageCopy bufferCopyRegion = new VkBufferImageCopy();
                    bufferCopyRegion.imageSubresource.aspectMask     = VkImageAspectFlags.Color;
                    bufferCopyRegion.imageSubresource.mipLevel       = i;
                    bufferCopyRegion.imageSubresource.baseArrayLayer = 0;
                    bufferCopyRegion.imageSubresource.layerCount     = 1;
                    bufferCopyRegion.imageExtent.width  = tex2D.Faces[0].Mipmaps[i].Width;
                    bufferCopyRegion.imageExtent.height = tex2D.Faces[0].Mipmaps[i].Height;
                    bufferCopyRegion.imageExtent.depth  = 1;
                    bufferCopyRegion.bufferOffset       = offset;

                    bufferCopyRegions.Add(bufferCopyRegion);

                    offset += tex2D.Faces[0].Mipmaps[i].SizeInBytes;
                }

                // Create optimal tiled target image
                VkImageCreateInfo imageCreateInfo = Initializers.imageCreateInfo();
                imageCreateInfo.imageType   = VkImageType._2d;
                imageCreateInfo.format      = format;
                imageCreateInfo.mipLevels   = texture.mipLevels;
                imageCreateInfo.arrayLayers = 1;
                imageCreateInfo.samples     = VkSampleCountFlags._1;
                imageCreateInfo.tiling      = VkImageTiling.Optimal;
                imageCreateInfo.sharingMode = VkSharingMode.Exclusive;
                // Set initial layout of the image to undefined
                imageCreateInfo.initialLayout = VkImageLayout.Undefined;
                imageCreateInfo.extent        = new VkExtent3D {
                    width = texture.width, height = texture.height, depth = 1
                };
                imageCreateInfo.usage = VkImageUsageFlags.TransferDst | VkImageUsageFlags.Sampled;

                Util.CheckResult(vkCreateImage(Device, &imageCreateInfo, null, out texture.image));

                vkGetImageMemoryRequirements(Device, texture.image, &memReqs);

                memAllocInfo.allocationSize  = memReqs.size;
                memAllocInfo.memoryTypeIndex = VulkanDevice.GetMemoryType(memReqs.memoryTypeBits, VkMemoryPropertyFlags.DeviceLocal);

                Util.CheckResult(vkAllocateMemory(Device, &memAllocInfo, null, out texture.DeviceMemory));
                Util.CheckResult(vkBindImageMemory(Device, texture.image, texture.DeviceMemory, 0));

                VkCommandBuffer copyCmd = base.createCommandBuffer(VkCommandBufferLevel.Primary, true);

                // Image barrier for optimal image

                // The sub resource range describes the regions of the image we will be transition
                VkImageSubresourceRange subresourceRange = new VkImageSubresourceRange();
                // Image only contains color data
                subresourceRange.aspectMask = VkImageAspectFlags.Color;
                // Start at first mip level
                subresourceRange.baseMipLevel = 0;
                // We will transition on all mip levels
                subresourceRange.levelCount = texture.mipLevels;
                // The 2D texture only has one layer
                subresourceRange.layerCount = 1;

                // Optimal image will be used as destination for the copy, so we must transfer from our
                // initial undefined image layout to the transfer destination layout
                setImageLayout(
                    copyCmd,
                    texture.image,
                    VkImageAspectFlags.Color,
                    VkImageLayout.Undefined,
                    VkImageLayout.TransferDstOptimal,
                    subresourceRange);

                // Copy mip levels from staging buffer
                vkCmdCopyBufferToImage(
                    copyCmd,
                    stagingBuffer,
                    texture.image,
                    VkImageLayout.TransferDstOptimal,
                    bufferCopyRegions.Count,
                    bufferCopyRegions.Data);

                // Change texture image layout to shader read after all mip levels have been copied
                texture.imageLayout = VkImageLayout.ShaderReadOnlyOptimal;
                setImageLayout(
                    copyCmd,
                    texture.image,
                    VkImageAspectFlags.Color,
                    VkImageLayout.TransferDstOptimal,
                    texture.imageLayout,
                    subresourceRange);

                flushCommandBuffer(copyCmd, Queue, true);

                // Clean up staging resources
                vkFreeMemory(Device, stagingMemory, null);
                vkDestroyBuffer(Device, stagingBuffer, null);
            }
            else
            {
                throw new NotImplementedException();

                /*
                 * // Prefer using optimal tiling, as linear tiling
                 * // may support only a small set of features
                 * // depending on implementation (e.g. no mip maps, only one layer, etc.)
                 *
                 * VkImage mappableImage;
                 * VkDeviceMemory mappableMemory;
                 *
                 * // Load mip map level 0 to linear tiling image
                 * VkImageCreateInfo imageCreateInfo = Initializers.imageCreateInfo();
                 * imageCreateInfo.imageType = VkImageType._2d;
                 * imageCreateInfo.format = format;
                 * imageCreateInfo.mipLevels = 1;
                 * imageCreateInfo.arrayLayers = 1;
                 * imageCreateInfo.samples = VkSampleCountFlags._1;
                 * imageCreateInfo.tiling = VkImageTiling.Linear;
                 * imageCreateInfo.usage = VkImageUsageFlags.Sampled;
                 * imageCreateInfo.sharingMode = VkSharingMode.Exclusive;
                 * imageCreateInfo.initialLayout = VkImageLayout.Preinitialized;
                 * imageCreateInfo.extent = new VkExtent3D { width = texture.width, height = texture.height, depth = 1 };
                 * Util.CheckResult(vkCreateImage(Device, &imageCreateInfo, null, &mappableImage));
                 *
                 * // Get memory requirements for this image
                 * // like size and alignment
                 * vkGetImageMemoryRequirements(Device, mappableImage, &memReqs);
                 * // Set memory allocation size to required memory size
                 * memAllocInfo.allocationSize = memReqs.size;
                 *
                 * // Get memory type that can be mapped to host memory
                 * memAllocInfo.memoryTypeIndex = VulkanDevice.GetMemoryType(memReqs.memoryTypeBits,  VkMemoryPropertyFlags.HostVisible |  VkMemoryPropertyFlags.HostCoherent);
                 *
                 * // Allocate host memory
                 * Util.CheckResult(vkAllocateMemory(Device, &memAllocInfo, null, &mappableMemory));
                 *
                 * // Bind allocated image for use
                 * Util.CheckResult(vkBindImageMemory(Device, mappableImage, mappableMemory, 0));
                 *
                 * // Get sub resource layout
                 * // Mip map count, array layer, etc.
                 * VkImageSubresource subRes = new VkImageSubresource();
                 * subRes.aspectMask =  VkImageAspectFlags.Color;
                 *
                 * VkSubresourceLayout subResLayout;
                 * void* data;
                 *
                 * // Get sub resources layout
                 * // Includes row pitch, size offsets, etc.
                 * vkGetImageSubresourceLayout(Device, mappableImage, &subRes, &subResLayout);
                 *
                 * // Map image memory
                 * Util.CheckResult(vkMapMemory(Device, mappableMemory, 0, memReqs.size, 0, &data));
                 *
                 * // Copy image data into memory
                 * memcpy(data, tex2D[subRes.mipLevel].data(), tex2D[subRes.mipLevel].size());
                 *
                 * vkUnmapMemory(Device, mappableMemory);
                 *
                 * // Linear tiled images don't need to be staged
                 * // and can be directly used as textures
                 * texture.image = mappableImage;
                 * texture.DeviceMemory = mappableMemory;
                 * texture.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
                 *
                 * VkCommandBuffer copyCmd = VulkanExampleBase::createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
                 *
                 * // Setup image memory barrier transfer image to shader read layout
                 *
                 * // The sub resource range describes the regions of the image we will be transition
                 * VkImageSubresourceRange subresourceRange = { };
                 * // Image only contains color data
                 * subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
                 * // Start at first mip level
                 * subresourceRange.baseMipLevel = 0;
                 * // Only one mip level, most implementations won't support more for linear tiled images
                 * subresourceRange.levelCount = 1;
                 * // The 2D texture only has one layer
                 * subresourceRange.layerCount = 1;
                 *
                 * setImageLayout(
                 *  copyCmd,
                 *  texture.image,
                 *  VK_IMAGE_ASPECT_COLOR_BIT,
                 *  VK_IMAGE_LAYOUT_PREINITIALIZED,
                 *  texture.imageLayout,
                 *  subresourceRange);
                 *
                 * VulkanExampleBase::flushCommandBuffer(copyCmd, queue, true);
                 */
            }

            // Create sampler
            // In Vulkan textures are accessed by samplers
            // This separates all the sampling information from the
            // texture data
            // This means you could have multiple sampler objects
            // for the same texture with different settings
            // Similar to the samplers available with OpenGL 3.3
            VkSamplerCreateInfo sampler = Initializers.samplerCreateInfo();

            sampler.magFilter    = VkFilter.Linear;
            sampler.minFilter    = VkFilter.Linear;
            sampler.mipmapMode   = VkSamplerMipmapMode.Linear;
            sampler.addressModeU = VkSamplerAddressMode.Repeat;
            sampler.addressModeV = VkSamplerAddressMode.Repeat;
            sampler.addressModeW = VkSamplerAddressMode.Repeat;
            sampler.mipLodBias   = 0.0f;
            sampler.compareOp    = VkCompareOp.Never;
            sampler.minLod       = 0.0f;
            // Set max level-of-detail to mip level count of the texture
            sampler.maxLod = (useStaging == 1) ? (float)texture.mipLevels : 0.0f;
            // Enable anisotropic filtering
            // This feature is optional, so we must check if it's supported on the Device
            if (VulkanDevice.Features.samplerAnisotropy == 1)
            {
                // Use max. level of anisotropy for this example
                sampler.maxAnisotropy    = VulkanDevice.Properties.limits.maxSamplerAnisotropy;
                sampler.anisotropyEnable = True;
            }
            else
            {
                // The Device does not support anisotropic filtering
                sampler.maxAnisotropy    = 1.0f;
                sampler.anisotropyEnable = False;
            }
            sampler.borderColor = VkBorderColor.FloatOpaqueWhite;
            Util.CheckResult(vkCreateSampler(Device, ref sampler, null, out texture.sampler));

            // Create image view
            // Textures are not directly accessed by the shaders and
            // are abstracted by image views containing additional
            // information and sub resource ranges
            VkImageViewCreateInfo view = Initializers.imageViewCreateInfo();

            view.viewType   = VkImageViewType._2d;
            view.format     = format;
            view.components = new VkComponentMapping {
                r = VkComponentSwizzle.R, g = VkComponentSwizzle.G, b = VkComponentSwizzle.B, a = VkComponentSwizzle.A
            };
            // The subresource range describes the set of mip levels (and array layers) that can be accessed through this image view
            // It's possible to create multiple image views for a single image referring to different (and/or overlapping) ranges of the image
            view.subresourceRange.aspectMask     = VkImageAspectFlags.Color;
            view.subresourceRange.baseMipLevel   = 0;
            view.subresourceRange.baseArrayLayer = 0;
            view.subresourceRange.layerCount     = 1;
            // Linear tiling usually won't support mip maps
            // Only set mip map count if optimal tiling is used
            view.subresourceRange.levelCount = (useStaging == 1) ? texture.mipLevels : 1;
            // The view will be based on the texture's image
            view.image = texture.image;
            Util.CheckResult(vkCreateImageView(Device, &view, null, out texture.view));
        }
Ejemplo n.º 4
0
        /**
         * Load a 2D texture including all mip levels
         *
         * @param filename File to load (supports .ktx and .dds)
         * @param format Vulkan format of the image data stored in the file
         * @param device Vulkan device to create the texture on
         * @param copyQueue Queue used for the texture staging copy commands (must support transfer)
         * @param (Optional) imageUsageFlags Usage flags for the texture's image (defaults to VK_IMAGE_USAGE_SAMPLED_BIT)
         * @param (Optional) imageLayout Usage layout for the texture (defaults VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
         * @param (Optional) forceLinear Force linear tiling (not advised, defaults to false)
         *
         */
        public void loadFromFile(
            string filename,
            VkFormat format,
            vksVulkanDevice device,
            VkQueue copyQueue,
            VkImageUsageFlags imageUsageFlags = VkImageUsageFlags.Sampled,
            VkImageLayout imageLayout         = VkImageLayout.ShaderReadOnlyOptimal,
            bool forceLinear = false)
        {
            KtxFile tex2D;

            using (var fs = File.OpenRead(filename))
            {
                tex2D = KtxFile.Load(fs, false);
            }

            this.device = device;
            width       = tex2D.Header.PixelWidth;
            height      = tex2D.Header.PixelHeight;
            if (height == 0)
            {
                height = width;
            }
            mipLevels = tex2D.Header.NumberOfMipmapLevels;

            // Get device properites for the requested texture format
            VkFormatProperties formatProperties;

            vkGetPhysicalDeviceFormatProperties(device.PhysicalDevice, format, out formatProperties);

            // Only use linear tiling if requested (and supported by the device)
            // Support for linear tiling is mostly limited, so prefer to use
            // optimal tiling instead
            // On most implementations linear tiling will only support a very
            // limited amount of formats and features (mip maps, cubemaps, arrays, etc.)
            bool useStaging = !forceLinear;

            VkMemoryAllocateInfo memAllocInfo = Initializers.memoryAllocateInfo();
            VkMemoryRequirements memReqs;

            // Use a separate command buffer for texture loading
            VkCommandBuffer copyCmd = device.createCommandBuffer(VkCommandBufferLevel.Primary, true);

            if (useStaging)
            {
                // Create a host-visible staging buffer that contains the raw image data
                VkBuffer       stagingBuffer;
                VkDeviceMemory stagingMemory;

                VkBufferCreateInfo bufferCreateInfo = Initializers.bufferCreateInfo();
                bufferCreateInfo.size = tex2D.GetTotalSize();
                // This buffer is used as a transfer source for the buffer copy
                bufferCreateInfo.usage       = VkBufferUsageFlags.TransferSrc;
                bufferCreateInfo.sharingMode = VkSharingMode.Exclusive;

                Util.CheckResult(vkCreateBuffer(device.LogicalDevice, &bufferCreateInfo, null, &stagingBuffer));

                // Get memory requirements for the staging buffer (alignment, memory type bits)
                vkGetBufferMemoryRequirements(device.LogicalDevice, stagingBuffer, &memReqs);

                memAllocInfo.allocationSize = memReqs.size;
                // Get memory type index for a host visible buffer
                memAllocInfo.memoryTypeIndex = device.getMemoryType(memReqs.memoryTypeBits, VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent);

                Util.CheckResult(vkAllocateMemory(device.LogicalDevice, &memAllocInfo, null, &stagingMemory));
                Util.CheckResult(vkBindBufferMemory(device.LogicalDevice, stagingBuffer, stagingMemory, 0));

                // Copy texture data into staging buffer
                byte *data;
                Util.CheckResult(vkMapMemory(device.LogicalDevice, stagingMemory, 0, memReqs.size, 0, (void **)&data));
                byte[] pixelData = tex2D.GetAllTextureData();
                fixed(byte *pixelDataPtr = &pixelData[0])
                {
                    Unsafe.CopyBlock(data, pixelDataPtr, (uint)pixelData.Length);
                }

                vkUnmapMemory(device.LogicalDevice, stagingMemory);

                // Setup buffer copy regions for each mip level
                NativeList <VkBufferImageCopy> bufferCopyRegions = new NativeList <VkBufferImageCopy>();
                uint offset = 0;

                for (uint i = 0; i < mipLevels; i++)
                {
                    VkBufferImageCopy bufferCopyRegion = new VkBufferImageCopy();
                    bufferCopyRegion.imageSubresource.aspectMask     = VkImageAspectFlags.Color;
                    bufferCopyRegion.imageSubresource.mipLevel       = i;
                    bufferCopyRegion.imageSubresource.baseArrayLayer = 0;
                    bufferCopyRegion.imageSubresource.layerCount     = 1;
                    bufferCopyRegion.imageExtent.width  = tex2D.Faces[0].Mipmaps[i].Width;
                    bufferCopyRegion.imageExtent.height = tex2D.Faces[0].Mipmaps[i].Height;
                    bufferCopyRegion.imageExtent.depth  = 1;
                    bufferCopyRegion.bufferOffset       = offset;

                    bufferCopyRegions.Add(bufferCopyRegion);

                    offset += tex2D.Faces[0].Mipmaps[i].SizeInBytes;
                }

                // Create optimal tiled target image
                VkImageCreateInfo imageCreateInfo = Initializers.imageCreateInfo();
                imageCreateInfo.imageType     = VkImageType.Image2D;
                imageCreateInfo.format        = format;
                imageCreateInfo.mipLevels     = mipLevels;
                imageCreateInfo.arrayLayers   = 1;
                imageCreateInfo.samples       = VkSampleCountFlags.Count1;
                imageCreateInfo.tiling        = VkImageTiling.Optimal;
                imageCreateInfo.sharingMode   = VkSharingMode.Exclusive;
                imageCreateInfo.initialLayout = VkImageLayout.Undefined;
                imageCreateInfo.extent        = new VkExtent3D {
                    width = width, height = height, depth = 1
                };
                imageCreateInfo.usage = imageUsageFlags;
                // Ensure that the TRANSFER_DST bit is set for staging
                if ((imageCreateInfo.usage & VkImageUsageFlags.TransferDst) == 0)
                {
                    imageCreateInfo.usage |= VkImageUsageFlags.TransferDst;
                }
                Util.CheckResult(vkCreateImage(device.LogicalDevice, &imageCreateInfo, null, out image));

                vkGetImageMemoryRequirements(device.LogicalDevice, image, &memReqs);

                memAllocInfo.allocationSize = memReqs.size;

                memAllocInfo.memoryTypeIndex = device.getMemoryType(memReqs.memoryTypeBits, VkMemoryPropertyFlags.DeviceLocal);
                Util.CheckResult(vkAllocateMemory(device.LogicalDevice, &memAllocInfo, null, out deviceMemory));
                Util.CheckResult(vkBindImageMemory(device.LogicalDevice, image, deviceMemory, 0));

                VkImageSubresourceRange subresourceRange = new VkImageSubresourceRange();
                subresourceRange.aspectMask   = VkImageAspectFlags.Color;
                subresourceRange.baseMipLevel = 0;
                subresourceRange.levelCount   = mipLevels;
                subresourceRange.layerCount   = 1;

                // Image barrier for optimal image (target)
                // Optimal image will be used as destination for the copy
                Tools.setImageLayout(
                    copyCmd,
                    image,
                    VkImageAspectFlags.Color,
                    VkImageLayout.Undefined,
                    VkImageLayout.TransferDstOptimal,
                    subresourceRange);

                // Copy mip levels from staging buffer
                vkCmdCopyBufferToImage(
                    copyCmd,
                    stagingBuffer,
                    image,
                    VkImageLayout.TransferDstOptimal,
                    bufferCopyRegions.Count,
                    bufferCopyRegions.Data);

                // Change texture image layout to shader read after all mip levels have been copied
                this.imageLayout = imageLayout;
                Tools.setImageLayout(
                    copyCmd,
                    image,
                    VkImageAspectFlags.Color,
                    VkImageLayout.TransferDstOptimal,
                    imageLayout,
                    subresourceRange);

                device.flushCommandBuffer(copyCmd, copyQueue);

                // Clean up staging resources
                vkFreeMemory(device.LogicalDevice, stagingMemory, null);
                vkDestroyBuffer(device.LogicalDevice, stagingBuffer, null);
            }
            else
            {
                throw new NotImplementedException();

                /*
                 * // Prefer using optimal tiling, as linear tiling
                 * // may support only a small set of features
                 * // depending on implementation (e.g. no mip maps, only one layer, etc.)
                 *
                 * // Check if this support is supported for linear tiling
                 * Debug.Assert((formatProperties.linearTilingFeatures & VkFormatFeatureFlags.SampledImage) != 0);
                 *
                 * VkImage mappableImage;
                 * VkDeviceMemory mappableMemory;
                 *
                 * VkImageCreateInfo imageCreateInfo = Initializers.imageCreateInfo();
                 * imageCreateInfo.imageType = VkImageType._2d;
                 * imageCreateInfo.format = format;
                 * imageCreateInfo.extent = new VkExtent3D { width = width, height = height, depth = 1 };
                 * imageCreateInfo.mipLevels = 1;
                 * imageCreateInfo.arrayLayers = 1;
                 * imageCreateInfo.samples = VkSampleCountFlags._1;
                 * imageCreateInfo.tiling = VkImageTiling.Linear;
                 * imageCreateInfo.usage = imageUsageFlags;
                 * imageCreateInfo.sharingMode = VkSharingMode.Exclusive;
                 * imageCreateInfo.initialLayout = VkImageLayout.Undefined;
                 *
                 * // Load mip map level 0 to linear tiling image
                 * Util.CheckResult(vkCreateImage(device.LogicalDevice, &imageCreateInfo, null, &mappableImage));
                 *
                 * // Get memory requirements for this image
                 * // like size and alignment
                 * vkGetImageMemoryRequirements(device.LogicalDevice, mappableImage, &memReqs);
                 * // Set memory allocation size to required memory size
                 * memAllocInfo.allocationSize = memReqs.size;
                 *
                 * // Get memory type that can be mapped to host memory
                 * memAllocInfo.memoryTypeIndex = device.GetMemoryType(memReqs.memoryTypeBits, VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent);
                 *
                 * // Allocate host memory
                 * Util.CheckResult(vkAllocateMemory(device.LogicalDevice, &memAllocInfo, null, &mappableMemory));
                 *
                 * // Bind allocated image for use
                 * Util.CheckResult(vkBindImageMemory(device.LogicalDevice, mappableImage, mappableMemory, 0));
                 *
                 * // Get sub resource layout
                 * // Mip map count, array layer, etc.
                 * VkImageSubresource subRes = new VkImageSubresource();
                 * subRes.aspectMask = VkImageAspectFlags.Color;
                 * subRes.mipLevel = 0;
                 *
                 * VkSubresourceLayout subResLayout;
                 * void* data;
                 *
                 * // Get sub resources layout
                 * // Includes row pitch, size offsets, etc.
                 * vkGetImageSubresourceLayout(device.LogicalDevice, mappableImage, &subRes, &subResLayout);
                 *
                 * // Map image memory
                 * Util.CheckResult(vkMapMemory(device.LogicalDevice, mappableMemory, 0, memReqs.size, 0, &data));
                 *
                 * // Copy image data into memory
                 * memcpy(data, tex2D[subRes.mipLevel].data(), tex2D[subRes.mipLevel].size());
                 *
                 * vkUnmapMemory(device.LogicalDevice, mappableMemory);
                 *
                 * // Linear tiled images don't need to be staged
                 * // and can be directly used as textures
                 * image = mappableImage;
                 * deviceMemory = mappableMemory;
                 * imageLayout = imageLayout;
                 *
                 * // Setup image memory barrier
                 * vks::tools::setImageLayout(copyCmd, image, VkImageAspectFlags.Color, VkImageLayout.Undefined, imageLayout);
                 *
                 * device.flushCommandBuffer(copyCmd, copyQueue);
                 */
            }

            // Create a defaultsampler
            VkSamplerCreateInfo samplerCreateInfo = VkSamplerCreateInfo.New();

            samplerCreateInfo.magFilter    = VkFilter.Linear;
            samplerCreateInfo.minFilter    = VkFilter.Linear;
            samplerCreateInfo.mipmapMode   = VkSamplerMipmapMode.Linear;
            samplerCreateInfo.addressModeU = VkSamplerAddressMode.Repeat;
            samplerCreateInfo.addressModeV = VkSamplerAddressMode.Repeat;
            samplerCreateInfo.addressModeW = VkSamplerAddressMode.Repeat;
            samplerCreateInfo.mipLodBias   = 0.0f;
            samplerCreateInfo.compareOp    = VkCompareOp.Never;
            samplerCreateInfo.minLod       = 0.0f;
            // Max level-of-detail should match mip level count
            samplerCreateInfo.maxLod = (useStaging) ? (float)mipLevels : 0.0f;
            // Enable anisotropic filtering
            samplerCreateInfo.maxAnisotropy    = 8;
            samplerCreateInfo.anisotropyEnable = True;
            samplerCreateInfo.borderColor      = VkBorderColor.FloatOpaqueWhite;
            Util.CheckResult(vkCreateSampler(device.LogicalDevice, &samplerCreateInfo, null, out sampler));

            // Create image view
            // Textures are not directly accessed by the shaders and
            // are abstracted by image views containing additional
            // information and sub resource ranges
            VkImageViewCreateInfo viewCreateInfo = VkImageViewCreateInfo.New();

            viewCreateInfo.viewType   = VkImageViewType.Image2D;
            viewCreateInfo.format     = format;
            viewCreateInfo.components = new VkComponentMapping {
                r = VkComponentSwizzle.R, g = VkComponentSwizzle.G, b = VkComponentSwizzle.B, a = VkComponentSwizzle.A
            };
            viewCreateInfo.subresourceRange = new VkImageSubresourceRange {
                aspectMask = VkImageAspectFlags.Color, baseMipLevel = 0, levelCount = 1, baseArrayLayer = 0, layerCount = 1
            };
            // Linear tiling usually won't support mip maps
            // Only set mip map count if optimal tiling is used
            viewCreateInfo.subresourceRange.levelCount = (useStaging) ? mipLevels : 1;
            viewCreateInfo.image = image;
            Util.CheckResult(vkCreateImageView(device.LogicalDevice, &viewCreateInfo, null, out view));

            // Update descriptor image info member that can be used for setting up descriptor sets
            updateDescriptor();
        }
Ejemplo n.º 5
0
        public VkResult CreateLogicalDevice(
            VkPhysicalDeviceFeatures enabledFeatures,
            NativeList <IntPtr> enabledExtensions,
            bool useSwapChain = true,
            VkQueueFlags requestedQueueTypes = VkQueueFlags.Graphics | VkQueueFlags.Compute)
        {
            // Desired queues need to be requested upon logical device creation
            // Due to differing queue family configurations of Vulkan implementations this can be a bit tricky, especially if the application
            // requests different queue types

            using (NativeList <VkDeviceQueueCreateInfo> queueCreateInfos = new NativeList <VkDeviceQueueCreateInfo>())
            {
                float defaultQueuePriority = 0.0f;

                // Graphics queue
                if ((requestedQueueTypes & VkQueueFlags.Graphics) != 0)
                {
                    QFIndices.Graphics = GetQueueFamilyIndex(VkQueueFlags.Graphics);
                    VkDeviceQueueCreateInfo queueInfo = new VkDeviceQueueCreateInfo();
                    queueInfo.sType            = VkStructureType.DeviceQueueCreateInfo;
                    queueInfo.queueFamilyIndex = QFIndices.Graphics;
                    queueInfo.queueCount       = 1;
                    queueInfo.pQueuePriorities = &defaultQueuePriority;
                    queueCreateInfos.Add(queueInfo);
                }
                else
                {
                    QFIndices.Graphics = (uint)NullHandle;
                }

                // Dedicated compute queue
                if ((requestedQueueTypes & VkQueueFlags.Compute) != 0)
                {
                    QFIndices.Compute = GetQueueFamilyIndex(VkQueueFlags.Compute);
                    if (QFIndices.Compute != QFIndices.Graphics)
                    {
                        // If compute family index differs, we need an additional queue create info for the compute queue
                        VkDeviceQueueCreateInfo queueInfo = new VkDeviceQueueCreateInfo();
                        queueInfo.sType            = VkStructureType.DeviceQueueCreateInfo;
                        queueInfo.queueFamilyIndex = QFIndices.Compute;
                        queueInfo.queueCount       = 1;
                        queueInfo.pQueuePriorities = &defaultQueuePriority;
                        queueCreateInfos.Add(queueInfo);
                    }
                }
                else
                {
                    // Else we use the same queue
                    QFIndices.Compute = QFIndices.Graphics;
                }

                // Dedicated transfer queue
                if ((requestedQueueTypes & VkQueueFlags.Transfer) != 0)
                {
                    QFIndices.Transfer = GetQueueFamilyIndex(VkQueueFlags.Transfer);
                    if (QFIndices.Transfer != QFIndices.Graphics && QFIndices.Transfer != QFIndices.Compute)
                    {
                        // If compute family index differs, we need an additional queue create info for the transfer queue
                        VkDeviceQueueCreateInfo queueInfo = new VkDeviceQueueCreateInfo();
                        queueInfo.sType            = VkStructureType.DeviceQueueCreateInfo;
                        queueInfo.queueFamilyIndex = QFIndices.Transfer;
                        queueInfo.queueCount       = 1;
                        queueInfo.pQueuePriorities = &defaultQueuePriority;
                        queueCreateInfos.Add(queueInfo);
                    }
                }
                else
                {
                    // Else we use the same queue
                    QFIndices.Transfer = QFIndices.Graphics;
                }

                // Create the logical device representation
                using (NativeList <IntPtr> deviceExtensions = new NativeList <IntPtr>(enabledExtensions))
                {
                    if (useSwapChain)
                    {
                        // If the device will be used for presenting to a display via a swapchain we need to request the swapchain extension
                        deviceExtensions.Add(Strings.VK_KHR_SWAPCHAIN_EXTENSION_NAME);
                    }

                    VkDeviceCreateInfo deviceCreateInfo = VkDeviceCreateInfo.New();
                    deviceCreateInfo.queueCreateInfoCount = queueCreateInfos.Count;
                    deviceCreateInfo.pQueueCreateInfos    = (VkDeviceQueueCreateInfo *)queueCreateInfos.Data.ToPointer();
                    deviceCreateInfo.pEnabledFeatures     = &enabledFeatures;

                    if (deviceExtensions.Count > 0)
                    {
                        deviceCreateInfo.enabledExtensionCount   = deviceExtensions.Count;
                        deviceCreateInfo.ppEnabledExtensionNames = (byte **)deviceExtensions.Data.ToPointer();
                    }

                    VkResult result = vkCreateDevice(PhysicalDevice, &deviceCreateInfo, null, out _logicalDevice);
                    if (result == VkResult.Success)
                    {
                        // Create a default command pool for graphics command buffers
                        CommandPool = CreateCommandPool(QFIndices.Graphics);
                    }

                    return(result);
                }
            }
        }