Example #1
0
        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
                                                                                                                                      ) });
            });
        }
Example #2
0
 /// <summary>
 /// Create an image view from an existing image.
 /// </summary>
 /// <param name="createInfo">
 /// The structure containing parameters to be used to create the image view.
 /// </param>
 /// <param name="allocator">Controls host memory allocation.</param>
 /// <exception cref="VulkanException">Vulkan returns an error code.</exception>
 public ImageView CreateView(ImageViewCreateInfo createInfo, AllocationCallbacks?allocator = null)
 {
     return(new ImageView(Parent, this, &createInfo, ref allocator));
 }
Example #3
0
        /// <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
                );
        }