-
Notifications
You must be signed in to change notification settings - Fork 58
Vulkan Limitations due to OpenGL Support
- No ability to use separate descriptor sets (disputed)
- Every UBo/SSBO is a Dynamic UBO/SSBO (for now)
- No texture/sampler separation, combined imageSamplers only
- Limit Active textures to 96
- Limit Active SSBOs to 24 (and 4 for dynamic)
- Limit Active Storage Images to 24
- Limit Active UBOs to 72 (and 8 for dynamic)
- Push Constants need to satisfy and explicitly declare the std140 packing rules
Because the Vulkan spec gloriously doesn't keep separate binding points for different descriptor types (OpenGL opaque uniform types), normal good old working GLSL shaders will cease to work as every uniform needs its own unique (set,binding) tuple.
But OpenGL has separate binding indices for all of these!
And while yes, arrays exist, you can only have the exact same UBO buffer structs and SSBO buffer structs in an array, only the same texture/sampler type, same images etc.
The problem is all of this needs to be fitted in an video::SMaterial replacement (to arrive soon).
This lead me to an original solutions of:
- Assign a separate set to each shader resource type (UBO=0, SSBO=1, combinedImageSamplers/uniformTexelBuffers=2, storageImages/storageTexelBuffers=3, inputAttachments=4)
- Slam everything together in set=0 and hope it works and doesn't hit some implementation limit
- Assign sub-ranges of bindings of set(s) to different types of resources
I almost abandoned the first idea, since many GPUs only support 4 descriptor sets (NVIDIA!!!! INTEL!!!!). However I noticed that 8 out of the current 11 vulkan descriptors map to only 3 distinct OpenGL object bind-point types!
The only ones left out were sampledImages, samplers and inputAttachments.
OpenGL does not allow samplers to be shared between contexts (threads), and also it does not allow for binding different samplers to unit slots with the same texture. Because of this we can only support imageview+sampler objects cross-API.
InputAttachments do not exist in OpenGL and have no API role, however in Vulkan they are necessary as a replacement to an explicit TextureBarrier. This can also help to implement an implicit TextureBarrier insertion for OpenGL when we are writing to the same FBO we're rendering to.
P.S. Still intend on creating texture view (vk image view) objects under OpenGL.
But we really want to use separate descriptor sets to save on binding costs, so two solutions are possible:
- Require GLSL shader for OpenGL and Spir-V for Vulkan
- Use https://github.com/KhronosGroup/SPIRV-Cross to down-compile SPIRV-V to GLSL and require all shaders to come in SPIR-V
Then we take it a whole level up and transcribe the (set,binding,type) vulkan tuple into a (type,binding) in OpenGL. The way we do it is simple, take the all the VK bindings of one type and generate a new binding to be the count of all objects of the same type in the previous sets or the previous bindings of the same type.
Then we get the best of both worlds, as all bindings in the same set live within the same continuous range, so that one vkBindDescriptorSet
call translates into one ARB_multi_bind call per resource type used in the set (with the exception of UBOs which get +1 added to this value).
And the Pipeline/Descriptor API can be consistent across IVideoDrivers.
If the above approach is followed, then we can support Non-Dynamic UBOs and SSBOs as OpenGL is more relaxed and can potentially do both.
While it would be nice to use this , its rather cumbersome and impractical anyway as no one using IrrBAW is likely to use it for multi-material multi-texture fragmented scenes (such as CAD or 3D Modelling software).
We know that its practical for AMD and recent Nvidia cards, but we need to realize that this requires essentially GL_NV_bindless level capability.
Secondly by maintaining our sights on ARM and Mobile Vulkan, we need to limit our maximum number of descriptor resources across all descriptor sets.
IrrBAW will encourage and strive to put all possible per-pass and per-draw UBO and SSBO data in packed buffers with push_constant offsets.
As for packing textures, we will work towards packing them in the same sized arrays or sparse texture arrays where possible.
The Push Constants are emulated in OpenGL as a special UBO at binding point 0, they cannot be emulated as a special Uniform Struct as structs have no cross-platform packing rules. So only UBO emulation is possible, hence a requirement to follow std140 packing rules for being cross platform.
There's room for OpenGL optimization, to have one or less UBO per emulated recorded command buffer and have it bound from the start till end, although with different offsets. Nvidia and AMD drivers optimize for rebinding the same buffer at the same bind-point at different offsets.