<commit_before>﻿namespace Aardvark.Rendering.Vulkan

open System
open System.Threading
open System.Collections.Generic
open System.Runtime.InteropServices
open System.Runtime.CompilerServices
open Microsoft.FSharp.NativeInterop
open Aardvark.Base
open System.Reflection
open KHRGetPhysicalDeviceProperties2
open KHRExternalMemoryCapabilities

#nowarn "9"
#nowarn "51"

type Instance(apiVersion : Version, layers : list<string>, extensions : list<string>) as this =   
    inherit VulkanObject()


    static let availableLayers =
        let mutable count = 0u
        VkRaw.vkEnumerateInstanceLayerProperties(&&count, NativePtr.zero)
            |> check "could not get available instance layers"

        let properties = Array.zeroCreate (int count)
        properties |> NativePtr.withA (fun ptr ->
            VkRaw.vkEnumerateInstanceLayerProperties(&&count, ptr)
                |> check "could not get available instance layers"
        )
        properties |> Array.map LayerInfo.ofVulkan

    static let globalExtensions =
        let mutable count = 0u
        VkRaw.vkEnumerateInstanceExtensionProperties(null, &&count, NativePtr.zero)
            |> check "could not get available instance layers"

        let properties = Array.zeroCreate (int count)
        properties |> NativePtr.withA (fun ptr ->
            VkRaw.vkEnumerateInstanceExtensionProperties(null, &&count, ptr)
                |> check "could not get available instance layers"
        )
        properties |> Array.map ExtensionInfo.ofVulkan


    static let availableLayerNames = availableLayers |> Seq.map (fun l -> l.name.ToLower(), l) |> Map.ofSeq
    static let globalExtensionNames = globalExtensions |> Seq.map (fun p -> p.name.ToLower(), p.name) |> Map.ofSeq


    static let filterLayersAndExtensions (wantedLayers : list<string>, wantedExtensions : list<string>) =
        let availableExtensions = Dictionary globalExtensionNames

        let enabledLayers = 
            wantedLayers |> List.filter (fun name ->
                let name = name.ToLower()
                match Map.tryFind name availableLayerNames with
                    | Some layer -> 
                        VkRaw.debug "enabled layer %A" name
                        for e in layer.extensions do
                            availableExtensions.[e.name.ToLower()] <- e.name
                        true
                    | _ ->
                        //VkRaw.warn "could not enable instance-layer '%s' since it is not available" name
                        false
            )

        let enabledExtensions =
            wantedExtensions |> List.choose (fun name ->
                let name = name.ToLower()
                match availableExtensions.TryGetValue name with
                    | (true, realName) -> 
                        VkRaw.debug "enabled extension %A" name
                        Some realName
                    | _ -> 
                        //VkRaw.warn "could not enable instance-extension '%s' since it is not available" name
                        None
            )

        enabledLayers, enabledExtensions

    let layers, extensions = filterLayersAndExtensions (layers, extensions)
    
    let appName = CStr.malloc "Aardvark"

    let mutable instance =
        let layers = List.toArray layers
        let extensions = List.toArray extensions

        layers |> CStr.susemany (fun cLayers pLayers ->
            extensions |> CStr.susemany (fun cExtensions pExtensions ->

        //let pLayers = CStr.sallocMany layers
        //let pExtensions = CStr.sallocMany extensions

                let apiVersion = apiVersion.ToVulkan()

                let mutable applicationInfo =
                    VkApplicationInfo(
                        VkStructureType.ApplicationInfo, 0n,
                        appName,
                        0u,
                        appName,
                        0u,
                        apiVersion
                    )

                let mutable info =
                    VkInstanceCreateInfo(
                        VkStructureType.InstanceCreateInfo, 0n,
                        VkInstanceCreateFlags.MinValue,
                        &&applicationInfo,
                        uint32 cLayers, pLayers,
                        uint32 cExtensions, pExtensions
                    )

                let mutable instance = VkInstance.Zero

                VkRaw.vkCreateInstance(&&info, NativePtr.zero, &&instance)
                    |> check "could not create instance"


                instance
            )
        )

    let devices =
        let mutable deviceCount = 0u
        VkRaw.vkEnumeratePhysicalDevices(instance, &&deviceCount, NativePtr.zero)
            |> check "could not get physical devices"

        let devices = Array.zeroCreate (int deviceCount)
        devices |> NativePtr.withA (fun ptr ->
            VkRaw.vkEnumeratePhysicalDevices(instance, &&deviceCount, ptr)
                |> check "could not get physical devices"
        )

        devices |> Array.map (fun d -> PhysicalDevice(this, d, extensions))

    let groups =    
        let mutable groupCount = 0u

        VkRaw.vkEnumeratePhysicalDeviceGroups(instance, &&groupCount, NativePtr.zero)
            |> check "could not get physical device groups"


        let groups = Array.zeroCreate (int groupCount)
        groups |> NativePtr.withA (fun ptr ->
            VkRaw.vkEnumeratePhysicalDeviceGroups(instance, &&groupCount, ptr)
                |> check "could not get physical device groups"
        )

        groups |> Array.mapi (fun i d -> 
            let devices = 
                Array.init (int d.physicalDeviceCount) (fun ii ->
                    let handle = d.physicalDevices.[ii]
                    devices |> Array.find (fun dd -> dd.Handle = handle)
                )
            PhysicalDeviceGroup(this, devices, extensions)
        )
        |> Array.filter (fun g -> g.Devices.Length > 1)
      

    let devicesAndGroups =
        Array.append devices (groups |> Array.map (fun a -> a :> _))
    
    static member AvailableLayers = availableLayers
    static member GlobalExtensions = globalExtensions<commit_msg>[Vulkan] version probing when 1.1 not supported<commit_after>﻿namespace Aardvark.Rendering.Vulkan

open System
open System.Threading
open System.Collections.Generic
open System.Runtime.InteropServices
open System.Runtime.CompilerServices
open Microsoft.FSharp.NativeInterop
open Aardvark.Base
open System.Reflection
open KHRGetPhysicalDeviceProperties2
open KHRExternalMemoryCapabilities

#nowarn "9"
#nowarn "51"

type Instance(apiVersion : Version, layers : list<string>, extensions : list<string>) as this =   
    inherit VulkanObject()


    static let availableLayers =
        let mutable count = 0u
        VkRaw.vkEnumerateInstanceLayerProperties(&&count, NativePtr.zero)
            |> check "could not get available instance layers"

        let properties = Array.zeroCreate (int count)
        properties |> NativePtr.withA (fun ptr ->
            VkRaw.vkEnumerateInstanceLayerProperties(&&count, ptr)
                |> check "could not get available instance layers"
        )
        properties |> Array.map LayerInfo.ofVulkan

    static let globalExtensions =
        let mutable count = 0u
        VkRaw.vkEnumerateInstanceExtensionProperties(null, &&count, NativePtr.zero)
            |> check "could not get available instance layers"

        let properties = Array.zeroCreate (int count)
        properties |> NativePtr.withA (fun ptr ->
            VkRaw.vkEnumerateInstanceExtensionProperties(null, &&count, ptr)
                |> check "could not get available instance layers"
        )
        properties |> Array.map ExtensionInfo.ofVulkan


    static let availableLayerNames = availableLayers |> Seq.map (fun l -> l.name.ToLower(), l) |> Map.ofSeq
    static let globalExtensionNames = globalExtensions |> Seq.map (fun p -> p.name.ToLower(), p.name) |> Map.ofSeq


    static let filterLayersAndExtensions (wantedLayers : list<string>, wantedExtensions : list<string>) =
        let availableExtensions = Dictionary globalExtensionNames

        let enabledLayers = 
            wantedLayers |> List.filter (fun name ->
                let name = name.ToLower()
                match Map.tryFind name availableLayerNames with
                    | Some layer -> 
                        VkRaw.debug "enabled layer %A" name
                        for e in layer.extensions do
                            availableExtensions.[e.name.ToLower()] <- e.name
                        true
                    | _ ->
                        //VkRaw.warn "could not enable instance-layer '%s' since it is not available" name
                        false
            )

        let enabledExtensions =
            wantedExtensions |> List.choose (fun name ->
                let name = name.ToLower()
                match availableExtensions.TryGetValue name with
                    | (true, realName) -> 
                        VkRaw.debug "enabled extension %A" name
                        Some realName
                    | _ -> 
                        //VkRaw.warn "could not enable instance-extension '%s' since it is not available" name
                        None
            )

        enabledLayers, enabledExtensions

    let layers, extensions = filterLayersAndExtensions (layers, extensions)
    
    let appName = CStr.malloc "Aardvark"

    let mutable instance, apiVersion =
        let layers = List.toArray layers
        let extensions = List.toArray extensions

        layers |> CStr.susemany (fun cLayers pLayers ->
            extensions |> CStr.susemany (fun cExtensions pExtensions ->
            
                let rec tryCreate (apiVersion : Version) =
                    let version = apiVersion.ToVulkan()
                
                    let mutable applicationInfo =
                        VkApplicationInfo(
                            VkStructureType.ApplicationInfo, 0n,
                            appName,
                            0u,
                            appName,
                            0u,
                            version
                        )

                    let mutable info =
                        VkInstanceCreateInfo(
                            VkStructureType.InstanceCreateInfo, 0n,
                            VkInstanceCreateFlags.MinValue,
                            &&applicationInfo,
                            uint32 cLayers, pLayers,
                            uint32 cExtensions, pExtensions
                        )

                    let mutable instance = VkInstance.Zero

                    let res = VkRaw.vkCreateInstance(&&info, NativePtr.zero, &&instance)
                    if res = VkResult.VkSuccess then 
                        Some (instance, apiVersion)
                    elif apiVersion.Minor > 0 then
                        tryCreate (Version(apiVersion.Major, apiVersion.Minor - 1, apiVersion.Build))
                    else
                        None
                        
                match tryCreate apiVersion with
                    | Some instance -> instance
                    | None -> failf "could not create instance"
            )
        )

    let devices =
        let mutable deviceCount = 0u
        VkRaw.vkEnumeratePhysicalDevices(instance, &&deviceCount, NativePtr.zero)
            |> check "could not get physical devices"

        let devices = Array.zeroCreate (int deviceCount)
        devices |> NativePtr.withA (fun ptr ->
            VkRaw.vkEnumeratePhysicalDevices(instance, &&deviceCount, ptr)
                |> check "could not get physical devices"
        )

        devices |> Array.map (fun d -> PhysicalDevice(this, d, extensions))

    let groups =    
        if apiVersion >= Version(1,1) then
            let mutable groupCount = 0u
        
            VkRaw.vkEnumeratePhysicalDeviceGroups(instance, &&groupCount, NativePtr.zero)
                |> check "could not get physical device groups"


            let groups = Array.zeroCreate (int groupCount)
            groups |> NativePtr.withA (fun ptr ->
                VkRaw.vkEnumeratePhysicalDeviceGroups(instance, &&groupCount, ptr)
                    |> check "could not get physical device groups"
            )

            groups |> Array.mapi (fun i d -> 
                let devices = 
                    Array.init (int d.physicalDeviceCount) (fun ii ->
                        let handle = d.physicalDevices.[ii]
                        devices |> Array.find (fun dd -> dd.Handle = handle)
                    )
                PhysicalDeviceGroup(this, devices, extensions)
            )
            |> Array.filter (fun g -> g.Devices.Length > 1)
        else
            [||]

    let devicesAndGroups =
        Array.append devices (groups |> Array.map (fun a -> a :> _))
    
    static member AvailableLayers = availableLayers
    static member GlobalExtensions = globalExtensions
{'fraction_non_alphanumeric': 0.07290708371665133, 'fraction_numerical': 0.0030665440049064702, 'mean_word_length': 1.6487309644670052, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 114, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1207407', 'n_tokens_mistral': 3352, 'n_tokens_neox': 3066, 'n_words': 883}