Skip to content

Vulkan instance functions exposed by device extensions fail to be loaded #2547

@Exanite

Description

@Exanite

Summary

Silk 2 assumes that all Vulkan functions exposed by device extensions can be retrieved by calling vkGetDeviceProcAddr, but apparently device level extensions can expose instance level functions that can only be retrieved by calling vkGetInstanceProcAddr (such as vkGetPhysicalDeviceCalibrateableTimeDomainsKHR).

The way that Vulkan functions are loaded in Silk 3 means that it will work (try device first, then instance), but it will also report a Vulkan validation warning:

vkGetDeviceProcAddr(): pName is trying to grab vkGetPhysicalDeviceCalibrateableTimeDomainsKHR which is an instance level function

Unfortunately, there doesn't seem to be an easy way to get around this either other than properly categorizing the functions according to the Vulkan spec for vkGetDeviceProcAddr:

The returned function pointer must only be called with a dispatchable object (the first parameter) that is device or a child of device e.g. VkDevice, VkQueue, or VkCommandBuffer.

Silk 2 implementation:

public bool TryGetDeviceExtension<T>
#endif
(Instance instance, Device device, out T ext, string layer = null) where T : NativeExtension<Vk> =>
!((ext = IsDeviceExtensionPresent(instance, ExtensionAttribute.GetExtensionAttribute(typeof(T)).Name, layer)
? (T)Activator.CreateInstance
(typeof(T), new LamdaNativeContext(x => GetDeviceProcAddr(device, x)))
: null) is null);

Silk 3 implementation:

void* ptr = Ivk.GetDeviceProcAddr(Vk.CurrentDevice, functionName);
if (ptr != null)
{
return ptr;
}
ptr = Ivk.GetInstanceProcAddr(Vk.CurrentInstance, functionName);

Steps to reproduce

On a device that has support for the VK_KHR_calibrated_timestamps extension, load the extension using TryGetDeviceExtension and call GetPhysicalDeviceCalibrateableTimeDomain.

You will get a Native symbol not found (Symbol: vkGetPhysicalDeviceCalibrateableTimeDomainsKHR) error and a Vulkan validation warning if Vulkan validation layers are turned on.

Calling GetInstanceProcAddr, as suggested by the warning, will result in a valid function pointer and no validation errors.

Comments

Since I'm the one in charge of the Vulkan bindings for Silk 3, I'll fix this at some point before the full release.

I'll use a workaround in my own codebase for Silk 2.
This seems to require reading the object type graph defined in the Vulkan XML spec and modifying codegen, so not a trivial fix.

This works as a workaround:

// Workaround for https://github.com/dotnet/Silk.NET/issues/2547
if (EnabledDeviceExtensions.Contains(KhrCalibratedTimestamps.ExtensionName))
{
    VkCalibratedTimestamps = new KhrCalibratedTimestamps(new LamdaNativeContext(name =>
    {
        if (name == "vkGetPhysicalDeviceCalibrateableTimeDomainsKHR")
        {
            // Instance only
            return vk.GetInstanceProcAddr(Instance, name);
        }

        // The usual try device, then instance fallback
        var pointer = vk.GetDeviceProcAddr(Device, name);
        if (pointer != 0)
        {
            return pointer;
        }

        return vk.GetInstanceProcAddr(Instance, name);
    }));
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    Status

    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions