-
Notifications
You must be signed in to change notification settings - Fork 194
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
extensions/khr: Add VK_KHR_pipeline_binary extension #944
base: master
Are you sure you want to change the base?
Conversation
e46d73b
to
a97aa7d
Compare
a97aa7d
to
0b62cd5
Compare
Our
It's quite unfortunate that the |
69cf5ec
to
dd71365
Compare
// TODO: This returns NOT_ENOUGH_SPACE_KHR, not INCOMPLETE (because nothing is written, instead of returning an impartial result) | ||
read_into_uninitialized_vector(|count, data| { | ||
(self.fp.get_pipeline_binary_data_khr)( |
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.
Not sure what to do here. We could map NOT_ENOUGH_SPACE_KHR
to INCOMPLETE
to make read_into_uninitialized_vector()
try again, though we could also be changing it at some point to return the incomplete but partial result to the user, which is invalid here.
If we don't, we can still use read_into_uninitialized_vector()
to help us call vkGetPipelineBinaryDataKHR()
twice. On NOT_ENOUGH_SPACE_KHR
- which is unexpected - that error is bubbled up to the caller (and they wouldn't know how to handle it, since the wrapper is the one that was dealing with querying and preallocating for the requested size initially...).
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.
Mapped to INCOMPLETE
and rewrote the documentation, also to reference the upstream issue (non-public repo).
@Ralith I think this is ready for merging unless you find anything glaring, and I'll follow up and clean up depending on how the upstream discussion pans out.
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.
After upstream clarification, VK_NOT_ENOUGH_SPACE_KHR
docs are accidentally missing and will be added. There's a fundamental difference with VK_INCOMPLETE
that's already described at vkGetPipelineBinaryDataKHR()
and supposedly the reason why this new return value was added:
and on return
pPipelineBinaryDataSize
is overwritten with the size of the data, in bytes, that is required to store the binary.
So even if the previously requested size is too small, the function doesn't write data (leaves it MaybeUninit
👀) but uses pPipelineBinaryDataSize
to communicate the required space again, so that the user doesn't have to call it yet another time.
This is unfortunately inconsistent from other binary-array-returning functions that predate the addition of this error return. They have their own ways of documenting "special behaviour"...
I think, but didn't ask, that this facilitates a pattern to preallocate static arrays on the stack with some predetermined upper bound. If less space is required only one API call is needed, otherwise the next call can be done immediately with the right size after heap-allocating something bigger. That pattern isn't possible with VK_INCOMPLETE
(and that would write data twice, too, for functions where partial results may still be valid).
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.
I wrote a new variant of read_into_uninitialized_binary_vector()
to deal with this.
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.
Also added some debug_assert!()
. None of the clauses invoke undefined behaviour, but do point to an incorrect implementation when returning VK_ERROR_NOT_ENOUGH_SPACE_KHR
.
Separate from this all, read_into_uninitialized_vector()
was initially designed (see its doc-comment) te deal with functions that arbitrarily change their count at runtime between calls, hence the infinite loop.
This behaviour is not expected for most functions currently using read_into_uninitialized_vector()
, but reuse it for conciseness due to also returning VK_INCOMPLETE
. These calls could benefit from the same "maximum of 2 calls" strategy (with debug asserts) and otherwise bubble VK_INCOMPLETE
back to the user. Unfortunately they cannot easily use a preallocated upper-bound Vec
like I did in read_into_uninitialized_binary_vector()
, because the Vulkan call wouldn't immediately tell us what the desired count is if it returned VK_INCOMPLETE
. We'd need a third call for that.
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.
These calls could benefit from the same "maximum of 2 calls" strategy
What's the benefit here? Just hypothetical improved detection of implementation bugs? Seems like unnecessary churn.
a28a63e
to
19c3eb3
Compare
19c3eb3
to
7be4595
Compare
pub unsafe fn get_pipeline_key( | ||
&self, | ||
pipeline_create_info: Option<&vk::PipelineCreateInfoKHR<'_>>, | ||
) -> VkResult<vk::PipelineBinaryKeyKHR<'_>> { |
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.
Shouldn't vk::PipelineBinaryKeyKHR
be an out parameter, to allow for extension? If this is for some reason undesired, then the lifetime should be 'static
.
/// Calls `f` twice until it does not return [`vk::Result::ERROR_NOT_ENOUGH_SPACE_KHR`], ensuring all | ||
/// available binary data has been read into the vector. |
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.
"twice until" is weird word choice. Maybe "at most twice"?
count > 4096, | ||
"Implementation should have updated the value to be higher than the initial request" | ||
); | ||
err_code = f(&mut count, data.as_mut_ptr().cast()); |
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.
This seems to be missing the code to actually expand the Vec
.
err_code = f(&mut count, data.as_mut_ptr().cast()); | |
data.reserve(count); | |
err_code = f(&mut count, data.as_mut_ptr().cast()); |
let mut count = 4096; | ||
let mut data = Vec::<u8>::with_capacity(count); |
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.
nit: with_capacity
may allocate extra space, and we might as well use it
let mut count = 4096; | |
let mut data = Vec::<u8>::with_capacity(count); | |
let mut data = Vec::<u8>::with_capacity(4096); | |
let mut count = data.capacity(); |
(and adjust the debug_assert
accordingly)
pub(crate) unsafe fn read_into_uninitialized_binary_vector( | ||
mut f: impl FnMut(&mut usize, *mut ffi::c_void) -> vk::Result, | ||
) -> VkResult<Vec<u8>> { | ||
let mut count = 4096; |
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.
Do we know that binaries are, in practice, usually smaller than this?
No description provided.