// Size in bytes, and the usages private protected Buffer(uint size, BufferType type, Vk.BufferUsages usages) { Device = SpectrumApp.Instance.GraphicsDevice; Size = size; Type = type; // Create the buffer var bci = new Vk.BufferCreateInfo( size, Vk.BufferUsages.TransferDst | Vk.BufferUsages.TransferSrc | usages, flags: Vk.BufferCreateFlags.None, sharingMode: Vk.SharingMode.Exclusive ); VkBuffer = Device.VkDevice.CreateBuffer(bci); // Create the backing memory var memReq = VkBuffer.GetMemoryRequirements(); var memIdx = Device.FindMemoryTypeIndex(memReq.MemoryTypeBits, Vk.MemoryProperties.DeviceLocal); if (memIdx == -1) { throw new InvalidOperationException("Cannot find a memory type that supports buffers (this means bad or out-of-date hardware)"); } var mai = new Vk.MemoryAllocateInfo(memReq.Size, memIdx); VkMemory = Device.VkDevice.AllocateMemory(mai); VkBuffer.BindMemory(VkMemory); }
/// <summary> /// Allocate GPU memory. /// </summary> /// <param name="allocateInfo"> /// The structure describing parameters of the allocation. A successful returned allocation /// must use the requested parameters — no substitution is permitted by the implementation. /// </param> /// <param name="allocator">Controls host memory allocation.</param> /// <exception cref="VulkanException">Vulkan returns an error code.</exception> public DeviceMemory AllocateMemory(MemoryAllocateInfo allocateInfo, AllocationCallbacks?allocator = null) { return(new DeviceMemory(this, &allocateInfo, ref allocator)); }
private protected Texture(TextureType type, uint w, uint h, uint d, uint layers) { Device = SpectrumApp.Instance.GraphicsDevice; Type = type; Width = w; Height = h; Depth = d; Layers = layers; // Limits checking if (w == 0) { throw new ArgumentOutOfRangeException(nameof(w), "A texture cannot have a width of zero"); } if (h == 0) { throw new ArgumentOutOfRangeException(nameof(h), "A texture cannot have a height of zero"); } if (d == 0) { throw new ArgumentOutOfRangeException(nameof(d), "A texture cannot have a depth of zero"); } if (layers == 0) { throw new ArgumentOutOfRangeException(nameof(layers), "A texture cannot have 0 layers"); } if (type == TextureType.Texture3D && layers != 1) { throw new ArgumentOutOfRangeException(nameof(layers), "3D textures cannot be arrays"); } if (layers > Limits.MaxTextureLayers) { throw new ArgumentOutOfRangeException(nameof(layers), $"The texture array count ({layers}) is too big for the device ({Limits.MaxTextureLayers})"); } switch (type) { case TextureType.Texture1D: if (w > Limits.MaxTextureSize1D) { throw new ArgumentOutOfRangeException( nameof(w), $"The 1D texture size ({w}) is too big for the device ({Limits.MaxTextureSize1D})" ); } break; case TextureType.Texture2D: if (w > Limits.MaxTextureSize2D || h > Limits.MaxTextureSize2D) { throw new ArgumentOutOfRangeException( nameof(w), $"The 2D texture size ({w}x{h}) is too big for the device ({Limits.MaxTextureSize2D})" ); } break; case TextureType.Texture3D: if (w > Limits.MaxTextureSize3D || h > Limits.MaxTextureSize3D || d > Limits.MaxTextureSize3D) { throw new ArgumentOutOfRangeException( nameof(w), $"The 3D texture size ({w}x{h}x{d}) is too big for the device ({Limits.MaxTextureSize3D})" ); } break; } // Create the image var ici = new Vk.ImageCreateInfo { ImageType = (Vk.ImageType)type, Extent = new Vk.Extent3D((int)w, (int)h, (int)d), MipLevels = 1, ArrayLayers = (int)layers, Format = Vk.Format.R8G8B8A8UNorm, Tiling = Vk.ImageTiling.Optimal, InitialLayout = Vk.ImageLayout.Undefined, Usage = Vk.ImageUsages.TransferDst | Vk.ImageUsages.Sampled | Vk.ImageUsages.TransferSrc, SharingMode = Vk.SharingMode.Exclusive, Samples = Vk.SampleCounts.Count1, Flags = Vk.ImageCreateFlags.None }; VkImage = Device.VkDevice.CreateImage(ici); // Create the backing memory for the image var memReq = VkImage.GetMemoryRequirements(); var memIdx = Device.FindMemoryTypeIndex(memReq.MemoryTypeBits, Vk.MemoryProperties.DeviceLocal); if (memIdx == -1) { throw new InvalidOperationException("Cannot find a memory type that supports textures (this means bad or out-of-date hardware)"); } var mai = new Vk.MemoryAllocateInfo(memReq.Size, memIdx); VkMemory = Device.VkDevice.AllocateMemory(mai); DataSize = (uint)memReq.Size; VkImage.BindMemory(VkMemory); // Create the view var vci = new Vk.ImageViewCreateInfo( Vk.Format.R8G8B8A8UNorm, new Vk.ImageSubresourceRange(Vk.ImageAspects.Color, 0, 1, 0, (int)Layers), viewType: GetViewType(Type, layers) ); VkView = VkImage.CreateView(vci); // Make the initial layout transition Device.SubmitScratchCommand(buf => { buf.CmdPipelineBarrier(Vk.PipelineStages.AllGraphics, Vk.PipelineStages.AllGraphics, imageMemoryBarriers: new[] { new Vk.ImageMemoryBarrier( VkImage, new Vk.ImageSubresourceRange(Vk.ImageAspects.Color, 0, 1, 0, 1), Vk.Accesses.None, Vk.Accesses.ShaderRead, Vk.ImageLayout.Undefined, Vk.ImageLayout.ShaderReadOnlyOptimal ) }); }); }
/// <summary> /// Rebuilds the render target to use a new size. /// </summary> /// <param name="width">The new width of the render target.</param> /// <param name="height">The new height of the render target.</param> /// <param name="force">If <c>true</c>, the render target will be rebuilt even if the size doesnt change.</param> public void Rebuild(uint width, uint height, bool force = false) { if (!force && width == Width && height == Height) { return; } Width = width; Height = height; // Destroy the existing objects, if needed VkView?.Dispose(); VkImage?.Dispose(); VkMemory?.Dispose(); // Create the image var ici = new Vk.ImageCreateInfo { ImageType = Vk.ImageType.Image2D, Extent = new Vk.Extent3D((int)width, (int)height, 1), MipLevels = 1, ArrayLayers = 1, Format = (Vk.Format)Format, Tiling = Vk.ImageTiling.Optimal, InitialLayout = Vk.ImageLayout.Undefined, Usage = Vk.ImageUsages.Sampled | Vk.ImageUsages.TransferSrc | Vk.ImageUsages.TransferDst | (HasDepth ? Vk.ImageUsages.DepthStencilAttachment : Vk.ImageUsages.ColorAttachment), // No subpassInput support yet, but add it here SharingMode = Vk.SharingMode.Exclusive, Samples = Vk.SampleCounts.Count1, // TODO: Change when we support multisampling Flags = Vk.ImageCreateFlags.None }; VkImage = Device.VkDevice.CreateImage(ici); // Create the backing memory for the image var memReq = VkImage.GetMemoryRequirements(); var memIdx = Device.FindMemoryTypeIndex(memReq.MemoryTypeBits, Vk.MemoryProperties.DeviceLocal); if (memIdx == -1) { throw new InvalidOperationException("Cannot find a memory type that supports render targets (this means bad or out-of-date hardware)"); } var mai = new Vk.MemoryAllocateInfo(memReq.Size, memIdx); VkMemory = Device.VkDevice.AllocateMemory(mai); DataSize = (uint)memReq.Size; VkImage.BindMemory(VkMemory); // Create the view var vci = new Vk.ImageViewCreateInfo( (Vk.Format)Format, new Vk.ImageSubresourceRange(VkAspects, 0, 1, 0, 1), viewType: Vk.ImageViewType.Image2D ); VkView = VkImage.CreateView(vci); // Make the initial layout transition Device.SubmitScratchCommand(buf => { buf.CmdPipelineBarrier(Vk.PipelineStages.AllGraphics, Vk.PipelineStages.AllGraphics, imageMemoryBarriers: new[] { new Vk.ImageMemoryBarrier( VkImage, new Vk.ImageSubresourceRange(VkAspects, 0, 1, 0, 1), Vk.Accesses.None, Vk.Accesses.None, Vk.ImageLayout.Undefined, DefaultImageLayout ) }); }); // Build the transitions ClearBarrier = new Vk.ImageMemoryBarrier( VkImage, new Vk.ImageSubresourceRange(VkAspects, 0, 1, 0, 1), Vk.Accesses.None, Vk.Accesses.None, DefaultImageLayout, Vk.ImageLayout.TransferDstOptimal ); AttachBarrier = new Vk.ImageMemoryBarrier( VkImage, new Vk.ImageSubresourceRange(VkAspects, 0, 1, 0, 1), Vk.Accesses.None, Vk.Accesses.None, Vk.ImageLayout.TransferDstOptimal, DefaultImageLayout ); }