internal Block AllocateAndBind(VulkanCore.Image image, Chunk.Location location) { ThrowIfDisposed(); var memRequirements = image.GetMemoryRequirements(); Block block = Allocate(location, memRequirements); image.BindMemory(block.Container.Memory, block.Offset); return(block); }
// Starts a transfer of raw data from the host to a device image // Unlike the buffers, which are easy to divide into blocks, it is very difficult to divide 3D spaces into blocks // with alignment and size constraints. For now, we see if we can easily upload the entire image region with the // existing staging buffer, otherwise we allocate a massive temp buffer to upload the data all at once with. // Yes, this is inefficient. Yes, this is slow. Yes, I hate this as much as you do. // We will improve this once the library is in a usable state. // As it stands, we do have 16MB available, which is a 2048x2048 image before the temp buffers are created. public unsafe static void PushImage(byte *src, uint length, TextureType type, Vk.Image dst, in Vk.Offset3D dstOff, in Vk.Extent3D dstSize, uint layer, uint layerCount)
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 ) }); }); }