Closed devshgraphicsprogramming closed 3 years ago
Looking on the https://repository.genmymodel.com/devshgraphicsprogramming/VulkanComputeAndRenderPassIndependentPipelines and https://repository.genmymodel.com/devshgraphicsprogramming/VulkanPipelineLayout
In Vulkan backend IGPUDescriptorSetLayout is going to hold descriptor set VK object?
Its a layout (result of vkCreateDescriptorSetLayout1), not the object itself (result of
vkAllocateDescriptorSets`).
In Vulkan objects sometimes have a layout, when they have a layout it means that there are actually two objects needed, one for the layout and one for an instance of the object that conforms to the layout.
Think of it as an Interface and Implementation in C++ with inheritance, the 3rd party objects (i.e. pipeline) that depend on the object (i.e. descriptor set) will usually only take the layout in the creation info, so that particular instances of the dependee can be interchangeable (different descriptor sets with same layout can be plugged into the same pipeline).
More info: https://vulkan-tutorial.com/Uniform_buffers/Descriptor_pool_and_sets
you can const bool = false
the two members of IGPUDescriptorSetLayout
, which are mIsPushDescLayout
and mCanUpdateAfterBind
. We'll have no use for them in the engine, yet.
should pipeline layout hold 4x descriptor set layout? I mean when drawing meshbuffer, pipeline layout is going to consist of 4 descriptor set layouts from 4 different locations in the engine (global, render pass, scene node, meshbuffer). So it seems like there shouldnt be such thing as pipeline layout in the engine API at all.
Up to 4x descriptor set layout, when not using the CPU to GPU object converter the user shall hook them all up manually.
The layout of the higher-level (global, render pass, scene node) descriptor sets has to match the shader used anyway, so even if we did not have a pipeline layout we'd be in deep shit.
To reiterate, the shader input types and bindings delcared in the SPIR-V have to match the descriptors bound 100%, so not putting that constraint on the engine programmer makes no difference, since it will crop up in the end anyway.
Even in OpenGL if you wanted to do stuff automagically you'd have to say that bindings [0,X), [X,Y) and [Y,Z) for every resource type are reserved by the engine for the default global/renderpass/scenenode UBOs, textures etc.
The best and only thing we can do is come up with a default decriptor layout for global, camera and scene node. Which will probably be just 1 UBO and 1 SSBO for each set or whatever we need to replace EMT_SOLID, EMT_TRANSPARENT_ALPHA and EMT_TRANSPARENT_ALPHA_REF.
Remember Descriptor set layout only says what type at what binding will be bound, not the contents or struct definition. Also it doesn't even say the texture type (1D/2D/3D).
Lastly we should read up on decriptor compatibility rules, namely whether one can just declare a descriptor set with extra bindings that are not used by the shader. The wording of the spec and NVidia explainers is fuzzy as hell.
In Vulkan objects sometimes have a layout, when they have a layout it means (...)
Yea, I know, but I don't see such thing as DescriptorSet or at least some way to bind actual resources to them in the UML. So are descriptor set VK objects going to be created, cached and maintained similarly as we're doing with samplers now? And what should be the API to actually bind resources?
I don't see such thing as DescriptorSet
Yes, you're correct, I was only thinking about the pipelines at the time (and for them to be created they need pipeline layouts, which in turn need to know about descriptor layout).
A descriptor set UML would have included a DescriptorPool and a CommandBuffer
Normally in Vulkan to set pipelines, bind descriptor sets, vertex inputs, etc. you do it with a vkCmd
* function that takes VkCommandBuffer
. However for now those functions need to be added to IVideoDriver
, since we're not spiralling out of control with implementing command buffers.
The descriptor set creation function is vkAllocateDescriptorSets
and its counterpart can be made in video::IDriver
because its a vkDevice function, also can take a descriptor pool object stub as parameter.
To actually populate/fill the descriptor set with the correct handles, there are two functions: https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkUpdateDescriptorSetWithTemplate.html https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkWriteDescriptorSet.html
Unsure which one is more appropriate. Will ask around
An excerpt from the Vulkan spec https://www.khronos.org/registry/vulkan/specs/1.0-extensions/html/vkspec.html#descriptorsets-compatibility
Two pipeline layouts are defined to be “compatible for push constants” if they were created with identical push constant ranges. Two pipeline layouts are defined to be “compatible for set N” if they were created with identically defined descriptor set layouts for sets zero through N, and if they were created with identical push constant ranges.
So for a descriptor set A to work with shader that uses descriptor layout B for the same set:
And for a descriptor set A to stay bound when a pipeline is changed, either:
For a pipeline layout to work with a shader:
All resource variables statically used in all shaders in a pipeline must be declared with a (set,binding,arrayElement) that exists in the corresponding descriptor set layout and is of an appropriate descriptor type and includes the set of shader stages it is used by in stageFlags. The pipeline layout can include entries that are not used by a particular pipeline, or that are dead-code eliminated from any of the shaders. The pipeline layout allows the application to provide a consistent set of bindings across multiple pipeline compiles, which enables those pipelines to be compiled in a way that the implementation may cheaply switch pipelines without reprogramming the bindings.
Similarly, the push constant block declared in each shader (if present) must only place variables at offsets that are each included in a push constant range with stageFlags including the bit corresponding to the shader stage that uses it. The pipeline layout can include ranges or portions of ranges that are not used by a particular pipeline, or for which the variables have been dead-code eliminated from any of the shaders.
So basically we can "over-declare" push constant ranges and bindings to make sure the pipeline layout works with multiple shaders, something that would be quite useful for the built-in shaders.
You're not answering my questions at all XD
So should there be c++ classes for descriptor sets?
YES
Is there any reason to have CPU and GPU descriptor set? (IMO not since descriptor sets are purely GPU objects)
Yes, because how else would you serialize of spit out a scene made of asset::IAsset
that also includes shaders, blending states and their input parameters?
what is the API to bind resources? I mean the thing which is done in Vulkan with vkUpdateDescriptorSets
IDriver::updateDescriptorSets
there's also an option to use descriptor set update templates, but I haven't read up on that yet.
ok so that Template Descriptor Update thing only makes sense after we move to Vulkan, cause its not useful for OpenGL (that has only like 32 texture bindings max, etc.).
But after RTX with Descriptor Indexing, why not.
Also might have to read up the Vulkan spec about immutable objects, for now I see two examples but there may be more:
In this case it would be useful to declare a class similar to core::IThreadBound
namespace irr
{
namespace video
{
class IRR_FORCE_EBO IReducedMutability
{
bool immutable;
protected:
IReducedMutability() : immutable(true) {}
inline void makeImmutable() {immutable = true;}
public:
inline bool isImmutable() const {return immutable;}
};
}
}
Yes, because how else would you serialize of spit out a scene made of asset::IAsset that also includes shaders, blending states and their input parameters?
shaders are separate thing, blending states live in IRenderpassIndependentPipeline, none of these need descriptor sets. And i dont know what u mean by input parameters. What should ICPUDescriptorSet actually be then? Should it hold ICPUBuffers as UBOs and SSBOs? And by the way what should ICPUDescriptorSets be held by? Pipelines hold just layouts.
Well, we need CPU counterparts of descriptor sets to be able to load meshes with textures, but exporting/loading UBOs and SSBOs seems weird to me.
IRenderpassIndependentPipeline, none of these need descriptor sets. And i dont know what u mean by input parameters.
Correct, they don't need descriptor sets
Wrong, they need descriptor set layouts. IRenderpassIndependentPipeline
is a counterpart to IComputePipeline
everything the VkPipeline is except for the renderpass info, so it needs the descriptor set layouts just like the compute pipeline.
And i dont know what u mean by input parameters.
Vertex input buffers I meant.
asset::ICPUMesh must hold references only to asset::IAsset derived objects, that includes all the shaders, render states, and inputs (Texutres, Vertex Input, etc.)
Old Set Up:
New Set Up:
The new thing here is that the previous system assumed IBuffer bind point = attribute bind point, with new system (this is also supported by OpenGL 4.3, and used internally) your shader inputs can be bound arbitrarily to pipeline bind-points (location!=bind point) so you can criss-cross the buffers more.
What should ICPUDescriptorSet actually be then? Should it hold ICPUBuffers as UBOs and SSBOs? And by the way what should ICPUDescriptorSets be held by? Pipelines hold just layouts.
Yes, ICPUDescriptorSet holds Textures, UBOs, SSBOs, TBOs (buffers just bound to a texture slot), Storage Images (just textures bound to appropriate slot, I'll manage the OpenGL refactor on that as part of #148 ), it would possibly make sense to add an empty abstract base asset::IDescriptor : public asset::IAsset
but only if it won't introduce diamond inheritance.
An IMeshBuffer
will hold IDescriptorSet
, just like it holds the pipeline and buffers to be used as vertex input and index buffer.
Well, we need CPU counterparts of descriptor sets to be able to load meshes with textures, but exporting/loading UBOs and SSBOs seems weird to me.
It will make sense with time, when you'll be able to serialize more complex shaders or systems (entire scenes with shared object transforms).
Ok, so meshbuffer hold just one descriptor set (the one which will go as number 3), and about the 3 other ones (desc set of numbers [0..2]) we rely on user (or default ones) to be compatible with shaders? Also i'm relying on your knowledge, that it's perfectly fine in Vulkan to have descriptor set in slot 3, and not have any in slots 0,1,2. Is that right? I mean there should be possibility that there's no global/camera/scenenode desc set currently present/needed.
So that clears a lot, thanks
A side-note, it would make sense to have at least your GPU object creation routines take structs as parameters, and then those structs to be defined to be almost the same as Vulkan function's.
For example this struct
https://github.com/buildaworldnet/IrrlichtBAW/blob/master/include/IDriverMemoryAllocation.h#L27
can be memcpy
onto the end of VkMappedMemoryRange
And this literal Vulkan struct is used here https://github.com/buildaworldnet/IrrlichtBAW/blob/master/include/IDriverMemoryBacked.h#L17
You can use Vulkan structs as much as you like, just remember to redeclare them and then wrap the redeclarations in (actually we should make a special header in irr/core/asset/vulkan/
for this)
#if !defined(VOLK_H_) && !defined(VULKAN_H_)
#endif
for our friends without the Vulkan SDK installed
Ok, so meshbuffer hold just one descriptor set (the one which will go as number 3), and about the 3 other ones (desc set of numbers [0..2]) we rely on user (or default ones) to be compatible with shaders?
Yes, we will have to rely on the user not to fuck this up. But thats the same case in OpenGL, but instead of getting an unexplained error with funny rendering or nothing rendering with no error message resulting in the spamming our discord, the Vulkan validation layer will complain or without the layer Vulkan will crash. Or we will complain on OpenGL anyway or in the null driver (we can perform debug validation checks there.
Also i'm relying on your knowledge, that it's perfectly fine in Vulkan to have descriptor set in slot 3, and not have any in slots 0,1,2. Is that right? I mean there should be possibility that there's no global/camera/scenenode desc set currently present/needed.
I think thats 99% surely correct, I've asked just to be 200% sure.
Few questions:
where should uint8_t[128] (push constants) live? And I assume the interface to set those is to just memcpy into that array and user is responsible for proper alignments?
They're the most likely to change on a per-draw basis, so in IMeshBuffer (together with descriptor set 3).
The interface to set those should be in the video
namespace and be almost "verbatim" what the vulkan interface is (on OpenGL this includes some translation of range to set of uniforms to update).
what will hold buffers with vertex attribs now? meshbuffer?
Buffers and global offsets yes, everything else IRenderpassIndependentPipeline.
where should vao GL object live now? meshbuffer?
Same as before, a cache, because VAOs are thread-bound. Just now the OpenGL derivation of IGPURenderpassIndependentPipeline will need to provide a "vao hash" function just like the derivation of IGPUMeshDataFormatDesc
used to (you can even copy the code).
Now just need pools (future PR)
Kinda done... on https://github.com/Devsh-Graphics-Programming/Nabla/pull/28
After #130 we will have the 95% of the necessary shader-reflection data to generate the descriptor set layout, and most of the data to generate a pipeline layout as well.
More info to come