-
Notifications
You must be signed in to change notification settings - Fork 190
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
ash: Repeatedly call enumeration functions when VK_INCOMPLETE
is returned
#465
Conversation
I think this PR can go in with a patch release as no API is modified. However, IMO we should perform a minor (breaking) release afterwards to get rid of explicit get_image_sparse_memory_requirements2_len()
get_physical_device_queue_family_properties2_len()
get_physical_device_sparse_image_format_properties2_len()
enumerate_physical_device_groups_len() The problem here is that their non- However, maybe some (embedded) applications perform "optimizations" and keep this in static arrays for which they want to have the |
ash/src/prelude.rs
Outdated
/// the result-vec is not large enough. | ||
/// | ||
/// [`vkEnumerateInstanceExtensionProperties]: https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkEnumerateInstanceExtensionProperties.html | ||
pub(crate) unsafe fn read_into_vector<T>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Naming suggestions are welcome, btw 😉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
However, IMO we should perform a minor (breaking) release afterwards to get rid of explicit *_len() functions and make them use the same helper instead
These variants were introduced for the case where an extension output structure may be needed, in which case each element's pNext
must be initialized to address a unique output structure. It'd be nice to develop a high-level, abstract interface for that case, but the helper introduced here isn't sufficient; it'll have to be significantly more complex (maybe a HList of vecs?).
Conveniently enough only We can think about helpers for initializing |
9a82158
to
32f7c48
Compare
Yeah, I think there's a whole bunch of cases where we haven't exposed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this really needed for all these functions? I'd think that the scenario when VK_INCOMPLETE shows up is very specific, since something must be able to change behind ones back. It doesn't mean that all of the vectored queries have to do it.
@kvark The documentation for every function that now uses Either way I don't want to be inconsistent in our API and only handle In any case, if we really want to make a distinction between those kinds of functions (again, if the Vulkan API clearly specifies this), the non-looping queries would get an assertion/panic instead as they're not allowed to change the count after initially querying it. |
Specification says |
Yes, that's the definition of the error. What it doesn't say is that the required capacity is guaranteed never to change. We should not rely on assumptions that implementations are under no obligation to comply with, particularly when there's clear precedent for getters that may change at any time. |
The exact phrasing in the specs is:
But it does not say when or how this array can be too small. |
This is extremely unlikely (dare I say impossible bar cosmic radiation) when ash just queried the count in the previous call. You yourself suggested to run this in a loop, and since If you want to get to the bottom of this I recommend checking if anything on the system of the original reporter is out of the ordinary, and otherwise insert some debug logging to see if the count indeed changes (and if possible, run this in some tight loop that could perhaps diff the list before and after). This is also my first time encountering I'd still like to keep the |
ok, I don't think my point got through, but I also don't want to block this fix that would clearly help us. So please land this :) |
@kvark It's important to get on the same page first as this fix is solving an issue reported by you - I have never seen it before and don't rely on this PR. If you think there is a specific environment in which a change in |
The problem originates from this clause:
This is specifically about |
@kvark Now that brings something new to the table. Up to this point it looks like everyone failed to notice that bit in the spec but you. Are you aware of any other function that has the same or a similar mention in the spec? I'll update this PR ASAP to deal with this. |
It's not new, it's the starting point - #464 (comment) |
VK_INCOMPLETE can happen : 1/ if the user provides an array that is too small. 2/ when using a Vulkan function that explicitly mentions that the list can change between two calls. 3/ with bad user code ? |
New in the sense that I hadn't noticed / forgotten this was mentioned in the issue.
Great, only one function to deal with then.
Couldn't happen before either, because Ash was querying the size and directly reusing this value in every instance.
We'll do this just for
Strongly doubt this. Maybe available layers can change at any point since that's an external factor? |
What about functions related to hardware ? |
Same thoughts here; quick testing shows this doesn't change until restarting the application. Maybe that is the case for similar functions, too. |
We should do this for every function that may return |
Rather, there's two camps now: those who want to spend one extra cycle for the compare, and those who don't. I'm all for the defensive route, feel free to merge. |
…erties The type and next-pointer of output structures must always be initialized. Fixes: ac4d046 ("Added `VK_EXT_tooling_info` extension support (ash-rs#310)")
ae3a715
to
92611e6
Compare
I don't care about extra cycles for this. I care about Ash knowing what API it abstracts over. So far, Vulkan spec does not explicitly spell out any guarantees about what the count is between different invocations, except for Also, I'm no longer sure that the loop is the right solution here. What's the point of ensuring that you got exactly all of the elements at some point of the program execution? If I got 3 layers reported, that doesn't mean that the next second the configuration isn't going to change, anyway. Did we consider just doing the following:
This seems marginally better than having a loop. And in a scenario where it happens - your configuration changed between two invocations - there isn't any guarantee that it's not going to change right after the call, anyway. This is all super bike-sheddy, and I understand if you folks just don't consider it worth improving. Landing the patch as is would be fine by me. |
There's also |
If the spec guarantees a thing in one case and doesn't guarantee that thing in other cases, that's not a bug, it's the absence of a guarantee. When behavior isn't guaranteed, we cannot assume a single possibility.
Good question. Unfortunately, it is necessary, because there's no guarantee which results are omitted from an incomplete set. A user can reasonably be expected to tolerate having fractionally out of date information regarding a change in configuration/whatever that just happened, but they should not expect to lose information that hasn't ever changed just because another datum in the same category changed.
IMO adding |
Merging as-is since this is a clear improvement over the status quo, and a code size reduction besides. We can discuss in a new issue if anyone feels further refinement is necessary. |
(In addition to what @Ralith said, which I totally agree with) I say we do, for the sake of being friendly to crate users instead of leaving them open to this under-specified part of the spec (as @Ralith said, there's no explicit guarantee that this won't happen).
If we get back less, that's fine. If we get back more, that's a
And if it's less, I don't think the caller is interested in that at all. Unless they're doing sub-microsecond poking of the Vulkan API to figure out when exactly this count changes (higher or lower) - I'll redirect them to use the raw pointer functions if that's their intended usecase 😬 |
0.33.2 is now released with this change. |
…`pNext` We've often discussed `pNext` chains in output arrays (i.e. #465, #588, #744), and I always wondered why `read_into_defaulted_vector()` still existed: turns out this helper function was only hiding a few more remaining cases where the caller was previously _not_ able to manually extend the `pNext` chain to request arbitrary more structures to be filled with information. Replace these remaining cases with a separate `_len()` getter, and have the main function take a caller-allocated `&mut [T]` slice where they can initialize the target struct including `pNext` pointer chains.
…`pNext` We've often discussed `pNext` chains in output arrays (i.e. #465, #588, #744), and I always wondered why `read_into_defaulted_vector()` still existed: turns out this helper function was only hiding a few more remaining cases where the caller was previously _not_ able to manually extend the `pNext` chain to request arbitrary more structures to be filled with information. Replace these remaining cases with a separate `_len()` getter, and have the main function take a caller-allocated `&mut [T]` slice where they can initialize the target struct including `pNext` pointer chains.
…`pNext` We've often discussed `pNext` chains in output arrays (i.e. #465, #588, #744), and I always wondered why `read_into_defaulted_vector()` still existed: turns out this helper function was only hiding a few more remaining cases where the caller was previously _not_ able to manually extend the `pNext` chain to request arbitrary more structures to be filled with information. Replace these remaining cases with a separate `_len()` getter, and have the main function take a caller-allocated `&mut [T]` slice where they can initialize the target struct including `pNext` pointer chains.
…`pNext` (#966) We've often discussed `pNext` chains in output arrays (i.e. #465, #588, #744), and I always wondered why `read_into_defaulted_vector()` still existed: turns out this helper function was only hiding a few more remaining cases where the caller was previously _not_ able to manually extend the `pNext` chain to request arbitrary more structures to be filled with information. Replace these remaining cases with a separate `_len()` getter, and have the main function take a caller-allocated `&mut [T]` slice where they can initialize the target struct including `pNext` pointer chains.
Fixes #464