示例#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);
        }
示例#2
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.Image2D;
                imageCreateInfo.format      = format;
                imageCreateInfo.mipLevels   = texture.mipLevels;
                imageCreateInfo.arrayLayers = 1;
                imageCreateInfo.samples     = VkSampleCountFlags.Count1;
                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.Image2D;
            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));
        }
示例#3
0
        // Setup the offscreen framebuffer for rendering the blurred scene
        // The color attachment of this framebuffer will then be used to sample frame in the fragment shader of the final pass
        void prepareOffscreen()
        {
            offscreenPass.width  = FB_DIM;
            offscreenPass.height = FB_DIM;

            // Find a suitable depth format
            VkFormat fbDepthFormat;
            VkBool32 validDepthFormat = Tools.getSupportedDepthFormat(physicalDevice, &fbDepthFormat);

            Debug.Assert(validDepthFormat);

            // Color attachment
            VkImageCreateInfo image = Initializers.imageCreateInfo();

            image.imageType     = VK_IMAGE_TYPE_2D;
            image.format        = FB_COLOR_FORMAT;
            image.extent.width  = (uint)offscreenPass.width;
            image.extent.height = (uint)offscreenPass.height;
            image.extent.depth  = 1;
            image.mipLevels     = 1;
            image.arrayLayers   = 1;
            image.samples       = VK_SAMPLE_COUNT_1_BIT;
            image.tiling        = VK_IMAGE_TILING_OPTIMAL;
            // We will sample directly from the color attachment
            image.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;

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

            Util.CheckResult(vkCreateImage(device, &image, null, out offscreenPass.color.image));
            vkGetImageMemoryRequirements(device, offscreenPass.color.image, &memReqs);
            memAlloc.allocationSize  = memReqs.size;
            memAlloc.memoryTypeIndex = vulkanDevice.getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
            Util.CheckResult(vkAllocateMemory(device, &memAlloc, null, out offscreenPass.color.mem));
            Util.CheckResult(vkBindImageMemory(device, offscreenPass.color.image, offscreenPass.color.mem, 0));

            VkImageViewCreateInfo colorImageView = Initializers.imageViewCreateInfo();

            colorImageView.viewType                        = VK_IMAGE_VIEW_TYPE_2D;
            colorImageView.format                          = FB_COLOR_FORMAT;
            colorImageView.subresourceRange                = new VkImageSubresourceRange();
            colorImageView.subresourceRange.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
            colorImageView.subresourceRange.baseMipLevel   = 0;
            colorImageView.subresourceRange.levelCount     = 1;
            colorImageView.subresourceRange.baseArrayLayer = 0;
            colorImageView.subresourceRange.layerCount     = 1;
            colorImageView.image = offscreenPass.color.image;
            Util.CheckResult(vkCreateImageView(device, &colorImageView, null, out offscreenPass.color.view));

            // Create sampler to sample from the attachment in the fragment shader
            VkSamplerCreateInfo samplerInfo = Initializers.samplerCreateInfo();

            samplerInfo.magFilter     = VK_FILTER_LINEAR;
            samplerInfo.minFilter     = VK_FILTER_LINEAR;
            samplerInfo.mipmapMode    = VK_SAMPLER_MIPMAP_MODE_LINEAR;
            samplerInfo.addressModeU  = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
            samplerInfo.addressModeV  = samplerInfo.addressModeU;
            samplerInfo.addressModeW  = samplerInfo.addressModeU;
            samplerInfo.mipLodBias    = 0.0f;
            samplerInfo.maxAnisotropy = 0;
            samplerInfo.minLod        = 0.0f;
            samplerInfo.maxLod        = 1.0f;
            samplerInfo.borderColor   = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
            Util.CheckResult(vkCreateSampler(device, &samplerInfo, null, out offscreenPass.sampler));

            // Depth stencil attachment
            image.format = fbDepthFormat;
            image.usage  = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;

            Util.CheckResult(vkCreateImage(device, &image, null, out offscreenPass.depth.image));
            vkGetImageMemoryRequirements(device, offscreenPass.depth.image, &memReqs);
            memAlloc.allocationSize  = memReqs.size;
            memAlloc.memoryTypeIndex = vulkanDevice.getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
            Util.CheckResult(vkAllocateMemory(device, &memAlloc, null, out offscreenPass.depth.mem));
            Util.CheckResult(vkBindImageMemory(device, offscreenPass.depth.image, offscreenPass.depth.mem, 0));

            VkImageViewCreateInfo depthStencilView = Initializers.imageViewCreateInfo();

            depthStencilView.viewType                        = VK_IMAGE_VIEW_TYPE_2D;
            depthStencilView.format                          = fbDepthFormat;
            depthStencilView.flags                           = 0;
            depthStencilView.subresourceRange                = new VkImageSubresourceRange();
            depthStencilView.subresourceRange.aspectMask     = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
            depthStencilView.subresourceRange.baseMipLevel   = 0;
            depthStencilView.subresourceRange.levelCount     = 1;
            depthStencilView.subresourceRange.baseArrayLayer = 0;
            depthStencilView.subresourceRange.layerCount     = 1;
            depthStencilView.image                           = offscreenPass.depth.image;
            Util.CheckResult(vkCreateImageView(device, &depthStencilView, null, out offscreenPass.depth.view));

            // Create a separate render pass for the offscreen rendering as it may differ from the one used for scene rendering

            FixedArray2 <VkAttachmentDescription> attchmentDescriptions = new FixedArray2 <VkAttachmentDescription>();

            // Color attachment
            attchmentDescriptions.First.format         = FB_COLOR_FORMAT;
            attchmentDescriptions.First.samples        = VK_SAMPLE_COUNT_1_BIT;
            attchmentDescriptions.First.loadOp         = VK_ATTACHMENT_LOAD_OP_CLEAR;
            attchmentDescriptions.First.storeOp        = VK_ATTACHMENT_STORE_OP_STORE;
            attchmentDescriptions.First.stencilLoadOp  = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
            attchmentDescriptions.First.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
            attchmentDescriptions.First.initialLayout  = VK_IMAGE_LAYOUT_UNDEFINED;
            attchmentDescriptions.First.finalLayout    = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
            // Depth attachment
            attchmentDescriptions.Second.format         = fbDepthFormat;
            attchmentDescriptions.Second.samples        = VK_SAMPLE_COUNT_1_BIT;
            attchmentDescriptions.Second.loadOp         = VK_ATTACHMENT_LOAD_OP_CLEAR;
            attchmentDescriptions.Second.storeOp        = VK_ATTACHMENT_STORE_OP_DONT_CARE;
            attchmentDescriptions.Second.stencilLoadOp  = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
            attchmentDescriptions.Second.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
            attchmentDescriptions.Second.initialLayout  = VK_IMAGE_LAYOUT_UNDEFINED;
            attchmentDescriptions.Second.finalLayout    = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;

            VkAttachmentReference colorReference = new VkAttachmentReference {
                attachment = 0, layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
            };
            VkAttachmentReference depthReference = new VkAttachmentReference {
                attachment = 1, layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
            };

            VkSubpassDescription subpassDescription = new VkSubpassDescription();

            subpassDescription.pipelineBindPoint       = VK_PIPELINE_BIND_POINT_GRAPHICS;
            subpassDescription.colorAttachmentCount    = 1;
            subpassDescription.pColorAttachments       = &colorReference;
            subpassDescription.pDepthStencilAttachment = &depthReference;

            // Use subpass dependencies for layout transitions
            FixedArray2 <VkSubpassDependency> dependencies = new FixedArray2 <VkSubpassDependency>();

            dependencies.First.srcSubpass      = VK_SUBPASS_EXTERNAL;
            dependencies.First.dstSubpass      = 0;
            dependencies.First.srcStageMask    = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
            dependencies.First.dstStageMask    = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
            dependencies.First.srcAccessMask   = VK_ACCESS_MEMORY_READ_BIT;
            dependencies.First.dstAccessMask   = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
            dependencies.First.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;

            dependencies.Second.srcSubpass      = 0;
            dependencies.Second.dstSubpass      = VK_SUBPASS_EXTERNAL;
            dependencies.Second.srcStageMask    = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
            dependencies.Second.dstStageMask    = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
            dependencies.Second.srcAccessMask   = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
            dependencies.Second.dstAccessMask   = VK_ACCESS_MEMORY_READ_BIT;
            dependencies.Second.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;

            // Create the actual renderpass
            VkRenderPassCreateInfo renderPassInfo = VkRenderPassCreateInfo.New();

            renderPassInfo.attachmentCount = attchmentDescriptions.Count;
            renderPassInfo.pAttachments    = &attchmentDescriptions.First;
            renderPassInfo.subpassCount    = 1;
            renderPassInfo.pSubpasses      = &subpassDescription;
            renderPassInfo.dependencyCount = dependencies.Count;
            renderPassInfo.pDependencies   = &dependencies.First;

            Util.CheckResult(vkCreateRenderPass(device, &renderPassInfo, null, out offscreenPass.renderPass));

            FixedArray2 <VkImageView> attachments = new FixedArray2 <VkImageView>(offscreenPass.color.view, offscreenPass.depth.view);

            VkFramebufferCreateInfo fbufCreateInfo = Initializers.framebufferCreateInfo();

            fbufCreateInfo.renderPass      = offscreenPass.renderPass;
            fbufCreateInfo.attachmentCount = 2;
            fbufCreateInfo.pAttachments    = &attachments.First;
            fbufCreateInfo.width           = (uint)offscreenPass.width;
            fbufCreateInfo.height          = (uint)offscreenPass.height;
            fbufCreateInfo.layers          = 1;

            Util.CheckResult(vkCreateFramebuffer(device, &fbufCreateInfo, null, out offscreenPass.frameBuffer));

            // Fill a descriptor for later use in a descriptor set
            offscreenPass.descriptor.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
            offscreenPass.descriptor.imageView   = offscreenPass.color.view;
            offscreenPass.descriptor.sampler     = offscreenPass.sampler;
        }
示例#4
0
        void loadTextureArray(string filename, VkFormat format)
        {
            KtxFile tex2DArray;

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

            textureArray.width  = tex2DArray.Header.PixelWidth;
            textureArray.height = tex2DArray.Header.PixelHeight;
            layerCount          = tex2DArray.Header.NumberOfArrayElements;

            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 = tex2DArray.GetTotalSize();
            // This buffer is used as a transfer source for the buffer copy
            bufferCreateInfo.usage       = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
            bufferCreateInfo.sharingMode = VK_SHARING_MODE_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, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);

            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 = tex2DArray.GetAllTextureData();
            fixed(byte *texPtr = allTextureData)
            {
                Unsafe.CopyBlock(data, texPtr, (uint)allTextureData.Length);
            }

            vkUnmapMemory(device, stagingMemory);

            // Setup buffer copy regions for array layers
            NativeList <VkBufferImageCopy> bufferCopyRegions;
            IntPtr offset = IntPtr.Zero;

            for (uint layer = 0; layer < layerCount; layer++)
            {
                VkBufferImageCopy bufferCopyRegion = new VkBufferImageCopy();
                bufferCopyRegion.imageSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
                bufferCopyRegion.imageSubresource.mipLevel       = 0;
                bufferCopyRegion.imageSubresource.baseArrayLayer = layer;
                bufferCopyRegion.imageSubresource.layerCount     = 1;
                bufferCopyRegion.imageExtent.width  = (uint)(tex2DArray[layer][0].extent().x);
                bufferCopyRegion.imageExtent.height = (uint)(tex2DArray[layer][0].extent().y);
                bufferCopyRegion.imageExtent.depth  = 1;
                bufferCopyRegion.bufferOffset       = offset;

                bufferCopyRegions.push_back(bufferCopyRegion);

                // Increase offset into staging buffer for next level / face
                offset += tex2DArray[layer][0].Count;
            }

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

            imageCreateInfo.imageType     = VK_IMAGE_TYPE_2D;
            imageCreateInfo.format        = format;
            imageCreateInfo.mipLevels     = 1;
            imageCreateInfo.samples       = VK_SAMPLE_COUNT_1_BIT;
            imageCreateInfo.tiling        = VK_IMAGE_TILING_OPTIMAL;
            imageCreateInfo.usage         = VK_IMAGE_USAGE_SAMPLED_BIT;
            imageCreateInfo.sharingMode   = VK_SHARING_MODE_EXCLUSIVE;
            imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
            imageCreateInfo.extent        = new  { textureArray.width, textureArray.height, 1 };
            imageCreateInfo.usage         = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
            imageCreateInfo.arrayLayers   = layerCount;

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

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

            memAllocInfo.allocationSize  = memReqs.size;
            memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);

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

            VkCommandBuffer copyCmd = VulkanExampleBase::createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);

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

            subresourceRange.aspectMask   = VK_IMAGE_ASPECT_COLOR_BIT;
            subresourceRange.baseMipLevel = 0;
            subresourceRange.levelCount   = 1;
            subresourceRange.layerCount   = layerCount;

            vkstools::setImageLayout(
                copyCmd,
                textureArray.image,
                VK_IMAGE_ASPECT_COLOR_BIT,
                VK_IMAGE_LAYOUT_UNDEFINED,
                VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
                subresourceRange);

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

            // Change texture image layout to shader read after all faces have been copied
            textureArray.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
            vkstools::setImageLayout(
                copyCmd,
                textureArray.image,
                VK_IMAGE_ASPECT_COLOR_BIT,
                VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
                textureArray.imageLayout,
                subresourceRange);

            VulkanExampleBase::flushCommandBuffer(copyCmd, queue, true);

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

            sampler.magFilter     = VK_FILTER_LINEAR;
            sampler.minFilter     = VK_FILTER_LINEAR;
            sampler.mipmapMode    = VK_SAMPLER_MIPMAP_MODE_LINEAR;
            sampler.addressModeU  = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
            sampler.addressModeV  = sampler.addressModeU;
            sampler.addressModeW  = sampler.addressModeU;
            sampler.mipLodBias    = 0.0f;
            sampler.maxAnisotropy = 8;
            sampler.compareOp     = VK_COMPARE_OP_NEVER;
            sampler.minLod        = 0.0f;
            sampler.maxLod        = 0.0f;
            sampler.borderColor   = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
            Util.CheckResult(vkCreateSampler(device, &sampler, null, &textureArray.sampler));

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

            view.viewType                    = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
            view.format                      = format;
            view.components                  = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };