Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed VkResult Error on macOS VulkanSDK 1.3.216 #6109

Closed
wants to merge 0 commits into from
Closed

Fixed VkResult Error on macOS VulkanSDK 1.3.216 #6109

wants to merge 0 commits into from

Conversation

NewSkyLine-dev
Copy link

@NewSkyLine-dev NewSkyLine-dev commented Jan 22, 2023

Since VulkanSDK 1.3.216 it is mandatory to use the VK_KHR_PORTABILITY_subset extension. Fixed by adding

create_info.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;

aswell as adding VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME and VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME to the extensions array.
Issue: #6101
Note:
Maybe considure changing the extensions array to a vector, for better readability and for easier adding new extensions.

@wolfpld
Copy link
Contributor

wolfpld commented Jan 24, 2023

A proper implementation needs to check for the availability of the VK_KHR_portability_subset extension, and does not rely on #ifdefs.

The intent is that this extension will be advertised only on implementations of the Vulkan 1.0 Portability Subset, and not on conformant implementations of Vulkan 1.0. Fully-conformant Vulkan implementations provide all the required capabilities, and so will not provide this extension. Therefore, the existence of this extension can be used to determine that an implementation is likely not fully conformant with the Vulkan spec.

If this extension is supported by the Vulkan implementation, the application must enable this extension.

Additionally, the application must enable the VK_KHR_portability_enumeration extension to be able to enumerate non-conformant devices.

This extension allows applications to control whether devices that expose the VK_KHR_portability_subset extension are included in the results of physical device enumeration. Since devices which support the VK_KHR_portability_subset extension are not fully conformant Vulkan implementations, the Vulkan loader does not report those devices unless the application explicitly asks for them. This prevents applications which may not be aware of non-conformant devices from accidentally using them, as any device which supports the VK_KHR_portability_subset extension mandates that the extension must be enabled if that device is used.

@NewSkyLine-dev
Copy link
Author

Thanks for the feedback, but I honestly don't know what you mean. If I read the documentation of 1.3.216 right for macOS, it is now enforcing the user, to enable the VK_KHR_PORTABILITY_subset extension. I did it by adding a contexpr to check the VulkanSDK version, if yes, I #define VULKAN_HAS_KHR_PORTABILITY later in the code, it checks if it is defined, If yes, it includes VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME and VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME to the extensions array. Do I have to check if the extension is even supported?
Maybe could you explain it further so, that I correct my PR?
Would be very welcome :)

@wolfpld
Copy link
Contributor

wolfpld commented Jan 24, 2023

Do I have to check if the extension is even supported?

Yes, basically you need to check if the three extensions you are using are supported by the implementation, and only then enable them. It is possible that a future Mac Vulkan implementation will be fully conformant, in which case it will no longer advertise the portability subset, so requesting it will be an error. It is also possible that some other non-Apple implementation provides a non-conformant driver that you want to support here, but restrict behind an Apple-specific #ifdef.

The two functions that return a list of available extensions are vkEnumerateDeviceExtensionProperties and vkEnumerateInstanceExtensionProperties.

Things get even more complicated because Omar wants to support previous releases of MoltenVK (mentioned in #6101). While the VK_KHR_portability_subset extension was "always" required to enable, the VK_KHR_portability_enumeration extension is a recent addition. So you may have to resort to some kind of #ifdefing based on the header version anyway.

Technically, it would be nice to extend the driver selection process to select a non-conforming implementation only if there are no conforming implementations. See the current selection logic below:

// If a number >1 of GPUs got reported, find discrete GPU if present, or use first one available. This covers
// most common cases (multi-gpu/integrated+dedicated graphics). Handling more complicated setups (multiple
// dedicated GPUs) is out of scope of this sample.
int use_gpu = 0;
for (int i = 0; i < (int)gpu_count; i++)
{
VkPhysicalDeviceProperties properties;
vkGetPhysicalDeviceProperties(gpus[i], &properties);
if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
{
use_gpu = i;
break;
}
}

@ocornut
Copy link
Owner

ocornut commented Jan 24, 2023

Maybe considure changing the extensions array to a vector, for better readability and for easier adding new extensions.

I agree. You could use a ImVector<const char*> there and copy result from the first call, then amend the vector in the new code-path.

Things get even more complicated because Omar wants to support previous releases of MoltenVK

In most cases we try to support old versions of SDK, but Apple ecosystems carrying a culture of aggressive-updating and MoltenVK (along with Vulkan) being known to be frequently updated I am OK if we don't support this if it can simplify examples and/or backends.

I can't comment on the other specifics here. Happy to merge when it feels like we have a concensus.

@wolfpld
Copy link
Contributor

wolfpld commented Jan 24, 2023

In most cases we try to support old versions of SDK, but Apple ecosystems carrying a culture of aggressive-updating and MoltenVK (along with Vulkan) being known to be frequently updated I am OK if we don't support this if it can simplify examples and/or backends.

Unfortunately, availability of header defines for these extensions ripples to other platforms as well. For example, both VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME and VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR first appeared only in Vulkan SDK 1.3.208, which would be a new requirement on all platforms, if these extensions would to be supported everywhere.

An alternative would be to provide own definitions for missing things. For example, if VK_KHR_portability_enumeration preprocessor macro is not defined, add the following:

#define VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR 0x00000001
#define VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME "VK_KHR_portability_enumeration"

But this is not a solution I would prefer.

@ocornut
Copy link
Owner

ocornut commented Jan 24, 2023 via email

Comment on lines 67 to 69
constexpr auto desired_version = VK_MAKE_VERSION(1, 3, 216);

#if defined(__APPLE__) && VK_HEADER_VERSION >= desired_version
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't perform the correct test. The preprocessor doesn't know about constexpr variables and substitutes the not-defined name desired_version with an integer zero in the comparison.

@NewSkyLine-dev
Copy link
Author

Updated the whole commit. Now there is a proper function, that checks if the extension has to be enabled. Also modernized the code with few C++ aspects(std::cerr, std::vector<>). Maybe check if out and give some feedback. :) Compiles on Windows, as well as on macOS.

@ocornut
Copy link
Owner

ocornut commented Feb 15, 2023

Also modernized the code with few C++ aspects(std::cerr, std::vector<>)

Please don't. This has turned this PR from "need some smal tweaks to merge" into "impossible to merge" :(
There are multiple examples to keep in sync, multi-viewport in docking branch which is a larger beast, and we have an explicit policy to avoid C++ std library as much as we can. So those changes are unfortunately moving us backward.

I just need the minimum amount of changes (closer to 32da8f3 but ok to refactor slightly to use ImVector<> exactly in that spot to simplify adding extension) that also happens to be correct.

Thank you for your patience.

@NewSkyLine-dev
Copy link
Author

Alright. I understand. So I will change the modernized part to the old one, and change the extension part, to the new one. Is that correct so that it is “merge ready”, if there are no more conflicts?

@ocornut
Copy link
Owner

ocornut commented Feb 15, 2023

Right now there are hundreds of noisy changes in the PR so I would suggest to get back to square one.
I don't know what will be correct but I imagine I would follow wolfpld feedback above.

@NewSkyLine-dev
Copy link
Author

Alright, changed it to the original one, only added the advantages of the extension vector and the function that checks if the enumeration extension has to be enabled.

@ocornut
Copy link
Owner

ocornut commented Feb 15, 2023

This is still using C++ library std::vector instead of ImVector.
I might be wrong as I am merely glancing at the changes but it also looks incorrect, as the IMGUI_VULKAN_DEBUG_REPORT path would override previous extension, there's duplicate code (create_into fields filled twice), they are unusual variables (e.g. enablePortabilitySubset), checkExtensions() seems insufficiently designed/named.

vkEnumerateInstanceVersion(&vulkanVersion);
if (VK_VERSION_MAJOR(vulkanVersion) >= 1 && VK_VERSION_MINOR(vulkanVersion) >= 3 && VK_VERSION_PATCH(vulkanVersion) >= 216)
{
portabilitySubsetEnabled = false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this check disabling portability subset? If the extension is available, it must be enabled.

Copy link
Author

@NewSkyLine-dev NewSkyLine-dev Feb 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see your point. Now that I'm looking over everything again, I see that it would probably be easier to create two functions. One that checks the flag for VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR and one that checks if the VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME is enabled. And of course both check if the OS is macOS and the Vulkan version is >= 1.3.216. Is this the best solution? Maybe you know a better one. I am always grateful for better ideas.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stop making unnecessary checks. What does the OS or driver version has to do with anything here? Read what the extension specification actually says, and follow that to the letter.

@NewSkyLine-dev
Copy link
Author

Alright, I will look over it again, and will try to terminate all the C++ stuff and will change it to the ImVec version. And will look at the function again. It may very well be that something is not be as it should. Sry for the troubles.

Copy link

@zao zao left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've only looked over the code from a legacy SDK standpoint, haven't tried building it or looked at what older SDKs define.

{
uint32_t vulkanVersion;
vkEnumerateInstanceVersion(&vulkanVersion);
if (VK_VERSION_MAJOR(vulkanVersion) >= 1 && VK_VERSION_MINOR(vulkanVersion) >= 3 && VK_VERSION_PATCH(vulkanVersion) >= 216)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test would fail for future major or minor version bumps such as 1.4.0 or 2.0.0 where the lesser version components reset to lower numbers.


for (const auto &extension : availableExtensions)
{
if (strcmp(extension.extensionName, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME) == 0)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are all these *_NAME and *_BIT_KHR names defined in all older Vulkan SDKs that we support, or do they need to be guarded by the preprocessor, conditionally defined by us, or use our own string literals and constants?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would have to look it up, if all *_NAME and *_BIT_KHR are in older versions. I only looked at the newest version. Thanks for pointing this out.

@NewSkyLine-dev
Copy link
Author

NewSkyLine-dev commented Feb 16, 2023

So now I reduced everything to one function:

bool is_instance_extension_enabled(const char *extension_name)
{
    uint32_t extension_count = 0;
    VkResult result = vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, nullptr);
    if (result != VK_SUCCESS)
    {
        return false;
    }

    ImVector<VkExtensionProperties> extensions;
    extensions.resize(extension_count);
    result = vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, extensions.Data);
    if (result != VK_SUCCESS)
    {
        return false;
    }

    for (int i = 0; i < extensions.Size; i++)
    {
        if (strcmp(extensions[i].extensionName, extension_name) == 0)
        {
            return true;
        }
    }
    return false;
}

It checks if an instance extension is enabled, and returns true, if so, and false, if not.
Now the parts that changed in the code itself:

#ifdef __APPLE__
if (is_instance_extension_enabled(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME))
    create_info.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
#endif
ImVector<const char*> extensions;
uint32_t extensions_count = 0;
const char** glfw_extensions = glfwGetRequiredInstanceExtensions(&extensions_count);
for (uint32_t i = 0; i < extensions_count; i++)
    extensions.push_back(glfw_extensions[i]);
#ifdef __APPLE__
if (is_instance_extension_enabled(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME))
    extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
#endif 

I haven't committed it yet, because I don't know if these solutions are any good.
@wolfpld or @ocornut, would you be so kind and check if these functions are as requested, or if they even do what they should do? :) I will commit as soon as there is an OK from your sites. :)

@ocornut
Copy link
Owner

ocornut commented Feb 16, 2023

Easier to commit so we can review.
Right now I put this aside for a bit, I'll look at it in details later when I can test myself on a Mac.

@NewSkyLine-dev
Copy link
Author

NewSkyLine-dev commented Feb 16, 2023

Accidentally closed PR. New is open on #6172 Sry for the trouble

ocornut added a commit that referenced this pull request Apr 13, 2023
…dation layer errors. (#6109, #6172, #6101)

Enable VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME, VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR
ocornut added a commit that referenced this pull request Apr 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants