what's the difference between .descriptorCount in VkDescriptorPoolSize and in VkDescriptorSetLayoutBinding(VkDescriptorSetLayoutCreateInfo)? how set? - gpu

what's the difference between .descriptorCount in VkDescriptorPoolSize and in VkDescriptorSetLayoutBinding(VkDescriptorSetLayoutCreateInfo)?
how to set them when there are many shaders, how to set them correctly?
eg.
layout(binding = 0) uniform Buffers {
uint x[];
} buffers[5];
then:
VkDescriptorSetLayoutBinding.descriptorCount = 5,//not 1,
VkDescriptorPoolSize.descriptorCount = 5,//not 1,
what if this same uniform Buffers are in many shaders? should add 5 to descriptorCount when it exist in 1 more shader?

In the case of VkDescriptorSetLayoutBinding::descriptorCount. The spec says:
descriptorCount is the number of descriptors contained in the binding,
accessed in a shader as an array, except if descriptorType is
VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK in which case descriptorCount
is the size in bytes of the inline uniform block. If descriptorCount
is zero this binding entry is reserved and the resource must not be
accessed from any stage via this binding within any pipeline using the
set layout.
So most likely be 1, unless you have an array of textures or array of uniform buffers (which is not very common).
VkDescriptorPoolSize::descriptorCount has nothing to do with the previous one. A descriptor pool is used for allocating descriptors. So descriptorCount here is how many descriptors this pool can provide. The spec says:
descriptorCount is the number of descriptors of that type to allocate.
If type is VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK then
descriptorCount is the number of bytes to allocate for descriptors of
this type.
You can use the same pool for allocating multiple descriptor sets of multiple different layouts. So this most likely needs to be a fairly large number.
Anyways, I think you need to keep studying the general basic concepts around descriptors!

Related

How to map SSBO buffer to CPU in Vulkan similar to glMapBuffer() in openGL

I am making a project in Vulkan, and I want to use an SSBO modified in the GPU on CPU; but Vulkan doesn't have a function to map the buffer, only have a memory function. I tried everything about MemoryMapping, but nothing worked.
With Vulkan, after creating the SSBO memory buffer and specifying memory property flag VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT (which will create the buffer from memory accessible by the system/CPU), use command vkMapMemory() and pass it the void *pointer to use to access the shader block.
The memcpy() command can then be used to read and write data to and from the block (be sure to use fences and avoid reading/writing while the GPU is still using the SSBO).
A quick note on casting and offsetting - whilst using the void pointer to write data to an SSBO with a single memcpy() call is fine, it can't be used to read in the same manner. The pointer has to be cast to the data type in use.
Also, offset arithmetic cannot be performed on void pointers to reach individual structs either.
The data type or struct to which the pointer is cast defines how increment/decrement works - it will do so by the size of said data type and not by bytes in the address (the latter may seem more intuitive).
For example:
(copy the fifth int from a block of ints...)
int theInt;
int *ssboBlockPointer = (int*)vTheSSBOMappedPointer;
memcpy(&theInt, ssboBlockPointer + 5, sizeof(int));
(or copy the 5th struct from a block of structs - offset will move 5 structs)
theStruct oneStruct;
theStruct *ssboBlockPointer = (theStruct*)vTheSSBOMappedPointer;
memcpy(&theStruct , ssboBlockPointer + 5, sizeof(theStruct));

What is the use of .range field when updating a buffer descriptor?

When I went to update a UNIFORM_BUFFER descriptor, I set up the buffer info:
VkDescriptorBufferInfo buffer_info;
buffer_info.buffer = /* SOME BUFFER */;
buffer_info.offset = 0;
buffer_info.range = 0; // I assume this doesn't do any thing for this use
And then vkUpdateDescriptorSets().
Get the validation layer error:
VkDescriptorBufferInfo range is not VK_WHOLE_SIZE and is zero, which
is not allowed.. The Vulkan spec states: If range is not equal to
VK_WHOLE_SIZE, range must be greater than 0
My question is, isn't the job of the buffer info to tell which buffer and what offset to read from the shaders at a particular descriptor set and binding? I didn't think the size of the buffer mattered because generally that's how these things work, you usually specify a buffer and offset and then you read outside that buffer in the shader at your peril.
Let's just I write the wrong range, what would that do? If I write a 32 and in the shader I access 64 bytes in, what happens? Is this argument for validation warnings?
Edit: I just want to clarify the range argument can't mean how much of the buffer I want to copy, what I'm writing to is essentially a pointer. The actual writing of the buffer data is done in a buffer to buffer copy transfer.
A descriptor describes a (usually memory) resource being used by a shader in some capacity. Buffers do have a size, but a shader can use a subset of a buffer's memory range. The descriptor describes which portion of the buffer is being used.
If a descriptor should use the whole size of the buffer assigned to it (starting at offset), that's what VK_WHOLE_SIZE is for.
This allows you to have multiple uniform buffers provided by the same VkBuffer resource. You can even use dynamic uniform block descriptors to change the offset/range without changing the buffer binding itself. This is faster than switching descriptor sets, thus making it easier to provide per-object data.
Let's just I write the wrong range, what would that do?
If the range is smaller than the size of the uniform block specified in the shader, then you'll get a validation failure/undefined behavior.

Specifying push constant block offset in HLSL

I am trying to write a Vulkan renderer, I use glslangValidator with HLSL for shaders and am trying to implement push constants.
[[vk::push_constant]]
cbuffer cbFragment {
float4 imageColor;
float4 aaaa;
};
[[vk::push_constant]]
cbuffer cbMatrices {
float4 bbbb;
};
The annotation "[[vk::push_constant]]" works, I use spirv_reflect for reflection and both push constants show up and they work as intended.
The problem I'm having is that they seemingly overlap, if I assign "bbbb" a value, "imageColor" is affected in exactly the same way and vice versa. In the reflection data both push constant blocks have the offset 0, which explains the issue. However, I seem to be completely unable to change the offset of either of the push constants.
[[vk::offset(x)]] does not work at all, it neither affects the individual member offsets nor the offset of the push constants. The only offset that works at all is HLSL's built in "packoffset", which only applies to the buffer members. And although it might actually be a solution to just offset the members of one of the push constants to be outside the range of the other, I hardly believe that can be a sensible solution as it's also causing the validation layer to fail because offsetting the individual member simply increases the size of the push constant unnecessarily and the overlap itself is still present.
I would greatly appreciate any help on this matter and am willing to provide any necessary clarification, thank you very much!
Push constants live in a single chunk of contiguous memory. The compiler doesn't try to append multiple blocks into that memory; like with the GLSL syntax, it's intended to just have one block containing all the push constant data.
This is consistent with other places where the compiler has to pack variables in a block: it only packs within a block, not across multiple blocks. Two separate non-pushconstant cbuffers would refer to two distinct buffers in memory, with contents that begin at offset zero within their individual buffer. There's only one "push constant buffer", hence you should only decorate one cbuffer with vk::push_constant.

Is VkDescriptorPoolSize struct really needed when creating descriptor pools?

I'm creating descriptor pool with poolSizeCount == 0 and pPoolSizes == nullptr and i still can allocate various number of descriptors of any type. There are no validation errors on Linux, only on Windows (but code works).
Another case: i'm providing VkDescriptorPoolSize with only 1 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, but can allocate more VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER or even descriptors of other types (in this case errors don't occur on both Linux and Windows).
Why is this happening?
It is not technically invalid usage to exceed the pool limits in general:
If a call to vkAllocateDescriptorSets would cause the total number of descriptor sets allocated from the pool to exceed the value of vkDescriptorPoolCreateInfo::maxSets used to create pAllocateInfo->descriptorPool, then the allocation may fail due to lack of space in the descriptor pool. Similarly, the allocation may fail due to lack of space if the call to vkAllocateDescriptorSets would cause the number of any given descriptor type to exceed the sum of all the descriptorCount members of each element of VkDescriptorPoolCreateInfo::pPoolSizes with a member equal to that type.
Note the use of the word "may", which allows implementations to fail but doesn't require them to do so. This means that you're supposed to stay within those limits, but nobody's going to stop you if you exceed them and get away with it.
Now, it is a violation of valid usage to pass no sizes at all:
poolSizeCount must be greater than 0
And the appropriate layer should catch that. But outside of layers, you just achieve undefined behavior. Which can be "appears to work".

maxDisplays of CGGetDisplaysWithPoint

Definition:
As defined here, CGGetDisplaysWithPoint takes 4 parameters:
A CGPoint object
An int32 representing the maximum number of displays returned
A mutable array passed by reference, which will be filled with the displayIDs found.
An int32 representing the matching display count
Syntax:
CGError CGGetDisplaysWithPoint(CGPoint point, uint32_t maxDisplays, CGDirectDisplayID *displays, uint32_t *matchingDisplayCount);
This is fine and I can get this function working however I am quite confused as to how I should deal with the maxDisplays parameter?
As I understand it, if I set maxDisplays to 5 then if someone has 6 displays, there is a 1/6 chance that a randomly selected pixel will find no displays?
So do we just set maxDisplays to something unrealistic, like 99, and release the array afterwards? What's the point in this argument?
The point of the argument is to prevent the function from writing past the end of your array. You have to tell it the capacity of the array. Note that the displays parameter is neither a Cocoa nor Core Foundation mutable array object. It's a C-style array. It's "mutable" in the sense that it's not "const", but it's not an object that manages its own storage. You are responsible for managing that storage and must communicate its capacity to any function that is intended to store data in it (or otherwise guarantee that such function won't overrun it).
So, your question should really be how to decide on the capacity of the array. There are two basic approaches:
1) Call the function passing NULL for the displays parameter and any arbitrary value (best to use 0) for maxDisplays. As documented, when displays is NULL, maxDisplays is ignored and the function outputs via matchingDisplayCount the number of displays whose bounds contain the given point. Then, allocate an array with (at least) that many elements to use to receive the display IDs and call the function again, passing that array for displays and its capacity for maxDisplays.
2) Use an array with capacity of 32. It's not explicitly documented but it's implicit in the API that that's the maximum number of supported displays. A display ID can be converted to an OpenGL display mask using CGDisplayIDToOpenGLDisplayMask(). The type CGOpenGLDisplayMask is used to hold OpenGL display masks. It is defined as uint32_t, a 32-bit value. Therefore, there can be at most 32 active displays.
This technique is used in some Apple docs, like here, here, here, and here. That last one even makes a direct connection between the number of bits in CGOpenGLDisplayMask and the maximum number of displays.