Example #1
0
        private void InitializeFromImpl(DataBox[] dataBoxes = null)
        {
            NativeFormat = VulkanConvertExtensions.ConvertPixelFormat(ViewFormat);
            HasStencil   = IsStencilFormat(ViewFormat);

            NativeImageAspect = IsDepthStencil ? VkImageAspectFlags.Depth : VkImageAspectFlags.Color;
            if (HasStencil)
            {
                NativeImageAspect |= VkImageAspectFlags.Stencil;
            }


            var arraySlice = ArraySlice;
            var mipLevel   = MipLevel;

            GetViewSliceBounds(ViewType, ref arraySlice, ref mipLevel, out var arrayOrDepthCount, out var mipCount);
            var arrayCount = Dimension == TextureDimension.Texture3D ? 1 : arrayOrDepthCount;

            NativeResourceRange = new VkImageSubresourceRange(NativeImageAspect, (uint)mipLevel, (uint)mipCount, (uint)arraySlice, (uint)arrayCount);

            // For depth-stencil formats, automatically fall back to a supported one
            if (IsDepthStencil && HasStencil)
            {
                NativeFormat = GetFallbackDepthStencilFormat(GraphicsDevice, NativeFormat);
            }

            if (Usage == GraphicsResourceUsage.Staging)
            {
                if (NativeImage != VkImage.Null)
                {
                    throw new InvalidOperationException();
                }

                if (isNotOwningResources)
                {
                    throw new InvalidOperationException();
                }

                NativeAccessMask = VkAccessFlags.HostRead | VkAccessFlags.HostWrite;

                NativePipelineStageMask = VkPipelineStageFlags.Host;

                if (ParentTexture != null)
                {
                    // Create only a view
                    NativeBuffer = ParentTexture.NativeBuffer;
                    NativeMemory = ParentTexture.NativeMemory;
                }
                else
                {
                    CreateBuffer();

                    if (dataBoxes != null && dataBoxes.Length > 0)
                    {
                        InitializeData(dataBoxes);
                    }
                }
            }
            else
            {
                if (NativeImage != VkImage.Null)
                {
                    throw new InvalidOperationException();
                }

                NativeLayout =
                    IsRenderTarget ? VkImageLayout.ColorAttachmentOptimal :
                    IsDepthStencil ? VkImageLayout.DepthStencilAttachmentOptimal :
                    IsShaderResource ? VkImageLayout.ShaderReadOnlyOptimal :
                    VkImageLayout.General;

                if (NativeLayout == VkImageLayout.TransferDstOptimal)
                {
                    NativeAccessMask = VkAccessFlags.TransferRead;
                }

                if (NativeLayout == VkImageLayout.ColorAttachmentOptimal)
                {
                    NativeAccessMask = VkAccessFlags.ColorAttachmentWrite;
                }

                if (NativeLayout == VkImageLayout.DepthStencilAttachmentOptimal)
                {
                    NativeAccessMask = VkAccessFlags.DepthStencilAttachmentWrite;
                }

                if (NativeLayout == VkImageLayout.ShaderReadOnlyOptimal)
                {
                    NativeAccessMask = VkAccessFlags.ShaderRead | VkAccessFlags.InputAttachmentRead;
                }

                NativePipelineStageMask =
                    IsRenderTarget ? VkPipelineStageFlags.ColorAttachmentOutput :
                    IsDepthStencil ? VkPipelineStageFlags.ColorAttachmentOutput | VkPipelineStageFlags.EarlyFragmentTests | VkPipelineStageFlags.LateFragmentTests :
                    IsShaderResource ? VkPipelineStageFlags.VertexInput | VkPipelineStageFlags.FragmentShader :
                    VkPipelineStageFlags.None;

                if (ParentTexture != null)
                {
                    // Create only a view
                    NativeImage  = ParentTexture.NativeImage;
                    NativeMemory = ParentTexture.NativeMemory;
                }
                else
                {
                    if (!isNotOwningResources)
                    {
                        CreateImage();

                        InitializeData(dataBoxes);
                    }
                }

                if (!isNotOwningResources)
                {
                    NativeImageView           = GetImageView(ViewType, ArraySlice, MipLevel);
                    NativeColorAttachmentView = GetColorAttachmentView(ViewType, ArraySlice, MipLevel);
                    NativeDepthStencilView    = GetDepthStencilView();
                }
            }
        }
Example #2
0
        private unsafe void CreateSwapChain()
        {
            var formats = new[] { PixelFormat.B8G8R8A8_UNorm_SRgb, PixelFormat.R8G8B8A8_UNorm_SRgb, PixelFormat.B8G8R8A8_UNorm, PixelFormat.R8G8B8A8_UNorm };

            foreach (var format in formats)
            {
                var nativeFromat = VulkanConvertExtensions.ConvertPixelFormat(format);

                vkGetPhysicalDeviceFormatProperties(GraphicsDevice.NativePhysicalDevice, nativeFromat, out var formatProperties);

                if ((formatProperties.optimalTilingFeatures & VkFormatFeatureFlags.ColorAttachment) != 0)
                {
                    Description.BackBufferFormat = format;
                    break;
                }
            }

            // Queue
            // TODO VULKAN: Queue family is needed when creating the Device, so here we can just do a sanity check?
            var queueNodeIndex = vkGetPhysicalDeviceQueueFamilyProperties(GraphicsDevice.NativePhysicalDevice).ToArray().
                                 Where((properties, index) => (properties.queueFlags & VkQueueFlags.Graphics) != 0 && vkGetPhysicalDeviceSurfaceSupportKHR(GraphicsDevice.NativePhysicalDevice, (uint)index, surface, out var supported) == VkResult.Success && supported).
                                 Select((properties, index) => index).First();

            // Surface format
            var backBufferFormat = VulkanConvertExtensions.ConvertPixelFormat(Description.BackBufferFormat);

            var surfaceFormats = vkGetPhysicalDeviceSurfaceFormatsKHR(GraphicsDevice.NativePhysicalDevice, surface).ToArray();

            if ((surfaceFormats.Length != 1 || surfaceFormats[0].format != VkFormat.Undefined) &&
                !surfaceFormats.Any(x => x.format == backBufferFormat))
            {
                backBufferFormat = surfaceFormats[0].format;
            }

            // Create swapchain
            vkGetPhysicalDeviceSurfaceCapabilitiesKHR(GraphicsDevice.NativePhysicalDevice, surface, out var surfaceCapabilities);

            // Buffer count
            uint desiredImageCount = Math.Max(surfaceCapabilities.minImageCount, 2);

            if (surfaceCapabilities.maxImageCount > 0 && desiredImageCount > surfaceCapabilities.maxImageCount)
            {
                desiredImageCount = surfaceCapabilities.maxImageCount;
            }

            // Transform
            VkSurfaceTransformFlagsKHR preTransform;

            if ((surfaceCapabilities.supportedTransforms & VkSurfaceTransformFlagsKHR.Identity) != 0)
            {
                preTransform = VkSurfaceTransformFlagsKHR.Identity;
            }
            else
            {
                preTransform = surfaceCapabilities.currentTransform;
            }

            // Find present mode
            var presentModes         = vkGetPhysicalDeviceSurfacePresentModesKHR(GraphicsDevice.NativePhysicalDevice, surface);
            var swapChainPresentMode = VkPresentModeKHR.Fifo; // Always supported

            foreach (var presentMode in presentModes)
            {
                // TODO VULKAN: Handle PresentInterval.Two
                if (Description.PresentationInterval == PresentInterval.Immediate)
                {
                    // Prefer mailbox to immediate
                    if (presentMode == VkPresentModeKHR.Immediate)
                    {
                        swapChainPresentMode = VkPresentModeKHR.Immediate;
                    }
                    else if (presentMode == VkPresentModeKHR.Mailbox)
                    {
                        swapChainPresentMode = VkPresentModeKHR.Mailbox;
                        break;
                    }
                }
            }

            // Create swapchain
            var swapchainCreateInfo = new VkSwapchainCreateInfoKHR
            {
                sType            = VkStructureType.SwapchainCreateInfoKHR,
                surface          = surface,
                imageArrayLayers = 1,
                imageSharingMode = VkSharingMode.Exclusive,
                imageExtent      = new Vortice.Mathematics.Size(Description.BackBufferWidth, Description.BackBufferHeight),
                imageFormat      = backBufferFormat,
                imageColorSpace  = Description.ColorSpace == ColorSpace.Gamma ? VkColorSpaceKHR.SrgbNonLinear : 0,
                imageUsage       = VkImageUsageFlags.ColorAttachment | VkImageUsageFlags.TransferDst | (surfaceCapabilities.supportedUsageFlags & VkImageUsageFlags.TransferSrc), // TODO VULKAN: Use off-screen buffer to emulate
                presentMode      = swapChainPresentMode,
                compositeAlpha   = VkCompositeAlphaFlagsKHR.Opaque,
                minImageCount    = desiredImageCount,
                preTransform     = preTransform,
                oldSwapchain     = swapChain,
                clipped          = true
            };

            vkCreateSwapchainKHR(GraphicsDevice.NativeDevice, &swapchainCreateInfo, null, out var newSwapChain);

            DestroySwapchain();

            swapChain = newSwapChain;
            CreateBackBuffers();
        }