#include "app.h"
#include "vk.h"
-struct swapchain {
- int fb;
- VkImageView img;
+#define NUM_FRM 2
+
+struct frame {
+ VkCommandBuffer cmdbuf;
VkSemaphore sem_getimg;
VkFence imgfence;
};
int win_width, win_height;
+static int frameno;
+
static int rpass, pipeln, num_swap_img;
-static struct swapchain *swapchain;
+static int *fb;
+static struct frame frame[NUM_FRM];
static VkSemaphore sem_draw;
static VkQueue queue;
int app_init(void)
{
- int i;
+ int i, qfam;
unsigned int flags;
+ VkCommandPool cmdpool;
if(vk_init(VKINIT_DEPTH, &flags) == -1) {
return -1;
if((num_swap_img = vk_num_swap_images()) <= 0) {
return -1;
}
- if(!(swapchain = malloc(num_swap_img * sizeof *swapchain))) {
+
+ if(!(fb = malloc(num_swap_img * sizeof *fb))) {
+ fprintf(stderr, "failed to allocate default framebuffers\n");
return -1;
}
rpass = vk_create_rpass();
for(i=0; i<num_swap_img; i++) {
- swapchain[i].img = vk_swap_image(i);
- swapchain[i].fb = vk_create_fb();
- vk_fb_size(swapchain[i].fb, win_width, win_height);
- vk_fb_rpass(swapchain[i].fb, rpass);
- vk_fb_images(swapchain[i].fb, 1, swapchain[i].img);
-
- swapchain[i].sem_getimg = vk_create_sem();
- swapchain[i].imgfence = vk_create_fence();
+ fb[i] = vk_create_fb();
+ vk_fb_size(fb[i], win_width, win_height);
+ vk_fb_rpass(fb[i], rpass);
+ vk_fb_images(fb[i], 1, vk_swap_image(i));
+ }
+
+ /* select queue family for the per-frame command buffers */
+ if((qfam = vk_find_qfamily(VKQ_GFX | VKQ_PRESENT)) == -1) {
+ fprintf(stderr, "failed to find a gfx|present-capable queue family\n");
+ return -1;
+ }
+
+ for(i=0; i<NUM_FRM; i++) {
+ if(!(frame[i].cmdbuf = vk_create_cmdbuf_fam(qfam, VK_COMMAND_BUFFER_LEVEL_PRIMARY))) {
+ fprintf(stderr, "failed to create per-frame command buffer\n");
+ return -1;
+ }
+ frame[i].sem_getimg = vk_create_sem();
+ frame[i].imgfence = vk_create_fence(1);
}
pipeln = vk_create_pipeln();
void app_cleanup(void)
{
int i;
+
+ vk_finish();
+
for(i=0; i<num_swap_img; i++) {
- vk_free_fence(swapchain[i].imgfence);
- vk_free_sem(swapchain[i].sem_getimg);
+ vk_free_fb(fb[i]);
+ }
+ vk_free_rpass(rpass);
+
+ for(i=0; i<NUM_FRM; i++) {
+ vk_free_fence(frame[i].imgfence);
+ vk_free_sem(frame[i].sem_getimg);
}
vk_free_sem(sem_draw);
vk_cleanup();
void app_display(void)
{
- static int semid = -1;
int imgid;
VkCommandBuffer cmdbuf;
+ struct frame *frm;
+ frm = frame + (frameno & 1);
/* get the next image from the swap chain */
- semid = (semid + 1) % num_swap_img;
- imgid = vk_next_swap_image(swapchain[semid].sem_getimg);
- cmdbuf = vk_get_cmdbuf(imgid);
+ vk_wait_fence(frm->imgfence, -1);
+ imgid = vk_next_swap_image(frm->sem_getimg);
+ cmdbuf = frm->cmdbuf;
{
VkCommandBufferBeginInfo cmdbegin = {0};
rpbegin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
rpbegin.renderPass = vk_rpass(rpass);
- rpbegin.framebuffer = vk_fb(swapchain[imgid].fb);
+ rpbegin.framebuffer = vk_fb(fb[imgid]);
vk_rect(&rpbegin.renderArea, 0, 0, win_width, win_height);
rpbegin.pClearValues = clear;
rpbegin.clearValueCount = 1;
}
/* submit the command buffer, wait for one semaphore, signal another */
- vk_submit(queue, cmdbuf, swapchain[semid].sem_getimg, sem_draw);
+ vk_submit(queue, cmdbuf, frm->sem_getimg, sem_draw, frm->imgfence);
/* swap buffers after drawing is finished */
vk_present(queue, imgid, sem_draw);
+
+ frameno++;
}
void app_reshape(int x, int y)
}
for(i=0; i<vk_num_swap_images(); i++) {
- vk_fb_size(swapchain[i].fb, x, y);
- vk_fb_images(swapchain[i].fb, 1, vk_swap_image(i));
+ vk_fb_size(fb[i], x, y);
+ vk_fb_images(fb[i], 1, vk_swap_image(i));
}
}
static int choose_phys_dev(void);
static int create_device(void);
static int create_swapchain(void);
-static int create_default_cmdbuf(void);
static void *init_rayext_list(void);
static int choose_pixfmt(void);
static VkImage *vksc_img;
static VkExtent2D vksc_extent;
static VkImageView *vksc_view;
-static VkCommandBuffer *vksc_cmdbuf; /* default command buffers (vksc_numimg) */
static VkLayerProperties *inst_layers;
static VkExtensionProperties *inst_ext, *dev_ext;
{
int i;
+ vk_finish();
+
free(vksc_img);
vksc_img = 0;
- free(vksc_view);
- vksc_view = 0;
if(vksc_view) {
for(i=0; i<vksc_numimg; i++) {
vkDestroyImageView(vkdev, vksc_view[i], 0);
}
+ free(vksc_view);
vksc_view = 0;
}
if(vksc) {
vkDestroySwapchainKHR(vkdev, vksc, 0);
vksc = 0;
}
+
+ for(i=0; i<MAX_INIT_QUEUE; i++) {
+ if(initq[i].cmdpool) {
+ vkDestroyCommandPool(vkdev, initq[i].cmdpool, 0);
+ initq[i].cmdpool = 0;
+ }
+ }
+
if(vkdev) {
vkDestroyDevice(vkdev, 0);
vkdev = 0;
if(create_swapchain() == -1) return -1;
- if(!vksc_cmdbuf) {
- if(create_default_cmdbuf() == -1) return -1;
- }
-
/* TODO create depth/stencil buffers as needed (initflags) */
return 0;
}
return -1;
}
-int vk_submit(VkQueue q, VkCommandBuffer cmdbuf, VkSemaphore semwait, VkSemaphore semsig)
+void vk_finish(void)
+{
+ vkDeviceWaitIdle(vkdev);
+}
+
+int vk_submit(VkQueue q, VkCommandBuffer cmdbuf, VkSemaphore semwait,
+ VkSemaphore semsig, VkFence fence)
{
/* TODO: investigate if we need to expose the wait stage */
VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
sinf.signalSemaphoreCount = semsig ? 1 : 0;
sinf.pSignalSemaphores = &semsig;
- if(vkQueueSubmit(q, 1, &sinf, 0) != 0) {
+ if(vkQueueSubmit(q, 1, &sinf, fence) != 0) {
fprintf(stderr, "failed to submit command buffer\n");
return -1;
}
return vk_create_cmdbuf_fam(qfam, level);
}
-VkCommandBuffer vk_get_cmdbuf(int imgid)
-{
- if(imgid < 0 || imgid >= vksc_numimg) {
- fprintf(stderr, "vk_get_cmdbuf: invalid id %d, swap chain has %d images\n",
- imgid, vksc_numimg);
- return 0;
- }
- return vksc_cmdbuf[imgid];
-}
-
int vk_create_rpass(void)
{
int i;
vkDestroySemaphore(vkdev, sem, 0);
}
-VkFence vk_create_fence(void)
+VkFence vk_create_fence(int state)
{
VkFence fence;
VkFenceCreateInfo finf = {0};
finf.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
+ if(state) {
+ finf.flags = VK_FENCE_CREATE_SIGNALED_BIT;
+ }
if(vkCreateFence(vkdev, &finf, 0, &fence) != 0) {
return 0;
}
vkDestroyFence(vkdev, fence, 0);
}
+void vk_wait_fence(VkFence fence, long timeout)
+{
+ vkWaitForFences(vkdev, 1, &fence, VK_TRUE, timeout < 0 ? UINT64_MAX : timeout);
+ vkResetFences(vkdev, 1, &fence);
+}
+
void vk_rect(VkRect2D *r, int x, int y, int w, int h)
{
r->offset.x = x;
scinf.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
scinf.surface = vksurf;
- scinf.minImageCount = 2;
+ scinf.minImageCount = vksurf_caps.minImageCount;
scinf.imageFormat = vksurf_fmt[vksurf_selfmt].format;
scinf.imageColorSpace = vksurf_fmt[vksurf_selfmt].colorSpace;
scinf.imageExtent = vksc_extent;
return 0;
}
-static int create_default_cmdbuf(void)
-{
- int qfam;
- VkCommandPool cmdpool;
- VkCommandBufferAllocateInfo cbinf = {0};
-
- assert(!vksc_cmdbuf);
-
- if((qfam = vk_find_qfamily(VKQ_GFX | VKQ_PRESENT)) == -1) {
- fprintf(stderr, "failed to find a gfx|present capable queue family\n");
- return -1;
- }
- if(!(cmdpool = find_cmdpool(qfam))) {
- fprintf(stderr, "failed to find usable command pool for default command buffers\n");
- return -1;
- }
- if(!(vksc_cmdbuf = malloc(vksc_numimg * sizeof *vksc_cmdbuf))) {
- fprintf(stderr, "failed to allocate %d command buffers for the swap-chain\n", vksc_numimg);
- return -1;
- }
-
- cbinf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
- cbinf.commandPool = cmdpool;
- cbinf.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
- cbinf.commandBufferCount = vksc_numimg;
-
- if(vkAllocateCommandBuffers(vkdev, &cbinf, vksc_cmdbuf) != 0) {
- fprintf(stderr, "failed to create %d command buffers for the swap-chain\n", vksc_numimg);
- return -1;
- }
- return 0;
-}
-
static int eval_pdev_score(VkPhysicalDevice dev)
{
int score = 0;
/* returns the image index, or -1 on failure. Pass optional semaphore to signal */
int vk_next_swap_image(VkSemaphore sem);
-int vk_submit(VkQueue q, VkCommandBuffer cmdbuf, VkSemaphore semwait, VkSemaphore semsig);
+void vk_finish(void);
+
+int vk_submit(VkQueue q, VkCommandBuffer cmdbuf, VkSemaphore semwait,
+ VkSemaphore semsig, VkFence fence);
int vk_present(VkQueue q, int imgid, VkSemaphore semwait);
int vk_find_qfamily(unsigned int flags);
VkCommandBuffer vk_create_cmdbuf_fam(int qfam, int level);
VkCommandBuffer vk_create_cmdbuf(unsigned int qflags, int level);
-/* return one of the swap-chain command buffers */
-VkCommandBuffer vk_get_cmdbuf(int imgid);
int vk_create_rpass(void);
void vk_free_rpass(int rp);
VkSemaphore vk_create_sem(void);
void vk_free_sem(VkSemaphore sem);
-VkFence vk_create_fence(void);
+VkFence vk_create_fence(int state);
void vk_free_fence(VkFence fence);
+void vk_wait_fence(VkFence fence, long timeout); /* -1 = inf */
/* random helpers */
void vk_rect(VkRect2D *r, int x, int y, int w, int h);