Mostly for consistency with everything else. If it proves to be
annoying, it can get removed again -- but suddenly realizing it's needed
would be much more painful and breaking user code.
I was hesitating a bit with the <chrono> include but I can't think of
anything better right now. It's "only" 4k lines on C++11 (and I bet most
of it is <type_traits>), so should be fine.
Because the drivers don't seem to check that features are actually
supported for anything beyond VkPhysicalDeviceFeatures2, we have to do
that instead. Additionally, we also check if a feature is enabled but
the extension that needs it is not (which isn't checked by drivers
either).
This was way more pain that initially expected, especially in regards to
preserving externally-specified pNext chains without writing to them in
any way.
This is what I needed BigEnumSet for -- good thing I didn't even try to
have 128-bit enums because I'm now at 110 values and it's still far from
complete. Next step is enabling those features when creating a device,
which should hopefully be a lot less code, reusing most of what was
here.
After I implemented the render pass wrapper, seeing how the
RenderPassCreateInfo structure and its dependencies were HUGE compared
to the actual tiny and lean RenderPass, I felt uneasy dragging their
definition along to every place where a RenderPass gets used. It's not
as bad with the others, but as new extensions are implemented I expect
that to get the same.
This change makes it easier for me to accept that Image.h / Buffer.h
depends on Memory.h. There isn't a real measurable difference when
building Magnum itself (50 ms out of 7 seconds for the Vk library
alone), but that's because most of the code (and tests) needs the
CreateInfo structures anyway.
Quite a big chunk of work, further expanded due to how
VK_KHR_create_renderpass2 is designed -- basically, due to the
tightly-packed nested structures that got replaced with their "version
2", we can no longer just extract the previous structure for backwards
compatibility, but instead have to deep-copy everything to a newly
allocated memory.
Thanks to the the new ArrayTuple structure and a few design iterations I
managed to kick the backwards-compatiblity code into just a single
allocation, while still keeping it possible for the "version 2" code
path to be fully allocation-free (if one passes a completely filled
VkRenderPassCreateInfo2 structure there).
More convenient to use since one doesn't have to explicitly store a
DeviceProperties instance to call pickQueueFamily() on it and then move
it to DeviceCreateInfo to keep it efficient.
This required a slight redesign of how DeviceProperties are stored in
DeviceCreateInfo, now we need the instance to be always valid (but it
can get never used). The wrap() API isn't doing any extra work so this
won't add any inefficiency.
For some reason it wants me to allocate 16 bytes more. Why can't that be
stored somewhere else, I wonder?
Hm, and for this I implemented VK_KHR_driver_properties only to discover
that the info is not queryable if we run the tests with
KHR_get_physical_device_properties2 disabled. Sigh.
Today I spent six hours wrongly convincing myself that it's a driver bug
when vkGetPhysicalDeviceProperties2() is null on a 1.1 instance for a
1.0 physical device. It's not a bug, it's me not reading specs
carefully.
This commit thus basically moves all Instance-level extension-dependent
state to DeviceProperties, because it's actually device-dependent. Which
makes the DeviceProperties class quite heavy and thus it's good it was
readied to be transferred all the way to a Device instance a few commits
back -- I don't really want to do all the dispatch, string processing,
sorting and other mess more times than strictly necessary.
In addition, DeviceProperties::apiVersion() got renamed to version() and
a new isVersionSupported() API got added, mirroring what's on Device
itself; plus thanks to the chicken-and-egg problem of having to call
vkGetPhysicalDeviceProperties() twice, the device version and other
things can now be retrieved in a slightly more efficient way.
Similarly to Corrade Assert.h, so it's possible to include this header
without having to worry about irrelevant overhead when asserts are
disabled.
Also test it properly, as it should have been from the start.
I'm a bit unsure why there's a device extension that actually gets used
on an instance and doesn't need any enabling (and thus there's
currently no way to disable it to test all code paths, hmm).
I have more and more cases where I need to query device properties later
down the road (memory capabilities, device name, ...) and leaving all
this up to the user / making this impossible to do in the library
internals is complicating everything too much.
Since there's a shitton of device properties with a new bag of props
coming with every other new extension, I expect the queries to get quite
involved / complicated over time (chaining 100s structs and such), so
let's design this upfront in a way that can avoid reqpeatedly querying
the same thing just because we needlessly discarded a fully populated
instance before.
It also means the users don't need to drag their own DeviceProperties
instance along anymore and can just let the Device take care of that.
Unfortunately the only nice way to make this work with DeviceCreateInfo
method chaining is to add & and && overloads for each. But it's quite
easy to test that all of them work and properly return a r-value
reference so it shouldn't be too much of a maintenance nightmare.