public unsafe Image(ref VkImageCreateInfo imageCreateInfo) { handle = Device.CreateImage(ref imageCreateInfo); imageType = imageCreateInfo.imageType; format = imageCreateInfo.format; extent = imageCreateInfo.extent; mipLevels = imageCreateInfo.mipLevels; arrayLayers = imageCreateInfo.arrayLayers; Device.GetImageMemoryRequirements(this, out var memReqs); Allocate(memReqs); Device.BindImageMemory(handle, memory, 0); }
public unsafe void SetImageData(MipmapLevel[] imageData) { this.imageData = imageData; this.extent = new VkExtent3D(imageData[0].Width, imageData[0].Height, 1); mipLevels = (uint)imageData.Length; layers = (uint)imageData[0].ArrayElements.Length; faceCount = (uint)imageData[0].ArrayElements[0].Faces.Length; ulong totalSize = 0; foreach (var mip in imageData) { totalSize += mip.TotalSize * layers * faceCount; } Buffer stagingBuffer = Buffer.CreateStagingBuffer(totalSize, IntPtr.Zero); image = Image.Create(width, height, imageCreateFlags, layers * faceCount, mipLevels, format, VkSampleCountFlags.Count1, VkImageUsageFlags.TransferDst | VkImageUsageFlags.Sampled); IntPtr mapped = stagingBuffer.Map(); // Setup buffer copy regions for each face including all of it's miplevels Span <VkBufferImageCopy> bufferCopyRegions = stackalloc VkBufferImageCopy[(int)(mipLevels * layers * faceCount)]; uint offset = 0; int index = 0; for (int layer = 0; layer < layers; layer++) { for (int face = 0; face < faceCount; face++) { for (uint level = 0; level < mipLevels; level++) { var mipLevel = imageData[level]; var layerElement = mipLevel.ArrayElements[layer]; var faceElement = layerElement.Faces[face]; Unsafe.CopyBlock((void *)(mapped + (int)offset), Unsafe.AsPointer(ref faceElement.Data[0]), (uint)faceElement.Data.Length); VkBufferImageCopy bufferCopyRegion = new VkBufferImageCopy { imageSubresource = new VkImageSubresourceLayers { aspectMask = VkImageAspectFlags.Color, mipLevel = level, baseArrayLayer = (uint)(layer * faceCount + face), layerCount = 1 }, imageExtent = new VkExtent3D(mipLevel.Width, mipLevel.Height, mipLevel.Depth), bufferOffset = offset }; bufferCopyRegions[index++] = bufferCopyRegion; offset += (uint)faceElement.Data.Length; } } } stagingBuffer.Unmap(); var subresourceRange = new VkImageSubresourceRange(VkImageAspectFlags.Color, 0, mipLevels, 0, layers * faceCount); CommandBuffer copyCmd = Graphics.BeginPrimaryCmd(); copyCmd.SetImageLayout(image, VkImageAspectFlags.Color, VkImageLayout.Undefined, VkImageLayout.TransferDstOptimal, subresourceRange); copyCmd.CopyBufferToImage(stagingBuffer, image, VkImageLayout.TransferDstOptimal, bufferCopyRegions); copyCmd.SetImageLayout(image, VkImageAspectFlags.Color, VkImageLayout.TransferDstOptimal, imageLayout, subresourceRange); Graphics.EndPrimaryCmd(copyCmd); imageLayout = VkImageLayout.ShaderReadOnlyOptimal; stagingBuffer.Dispose(); imageView = ImageView.Create(image, ImageViewType, format, VkImageAspectFlags.Color, 0, mipLevels, 0, layers); sampler = new Sampler(VkFilter.Linear, VkSamplerMipmapMode.Linear, samplerAddressMode, mipLevels, Device.Features.samplerAnisotropy == true, borderColor); UpdateDescriptor(); }
/** * 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 unsafe void Create(ref uint width, ref uint height, bool vsync = false) { VkResult err; VkSwapchainKHR oldSwapchain = swapchain; // Get physical Device Surface properties and formats VkSurfaceCapabilitiesKHR surfCaps; err = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(Device.PhysicalDevice, Surface, out surfCaps); Debug.Assert(err == VkResult.Success); // Get available present modes uint presentModeCount; err = vkGetPhysicalDeviceSurfacePresentModesKHR(Device.PhysicalDevice, Surface, &presentModeCount, null); Debug.Assert(err == VkResult.Success); Debug.Assert(presentModeCount > 0); using (Vector <VkPresentModeKHR> presentModes = new Vector <VkPresentModeKHR>(presentModeCount)) { err = vkGetPhysicalDeviceSurfacePresentModesKHR(Device.PhysicalDevice, Surface, &presentModeCount, (VkPresentModeKHR *)presentModes.Data); Debug.Assert(err == VkResult.Success); presentModes.Count = presentModeCount; // 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)) { width = surfCaps.currentExtent.width; height = surfCaps.currentExtent.height; } extent = new VkExtent3D(width, height, 1); // 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.Fifo; // 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.Mailbox) { swapchainPresentMode = VkPresentModeKHR.Mailbox; break; } if ((swapchainPresentMode != VkPresentModeKHR.Mailbox) && (presentModes[i] == VkPresentModeKHR.Immediate)) { swapchainPresentMode = VkPresentModeKHR.Immediate; } } } // Determine the number of Images uint desiredNumberOfSwapchainImages = IMAGE_COUNT;// surfCaps.minImageCount + 1; if ((surfCaps.maxImageCount > 0) && (desiredNumberOfSwapchainImages > surfCaps.maxImageCount)) { Debug.Assert(false); desiredNumberOfSwapchainImages = surfCaps.maxImageCount; } // Find the transformation of the Surface VkSurfaceTransformFlagsKHR preTransform; if ((surfCaps.supportedTransforms & VkSurfaceTransformFlagsKHR.Identity) != 0) { // We prefer a non-rotated transform preTransform = VkSurfaceTransformFlagsKHR.Identity; } else { preTransform = surfCaps.currentTransform; } VkSwapchainCreateInfoKHR swapchainCI = new VkSwapchainCreateInfoKHR { sType = VkStructureType.SwapchainCreateInfoKHR, pNext = null, surface = Surface, minImageCount = desiredNumberOfSwapchainImages, imageFormat = ColorFormat, imageColorSpace = ColorSpace, imageExtent = new VkExtent2D(extent.width, extent.height), imageUsage = VkImageUsageFlags.ColorAttachment, preTransform = preTransform, imageArrayLayers = 1, imageSharingMode = VkSharingMode.Exclusive, queueFamilyIndexCount = 0, pQueueFamilyIndices = null, presentMode = swapchainPresentMode, oldSwapchain = oldSwapchain, // Setting clipped to VK_TRUE allows the implementation to discard rendering outside of the Surface area clipped = true, compositeAlpha = VkCompositeAlphaFlagsKHR.Opaque }; // Set additional usage flag for blitting from the swapchain Images if supported Device.GetPhysicalDeviceFormatProperties(ColorFormat, out VkFormatProperties formatProps); if ((formatProps.optimalTilingFeatures & VkFormatFeatureFlags.BlitDst) != 0) { swapchainCI.imageUsage |= VkImageUsageFlags.TransferSrc; } swapchain = Device.CreateSwapchainKHR(ref swapchainCI); // 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++) { ImageViews[i].Dispose(); } Device.DestroySwapchainKHR(oldSwapchain); } var vkImages = Vulkan.vkGetSwapchainImagesKHR(Device.Handle, swapchain); VkImages.Clear(); Images = new Image[vkImages.Length]; ImageViews = new ImageView[vkImages.Length]; for (int i = 0; i < vkImages.Length; i++) { Images[i] = new Image(vkImages[i]) { imageType = VkImageType.Image2D, extent = extent }; ImageViews[i] = ImageView.Create(Images[i], VkImageViewType.Image2D, ColorFormat, VkImageAspectFlags.Color, 0, 1); } // Get the swap chain Images VkImages.Add(vkImages); } }