private unsafe VkImageView GetDepthStencilView() { if (!IsDepthStencil) { return(VkImageView.Null); } // Check that the format is supported //if (ComputeShaderResourceFormatFromDepthFormat(ViewFormat) == PixelFormat.None) // throw new NotSupportedException("Depth stencil format [{0}] not supported".ToFormat(ViewFormat)); // Create a Depth stencil view on this texture2D var createInfo = new VkImageViewCreateInfo { sType = VkStructureType.ImageViewCreateInfo, viewType = VkImageViewType.Image2D, format = NativeFormat, //VulkanConvertExtensions.ConvertPixelFormat(ViewFormat), image = NativeImage, components = VkComponentMapping.Identity, subresourceRange = new VkImageSubresourceRange(NativeImageAspect, 0, 1, 0, 1) }; //if (IsDepthStencilReadOnly) //{ // if (!IsDepthStencilReadOnlySupported(GraphicsDevice)) // throw new NotSupportedException("Cannot instantiate ReadOnly DepthStencilBuffer. Not supported on this device."); // // Create a Depth stencil view on this texture2D // createInfo.SubresourceRange.AspectMask = ? ; // if (HasStencil) // createInfo.Flags |= (int)AttachmentViewCreateFlags.AttachmentViewCreateReadOnlyStencilBit; //} vkCreateImageView(GraphicsDevice.NativeDevice, &createInfo, null, out var imageView); return(imageView); }
void CreateImageView(ImageViewCreateInfo mInfo) { VkImageViewCreateInfo info = new VkImageViewCreateInfo(); info.sType = VkStructureType.ImageViewCreateInfo; info.image = mInfo.image.Native; info.viewType = mInfo.viewType; info.format = mInfo.format; info.components = mInfo.components; info.subresourceRange = mInfo.subresourceRange; var result = Device.Commands.createImageView(Device.Native, ref info, Device.Instance.AllocationCallbacks, out imageView); if (result != VkResult.Success) { throw new ImageViewException(string.Format("Error creating image view: {0}", result)); } Image = mInfo.image; ViewType = mInfo.viewType; Format = mInfo.format; Components = mInfo.components; SubresourceRange = mInfo.subresourceRange; }
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 };
private unsafe void CreateBackBuffers() { // Create the texture object var backBufferDescription = new TextureDescription { ArraySize = 1, Dimension = TextureDimension.Texture2D, Height = Description.BackBufferHeight, Width = Description.BackBufferWidth, Depth = 1, Flags = TextureFlags.RenderTarget, Format = Description.BackBufferFormat, MipLevels = 1, MultisampleCount = MultisampleCount.None, Usage = GraphicsResourceUsage.Default }; backbuffer.InitializeWithoutResources(backBufferDescription); var createInfo = new VkImageViewCreateInfo { sType = VkStructureType.ImageViewCreateInfo, subresourceRange = new VkImageSubresourceRange(VkImageAspectFlags.Color, 0, 1, 0, 1), format = backbuffer.NativeFormat, viewType = VkImageViewType.Image2D, }; // We initialize swapchain images to PresentSource, since we swap them out while in this layout. backbuffer.NativeAccessMask = VkAccessFlags.MemoryRead; backbuffer.NativeLayout = VkImageLayout.PresentSrcKHR; var imageMemoryBarrier = new VkImageMemoryBarrier { sType = VkStructureType.ImageMemoryBarrier, subresourceRange = new VkImageSubresourceRange(VkImageAspectFlags.Color, 0, 1, 0, 1), oldLayout = VkImageLayout.Undefined, newLayout = VkImageLayout.PresentSrcKHR, srcAccessMask = VkAccessFlags.None, dstAccessMask = VkAccessFlags.MemoryRead }; var commandBufferAllocationInfo = new VkCommandBufferAllocateInfo { sType = VkStructureType.CommandBufferAllocateInfo, level = VkCommandBufferLevel.Primary, commandPool = GraphicsDevice.NativeCopyCommandPools.Value, commandBufferCount = 1 }; VkCommandBuffer commandBuffer; vkAllocateCommandBuffers(GraphicsDevice.NativeDevice, &commandBufferAllocationInfo, &commandBuffer); var beginInfo = new VkCommandBufferBeginInfo { sType = VkStructureType.CommandBufferBeginInfo }; vkBeginCommandBuffer(commandBuffer, &beginInfo); var buffers = vkGetSwapchainImagesKHR(GraphicsDevice.NativeDevice, swapChain); swapchainImages = new SwapChainImageInfo[buffers.Length]; for (int i = 0; i < buffers.Length; i++) { // Create image views swapchainImages[i].NativeImage = createInfo.image = buffers[i]; vkCreateImageView(GraphicsDevice.NativeDevice, &createInfo, null, out swapchainImages[i].NativeColorAttachmentView); // Transition to default layout imageMemoryBarrier.image = buffers[i]; vkCmdPipelineBarrier(commandBuffer, VkPipelineStageFlags.AllCommands, VkPipelineStageFlags.AllCommands, VkDependencyFlags.None, 0, null, 0, null, 1, &imageMemoryBarrier); } // Close and submit vkEndCommandBuffer(commandBuffer); var submitInfo = new VkSubmitInfo { sType = VkStructureType.SubmitInfo, commandBufferCount = 1, pCommandBuffers = &commandBuffer, }; lock (GraphicsDevice.QueueLock) { vkQueueSubmit(GraphicsDevice.NativeCommandQueue, 1, &submitInfo, VkFence.Null); vkQueueWaitIdle(GraphicsDevice.NativeCommandQueue); } vkFreeCommandBuffers(GraphicsDevice.NativeDevice, GraphicsDevice.NativeCopyCommandPools.Value, 1, &commandBuffer); // Get next image vkAcquireNextImageKHR(GraphicsDevice.NativeDevice, swapChain, ulong.MaxValue, GraphicsDevice.GetNextPresentSemaphore(), VkFence.Null, out currentBufferIndex); // Apply the first swap chain image to the texture backbuffer.SetNativeHandles(swapchainImages[currentBufferIndex].NativeImage, swapchainImages[currentBufferIndex].NativeColorAttachmentView); }
private unsafe VkImageView GetImageView(ViewType viewType, int arrayOrDepthSlice, int mipIndex) { if (!IsShaderResource) { return(VkImageView.Null); } if (viewType == ViewType.MipBand) { throw new NotSupportedException("ViewSlice.MipBand is not supported for render targets"); } int arrayOrDepthCount; int mipCount; GetViewSliceBounds(viewType, ref arrayOrDepthSlice, ref mipIndex, out arrayOrDepthCount, out mipCount); var layerCount = Dimension == TextureDimension.Texture3D ? 1 : arrayOrDepthCount; var createInfo = new VkImageViewCreateInfo { sType = VkStructureType.ImageViewCreateInfo, format = NativeFormat, //VulkanConvertExtensions.ConvertPixelFormat(ViewFormat), image = NativeImage, components = VkComponentMapping.Identity, subresourceRange = new VkImageSubresourceRange(IsDepthStencil ? VkImageAspectFlags.Depth : VkImageAspectFlags.Color, (uint)mipIndex, (uint)mipCount, (uint)arrayOrDepthSlice, (uint)layerCount) // TODO VULKAN: Select between depth and stencil? }; if (IsMultisample) { throw new NotImplementedException(); } if (this.ArraySize > 1) { if (IsMultisample && Dimension != TextureDimension.Texture2D) { throw new NotSupportedException("Multisample is only supported for 2D Textures"); } if (Dimension == TextureDimension.Texture3D) { throw new NotSupportedException("Texture Array is not supported for Texture3D"); } switch (Dimension) { case TextureDimension.Texture1D: createInfo.viewType = VkImageViewType.Image1DArray; break; case TextureDimension.Texture2D: createInfo.viewType = VkImageViewType.Image2DArray; break; case TextureDimension.TextureCube: if (ArraySize % 6 != 0) { throw new NotSupportedException("Texture cubes require an ArraySize which is a multiple of 6"); } createInfo.viewType = ArraySize > 6 ? VkImageViewType.ImageCubeArray : VkImageViewType.ImageCube; break; } } else { if (IsMultisample && Dimension != TextureDimension.Texture2D) { throw new NotSupportedException("Multisample is only supported for 2D RenderTarget Textures"); } if (Dimension == TextureDimension.TextureCube) { throw new NotSupportedException("TextureCube dimension is expecting an arraysize > 1"); } switch (Dimension) { case TextureDimension.Texture1D: createInfo.viewType = VkImageViewType.Image1D; break; case TextureDimension.Texture2D: createInfo.viewType = VkImageViewType.Image2D; break; case TextureDimension.Texture3D: createInfo.viewType = VkImageViewType.Image3D; break; } } vkCreateImageView(GraphicsDevice.NativeDevice, &createInfo, null, out var imageView); return(imageView); }
public VkFramebuffer(VkGraphicsDevice gd, ref FramebufferDescription description, bool isPresented) : base(description.DepthTarget, description.ColorTargets) { _gd = gd; VkRenderPassCreateInfo renderPassCI = VkRenderPassCreateInfo.New(); StackList <VkAttachmentDescription> attachments = new StackList <VkAttachmentDescription>(); uint colorAttachmentCount = (uint)ColorTargets.Count; StackList <VkAttachmentReference> colorAttachmentRefs = new StackList <VkAttachmentReference>(); for (int i = 0; i < colorAttachmentCount; i++) { VkTexture vkColorTex = Util.AssertSubtype <Texture, VkTexture>(ColorTargets[i].Target); VkAttachmentDescription colorAttachmentDesc = new VkAttachmentDescription(); colorAttachmentDesc.format = vkColorTex.VkFormat; colorAttachmentDesc.samples = vkColorTex.VkSampleCount; colorAttachmentDesc.loadOp = VkAttachmentLoadOp.DontCare; colorAttachmentDesc.storeOp = VkAttachmentStoreOp.Store; colorAttachmentDesc.stencilLoadOp = VkAttachmentLoadOp.DontCare; colorAttachmentDesc.stencilStoreOp = VkAttachmentStoreOp.DontCare; colorAttachmentDesc.initialLayout = VkImageLayout.Undefined; colorAttachmentDesc.finalLayout = VkImageLayout.ColorAttachmentOptimal; attachments.Add(colorAttachmentDesc); VkAttachmentReference colorAttachmentRef = new VkAttachmentReference(); colorAttachmentRef.attachment = (uint)i; colorAttachmentRef.layout = VkImageLayout.ColorAttachmentOptimal; colorAttachmentRefs.Add(colorAttachmentRef); } VkAttachmentDescription depthAttachmentDesc = new VkAttachmentDescription(); VkAttachmentReference depthAttachmentRef = new VkAttachmentReference(); if (DepthTarget != null) { VkTexture vkDepthTex = Util.AssertSubtype <Texture, VkTexture>(DepthTarget.Value.Target); bool hasStencil = FormatHelpers.IsStencilFormat(vkDepthTex.Format); depthAttachmentDesc.format = vkDepthTex.VkFormat; depthAttachmentDesc.samples = vkDepthTex.VkSampleCount; depthAttachmentDesc.loadOp = VkAttachmentLoadOp.DontCare; depthAttachmentDesc.storeOp = VkAttachmentStoreOp.Store; depthAttachmentDesc.stencilLoadOp = VkAttachmentLoadOp.DontCare; depthAttachmentDesc.stencilStoreOp = hasStencil ? VkAttachmentStoreOp.Store : VkAttachmentStoreOp.DontCare; depthAttachmentDesc.initialLayout = VkImageLayout.Undefined; depthAttachmentDesc.finalLayout = VkImageLayout.DepthStencilAttachmentOptimal; depthAttachmentRef.attachment = (uint)description.ColorTargets.Length; depthAttachmentRef.layout = VkImageLayout.DepthStencilAttachmentOptimal; } VkSubpassDescription subpass = new VkSubpassDescription(); subpass.pipelineBindPoint = VkPipelineBindPoint.Graphics; if (ColorTargets.Count > 0) { subpass.colorAttachmentCount = colorAttachmentCount; subpass.pColorAttachments = (VkAttachmentReference *)colorAttachmentRefs.Data; } if (DepthTarget != null) { subpass.pDepthStencilAttachment = &depthAttachmentRef; attachments.Add(depthAttachmentDesc); } VkSubpassDependency subpassDependency = new VkSubpassDependency(); subpassDependency.srcSubpass = SubpassExternal; subpassDependency.srcStageMask = VkPipelineStageFlags.ColorAttachmentOutput; subpassDependency.dstStageMask = VkPipelineStageFlags.ColorAttachmentOutput; subpassDependency.dstAccessMask = VkAccessFlags.ColorAttachmentRead | VkAccessFlags.ColorAttachmentWrite; if (DepthTarget != null) { subpassDependency.dstAccessMask |= VkAccessFlags.DepthStencilAttachmentRead | VkAccessFlags.DepthStencilAttachmentWrite; } renderPassCI.attachmentCount = attachments.Count; renderPassCI.pAttachments = (VkAttachmentDescription *)attachments.Data; renderPassCI.subpassCount = 1; renderPassCI.pSubpasses = &subpass; renderPassCI.dependencyCount = 1; renderPassCI.pDependencies = &subpassDependency; VkResult creationResult = vkCreateRenderPass(_gd.Device, ref renderPassCI, null, out _renderPassNoClear); CheckResult(creationResult); for (int i = 0; i < colorAttachmentCount; i++) { attachments[i].loadOp = VkAttachmentLoadOp.Load; attachments[i].initialLayout = VkImageLayout.ColorAttachmentOptimal; } if (DepthTarget != null) { attachments[attachments.Count - 1].loadOp = VkAttachmentLoadOp.Load; attachments[attachments.Count - 1].initialLayout = VkImageLayout.DepthStencilAttachmentOptimal; bool hasStencil = FormatHelpers.IsStencilFormat(DepthTarget.Value.Target.Format); if (hasStencil) { attachments[attachments.Count - 1].stencilLoadOp = VkAttachmentLoadOp.Load; } } creationResult = vkCreateRenderPass(_gd.Device, ref renderPassCI, null, out _renderPassNoClearLoad); CheckResult(creationResult); // Load version if (DepthTarget != null) { attachments[attachments.Count - 1].loadOp = VkAttachmentLoadOp.Clear; attachments[attachments.Count - 1].initialLayout = VkImageLayout.Undefined; bool hasStencil = FormatHelpers.IsStencilFormat(DepthTarget.Value.Target.Format); if (hasStencil) { attachments[attachments.Count - 1].stencilLoadOp = VkAttachmentLoadOp.Clear; } } for (int i = 0; i < colorAttachmentCount; i++) { attachments[i].loadOp = VkAttachmentLoadOp.Clear; attachments[i].initialLayout = VkImageLayout.Undefined; } creationResult = vkCreateRenderPass(_gd.Device, ref renderPassCI, null, out _renderPassClear); CheckResult(creationResult); VkFramebufferCreateInfo fbCI = VkFramebufferCreateInfo.New(); uint fbAttachmentsCount = (uint)description.ColorTargets.Length; if (description.DepthTarget != null) { fbAttachmentsCount += 1; } VkImageView *fbAttachments = stackalloc VkImageView[(int)fbAttachmentsCount]; for (int i = 0; i < colorAttachmentCount; i++) { VkTexture vkColorTarget = Util.AssertSubtype <Texture, VkTexture>(description.ColorTargets[i].Target); VkImageViewCreateInfo imageViewCI = VkImageViewCreateInfo.New(); imageViewCI.image = vkColorTarget.OptimalDeviceImage; imageViewCI.format = vkColorTarget.VkFormat; imageViewCI.viewType = VkImageViewType.Image2D; imageViewCI.subresourceRange = new VkImageSubresourceRange( VkImageAspectFlags.Color, description.ColorTargets[i].MipLevel, 1, description.ColorTargets[i].ArrayLayer, 1); VkImageView *dest = (fbAttachments + i); VkResult result = vkCreateImageView(_gd.Device, ref imageViewCI, null, dest); CheckResult(result); _attachmentViews.Add(*dest); } // Depth if (description.DepthTarget != null) { VkTexture vkDepthTarget = Util.AssertSubtype <Texture, VkTexture>(description.DepthTarget.Value.Target); bool hasStencil = FormatHelpers.IsStencilFormat(vkDepthTarget.Format); VkImageViewCreateInfo depthViewCI = VkImageViewCreateInfo.New(); depthViewCI.image = vkDepthTarget.OptimalDeviceImage; depthViewCI.format = vkDepthTarget.VkFormat; depthViewCI.viewType = description.DepthTarget.Value.Target.ArrayLayers == 1 ? VkImageViewType.Image2D : VkImageViewType.Image2DArray; depthViewCI.subresourceRange = new VkImageSubresourceRange( hasStencil ? VkImageAspectFlags.Depth | VkImageAspectFlags.Stencil : VkImageAspectFlags.Depth, description.DepthTarget.Value.MipLevel, 1, description.DepthTarget.Value.ArrayLayer, 1); VkImageView *dest = (fbAttachments + (fbAttachmentsCount - 1)); VkResult result = vkCreateImageView(_gd.Device, ref depthViewCI, null, dest); CheckResult(result); _attachmentViews.Add(*dest); } Texture dimTex; uint mipLevel; if (ColorTargets.Count > 0) { dimTex = ColorTargets[0].Target; mipLevel = ColorTargets[0].MipLevel; } else { Debug.Assert(DepthTarget != null); dimTex = DepthTarget.Value.Target; mipLevel = DepthTarget.Value.MipLevel; } Util.GetMipDimensions( dimTex, mipLevel, out uint mipWidth, out uint mipHeight, out _); fbCI.width = mipWidth; fbCI.height = mipHeight; fbCI.attachmentCount = fbAttachmentsCount; fbCI.pAttachments = fbAttachments; fbCI.layers = 1; fbCI.renderPass = _renderPassNoClear; creationResult = vkCreateFramebuffer(_gd.Device, ref fbCI, null, out _deviceFramebuffer); CheckResult(creationResult); if (DepthTarget != null) { AttachmentCount += 1; } AttachmentCount += (uint)ColorTargets.Count; }
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); }
public static extern VkResult CreateImageView( VkDevice device, ref VkImageViewCreateInfo pCreateInfo, IntPtr pAllocator, out VkImageView pView );
public void SetData(byte[] data) { buffer = new Buffer(NativeDevice, new() { BufferFlags = BufferFlags.ShaderResource, SizeInBytes = Size, ByteStride = Size, Usage = ResourceUsage.CPU_To_GPU }); buffer.SetData(data); CommandBuffer cmd = new(NativeDevice, CommandBufferType.AsyncTransfer); cmd.BeginOneTimeSubmit(); VkImageSubresourceRange subresource_range = new(VkImageAspectFlags.Color, 0, (uint)MipLevels, 0, 1); VkImageMemoryBarrier memory_barrier = new() { sType = VkStructureType.ImageMemoryBarrier, pNext = null, image = handle, subresourceRange = subresource_range, srcAccessMask = VkAccessFlags.None, dstAccessMask = VkAccessFlags.TransferWrite, oldLayout = VkImageLayout.Undefined, newLayout = VkImageLayout.TransferDstOptimal, srcQueueFamilyIndex = QueueFamilyIgnored, dstQueueFamilyIndex = QueueFamilyIgnored }; cmd.PipelineBarrier(VkPipelineStageFlags.TopOfPipe, VkPipelineStageFlags.Transfer, VkDependencyFlags.None, 0, null, 0, null, memory_barrier); uint num_blits = (uint)1; int offset = 0; VkBufferImageCopy *blits = stackalloc VkBufferImageCopy[MipLevels]; // Setup buffer copy regions for each mip level. for (uint i = 0; i < num_blits; i++) { blits[i] = new() { imageSubresource = new(VkImageAspectFlags.Color, i, 0, 1), imageExtent = new(Width, Height, 1), bufferOffset = (ulong)offset }; offset += Size; } cmd.copy_buffer_to_image(handle, buffer.handle, num_blits, blits, VkImageLayout.TransferDstOptimal); VkImageMemoryBarrier memory_barrier_read = new() { sType = VkStructureType.ImageMemoryBarrier, pNext = null, image = handle, subresourceRange = subresource_range, srcAccessMask = VkAccessFlags.TransferWrite, dstAccessMask = VkAccessFlags.ShaderRead, oldLayout = VkImageLayout.TransferDstOptimal, newLayout = VkImageLayout.ShaderReadOnlyOptimal, srcQueueFamilyIndex = QueueFamilyIgnored, dstQueueFamilyIndex = QueueFamilyIgnored }; cmd.PipelineBarrier(VkPipelineStageFlags.Transfer, VkPipelineStageFlags.FragmentShader, VkDependencyFlags.None, 0, null, 0, null, memory_barrier_read); cmd.End(); Fence fence = new Fence(NativeDevice); NativeDevice.Submit(cmd, fence); fence.Wait(); //if (fence.IsSignaled) // Cleanup staging resources. fence.Dispose(); vkFreeMemory(NativeDevice.handle, buffer_memory, null); vkDestroyBuffer(NativeDevice.handle, buffer.handle, null); } public void Image2D() { buffer = new Buffer(NativeDevice, new() { BufferFlags = BufferFlags.ShaderResource, SizeInBytes = Size, ByteStride = Size, Usage = ResourceUsage.CPU_To_GPU }); buffer.SetData(Data); CommandBuffer cmd = new(NativeDevice, CommandBufferType.AsyncTransfer); cmd.BeginOneTimeSubmit(); VkImageSubresourceRange subresource_range = new(VkImageAspectFlags.Color, 0, (uint)MipLevels, 0, 1); VkImageMemoryBarrier memory_barrier = new() { sType = VkStructureType.ImageMemoryBarrier, pNext = null, image = handle, subresourceRange = subresource_range, srcAccessMask = VkAccessFlags.None, dstAccessMask = VkAccessFlags.TransferWrite, oldLayout = VkImageLayout.Undefined, newLayout = VkImageLayout.TransferDstOptimal, srcQueueFamilyIndex = QueueFamilyIgnored, dstQueueFamilyIndex = QueueFamilyIgnored }; cmd.PipelineBarrier(VkPipelineStageFlags.TopOfPipe, VkPipelineStageFlags.Transfer, VkDependencyFlags.None, 0, null, 0, null, memory_barrier); uint num_blits = (uint)1; int offset = 0; VkBufferImageCopy *blits = stackalloc VkBufferImageCopy[MipLevels]; // Setup buffer copy regions for each mip level. for (uint i = 0; i < num_blits; i++) { blits[i] = new() { imageSubresource = new(VkImageAspectFlags.Color, i, 0, 1), imageExtent = new(Width, Height, 1), bufferOffset = (ulong)offset }; offset += Size; } cmd.copy_buffer_to_image(handle, buffer.handle, num_blits, blits, VkImageLayout.TransferDstOptimal); VkImageMemoryBarrier memory_barrier_read = new() { sType = VkStructureType.ImageMemoryBarrier, pNext = null, image = handle, subresourceRange = subresource_range, srcAccessMask = VkAccessFlags.TransferWrite, dstAccessMask = VkAccessFlags.ShaderRead, oldLayout = VkImageLayout.TransferDstOptimal, newLayout = VkImageLayout.ShaderReadOnlyOptimal, srcQueueFamilyIndex = QueueFamilyIgnored, dstQueueFamilyIndex = QueueFamilyIgnored }; cmd.PipelineBarrier(VkPipelineStageFlags.Transfer, VkPipelineStageFlags.FragmentShader, VkDependencyFlags.None, 0, null, 0, null, memory_barrier_read); cmd.End(); Fence fence = new Fence(NativeDevice); NativeDevice.Submit(cmd, fence); fence.Wait(); //if (fence.IsSignaled) // Cleanup staging resources. fence.Dispose(); vkFreeMemory(NativeDevice.handle, buffer_memory, null); vkDestroyBuffer(NativeDevice.handle, buffer.handle, null); } internal VkImageView get_depth_stencil_view() { if (!IsDepthStencil) { return(VkImageView.Null); } // Create a Depth stencil view on this texture2D VkImageViewCreateInfo createInfo = new VkImageViewCreateInfo { sType = VkStructureType.ImageViewCreateInfo, flags = VkImageViewCreateFlags.None, pNext = null, viewType = VkImageViewType.Image2D, format = Format, image = handle, components = VkComponentMapping.Identity, subresourceRange = new VkImageSubresourceRange(VkImageAspectFlags.Depth | VkImageAspectFlags.Stencil, 0, 1, 0, 1) }; vkCreateImageView(NativeDevice.handle, &createInfo, null, out VkImageView _view).CheckResult(); return(_view); } internal VkImageView get_image_view() { if (!IsShaderResource) { return(VkImageView.Null); } // Create image view. VkImageViewCreateInfo imageViewCreateInfo = new VkImageViewCreateInfo() { sType = VkStructureType.ImageViewCreateInfo, image = handle, viewType = VkImageViewType.Image2D, format = Format, subresourceRange = new VkImageSubresourceRange(VkImageAspectFlags.Color, 0, 1, 0, 1), // TODO: MipMaps }; vkCreateImageView(NativeDevice.handle, &imageViewCreateInfo, null, out var _view); return(_view); }
public static VulkanImage DepthStencil(VulkanContext device, int width, int height) { VkFormat[] validFormats = { VkFormat.D32SFloatS8UInt, VkFormat.D32SFloat, VkFormat.D24UNormS8UInt, VkFormat.D16UNormS8UInt, VkFormat.D16UNorm }; VkFormat?potentialFormat = validFormats.FirstOrDefault( validFormat => { VkFormatProperties formatProps; vkGetPhysicalDeviceFormatProperties(device.PhysicalDevice, validFormat, out formatProps); return((formatProps.optimalTilingFeatures & VkFormatFeatureFlags.DepthStencilAttachment) > 0); }); if (!potentialFormat.HasValue) { throw new InvalidOperationException("Required depth stencil format not supported."); } VkFormat format = potentialFormat.Value; VkImageCreateInfo imageCreateInfo = new VkImageCreateInfo { sType = VkStructureType.ImageCreateInfo, pNext = null, imageType = VkImageType.Image2D, format = format, extent = new Vortice.Mathematics.Size3 { Width = width, Height = height, Depth = 1 }, mipLevels = 1, arrayLayers = 1, samples = VkSampleCountFlags.Count1, tiling = VkImageTiling.Optimal, usage = VkImageUsageFlags.DepthStencilAttachment | VkImageUsageFlags.TransferSrc }; VkImage image; VkResult result = vkCreateImage(device.Device, &imageCreateInfo, null, out image); result.CheckResult(); VkMemoryRequirements memReq; vkGetImageMemoryRequirements(device.Device, image, out memReq); vkGetPhysicalDeviceMemoryProperties(device.PhysicalDevice, out VkPhysicalDeviceMemoryProperties memoryProperties); uint heapIndex = BufferHelper.GetMemoryTypeIndex(memReq.memoryTypeBits, VkMemoryPropertyFlags.DeviceLocal, memoryProperties); VkMemoryAllocateInfo memAllocInfo = new VkMemoryAllocateInfo() { sType = VkStructureType.MemoryAllocateInfo, pNext = null, allocationSize = memReq.size, memoryTypeIndex = heapIndex }; VkDeviceMemory memory; result = vkAllocateMemory(device.Device, &memAllocInfo, null, &memory); result.CheckResult(); result = vkBindImageMemory(device.Device, image, memory, 0); result.CheckResult(); VkImageViewCreateInfo imageViewCreateInfo = new VkImageViewCreateInfo { sType = VkStructureType.ImageViewCreateInfo, pNext = null, format = format, subresourceRange = new VkImageSubresourceRange(VkImageAspectFlags.Depth | VkImageAspectFlags.Stencil, 0, 1, 0, 1), image = image, viewType = VkImageViewType.Image2D }; VkImageView view; result = vkCreateImageView(device.Device, &imageViewCreateInfo, null, out view); result.CheckResult(); return(new VulkanImage(device, image, memory, view, format)); }
// 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 var imageInfo = VkImageCreateInfo.Alloc(); imageInfo->imageType = VkImageType._2d;// VK_IMAGE_TYPE_2D; imageInfo->format = FB_COLOR_FORMAT; imageInfo->extent.width = (uint)offscreenPass.width; imageInfo->extent.height = (uint)offscreenPass.height; imageInfo->extent.depth = 1; imageInfo->mipLevels = 1; imageInfo->arrayLayers = 1; imageInfo->samples = VkSampleCountFlagBits._1; // VK_SAMPLE_COUNT_1_BIT; imageInfo->tiling = VkImageTiling.Optimal; // VK_IMAGE_TILING_OPTIMAL; // We will sample directly from the color attachment imageInfo->usage = VkImageUsageFlagBits.ColorAttachment | VkImageUsageFlagBits.Sampled; //VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; var memAlloc = VkMemoryAllocateInfo.Alloc(); VkMemoryRequirements memReqs; { VkImage image; vkCreateImage(device, imageInfo, null, &image); offscreenPass.colorAttachment.image = image; } vkGetImageMemoryRequirements(device, offscreenPass.colorAttachment.image, &memReqs); memAlloc->allocationSize = memReqs.size; memAlloc->memoryTypeIndex = vulkanDevice.getMemoryType(memReqs.memoryTypeBits, VkMemoryPropertyFlagBits.DeviceLocal); //VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); { VkDeviceMemory memory; vkAllocateMemory(device, memAlloc, null, &memory); offscreenPass.colorAttachment.mem = memory; } vkBindImageMemory(device, offscreenPass.colorAttachment.image, offscreenPass.colorAttachment.mem, 0); var colorViewInfo = VkImageViewCreateInfo.Alloc(); colorViewInfo->viewType = VkImageViewType._2d;// VK_IMAGE_VIEW_TYPE_2D; colorViewInfo->format = FB_COLOR_FORMAT; colorViewInfo->subresourceRange = new VkImageSubresourceRange(); colorViewInfo->subresourceRange.aspectMask = VkImageAspectFlagBits.Color;// VK_IMAGE_ASPECT_COLOR_BIT; colorViewInfo->subresourceRange.baseMipLevel = 0; colorViewInfo->subresourceRange.levelCount = 1; colorViewInfo->subresourceRange.baseArrayLayer = 0; colorViewInfo->subresourceRange.layerCount = 1; colorViewInfo->image = offscreenPass.colorAttachment.image; { VkImageView view; vkCreateImageView(device, colorViewInfo, null, &view); offscreenPass.colorAttachment.view = view; } // Create sampler to sample from the attachment in the fragment shader var samplerInfo = VkSamplerCreateInfo.Alloc(); samplerInfo->magFilter = VkFilter.Linear; // VK_FILTER_LINEAR; samplerInfo->minFilter = VkFilter.Linear; // VK_FILTER_LINEAR; samplerInfo->mipmapMode = VkSamplerMipmapMode.Linear; // VK_SAMPLER_MIPMAP_MODE_LINEAR; samplerInfo->addressModeU = VkSamplerAddressMode.ClampToEdge; // 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 = VkBorderColor.FloatOpaqueWhite;// VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; { VkSampler sampler; vkCreateSampler(device, samplerInfo, null, &sampler); offscreenPass.sampler = sampler; } // Depth stencil attachment imageInfo->format = fbDepthFormat; imageInfo->usage = VkImageUsageFlagBits.DepthStencilAttachment;// VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; { VkImage image; vkCreateImage(device, imageInfo, null, &image); offscreenPass.depthAttachment.image = image; } vkGetImageMemoryRequirements(device, offscreenPass.depthAttachment.image, &memReqs); memAlloc->allocationSize = memReqs.size; memAlloc->memoryTypeIndex = vulkanDevice.getMemoryType(memReqs.memoryTypeBits, VkMemoryPropertyFlagBits.DeviceLocal); //VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); { VkDeviceMemory memory; vkAllocateMemory(device, memAlloc, null, &memory); offscreenPass.depthAttachment.mem = memory; } vkBindImageMemory(device, offscreenPass.depthAttachment.image, offscreenPass.depthAttachment.mem, 0); var depthViewInfo = VkImageViewCreateInfo.Alloc(); depthViewInfo->viewType = VkImageViewType._2d;// VK_IMAGE_VIEW_TYPE_2D; depthViewInfo->format = fbDepthFormat; depthViewInfo->flags = 0; depthViewInfo->subresourceRange = new VkImageSubresourceRange(); depthViewInfo->subresourceRange.aspectMask = VkImageAspectFlagBits.Depth | VkImageAspectFlagBits.Stencil; //VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; depthViewInfo->subresourceRange.baseMipLevel = 0; depthViewInfo->subresourceRange.levelCount = 1; depthViewInfo->subresourceRange.baseArrayLayer = 0; depthViewInfo->subresourceRange.layerCount = 1; depthViewInfo->image = offscreenPass.depthAttachment.image; { VkImageView view; vkCreateImageView(device, depthViewInfo, null, &view); offscreenPass.depthAttachment.view = view; } // Create a separate render pass for the offscreen rendering as it may differ from the one used for scene rendering var attchmentDescriptions = new VkAttachmentDescription[2]; // Color attachment attchmentDescriptions[0].format = FB_COLOR_FORMAT; attchmentDescriptions[0].samples = VkSampleCountFlagBits._1; // VK_SAMPLE_COUNT_1_BIT; attchmentDescriptions[0].loadOp = VkAttachmentLoadOp.Clear; // VK_ATTACHMENT_LOAD_OP_CLEAR; attchmentDescriptions[0].storeOp = VkAttachmentStoreOp.Store; // VK_ATTACHMENT_STORE_OP_STORE; attchmentDescriptions[0].stencilLoadOp = VkAttachmentLoadOp.DontCare; // VK_ATTACHMENT_LOAD_OP_DONT_CARE; attchmentDescriptions[0].stencilStoreOp = VkAttachmentStoreOp.DontCare; // VK_ATTACHMENT_STORE_OP_DONT_CARE; attchmentDescriptions[0].initialLayout = VkImageLayout.Undefined; // VK_IMAGE_LAYOUT_UNDEFINED; attchmentDescriptions[0].finalLayout = VkImageLayout.ShaderReadOnlyOptimal; // VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; // Depth attachment attchmentDescriptions[1].format = fbDepthFormat; attchmentDescriptions[1].samples = VkSampleCountFlagBits._1; // VK_SAMPLE_COUNT_1_BIT; attchmentDescriptions[1].loadOp = VkAttachmentLoadOp.Clear; // VK_ATTACHMENT_LOAD_OP_CLEAR; attchmentDescriptions[1].storeOp = VkAttachmentStoreOp.DontCare; // VK_ATTACHMENT_STORE_OP_DONT_CARE; attchmentDescriptions[1].stencilLoadOp = VkAttachmentLoadOp.DontCare; // VK_ATTACHMENT_LOAD_OP_DONT_CARE; attchmentDescriptions[1].stencilStoreOp = VkAttachmentStoreOp.DontCare; // VK_ATTACHMENT_STORE_OP_DONT_CARE; attchmentDescriptions[1].initialLayout = VkImageLayout.Undefined; // VK_IMAGE_LAYOUT_UNDEFINED; attchmentDescriptions[1].finalLayout = VkImageLayout.DepthStencilAttachmentOptimal; // VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; var colorReference = new VkAttachmentReference { attachment = 0, layout = VkImageLayout.ColorAttachmentOptimal// VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; var depthReference = new VkAttachmentReference { attachment = 1, layout = VkImageLayout.DepthStencilAttachmentOptimal// VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL }; VkSubpassDescription subpassDescription = new VkSubpassDescription(); subpassDescription.pipelineBindPoint = VkPipelineBindPoint.Graphics;// VK_PIPELINE_BIND_POINT_GRAPHICS; subpassDescription.colorResolveAttachments.SetColorAttachments(colorReference); subpassDescription.pDepthStencilAttachment = &depthReference; // Use subpass dependencies for layout transitions var dependencies = new VkSubpassDependency[2]; dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL; dependencies[0].dstSubpass = 0; dependencies[0].srcStageMask = VkPipelineStageFlagBits.BottomOfPipe; // VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; dependencies[0].dstStageMask = VkPipelineStageFlagBits.ColorAttachmentOutput; // VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; dependencies[0].srcAccessMask = VkAccessFlagBits.MemoryRead; // VK_ACCESS_MEMORY_READ_BIT; dependencies[0].dstAccessMask = VkAccessFlagBits.ColorAttachmentRead | VkAccessFlagBits.ColorAttachmentWrite; //VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; dependencies[0].dependencyFlags = VkDependencyFlagBits.ByRegion;// VK_DEPENDENCY_BY_REGION_BIT; dependencies[1].srcSubpass = 0; dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL; dependencies[1].srcStageMask = VkPipelineStageFlagBits.ColorAttachmentOutput; // VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; dependencies[1].dstStageMask = VkPipelineStageFlagBits.BottomOfPipe; // VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; dependencies[1].srcAccessMask = VkAccessFlagBits.ColorAttachmentRead | VkAccessFlagBits.ColorAttachmentWrite; //VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; dependencies[1].dstAccessMask = VkAccessFlagBits.MemoryRead; // VK_ACCESS_MEMORY_READ_BIT; dependencies[1].dependencyFlags = VkDependencyFlagBits.ByRegion; // VK_DEPENDENCY_BY_REGION_BIT; // Create the actual renderpass var renderPassInfo = VkRenderPassCreateInfo.Alloc(); renderPassInfo->attachments = attchmentDescriptions; renderPassInfo->subpasses = subpassDescription; renderPassInfo->dependencies = dependencies; { VkRenderPass renderPass; vkCreateRenderPass(device, renderPassInfo, null, &renderPass); offscreenPass.renderPass = renderPass; } var attachments = new VkImageView[] { offscreenPass.colorAttachment.view, offscreenPass.depthAttachment.view }; var framebufferInfo = VkFramebufferCreateInfo.Alloc(); framebufferInfo->renderPass = offscreenPass.renderPass; framebufferInfo->attachments = attachments; framebufferInfo->width = (uint)offscreenPass.width; framebufferInfo->height = (uint)offscreenPass.height; framebufferInfo->layers = 1; { VkFramebuffer framebuffer; vkCreateFramebuffer(device, framebufferInfo, null, &framebuffer); offscreenPass.framebuffer = framebuffer; } // Fill a descriptor for later use in a descriptor set offscreenPass.descriptorImage.imageLayout = VkImageLayout.ShaderReadOnlyOptimal;// VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; offscreenPass.descriptorImage.imageView = offscreenPass.colorAttachment.view; offscreenPass.descriptorImage.sampler = offscreenPass.sampler; }
internal static VulkanImage Texture2D(VulkanContext ctx, TextureData tex2D) { ulong size = (ulong)tex2D.Mipmaps[0].Size; VkBuffer stagingBuffer; var bufferCreateInfo = new VkBufferCreateInfo { sType = VkStructureType.BufferCreateInfo, pNext = null, size = (ulong)tex2D.Mipmaps[0].Size, usage = VkBufferUsageFlags.TransferSrc }; vkCreateBuffer(ctx.Device, &bufferCreateInfo, null, out stagingBuffer); vkGetPhysicalDeviceMemoryProperties(ctx.PhysicalDevice, out VkPhysicalDeviceMemoryProperties memoryProperties); vkGetBufferMemoryRequirements(ctx.Device, stagingBuffer, out VkMemoryRequirements stagingMemReq); uint heapIndex = BufferHelper.GetMemoryTypeIndex(stagingMemReq.memoryTypeBits, VkMemoryPropertyFlags.HostVisible, memoryProperties); VkMemoryAllocateInfo memAllocInfo = new VkMemoryAllocateInfo() { sType = VkStructureType.MemoryAllocateInfo, pNext = null, allocationSize = stagingMemReq.size, memoryTypeIndex = heapIndex }; VkDeviceMemory stagingMemory; VkResult result = vkAllocateMemory(ctx.Device, &memAllocInfo, null, &stagingMemory); result.CheckResult(); result = vkBindBufferMemory(ctx.Device, stagingBuffer, stagingMemory, 0); result.CheckResult(); void *vertexPtr; result = vkMapMemory(ctx.Device, stagingMemory, 0, (ulong)tex2D.Mipmaps[0].Size, 0, &vertexPtr); result.CheckResult(); fixed(byte *dataPtr = &tex2D.Mipmaps[0].Data[0]) { Buffer.MemoryCopy(dataPtr, vertexPtr, size, size); } vkUnmapMemory(ctx.Device, stagingMemory); // Setup buffer copy regions for each mip level. var bufferCopyRegions = new VkBufferImageCopy[tex2D.Mipmaps.Length]; // TODO: stackalloc int offset = 0; for (int i = 0; i < bufferCopyRegions.Length; i++) { // TODO: from VulkanCore, doesn't look correct (reassigns bufferCopyRegions in each loop) bufferCopyRegions = new[] { new VkBufferImageCopy { imageSubresource = new VkImageSubresourceLayers(VkImageAspectFlags.Color, (uint)i, 0, 1), imageExtent = tex2D.Mipmaps[0].Extent, bufferOffset = (ulong)offset } }; offset += tex2D.Mipmaps[i].Size; } // Create optimal tiled target image. var createInfo = new VkImageCreateInfo { sType = VkStructureType.ImageCreateInfo, pNext = null, imageType = VkImageType.Image2D, format = tex2D.Format, mipLevels = (uint)tex2D.Mipmaps.Length, arrayLayers = 1, samples = VkSampleCountFlags.Count1, tiling = VkImageTiling.Optimal, sharingMode = VkSharingMode.Exclusive, initialLayout = VkImageLayout.Undefined, extent = tex2D.Mipmaps[0].Extent, usage = VkImageUsageFlags.Sampled | VkImageUsageFlags.TransferDst }; VkImage image; result = vkCreateImage(ctx.Device, &createInfo, null, out image); result.CheckResult(); VkMemoryRequirements imageMemReq; vkGetImageMemoryRequirements(ctx.Device, image, out imageMemReq); vkGetPhysicalDeviceMemoryProperties(ctx.PhysicalDevice, out VkPhysicalDeviceMemoryProperties imageMemoryProperties); uint imageHeapIndex = BufferHelper.GetMemoryTypeIndex(imageMemReq.memoryTypeBits, VkMemoryPropertyFlags.DeviceLocal, imageMemoryProperties); var allocInfo = new VkMemoryAllocateInfo { sType = VkStructureType.MemoryAllocateInfo, pNext = null, allocationSize = imageMemReq.size, memoryTypeIndex = imageHeapIndex, }; VkDeviceMemory memory; result = vkAllocateMemory(ctx.Device, &allocInfo, null, &memory); result.CheckResult(); result = vkBindImageMemory(ctx.Device, image, memory, 0); result.CheckResult(); var subresourceRange = new VkImageSubresourceRange(VkImageAspectFlags.Color, 0, (uint)tex2D.Mipmaps.Length, 0, 1); // Copy the data from staging buffers to device local buffers. var allocInfo2 = new VkCommandBufferAllocateInfo() { sType = VkStructureType.CommandBufferAllocateInfo, commandPool = ctx.GraphicsCommandPool, level = VkCommandBufferLevel.Primary, commandBufferCount = 1, }; VkCommandBuffer cmdBuffer; vkAllocateCommandBuffers(ctx.Device, &allocInfo2, &cmdBuffer); VkCommandBufferBeginInfo beginInfo = new VkCommandBufferBeginInfo() { sType = VkStructureType.CommandBufferBeginInfo, flags = VkCommandBufferUsageFlags.OneTimeSubmit, }; vkBeginCommandBuffer(cmdBuffer, &beginInfo); VkImageMemoryBarrier imageMemoryBarrier = new VkImageMemoryBarrier { sType = VkStructureType.ImageMemoryBarrier, pNext = null, image = image, subresourceRange = subresourceRange, srcAccessMask = 0, dstAccessMask = VkAccessFlags.TransferWrite, oldLayout = VkImageLayout.Undefined, newLayout = VkImageLayout.TransferDstOptimal, srcQueueFamilyIndex = QueueFamilyIgnored, dstQueueFamilyIndex = QueueFamilyIgnored }; vkCmdPipelineBarrier(cmdBuffer, VkPipelineStageFlags.TopOfPipe, VkPipelineStageFlags.Transfer, VkDependencyFlags.None, 0, null, 0, null, 1, &imageMemoryBarrier); fixed(VkBufferImageCopy *regionsPtr = bufferCopyRegions) { vkCmdCopyBufferToImage(cmdBuffer, stagingBuffer, image, VkImageLayout.TransferDstOptimal, (uint)bufferCopyRegions.Length, regionsPtr); } VkImageMemoryBarrier imageMemoryBarrier2 = new VkImageMemoryBarrier { sType = VkStructureType.ImageMemoryBarrier, pNext = null, image = image, subresourceRange = subresourceRange, srcAccessMask = VkAccessFlags.TransferWrite, dstAccessMask = VkAccessFlags.ShaderRead, oldLayout = VkImageLayout.TransferDstOptimal, newLayout = VkImageLayout.ShaderReadOnlyOptimal, srcQueueFamilyIndex = (uint)QueueFamilyIgnored, dstQueueFamilyIndex = (uint)QueueFamilyIgnored }; vkCmdPipelineBarrier(cmdBuffer, VkPipelineStageFlags.Transfer, VkPipelineStageFlags.FragmentShader, VkDependencyFlags.None, 0, null, 0, null, 1, &imageMemoryBarrier2); vkEndCommandBuffer(cmdBuffer); // Submit. VkFenceCreateInfo fenceCreateInfo = new VkFenceCreateInfo { sType = VkStructureType.FenceCreateInfo, pNext = null }; VkFence fence; result = vkCreateFence(ctx.Device, &fenceCreateInfo, null, out fence); result.CheckResult(); var submitInfo = new VkSubmitInfo { sType = VkStructureType.SubmitInfo, pNext = null, commandBufferCount = 1, pCommandBuffers = &cmdBuffer }; vkQueueSubmit(ctx.GraphicsQueue, submitInfo, fence); result = vkWaitForFences(ctx.Device, 1, &fence, false, ulong.MaxValue); result.CheckResult(); // Cleanup staging resources. vkDestroyFence(ctx.Device, fence, null); vkFreeMemory(ctx.Device, stagingMemory, null); vkDestroyBuffer(ctx.Device, stagingBuffer, null); // Create image view. VkImageViewCreateInfo imageViewCreateInfo = new VkImageViewCreateInfo() { sType = VkStructureType.ImageViewCreateInfo, image = image, viewType = VkImageViewType.Image2D, format = tex2D.Format, subresourceRange = subresourceRange }; VkImageView view; vkCreateImageView(ctx.Device, &imageViewCreateInfo, null, out view); return(new VulkanImage(ctx, image, memory, view, tex2D.Format)); }
public VkFramebuffer(VkGraphicsDevice gd, ref FramebufferDescription description) : base(description.DepthTarget, description.ColorTargets) { _gd = gd; VkRenderPassCreateInfo renderPassCI = VkRenderPassCreateInfo.New(); StackList <VkAttachmentDescription> attachments = new StackList <VkAttachmentDescription>(); uint colorAttachmentCount = (uint)ColorTextures.Count; StackList <VkAttachmentDescription> colorAttachmentDescriptions = new StackList <VkAttachmentDescription>(); StackList <VkAttachmentReference> colorAttachmentRefs = new StackList <VkAttachmentReference>(); for (int i = 0; i < colorAttachmentCount; i++) { VkTexture vkColorTex = Util.AssertSubtype <Texture, VkTexture>(ColorTextures[i]); VkAttachmentDescription colorAttachmentDesc = new VkAttachmentDescription(); colorAttachmentDesc.format = vkColorTex.VkFormat; colorAttachmentDesc.samples = VkSampleCountFlags.Count1; colorAttachmentDesc.loadOp = VkAttachmentLoadOp.DontCare; colorAttachmentDesc.storeOp = VkAttachmentStoreOp.Store; colorAttachmentDesc.stencilLoadOp = VkAttachmentLoadOp.DontCare; colorAttachmentDesc.stencilStoreOp = VkAttachmentStoreOp.DontCare; colorAttachmentDesc.initialLayout = VkImageLayout.Undefined; colorAttachmentDesc.finalLayout = VkImageLayout.PresentSrcKHR; colorAttachmentDescriptions.Add(colorAttachmentDesc); attachments.Add(colorAttachmentDesc); VkAttachmentReference colorAttachmentRef = new VkAttachmentReference(); colorAttachmentRef.attachment = (uint)i; colorAttachmentRef.layout = VkImageLayout.ColorAttachmentOptimal; colorAttachmentRefs.Add(colorAttachmentRef); } VkTexture vkDepthTex = Util.AssertSubtype <Texture, VkTexture>(DepthTexture); VkAttachmentDescription depthAttachmentDesc = new VkAttachmentDescription(); VkAttachmentReference depthAttachmentRef = new VkAttachmentReference(); if (vkDepthTex != null) { depthAttachmentDesc.format = vkDepthTex.VkFormat; depthAttachmentDesc.samples = VkSampleCountFlags.Count1; depthAttachmentDesc.loadOp = VkAttachmentLoadOp.DontCare; depthAttachmentDesc.storeOp = VkAttachmentStoreOp.Store; depthAttachmentDesc.stencilLoadOp = VkAttachmentLoadOp.DontCare; depthAttachmentDesc.stencilStoreOp = VkAttachmentStoreOp.DontCare; depthAttachmentDesc.initialLayout = VkImageLayout.Undefined; depthAttachmentDesc.finalLayout = VkImageLayout.ShaderReadOnlyOptimal; depthAttachmentRef.attachment = (uint)description.ColorTargets.Length; depthAttachmentRef.layout = VkImageLayout.DepthStencilAttachmentOptimal; } VkSubpassDescription subpass = new VkSubpassDescription(); subpass.pipelineBindPoint = VkPipelineBindPoint.Graphics; if (ColorTextures.Count > 0) { subpass.colorAttachmentCount = colorAttachmentCount; subpass.pColorAttachments = (VkAttachmentReference *)colorAttachmentRefs.Data; } if (DepthTexture != null) { subpass.pDepthStencilAttachment = &depthAttachmentRef; attachments.Add(depthAttachmentDesc); } VkSubpassDependency subpassDependency = new VkSubpassDependency(); subpassDependency.srcSubpass = SubpassExternal; subpassDependency.srcStageMask = VkPipelineStageFlags.ColorAttachmentOutput; subpassDependency.dstStageMask = VkPipelineStageFlags.ColorAttachmentOutput; subpassDependency.dstAccessMask = VkAccessFlags.ColorAttachmentRead | VkAccessFlags.ColorAttachmentWrite; if (DepthTexture != null) { subpassDependency.dstAccessMask |= VkAccessFlags.DepthStencilAttachmentRead | VkAccessFlags.DepthStencilAttachmentWrite; } renderPassCI.attachmentCount = attachments.Count; renderPassCI.pAttachments = (VkAttachmentDescription *)attachments.Data; renderPassCI.subpassCount = 1; renderPassCI.pSubpasses = &subpass; renderPassCI.dependencyCount = 1; renderPassCI.pDependencies = &subpassDependency; VkResult creationResult = vkCreateRenderPass(_gd.Device, ref renderPassCI, null, out _renderPass); CheckResult(creationResult); VkFramebufferCreateInfo fbCI = VkFramebufferCreateInfo.New(); uint fbAttachmentsCount = (uint)description.ColorTargets.Length; if (description.DepthTarget != null) { fbAttachmentsCount += 1; } VkImageView *fbAttachments = stackalloc VkImageView[(int)fbAttachmentsCount]; for (int i = 0; i < fbAttachmentsCount - 1; i++) { Texture colorTarget = description.ColorTargets[i]; VkTexture vkColorTarget = Util.AssertSubtype <Texture, VkTexture>(colorTarget); VkImageViewCreateInfo imageViewCI = VkImageViewCreateInfo.New(); imageViewCI.image = vkColorTarget.DeviceImage; imageViewCI.format = vkColorTarget.VkFormat; imageViewCI.viewType = VkImageViewType.Image2D; imageViewCI.subresourceRange = new VkImageSubresourceRange(VkImageAspectFlags.Color, 0, 1, 0, 1); VkImageView *dest = (fbAttachments + i); VkResult result = vkCreateImageView(_gd.Device, ref imageViewCI, null, dest); CheckResult(result); _attachmentViews.Add(*dest); } // Depth if (description.DepthTarget != null) { VkTexture vkDepthTarget = Util.AssertSubtype <Texture, VkTexture>(description.DepthTarget); VkImageViewCreateInfo depthViewCI = VkImageViewCreateInfo.New(); depthViewCI.image = vkDepthTarget.DeviceImage; depthViewCI.format = vkDepthTarget.VkFormat; depthViewCI.viewType = VkImageViewType.Image2D; depthViewCI.subresourceRange = new VkImageSubresourceRange(VkImageAspectFlags.Depth, 0, 1, 0, 1); VkImageView *dest = (fbAttachments + (fbAttachmentsCount - 1)); VkResult result = vkCreateImageView(_gd.Device, ref depthViewCI, null, dest); CheckResult(result); _attachmentViews.Add(*dest); } if (ColorTextures.Count > 0) { fbCI.width = ColorTextures[0].Width; fbCI.height = ColorTextures[0].Height; } else if (vkDepthTex != null) { fbCI.width = vkDepthTex.Width; fbCI.height = vkDepthTex.Height; } fbCI.attachmentCount = fbAttachmentsCount; fbCI.pAttachments = fbAttachments; fbCI.layers = 1; fbCI.renderPass = _renderPass; creationResult = vkCreateFramebuffer(_gd.Device, ref fbCI, null, out _deviceFramebuffer); CheckResult(creationResult); }
public override VkResult CreateImageView(VkImageViewCreateInfo createInfo, out VkImageView imageView) { imageView = new SoftwareImageView(this, createInfo); return(VkResult.VK_SUCCESS); }
public override VkResult CreateImageView(VkImageViewCreateInfo createInfo, out VkImageView imageView) { imageView = new DummyImageView(); return(VkResult.VK_SUCCESS); }
protected virtual void SetupDepthStencil() { VkImageCreateInfo image = new VkImageCreateInfo(); image.sType = ImageCreateInfo; image.imageType = VkImageType._2d; image.format = DepthFormat; image.extent = new VkExtent3D() { width = width, height = height, depth = 1 }; image.mipLevels = 1; image.arrayLayers = 1; image.samples = VkSampleCountFlagBits._1; image.tiling = VkImageTiling.Optimal; image.usage = (VkImageUsageFlagBits.DepthStencilAttachment | VkImageUsageFlagBits.TransferSrc); image.flags = 0; VkMemoryAllocateInfo mem_alloc = new VkMemoryAllocateInfo(); mem_alloc.sType = MemoryAllocateInfo; mem_alloc.allocationSize = 0; mem_alloc.memoryTypeIndex = 0; VkImageViewCreateInfo depthStencilView = new VkImageViewCreateInfo(); depthStencilView.sType = ImageViewCreateInfo; depthStencilView.viewType = VkImageViewType._2d; depthStencilView.format = DepthFormat; depthStencilView.flags = 0; depthStencilView.subresourceRange = new VkImageSubresourceRange(); depthStencilView.subresourceRange.aspectMask = (VkImageAspectFlagBits.Depth | VkImageAspectFlagBits.Stencil); depthStencilView.subresourceRange.baseMipLevel = 0; depthStencilView.subresourceRange.levelCount = 1; depthStencilView.subresourceRange.baseArrayLayer = 0; depthStencilView.subresourceRange.layerCount = 1; { VkImage vkImage; vkCreateImage(device, &image, null, &vkImage); DepthStencil.Image = vkImage; } VkMemoryRequirements memReqs; vkGetImageMemoryRequirements(device, DepthStencil.Image, &memReqs); mem_alloc.allocationSize = memReqs.size; mem_alloc.memoryTypeIndex = vulkanDevice.getMemoryType(memReqs.memoryTypeBits, VkMemoryPropertyFlagBits.DeviceLocal); { VkDeviceMemory memory; vkAllocateMemory(device, &mem_alloc, null, &memory); DepthStencil.Mem = memory; } vkBindImageMemory(device, DepthStencil.Image, DepthStencil.Mem, 0); depthStencilView.image = DepthStencil.Image; { VkImageView imageView; vkCreateImageView(device, &depthStencilView, null, &imageView); DepthStencil.View = imageView; } }
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)); }
public abstract VkResult CreateImageView(VkImageViewCreateInfo createInfo, out VkImageView imageView);
// 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; }
public static VkImageViewCreateInfo imageViewCreateInfo() { VkImageViewCreateInfo imageViewCreateInfo = VkImageViewCreateInfo.New(); return(imageViewCreateInfo); }
/** * Create the swapchain and get it's Images with given width and height * * @param width Pointer to the width of the swapchain (may be adjusted to fit the requirements of the swapchain) * @param height Pointer to the height of the swapchain (may be adjusted to fit the requirements of the swapchain) * @param vsync (Optional) Can be used to force vsync'd rendering (by using VK_PRESENT_MODE_FIFO_KHR as presentation mode) */ public void Create(uint *width, uint *height, bool vsync = false) { VkResult err; VkSwapchainKHR oldSwapchain = Swapchain; // Get physical Device Surface properties and formats VkSurfaceCapabilitiesKHR surfCaps; err = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(PhysicalDevice, Surface, &surfCaps); Debug.Assert(err == VkResult.Success); // Get available present modes uint presentModeCount; err = vkGetPhysicalDeviceSurfacePresentModesKHR(PhysicalDevice, Surface, &presentModeCount, null); Debug.Assert(err == VkResult.Success); Debug.Assert(presentModeCount > 0); using (NativeList <VkPresentModeKHR> presentModes = new NativeList <VkPresentModeKHR>(presentModeCount)) { err = vkGetPhysicalDeviceSurfacePresentModesKHR(PhysicalDevice, Surface, &presentModeCount, (VkPresentModeKHR *)presentModes.Data); Debug.Assert(err == VkResult.Success); presentModes.Count = presentModeCount; VkExtent2D swapchainExtent; // If width (and height) equals the special value 0xFFFFFFFF, the size of the Surface will be set by the swapchain if (surfCaps.currentExtent.width == unchecked ((uint)-1)) { // If the Surface size is undefined, the size is set to // the size of the Images requested. swapchainExtent.width = *width; swapchainExtent.height = *height; } else { // If the Surface size is defined, the swap chain size must match swapchainExtent = surfCaps.currentExtent; *width = surfCaps.currentExtent.width; *height = surfCaps.currentExtent.height; } // Select a present mode for the swapchain // The VK_PRESENT_MODE_FIFO_KHR mode must always be present as per spec // This mode waits for the vertical blank ("v-sync") VkPresentModeKHR swapchainPresentMode = VkPresentModeKHR.FifoKHR; // If v-sync is not requested, try to find a mailbox mode // It's the lowest latency non-tearing present mode available if (!vsync) { for (uint i = 0; i < presentModeCount; i++) { if (presentModes[i] == VkPresentModeKHR.MailboxKHR) { swapchainPresentMode = VkPresentModeKHR.MailboxKHR; break; } if ((swapchainPresentMode != VkPresentModeKHR.MailboxKHR) && (presentModes[i] == VkPresentModeKHR.ImmediateKHR)) { swapchainPresentMode = VkPresentModeKHR.ImmediateKHR; } } } // Determine the number of Images uint desiredNumberOfSwapchainImages = surfCaps.minImageCount + 1; if ((surfCaps.maxImageCount > 0) && (desiredNumberOfSwapchainImages > surfCaps.maxImageCount)) { desiredNumberOfSwapchainImages = surfCaps.maxImageCount; } // Find the transformation of the Surface VkSurfaceTransformFlagsKHR preTransform; if ((surfCaps.supportedTransforms & VkSurfaceTransformFlagsKHR.IdentityKHR) != 0) { // We prefer a non-rotated transform preTransform = VkSurfaceTransformFlagsKHR.IdentityKHR; } else { preTransform = surfCaps.currentTransform; } VkSwapchainCreateInfoKHR swapchainCI = VkSwapchainCreateInfoKHR.New(); swapchainCI.pNext = null; swapchainCI.surface = Surface; swapchainCI.minImageCount = desiredNumberOfSwapchainImages; swapchainCI.imageFormat = ColorFormat; swapchainCI.imageColorSpace = ColorSpace; swapchainCI.imageExtent = new VkExtent2D() { width = swapchainExtent.width, height = swapchainExtent.height }; swapchainCI.imageUsage = VkImageUsageFlags.ColorAttachment; swapchainCI.preTransform = preTransform; swapchainCI.imageArrayLayers = 1; swapchainCI.imageSharingMode = VkSharingMode.Exclusive; swapchainCI.queueFamilyIndexCount = 0; swapchainCI.pQueueFamilyIndices = null; swapchainCI.presentMode = swapchainPresentMode; swapchainCI.oldSwapchain = oldSwapchain; // Setting clipped to VK_TRUE allows the implementation to discard rendering outside of the Surface area swapchainCI.clipped = True; swapchainCI.compositeAlpha = VkCompositeAlphaFlagsKHR.OpaqueKHR; // Set additional usage flag for blitting from the swapchain Images if supported VkFormatProperties formatProps; vkGetPhysicalDeviceFormatProperties(PhysicalDevice, ColorFormat, out formatProps); if ((formatProps.optimalTilingFeatures & VkFormatFeatureFlags.BlitDst) != 0) { swapchainCI.imageUsage |= VkImageUsageFlags.TransferSrc; } VkSwapchainKHR swapChain; err = vkCreateSwapchainKHR(Device, &swapchainCI, null, out swapChain); Debug.Assert(err == VkResult.Success); Swapchain = swapChain; // If an existing swap chain is re-created, destroy the old swap chain // This also cleans up all the presentable Images if (oldSwapchain.Handle != 0) { for (uint i = 0; i < ImageCount; i++) { vkDestroyImageView(Device, Buffers[i].View, null); } vkDestroySwapchainKHR(Device, oldSwapchain, null); } uint imageCount; err = vkGetSwapchainImagesKHR(Device, swapChain, &imageCount, null); Debug.Assert(err == VkResult.Success); ImageCount = imageCount; // Get the swap chain Images Images.Resize(imageCount); err = vkGetSwapchainImagesKHR(Device, swapChain, &imageCount, (VkImage *)Images.Data.ToPointer()); Images.Count = imageCount; Debug.Assert(err == VkResult.Success); // Get the swap chain Buffers containing the image and imageview Buffers.Resize(imageCount); Buffers.Count = imageCount; for (uint i = 0; i < imageCount; i++) { VkImageViewCreateInfo colorAttachmentView = new VkImageViewCreateInfo(); colorAttachmentView.sType = VkStructureType.ImageViewCreateInfo; colorAttachmentView.pNext = null; colorAttachmentView.format = ColorFormat; colorAttachmentView.components = new VkComponentMapping() { r = VkComponentSwizzle.R, g = VkComponentSwizzle.G, b = VkComponentSwizzle.B, a = VkComponentSwizzle.A }; colorAttachmentView.subresourceRange.aspectMask = VkImageAspectFlags.Color; colorAttachmentView.subresourceRange.baseMipLevel = 0; colorAttachmentView.subresourceRange.levelCount = 1; colorAttachmentView.subresourceRange.baseArrayLayer = 0; colorAttachmentView.subresourceRange.layerCount = 1; colorAttachmentView.viewType = VkImageViewType.Image2D; colorAttachmentView.flags = 0; Buffers[i].Image = Images[i]; colorAttachmentView.image = Buffers[i].Image; VkImageView view; err = vkCreateImageView(Device, &colorAttachmentView, null, &view); Buffers[i].View = view; Debug.Assert(err == VkResult.Success); } } }
internal SoftwareImageView(SoftwareDevice device, VkImageViewCreateInfo createInfo) { this.m_device = device; this.m_createInfo = createInfo; this.m_image = (SoftwareImage)createInfo.image; }
/** * 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, VkImageUsageFlagBits imageUsageFlags = VkImageUsageFlagBits.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, &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 = new VkMemoryAllocateInfo(); memAllocInfo.sType = 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 = new VkBufferCreateInfo(); bufferCreateInfo.sType = BufferCreateInfo; bufferCreateInfo.size = tex2D.GetTotalSize(); // This buffer is used as a transfer source for the buffer copy bufferCreateInfo.usage = VkBufferUsageFlagBits.TransferSrc; bufferCreateInfo.sharingMode = VkSharingMode.Exclusive; 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, VkMemoryPropertyFlagBits.HostVisible | VkMemoryPropertyFlagBits.HostCoherent); vkAllocateMemory(device.LogicalDevice, &memAllocInfo, null, &stagingMemory); vkBindBufferMemory(device.LogicalDevice, stagingBuffer, stagingMemory, 0); // Copy texture data into staging buffer IntPtr data; vkMapMemory(device.LogicalDevice, stagingMemory, 0, memReqs.size, 0, &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 var bufferCopyRegions = new List <VkBufferImageCopy>(); uint offset = 0; for (uint i = 0; i < mipLevels; i++) { VkBufferImageCopy bufferCopyRegion = new VkBufferImageCopy(); bufferCopyRegion.imageSubresource.aspectMask = VkImageAspectFlagBits.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 = new VkImageCreateInfo(); imageCreateInfo.sType = ImageCreateInfo; imageCreateInfo.imageType = VkImageType._2d; imageCreateInfo.format = format; imageCreateInfo.mipLevels = mipLevels; imageCreateInfo.arrayLayers = 1; imageCreateInfo.samples = VkSampleCountFlagBits._1; 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 & VkImageUsageFlagBits.TransferDst) == 0) { imageCreateInfo.usage |= VkImageUsageFlagBits.TransferDst; } { VkImage vkImage; vkCreateImage(device.LogicalDevice, &imageCreateInfo, null, &vkImage); this.image = vkImage; } vkGetImageMemoryRequirements(device.LogicalDevice, image, &memReqs); memAllocInfo.allocationSize = memReqs.size; memAllocInfo.memoryTypeIndex = device.getMemoryType(memReqs.memoryTypeBits, VkMemoryPropertyFlagBits.DeviceLocal); { VkDeviceMemory memory; vkAllocateMemory(device.LogicalDevice, &memAllocInfo, null, &memory); this.deviceMemory = memory; } vkBindImageMemory(device.LogicalDevice, image, deviceMemory, 0); VkImageSubresourceRange subresourceRange = new VkImageSubresourceRange(); subresourceRange.aspectMask = VkImageAspectFlagBits.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, VkImageAspectFlagBits.Color, VkImageLayout.Undefined, VkImageLayout.TransferDstOptimal, subresourceRange); // Copy mip levels from staging buffer fixed(VkBufferImageCopy *pointer = bufferCopyRegions.ToArray()) { vkCmdCopyBufferToImage( copyCmd, stagingBuffer, image, VkImageLayout.TransferDstOptimal, (UInt32)bufferCopyRegions.Count, pointer); } // Change texture image layout to shader read after all mip levels have been copied this.imageLayout = imageLayout; Tools.setImageLayout( copyCmd, image, VkImageAspectFlagBits.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 = new VkSamplerCreateInfo(); samplerCreateInfo.sType = SamplerCreateInfo; 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; { VkSampler vkSampler; vkCreateSampler(device.LogicalDevice, &samplerCreateInfo, null, &vkSampler); this.sampler = vkSampler; } // 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 = new VkImageViewCreateInfo(); viewCreateInfo.sType = ImageViewCreateInfo; viewCreateInfo.viewType = VkImageViewType._2d; viewCreateInfo.format = format; viewCreateInfo.components = new VkComponentMapping { r = VkComponentSwizzle.R, g = VkComponentSwizzle.G, b = VkComponentSwizzle.B, a = VkComponentSwizzle.A }; viewCreateInfo.subresourceRange = new VkImageSubresourceRange { aspectMask = VkImageAspectFlagBits.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; { VkImageView vkImageView; vkCreateImageView(device.LogicalDevice, &viewCreateInfo, null, &vkImageView); this.view = vkImageView; } // Update descriptor image info member that can be used for setting up descriptor sets updateDescriptor(); }
public Swapchain(GraphicsDevice device, VkSurfaceKHR surface, Window window) { Device = device; _surface = surface; Window = window; SwapChainSupportDetails swapChainSupport = QuerySwapChainSupport(device.PhysicalDevice, surface); VkSurfaceFormatKHR surfaceFormat = ChooseSwapSurfaceFormat(swapChainSupport.Formats); VkPresentModeKHR presentMode = ChooseSwapPresentMode(swapChainSupport.PresentModes); Extent = ChooseSwapExtent(swapChainSupport.Capabilities); CreateRenderPass(surfaceFormat.format); uint imageCount = swapChainSupport.Capabilities.minImageCount + 1; if (swapChainSupport.Capabilities.maxImageCount > 0 && imageCount > swapChainSupport.Capabilities.maxImageCount) { imageCount = swapChainSupport.Capabilities.maxImageCount; } var createInfo = new VkSwapchainCreateInfoKHR { sType = VkStructureType.SwapchainCreateInfoKHR, surface = surface, minImageCount = imageCount, imageFormat = surfaceFormat.format, imageColorSpace = surfaceFormat.colorSpace, imageExtent = Extent, imageArrayLayers = 1, imageUsage = VkImageUsageFlags.ColorAttachment, imageSharingMode = VkSharingMode.Exclusive, preTransform = swapChainSupport.Capabilities.currentTransform, compositeAlpha = VkCompositeAlphaFlagsKHR.Opaque, presentMode = presentMode, clipped = true, oldSwapchain = VkSwapchainKHR.Null }; vkCreateSwapchainKHR(device.VkDevice, &createInfo, null, out Handle).CheckResult(); ReadOnlySpan <VkImage> swapChainImages = vkGetSwapchainImagesKHR(device.VkDevice, Handle); _swapChainImageViews = new VkImageView[swapChainImages.Length]; Framebuffers = new VkFramebuffer[swapChainImages.Length]; for (int i = 0; i < swapChainImages.Length; i++) { var viewCreateInfo = new VkImageViewCreateInfo( swapChainImages[i], VkImageViewType.Image2D, surfaceFormat.format, VkComponentMapping.Rgba, new VkImageSubresourceRange(VkImageAspectFlags.Color, 0, 1, 0, 1) ); vkCreateImageView(Device.VkDevice, &viewCreateInfo, null, out _swapChainImageViews[i]).CheckResult(); vkCreateFramebuffer(Device.VkDevice, RenderPass, new[] { _swapChainImageViews[i] }, Extent, 1u, out Framebuffers[i]); } }