summaryrefslogtreecommitdiff
path: root/unused code/rend_vk_command_queue.c
blob: 1ddd780982a5fa17c2b5b14e343ce59c76cae58d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#pragma once
#include "rend_internal.h"
#include "rend_vk_internal.h"
#include <vulkan/vulkan_core.h>
#include <stdatomic.h>
#include <stdlib.h>

/* DEFERRED COMMANDS:
 * Tracks single-use command buffers submitted for async GPU work,
 * so callers don't have to block (vkQueueWaitIdle) to know when it's
 * safe to free/reset them. One shared timeline semaphore; every
 * submission claims the next monotonic value.
 */

struct RendVkPendingCmd {
    VkCommandPool   pool;
    VkCommandBuffer cmd;
    uint64_t        wait_value;
};

struct RendVkDeferredCmds {
    VkSemaphore        timeline;
    RendVkPendingCmd  *darray;
    size_t             count;
    size_t             capacity;
};

#define RENDER_VK_DEFERRED_CMDS_INITIAL_CAPACITY 16

static inline RendVkDeferredCmds
rend_vk_cmdbuf_deferred_create(void)
{
    RendVkDeferredCmds tracker = {0};

    VkSemaphoreTypeCreateInfo type_info = {
        .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
        .semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE,
        .initialValue = 0,
    };
    VkSemaphoreCreateInfo sem_info = {
        .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
        .pNext = &type_info,
    };
    vkCreateSemaphore(vk_device.logical_device, &sem_info, vk_allocator, &tracker.timeline);

    tracker.capacity = RENDER_VK_DEFERRED_CMDS_INITIAL_CAPACITY;
    tracker.darray = rmalloc(sizeof(RendVkPendingCmd) * tracker.capacity);
    tracker.count = 0;

    return tracker;
}

static inline void
rend_vk_cmdbuf_deferred_destroy(RendVkDeferredCmds *tracker)
{
    vkDestroySemaphore(vk_device.logical_device, tracker->timeline, vk_allocator);
    rfree(tracker->darray);
    *tracker = (RendVkDeferredCmds) {0};
}

static inline void rend_vk_cmdbuf_deferred_lock(RendVkDeferredCmds *t)   { (void)t; }
static inline void rend_vk_cmdbuf_deferred_unlock(RendVkDeferredCmds *t) { (void)t; }

static inline VkCommandBuffer
rend_vk_cmdbuf_deferred_begin(VkCommandPool pool)
{
    VkCommandBufferAllocateInfo alloc_info = {
        .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
        .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
        .commandPool = pool,
        .commandBufferCount = 1,
    };

    VkCommandBuffer cmd;
    vkAllocateCommandBuffers(vk_device.logical_device, &alloc_info, &cmd);

    VkCommandBufferBeginInfo begin = {
        .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
        .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
    };

    vkBeginCommandBuffer(cmd, &begin);
    return cmd;
}

static inline void
rend_vk_cmdbuf_deferred_push(RendVkDeferredCmds *tracker, VkCommandPool pool, VkCommandBuffer cmd, uint64_t wait_value)
{
    rend_vk_cmdbuf_deferred_lock(tracker);
    if (tracker->count == tracker->capacity) {
        tracker->capacity *= 2;
        tracker->darray = realloc(tracker->darray, sizeof(RendVkPendingCmd) * tracker->capacity);
    }
    tracker->darray[tracker->count++] = (RendVkPendingCmd) {
        .pool = pool,
        .cmd = cmd,
        .wait_value = wait_value,
    };
    rend_vk_cmdbuf_deferred_unlock(tracker);
}

static inline uint64_t
rend_vk_cmdbuf_deferred_submit(RendVkDeferredCmds *tracker, VkCommandPool pool, VkCommandBuffer cmd, VkQueue queue, uint64_t wait_value, VkPipelineStageFlags2 wait_stage, VkPipelineStageFlags2 signal_stage)
{
    uint64_t signal_value = wait_value + 1;

    VkCommandBufferSubmitInfo cmd_info = {
        .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO,
        .commandBuffer = cmd,
    };
    VkSemaphoreSubmitInfo wait_info = {
        .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO,
        .semaphore = tracker->timeline,
        .value = wait_value,
        .stageMask = wait_stage,
    };
    VkSemaphoreSubmitInfo signal_info = {
        .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO,
        .semaphore = tracker->timeline,
        .value = signal_value,
        .stageMask = signal_stage,
    };
    VkSubmitInfo2 submit = {
        .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2,
        .waitSemaphoreInfoCount = wait_value ? 1 : 0,
        .pWaitSemaphoreInfos = &wait_info,
        .commandBufferInfoCount = 1,
        .pCommandBufferInfos = &cmd_info,
        .signalSemaphoreInfoCount = 1,
        .pSignalSemaphoreInfos = &signal_info,
    };

    vkQueueSubmit2(queue, 1, &submit, VK_NULL_HANDLE);

    rend_vk_cmdbuf_deferred_push(tracker, pool, cmd, signal_value);
    return signal_value;
}

static inline void
rend_vk_cmdbuf_deferred_flush(RendVkDeferredCmds *tracker)
{
    uint64_t completed;
    vkGetSemaphoreCounterValue(vk_device.logical_device, tracker->timeline, &completed);

    for (size_t i = 0; i < tracker->count; ) {
        if (completed >= tracker->darray[i].wait_value) {
            vkFreeCommandBuffers(vk_device.logical_device, tracker->darray[i].pool, 1, &tracker->darray[i].cmd);
            tracker->darray[i] = tracker->darray[--tracker->count];
        } else {
            i++;
        }
    }
}