@@ -131,6 +131,11 @@ image::{images}descriptor_buffer_2.svg[descriptor_buffer_2.svg]
131131
132132Using `vkGetDescriptorEXT` we find a spot in the "descriptor buffer" and map it you our resources.
133133
134+ [NOTE]
135+ ====
136+ You can actually use any host memory for this, but for simplicity, we will map it directly to the descriptor buffer for now.
137+ ====
138+
134139The following code will map the 3 of the descriptors using a single resource buffer.
135140
136141[source,c++]
@@ -253,3 +258,80 @@ image::{images}descriptor_buffer_7.svg[descriptor_buffer_7.svg]
253258That is it, from here you can just call `vkCmdDraw` (or other action commands such as `vkCmdDispatch`) and everything should be working!
254259
255260image::{images}descriptor_buffer_8.svg[descriptor_buffer_8.svg]
261+
262+ == Descriptor is actually just memory
263+
264+ When you call `vkGetDescriptorEXT` what is really happening? The driver is actually just taking the `VkDescriptorGetInfoEXT` information and turning it into a binary blob, which even the application can read now!
265+
266+ [source,c++]
267+ ----
268+ // Can be used to print on your machine as well
269+ void print_bytes(const void* memory, size_t size) {
270+ const uint8_t* bytes = (uint8_t*)memory;
271+ printf("--- (at %p) ---\n", memory);
272+ for (size_t i = 0; i < size; ++i) {
273+ printf("%02X ", bytes[i]);
274+ if ((i + 1) % 16 == 0) {
275+ printf("\n");
276+ }
277+ }
278+ printf("\n");
279+ }
280+
281+
282+ void* some_host_memory = buffer.GetMappedMemory();
283+ vkGetDescriptorEXT(device, get_info, descriptor_size, some_host_memory);
284+
285+ print_bytes(some_host_memory, descriptor_size);
286+
287+ // printf output running on Lavapipe
288+ // This represents what a "descriptor" is as a binary blob
289+ --- (at 0x71841c1e7240) ---
290+ 00 80 1E 1C 84 71 00 00 10 00 00 00 00 00 00 00
291+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
292+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
293+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
294+ ----
295+
296+ === Copying the descriptor yourself
297+
298+ So with this knowledge, we should now realize we can actually just `memcpy` the descriptor ourselves.
299+
300+ [source,c++]
301+ ----
302+ void* host_memory = malloc(descriptor_size);
303+
304+ VkDescriptorGetInfoEXT get_info;
305+ get_info.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
306+ get_info.data.pStorageBuffer->range = 4;
307+ get_info.data.pStorageBuffer->address = buffer_x_address;
308+ vkGetDescriptorEXT(get_info, descriptor_size, host_memory);
309+
310+ void* descriptor_ptr = descriptor_buffer_a.GetMappedMemory();
311+
312+ memcpy(descriptor_ptr, host_memory, descriptor_size)
313+ ----
314+
315+ image::{images}descriptor_buffer_9.svg[descriptor_buffer_9.svg]
316+
317+
318+ === Copying the descriptor on the GPU
319+
320+ So we can go another step and make our descriptor buffer not even host visible.
321+
322+ We can write the descriptor into a "staging" `VkBuffer` and then copy it on the GPU.
323+
324+ [source,c++]
325+ ----
326+ void* staging_buffer_ptr = staging_buffer.GetMappedMemory();
327+
328+ vkGetDescriptorEXT(get_info, descriptor_size, staging_buffer_ptr);
329+
330+ vkCmdCopyBuffer(srcBuffer = staging_buffer, dstBuffer = descriptor_buffer_a);
331+ ----
332+
333+ image::{images}descriptor_buffer_10.svg[descriptor_buffer_10.svg]
334+
335+ === Don't forget to add synchronization
336+
337+ When copying memory into your descriptor buffer, make sure to add a barrier with `VK_ACCESS_2_DESCRIPTOR_BUFFER_READ_BIT_EXT` to ensure that any writes will be visible by the GPU when it needs to access it!
0 commit comments