コード例 #1
0
ファイル: ktx.cs プロジェクト: Svengali/vk.net
        public static Image Load(Queue staggingQ, CommandPool staggingCmdPool, string ktxPath, VkImageUsageFlags usage = VkImageUsageFlags.Sampled,
                                 VkMemoryPropertyFlags memoryProperty = VkMemoryPropertyFlags.DeviceLocal, bool generateMipmaps = true,
                                 VkImageTiling tiling = VkImageTiling.Optimal)
        {
            Image img = null;

            using (Stream ktxStream = File.Open(ktxPath, FileMode.Open, FileAccess.Read)) {
                using (BinaryReader br = new BinaryReader(ktxStream)) {
                    if (!br.ReadBytes(12).AreEquals(ktxSignature))
                    {
                        throw new KtxException("Not a ktx file: " + ktxPath);
                    }

                    UInt32 endianness            = br.ReadUInt32();
                    UInt32 glType                = br.ReadUInt32();
                    UInt32 glTypeSize            = br.ReadUInt32();
                    UInt32 glFormat              = br.ReadUInt32();
                    UInt32 glInternalFormat      = br.ReadUInt32();
                    UInt32 glBaseInternalFormat  = br.ReadUInt32();
                    UInt32 pixelWidth            = br.ReadUInt32();
                    UInt32 pixelHeight           = br.ReadUInt32();
                    UInt32 pixelDepth            = Math.Min(1, br.ReadUInt32());
                    UInt32 numberOfArrayElements = br.ReadUInt32();             //only for array text, else 0
                    UInt32 numberOfFaces         = br.ReadUInt32();             //only for cube map, else
                    UInt32 numberOfMipmapLevels  = Math.Min(1, br.ReadUInt32());
                    UInt32 bytesOfKeyValueData   = br.ReadUInt32();

                    VkFormat vkFormat = GLHelper.vkGetFormatFromOpenGLInternalFormat(glInternalFormat);
                    if (vkFormat == VkFormat.Undefined)
                    {
                        vkFormat = GLHelper.vkGetFormatFromOpenGLFormat(glFormat, glType);
                        if (vkFormat == VkFormat.Undefined)
                        {
                            throw new KtxException("Undefined format: " + ktxPath);
                        }
                    }

                    VkFormatFeatureFlags phyFormatSupport = (tiling == VkImageTiling.Linear) ?
                                                            staggingQ.Dev.phy.GetFormatProperties(vkFormat).linearTilingFeatures :
                                                            staggingQ.Dev.phy.GetFormatProperties(vkFormat).optimalTilingFeatures;

                    uint requestedMipsLevels = numberOfMipmapLevels;
                    if (numberOfMipmapLevels == 1)
                    {
                        requestedMipsLevels = (generateMipmaps && phyFormatSupport.HasFlag(VkFormatFeatureFlags.BlitSrc | VkFormatFeatureFlags.BlitDst)) ?
                                              (uint)Math.Floor(Math.Log(Math.Max(pixelWidth, pixelHeight))) + 1 : 1;
                    }

                    if (tiling == VkImageTiling.Optimal)
                    {
                        usage |= VkImageUsageFlags.TransferDst;
                    }
                    if (generateMipmaps)
                    {
                        usage |= (VkImageUsageFlags.TransferSrc | VkImageUsageFlags.TransferDst);
                    }

                    VkImageCreateFlags createFlags = 0;

                    VkImageType imgType =
                        (pixelWidth == 0) ? throw new KtxException("pixelWidth must be > 0") :
                              (pixelHeight == 0) ? imgType = VkImageType.Image1D :
                                                             (pixelDepth == 0) ? imgType = VkImageType.Image2D : imgType = VkImageType.Image3D;


                    VkSampleCountFlags samples = VkSampleCountFlags.SampleCount1;

                    if (numberOfFaces > 1)
                    {
                        if (imgType != VkImageType.Image2D)
                        {
                            throw new KtxException("cubemap faces must be 2D textures");
                        }
                        createFlags           = VkImageCreateFlags.CubeCompatible;
                        samples               = VkSampleCountFlags.SampleCount1;
                        numberOfArrayElements = numberOfFaces;
                    }
                    else
                    {
                        numberOfFaces = 1;
                        if (numberOfArrayElements == 0)
                        {
                            numberOfArrayElements = 1;
                        }
                    }

                    if (imgType != VkImageType.Image3D)
                    {
                        pixelDepth = 1;
                    }

                    img = new Image(staggingQ.Dev, vkFormat, usage, memoryProperty, pixelWidth, pixelHeight, imgType, samples,
                                    tiling, requestedMipsLevels, numberOfArrayElements, pixelDepth, createFlags);

                    byte[] keyValueDatas = br.ReadBytes((int)bytesOfKeyValueData);


                    if (memoryProperty.HasFlag(VkMemoryPropertyFlags.DeviceLocal))
                    {
                        ulong staggingSize = img.AllocatedDeviceMemorySize;


                        using (HostBuffer stagging = new HostBuffer(staggingQ.Dev, VkBufferUsageFlags.TransferSrc, staggingSize)) {
                            stagging.Map();

                            CommandBuffer cmd = staggingCmdPool.AllocateCommandBuffer();
                            cmd.Start(VkCommandBufferUsageFlags.OneTimeSubmit);
                            img.SetLayout(cmd, VkImageAspectFlags.Color,
                                          VkImageLayout.Undefined, VkImageLayout.TransferDstOptimal,
                                          VkPipelineStageFlags.AllCommands, VkPipelineStageFlags.Transfer);

                            List <VkBufferImageCopy> buffCopies = new List <VkBufferImageCopy> ();

                            VkBufferImageCopy bufferCopyRegion = new VkBufferImageCopy {
                                imageExtent      = img.CreateInfo.extent,
                                imageSubresource = new VkImageSubresourceLayers(VkImageAspectFlags.Color, img.CreateInfo.arrayLayers, 0)
                            };

                            ulong bufferOffset = 0;
                            uint  imgWidth     = img.CreateInfo.extent.height;
                            uint  imgHeight    = img.CreateInfo.extent.width;

                            for (int mips = 0; mips < numberOfMipmapLevels; mips++)
                            {
                                UInt32 imgSize = br.ReadUInt32();

                                bufferCopyRegion.bufferImageHeight = imgWidth;
                                bufferCopyRegion.bufferRowLength   = imgHeight;
                                bufferCopyRegion.bufferOffset      = bufferOffset;

                                if (createFlags.HasFlag(VkImageCreateFlags.CubeCompatible))
                                {
                                    IntPtr ptrFace = img.MappedData;
                                    bufferCopyRegion.imageSubresource.layerCount = 1;
                                    for (uint face = 0; face < numberOfFaces; face++)
                                    {
                                        bufferCopyRegion.imageSubresource.baseArrayLayer = face;
                                        Marshal.Copy(br.ReadBytes((int)imgSize), 0, stagging.MappedData + (int)bufferOffset, (int)imgSize);
                                        buffCopies.Add(bufferCopyRegion);
                                        uint faceOffset = imgSize + (imgSize % 4);
                                        ptrFace      += (int)faceOffset;                                   //cube padding
                                        bufferOffset += faceOffset;
                                        bufferCopyRegion.bufferOffset = bufferOffset;
                                    }
                                }
                                else
                                {
                                    Marshal.Copy(br.ReadBytes((int)imgSize), 0, stagging.MappedData, (int)imgSize);
                                    buffCopies.Add(bufferCopyRegion);
                                }
                                bufferOffset += imgSize;
                                imgWidth     /= 2;
                                imgHeight    /= 2;
                            }
                            stagging.Unmap();
                            Vk.vkCmdCopyBufferToImage(cmd.Handle, stagging.handle, img.handle, VkImageLayout.TransferDstOptimal,
                                                      (uint)buffCopies.Count, buffCopies.Pin());
                            buffCopies.Unpin();

                            if (requestedMipsLevels > numberOfMipmapLevels)
                            {
                                img.BuildMipmaps(cmd);
                            }
                            else
                            {
                                img.SetLayout(cmd, VkImageAspectFlags.Color,
                                              VkImageLayout.TransferDstOptimal, VkImageLayout.ShaderReadOnlyOptimal,
                                              VkPipelineStageFlags.Transfer, VkPipelineStageFlags.AllGraphics);
                            }

                            cmd.End();

                            staggingQ.Submit(cmd);
                            staggingQ.WaitIdle();

                            cmd.Free();
                        }

                        //for (int mips = 0; mips < numberOfMipmapLevels; mips++) {
                        //UInt32 imgSize = br.ReadUInt32 ();

                        /*VkImageBlit imageBlit = new VkImageBlit {
                         *      srcSubresource = new VkImageSubresourceLayers(VkImageAspectFlags.Color, numberOfArrayElements, (uint)mips - 1),
                         *      srcOffsets_1 = new VkOffset3D((int)pixelWidth >> (mips - 1), (int)pixelHeight >> (mips - 1),1),
                         *      dstSubresource = new VkImageSubresourceLayers (VkImageAspectFlags.Color, numberOfArrayElements, (uint)mips),
                         *      dstOffsets_1 = new VkOffset3D ((int)pixelWidth >> mips, (int)pixelHeight >> mips, 1),
                         * };*/
                        //for (int layer = 0; layer < numberOfArrayElements; layer++) {
                        //for (int face = 0; face < numberOfFaces; face++) {
                        //for (int slice = 0; slice < pixelDepth; slice++) {

                        /*for (int y = 0; y < pixelHeight; y++) {
                         *      for (int x = 0; x < pixelWidth; x++) {
                         *              //Uncompressed texture data matches a GL_UNPACK_ALIGNMENT of 4.
                         *      }
                         * }*/
                        //}
                        //Byte cubePadding[0-3]
                        //}
                        //}
                        //Byte mipPadding[0-3]
                        //}
                    }
                }
            }

            return(img);
        }
コード例 #2
0
ファイル: ktx.cs プロジェクト: jpbruyere/vke.net
        public static Image Load(Queue staggingQ, CommandPool staggingCmdPool, string ktxPath, VkImageUsageFlags usage = VkImageUsageFlags.Sampled,
                                 VkMemoryPropertyFlags memoryProperty = VkMemoryPropertyFlags.DeviceLocal, bool generateMipmaps = true,
                                 VkImageTiling tiling = VkImageTiling.Optimal)
        {
            Image img = null;

            using (Stream ktxStream = File.Open(ktxPath, FileMode.Open, FileAccess.Read)) {
                using (BinaryReader br = new BinaryReader(ktxStream)) {
                    if (!br.ReadBytes(12).AreEquals(ktxSignature))
                    {
                        throw new KtxException("Not a ktx file: " + ktxPath);
                    }

                    UInt32 endianness            = br.ReadUInt32();
                    UInt32 glType                = br.ReadUInt32();
                    UInt32 glTypeSize            = br.ReadUInt32();
                    UInt32 glFormat              = br.ReadUInt32();
                    UInt32 glInternalFormat      = br.ReadUInt32();
                    UInt32 glBaseInternalFormat  = br.ReadUInt32();
                    UInt32 pixelWidth            = br.ReadUInt32();
                    UInt32 pixelHeight           = br.ReadUInt32();
                    UInt32 pixelDepth            = Math.Max(1, br.ReadUInt32());
                    UInt32 numberOfArrayElements = br.ReadUInt32();             //only for array text, else 0
                    UInt32 numberOfFaces         = br.ReadUInt32();             //only for cube map, else 1
                    UInt32 numberOfMipmapLevels  = Math.Max(1, br.ReadUInt32());
                    UInt32 bytesOfKeyValueData   = br.ReadUInt32();

                    VkFormat vkFormat = GLHelper.vkGetFormatFromOpenGLInternalFormat(glInternalFormat);
                    if (vkFormat == VkFormat.Undefined)
                    {
                        vkFormat = GLHelper.vkGetFormatFromOpenGLFormat(glFormat, glType);
                        if (vkFormat == VkFormat.Undefined)
                        {
                            throw new KtxException("Undefined format: " + ktxPath);
                        }
                    }
                    VkFormatProperties   formatProperties = staggingQ.Dev.phy.GetFormatProperties(vkFormat);
                    VkFormatFeatureFlags phyFormatSupport = (tiling == VkImageTiling.Linear) ?
                                                            formatProperties.linearTilingFeatures :
                                                            formatProperties.optimalTilingFeatures;

                    uint requestedMipsLevels = numberOfMipmapLevels;
                    if (numberOfMipmapLevels == 1)
                    {
                        requestedMipsLevels = (generateMipmaps && phyFormatSupport.HasFlag(VkFormatFeatureFlags.BlitSrc | VkFormatFeatureFlags.BlitDst)) ?
                                              (uint)Math.Floor(Math.Log(Math.Max(pixelWidth, pixelHeight))) + 1 : 1;
                    }

                    if (tiling == VkImageTiling.Optimal)
                    {
                        usage |= VkImageUsageFlags.TransferDst;
                    }
                    if (generateMipmaps)
                    {
                        usage |= (VkImageUsageFlags.TransferSrc | VkImageUsageFlags.TransferDst);
                    }

                    VkImageCreateFlags createFlags = 0;

                    VkImageType imgType =
                        (pixelWidth == 0) ? throw new KtxException("pixelWidth must be > 0") :
                              (pixelHeight == 0) ? imgType = VkImageType.Image1D :
                                                             (pixelDepth == 1) ? imgType = VkImageType.Image2D : imgType = VkImageType.Image3D;


                    VkSampleCountFlags samples = VkSampleCountFlags.SampleCount1;

                    if (numberOfFaces > 1)
                    {
                        if (imgType != VkImageType.Image2D)
                        {
                            throw new KtxException("cubemap faces must be 2D textures");
                        }
                        createFlags           = VkImageCreateFlags.CubeCompatible;
                        samples               = VkSampleCountFlags.SampleCount1;
                        numberOfArrayElements = numberOfFaces;
                    }
                    else
                    {
                        numberOfFaces = 1;
                        if (numberOfArrayElements == 0)
                        {
                            numberOfArrayElements = 1;
                        }
                    }

                    if (!Image.CheckFormatIsSupported(usage, phyFormatSupport))
                    {
                        throw new Exception($"Unsupported image format: {vkFormat}, {tiling}, {usage}");
                    }

                    img = new Image(staggingQ.Dev, vkFormat, usage, memoryProperty, pixelWidth, pixelHeight, imgType, samples,
                                    tiling, requestedMipsLevels, numberOfArrayElements, pixelDepth, createFlags);

                    byte[] keyValueDatas = br.ReadBytes((int)bytesOfKeyValueData);

                    uint blockW, blockH;
                    bool isCompressed = vkFormat.TryGetCompressedFormatBlockSize(out blockW, out blockH);
                    uint blockSize    = blockW * blockH;

                    if (memoryProperty.HasFlag(VkMemoryPropertyFlags.DeviceLocal))
                    {
                        ulong staggingSize = img.AllocatedDeviceMemorySize;
                        Console.WriteLine($"KtxStream size = {ktxStream.Length}, img Allocation = {img.AllocatedDeviceMemorySize}");

                        using (HostBuffer stagging = new HostBuffer(staggingQ.Dev, VkBufferUsageFlags.TransferSrc, staggingSize)) {
                            stagging.Map();

                            PrimaryCommandBuffer cmd = staggingCmdPool.AllocateAndStart(VkCommandBufferUsageFlags.OneTimeSubmit);
                            img.SetLayout(cmd, VkImageAspectFlags.Color,
                                          VkImageLayout.Undefined, VkImageLayout.TransferDstOptimal,
                                          VkPipelineStageFlags.AllCommands, VkPipelineStageFlags.Transfer);

                            List <VkBufferImageCopy> buffCopies = new List <VkBufferImageCopy> ();

                            VkBufferImageCopy bufferCopyRegion = new VkBufferImageCopy {
                                imageExtent      = img.CreateInfo.extent,
                                imageSubresource = new VkImageSubresourceLayers(VkImageAspectFlags.Color, img.CreateInfo.arrayLayers, 0)
                            };

                            ulong bufferOffset = 0;
                            uint  imgWidth     = img.CreateInfo.extent.width;
                            uint  imgHeight    = img.CreateInfo.extent.height;

                            for (int mips = 0; mips < numberOfMipmapLevels; mips++)
                            {
                                UInt32 imgSize = br.ReadUInt32();

                                bufferCopyRegion.bufferRowLength   = imgWidth;
                                bufferCopyRegion.bufferImageHeight = imgHeight;

                                if (isCompressed && (imgWidth % blockW > 0 || imgHeight % blockH > 0))
                                {
                                    bufferCopyRegion.bufferRowLength   += blockW - imgWidth % blockW;
                                    bufferCopyRegion.bufferImageHeight += blockH - imgHeight % blockH;
                                }
                                bufferCopyRegion.bufferOffset = bufferOffset;
                                bufferCopyRegion.imageSubresource.mipLevel = (uint)mips;
                                bufferCopyRegion.imageExtent.width         = imgWidth;
                                bufferCopyRegion.imageExtent.height        = imgHeight;

                                if (createFlags.HasFlag(VkImageCreateFlags.CubeCompatible))
                                {
                                    //TODO:handle compressed formats
                                    for (uint face = 0; face < numberOfFaces; face++)
                                    {
                                        Marshal.Copy(br.ReadBytes((int)imgSize), 0, stagging.MappedData + (int)bufferOffset, (int)imgSize);
                                        uint faceOffset = imgSize + (imgSize % 4);                                        //cube padding
                                        bufferOffset += faceOffset;
                                    }
                                    buffCopies.Add(bufferCopyRegion);
                                    bufferCopyRegion.bufferOffset = bufferOffset;
                                }
                                else if (isCompressed && (imgWidth % blockW > 0 || imgHeight % blockH > 0))
                                {
                                    for (int line = 0; line < imgHeight; line++)
                                    {
                                        Marshal.Copy(br.ReadBytes((int)imgWidth), 0, stagging.MappedData + (int)bufferOffset, (int)imgWidth);
                                        bufferOffset += bufferCopyRegion.bufferRowLength;
                                    }
                                    buffCopies.Add(bufferCopyRegion);
                                }
                                else
                                {
                                    Marshal.Copy(br.ReadBytes((int)imgSize), 0, stagging.MappedData + (int)bufferOffset, (int)imgSize);
                                    buffCopies.Add(bufferCopyRegion);
                                    bufferOffset += imgSize;
                                }

                                if (isCompressed && bufferOffset % blockSize > 0)
                                {
                                    bufferOffset += blockSize - bufferOffset % blockSize;
                                }

                                imgWidth  /= 2;
                                imgHeight /= 2;
                            }
                            stagging.Unmap();

                            Vk.vkCmdCopyBufferToImage(cmd.Handle, stagging.handle, img.handle, VkImageLayout.TransferDstOptimal,
                                                      (uint)buffCopies.Count, buffCopies.Pin());
                            buffCopies.Unpin();

                            if (requestedMipsLevels > numberOfMipmapLevels)
                            {
                                img.BuildMipmaps(cmd);
                            }
                            else
                            {
                                img.SetLayout(cmd, VkImageAspectFlags.Color,
                                              VkImageLayout.TransferDstOptimal, VkImageLayout.ShaderReadOnlyOptimal,
                                              VkPipelineStageFlags.Transfer, VkPipelineStageFlags.FragmentShader);
                            }

                            cmd.End();

                            staggingQ.Submit(cmd);
                            staggingQ.WaitIdle();

                            cmd.Free();
                        }
                    }
                    else
                    {
                    }
                }
            }

            return(img);
        }