-
Notifications
You must be signed in to change notification settings - Fork 192
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
[WIP] Implement extension chaining #183
Conversation
pub struct ExtensionChainMut { | ||
pub s_type: StructureType, | ||
pub p_next: *mut c_void | ||
} |
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.
Dead code?
generator/src/lib.rs
Outdated
pub struct ExtensionChain { | ||
pub s_type: StructureType, | ||
pub p_next: *mut c_void | ||
} |
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 this be named BaseStructure
or similar, along the lines of upstream?
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.
There is also vk::BaseOutStructure
which we might just reuse.
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.
That makes sense; then the loop helper can just be a top-level function, which perhaps shouldn't even be exported; it doesn't seem very broadly useful, and reducing API surface area is nice.
generator/src/lib.rs
Outdated
unsafe{ | ||
let ptr = &mut self.inner as *mut _ as *mut c_void; | ||
let last_extension = ExtensionChain::last_chain(ptr); | ||
(*last_extension).p_next = next.deref_mut() as *mut T as *mut c_void; |
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 kinda like the idea of prepending to the chain rather than appending, since it means we don't have to rely on the optimizer to erase the loop. On the other hand, the resulting sequence of links is less intuitive, and I'm not certain that the ordering never matters.
e7d9494
to
b7863d1
Compare
Difficult to review this due to the mangled history. Rebase? |
5b427dd
to
b5257bf
Compare
b5257bf
to
d6a6aa3
Compare
examples/src/lib.rs
Outdated
use std::ops::Deref; | ||
println!("--"); | ||
println!("{:?}", corner.deref() as *const _); | ||
println!("{:?}", variable_pointers.deref() as *const _); |
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 still need these prints?
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.
No I'll convert this code to a test. Not quite sure where to put it though. Possibly into the vk.rs
.
generator/src/lib.rs
Outdated
unsafe{ | ||
let last_extension = ptr_chain_iter(&mut self.inner) | ||
.last() | ||
.expect("Initial ptr was null"); |
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.
Can we get rid of ptr_chain_iter
too, now, and keep the API narrower?
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 wanted to use it for tests. Maybe we can just define it inside the test module.
generator/src/lib.rs
Outdated
.expect("Initial ptr was null"); | ||
// Append the extension at the end | ||
(*last_extension).p_next = next as *mut T as *mut _; | ||
let next_ptr: *mut BaseOutStructure = ::std::mem::transmute(next); |
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.
Transmute isn't needed for casting between pointers.
generator/src/lib.rs
Outdated
|
||
let next_function = if has_next { | ||
let next_extends = _struct.extends.as_ref().map(|extends| { |
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 variable name is confusing. Maybe something like extension_trait_name
?
generator/src/lib.rs
Outdated
let next_extends = _struct.extends.as_ref().map(|extends| { | ||
let extends = extends | ||
.split(',') | ||
.find(|extend| root_create_info_names.contains(&extend.to_string())) |
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.
When is this check necessary? Do there exist structs that extend non-root structs?
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 there exist structs that extend non-root structs?
Yes not all extend structs are root. I'll add a comment, and I to slightly rewrite this anyway.
generator/src/lib.rs
Outdated
.split(',') | ||
.find(|extend| root_create_info_names.contains(&extend.to_string())) | ||
.expect("Should have a root create info"); | ||
name_to_tokens(&format!("Extends{}", name_to_tokens(&extends))) |
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 we be implementing the extension trait of every struct that this struct extends, rather than just an arbitrary one?
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.
What do you mean by arbitrary one? Only root create infos will create a new trait, and only non root create infos that extend a root create info will implement this trait.
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.
Unless I'm missing something, this seems to be used for deciding when to implement the trait, not when to define it. A single extension struct (e.g. VkPhysicalDeviceVariablePointerFeatures
) can extend multiple root structs, and must implement all of their extension traits.
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.
Ah yes that is what I wanted to implement. I just chose the first one.
generator/src/lib.rs
Outdated
@@ -1613,7 +1612,9 @@ pub fn derive_setters( | |||
// implement | |||
let next_trait = if has_next && _struct.extends.is_none() { | |||
quote! { | |||
pub unsafe trait #extends_name {} | |||
pub unsafe trait #extends_name { | |||
unsafe fn as_ptr_mut(&mut self) -> *mut BaseOutStructure; |
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.
Instead of generating more code here, we should mark all builders as #[repr(transparent)]
and coerce the pointers directly in push_next
. This is legal because the builders contain only one non-zero-sized member.
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.
That is a great idea, I completely forgot about #[repr(transparent)]
.
We shouldn't be referring to extensible root structs as "create infos," because not every extensible struct is named |
@Ralith I think I addressed all issues.
I don't think that I am? I think I only refer to root create infos if they are structs that are passed into a function. |
generator/src/lib.rs
Outdated
|
||
// We only implement a next methods for root create infos | ||
let next_function = if has_next && next_extends.is_none() { | ||
let next_function = if has_next && root_extends.is_empty() { | ||
quote! { | ||
/// Prepends the given extension struct between the root and the first pointer. This | ||
/// method only exists on create infos that can be passed to a function directly. Only |
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 method only exists on create infos that can be passed to a function directly
This is incorrect, because this method exists (and is useful) on output structs too.
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 you have an example?
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.
For example, it should be (but seemingly is not yet) defined for VkPhysicalDeviceProperties2
. The same goes for any other root output struct with a p_next
member.
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.
The current implementation doesn't allow for pointer chains to be added. As in push_next
on VkPhysicalDeviceProperties2
and then insert VkPhysicalDeviceProperties2
into DeviceCreateInfo
. We would need to iterate over the chains (which is fine). I don't think this is necessary though. push_next
only on root create infos seems fine to me.
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 don't understand what you're trying to say. VkPhysicalDeviceProperties2
is an output struct; it does not extend VkDeviceCreateInfo
, it is used to return data from vkGetPhysicalDeviceProperties2
. It, and every struct like it, needs exactly the same extension semantics as you've implemented so far for root CreateInfo
structs.
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.
Okay I see what you mean. It is correctly implemented (as in VkPhysicalDeviceProperties2
has a push_next
fn). I'll just have to update the comments.
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.
Oh, so it is, was just searching badly.
generator/src/lib.rs
Outdated
} | ||
} | ||
} | ||
} |
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.
Does this need to be in the generated code, rather than a regular module of the ash
crate?
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.
We could have this code outside of the generator, and if we have ash-sys
it will then be part of that crate. I'll change it.
generator/src/lib.rs
Outdated
.iter() | ||
.filter_map(|definition| match *definition { | ||
vkxml::DefinitionsElement::Struct(ref _struct) => { | ||
let is_root_create_info = _struct.extends.is_none(); |
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 is incorrect for VkPhysicalDeviceProperties2
, which is both a root getter struct and an extension struct for CreateInfo
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.
Instead, why don't we use the set of things that appears in structextends
attributes? I haven't seen any cases where those are layered, though maybe I haven't looked hard enough.
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.
which is both a root getter struct and an extension struct for CreateInfo
What exactly do you mean by that? Afaik it is just used in vkGetPhysicalDeviceProperties2
.
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.
Disregard, I was confused; too early for code review...
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.
Don't worry happens to me all the time :).
Right now the only thing that is missing are better variable names and fixing some comments right? |
There's still the test code in the generator that doesn't need to be there. |
I believe we should still iterate through the chains even if it not necessary for the builder.(Attach head and tail) You can still create pointer chains without the builders and inserting those would not work. Otherwise we could implement |
How about Iterating through the chain of the argument to |
Yeah that was the idea :). |
e61bfd6
to
c8253cf
Compare
c8253cf
to
1744159
Compare
generator/src/lib.rs
Outdated
@@ -2144,6 +2198,23 @@ pub fn write_source_code(path: &Path) { | |||
let source_code = quote! { | |||
use std::fmt; | |||
use std::os::raw::*; | |||
/// Iterates through the pointer chain. Includes the item that is passed into the function. | |||
/// Stops at the last `BaseOutStructure` that has a null `p_next` field. | |||
pub unsafe fn ptr_chain_iter<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.
Is there a good reason for this to be part of the public API?
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.
It is used in the test api. I am not sure, is it even possible to share pub(crate)
code in the external tests module? I could move the tests into lib.rs
, and it should work with use super::vk
.
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.
That sounds like a better solution to me. You could also have an internal tests module, rather than cramming everything into lib.rs.
We should be trying to minimize the amount of code the generator emits (because it's inconvenient to manipulate) and the amount of public API that doesn't have a specific strong motivation (for ease of maintenance).
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.
Agreed, a lot of the trait / macro definitions could be defined outside of the generator.
@@ -657,11 +657,18 @@ impl<'a> ::std::ops::Deref for PhysicalDeviceWaveLimitPropertiesAmdBuilder<'a> { | |||
} | |||
} | |||
impl<'a> PhysicalDeviceWaveLimitPropertiesAmdBuilder<'a> { | |||
pub fn next<T>(mut self, next: &'a mut T) -> PhysicalDeviceWaveLimitPropertiesAmdBuilder<'a> | |||
pub fn push_next<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.
I'm confused about where this definition is coming from. It's missing the chain support added to the generated version. I guess it's hand-written? Is that necessary?
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.
Yes it is handwritten. I am not sure what we should do about it. Maybe we should remove all the builder stuff because it will probably get out of date anyway?
I am going to update it anyway.
Everything in experimental won't adhere to semver, so we can remove some parts in the future. I probably should document 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.
Not a blocker, then, but why isn't this generated?
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.
Oh this is not included in the vk.xml. That is why it is inside the experimental module. @msiglreith basically reversed the API :). This will be deleted when it is officially included in the vk.xml.
b4c5ffa
to
2635e86
Compare
2635e86
to
cbc96b2
Compare
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.
Remaining issues aren't stability-sensitive, and can be fixed in future work.
@@ -657,11 +657,18 @@ impl<'a> ::std::ops::Deref for PhysicalDeviceWaveLimitPropertiesAmdBuilder<'a> { | |||
} | |||
} | |||
impl<'a> PhysicalDeviceWaveLimitPropertiesAmdBuilder<'a> { | |||
pub fn next<T>(mut self, next: &'a mut T) -> PhysicalDeviceWaveLimitPropertiesAmdBuilder<'a> | |||
pub fn push_next<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.
Not a blocker, then, but why isn't this generated?
@@ -2144,6 +2198,23 @@ pub fn write_source_code(path: &Path) { | |||
let source_code = quote! { | |||
use std::fmt; | |||
use std::os::raw::*; | |||
/// Iterates through the pointer chain. Includes the item that is passed into the function. | |||
/// Stops at the last `BaseOutStructure` that has a null `p_next` field. | |||
pub(crate) unsafe fn ptr_chain_iter<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.
Because it's static code, this should probably be defined in ash/lib.rs, not spliced into the generator output.
bors r+ |
183: [WIP] Implement extension chaining r=MaikKlein a=MaikKlein This is only a proof on concept right now. I'll finish it up next week. What are your thoughts? Right now this requires a cast from `*const` to `*mut`. Co-authored-by: Maik Klein <[email protected]>
This is only a proof on concept right now. I'll finish it up next week.
What are your thoughts? Right now this requires a cast from
*const
to*mut
.