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 ) }); }); }