fixed some validation bugs
[vktest3] / src / vk.c
index a22b7a3..3ea0060 100644 (file)
--- a/src/vk.c
+++ b/src/vk.c
@@ -2,6 +2,8 @@
 #include <string.h>
 #include <stdint.h>
 #include <stdarg.h>
+#include <errno.h>
+#include <assert.h>
 #include <vulkan/vulkan.h>
 #include "vk.h"
 #include "util.h"
@@ -45,14 +47,17 @@ struct framebuf {
 
 struct pipeline {
        int used;
-       int vport[4], scissor[4];
+       VkViewport vport;
+       VkRect2D scissor;
        VkShaderModule sdr[VKSDR_MAX];
        VkPrimitiveTopology prim;
        VkPolygonMode polymode;
+       float line_width;
        VkCullModeFlags cull;
        VkFrontFace     frontface;
        VkColorComponentFlags colorwr;
        int zbuf, depthwr;
+       VkCompareOp zop;
        int stencil, stencilwr;
        VkStencilOp sfail, szfail, szpass;
        VkCompareOp sop;
@@ -60,8 +65,11 @@ struct pipeline {
        int blend;
        VkBlendFactor srcblend, dstblend, srcblend_a, dstblend_a;
 
+       VkRenderPass rpass;
+
        int vkobj_valid;
        VkPipeline vkobj;
+       VkPipelineLayout vkobj_layout;  /* TODO probably best to split this */
 };
 
 
@@ -75,6 +83,7 @@ static int create_surface(void);
 static int choose_phys_dev(void);
 static int create_device(void);
 static int create_swapchain(void);
+static int create_default_cmdbuf(void);
 
 static int choose_pixfmt(void);
 static int eval_pdev_score(VkPhysicalDevice dev);
@@ -107,6 +116,7 @@ static int vksc_numimg;
 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;
@@ -226,10 +236,72 @@ int vk_reshape(int xsz, int ysz)
 
        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;
 }
 
+int vk_num_swap_images(void)
+{
+       return vksc_numimg;
+}
+
+VkImageView vk_swap_image(int idx)
+{
+       return vksc_view[idx];
+}
+
+int vk_next_swap_image(VkSemaphore sem)
+{
+       uint32_t idx;
+       if(vkAcquireNextImageKHR(vkdev, vksc, UINT64_MAX, sem, 0, &idx) != 0) {
+               return -1;
+       }
+       return (int)idx;
+}
+
+int vk_submit(VkQueue q, VkCommandBuffer cmdbuf, VkSemaphore semwait, VkSemaphore semsig)
+{
+       /* TODO: investigate if we need to expose the wait stage */
+       VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+       VkSubmitInfo sinf = {0};
+       sinf.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+       sinf.waitSemaphoreCount = semwait ? 1 : 0;
+       sinf.pWaitSemaphores = &semwait;
+       sinf.pWaitDstStageMask = &wait_stage;
+       sinf.commandBufferCount = 1;
+       sinf.pCommandBuffers = &cmdbuf;
+       sinf.signalSemaphoreCount = semsig ? 1 : 0;
+       sinf.pSignalSemaphores = &semsig;
+
+       if(vkQueueSubmit(q, 1, &sinf, 0) != 0) {
+               fprintf(stderr, "failed to submit command buffer\n");
+               return -1;
+       }
+       return 0;
+}
+
+int vk_present(VkQueue q, int imgid, VkSemaphore semwait)
+{
+       VkPresentInfoKHR pinf = {0};
+
+       pinf.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
+       pinf.waitSemaphoreCount = semwait ? 1 : 0;
+       pinf.pWaitSemaphores = &semwait;
+       pinf.swapchainCount = 1;
+       pinf.pSwapchains = &vksc;
+       pinf.pImageIndices = (unsigned int*)&imgid;
+
+       if(vkQueuePresentKHR(q, &pinf) != 0) {
+               fprintf(stderr, "present failed\n");
+               return -1;
+       }
+       return 0;
+}
+
 int vk_find_qfamily(unsigned int flags)
 {
        int i, famidx = -1;
@@ -336,6 +408,16 @@ VkCommandBuffer vk_create_cmdbuf(unsigned int qflags, int level)
        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;
@@ -429,6 +511,7 @@ VkRenderPass vk_rpass(int rp)
                        att[i].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
                        att[i].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
                }
+               /*
                att[zidx].format = r->zfmt;
                att[zidx].samples = 1;
                att[zidx].loadOp = r->clear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_DONT_CARE;
@@ -437,23 +520,26 @@ VkRenderPass vk_rpass(int rp)
                att[zidx].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
                att[zidx].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
                att[zidx].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+               */
 
                for(i=0; i<r->num_colbuf; i++) {
                        catref[i].attachment = i;
                        catref[i].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
                }
+               /*
                zatref.attachment = zidx;
                zatref.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+               */
 
                memset(&subpass, 0, sizeof subpass);
                subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
                subpass.colorAttachmentCount = r->num_colbuf;
                subpass.pColorAttachments = catref;
-               subpass.pDepthStencilAttachment = &zatref;
+               subpass.pDepthStencilAttachment = 0;//&zatref;
 
                memset(&pinf, 0, sizeof pinf);
                pinf.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
-               pinf.attachmentCount = r->num_colbuf + 1;
+               pinf.attachmentCount = r->num_colbuf;// + 1;
                pinf.pAttachments = att;
                pinf.subpassCount = 1;
                pinf.pSubpasses = &subpass;
@@ -476,7 +562,7 @@ int vk_create_fb(void)
 
        if(!framebufs) {
                framebufs = darr_alloc(0, sizeof *framebufs);
-               darr_push(framebufs, &framebuf);        /* add dummy rpass */
+               darr_push(framebufs, &framebuf);        /* add dummy framebuffer */
        }
 
        for(i=1; i<darr_size(framebufs); i++) {
@@ -510,9 +596,11 @@ void vk_free_fb(int fb)
 
 void vk_fb_size(int fb, int x, int  y)
 {
-       framebufs[fb].width = x;
-       framebufs[fb].height = y;
-       framebufs[fb].vkobj_valid = 0;
+       if(x != framebufs[fb].width || y != framebufs[fb].height) {
+               framebufs[fb].width = x;
+               framebufs[fb].height = y;
+               framebufs[fb].vkobj_valid = 0;
+       }
 }
 
 void vk_fb_rpass(int fb, int rpass)
@@ -576,6 +664,7 @@ VkFramebuffer vk_fb(int fb)
                fbinf.pAttachments = f->imgv;
                fbinf.width = f->width;
                fbinf.height = f->height;
+               fbinf.layers = 1;
 
                if(vkCreateFramebuffer(vkdev, &fbinf, 0, &f->vkobj) != 0) {
                        fprintf(stderr, "vk_fb: failed to create framebuffer\n");
@@ -606,14 +695,18 @@ int vk_create_pipeln(void)
        /* init pipeline defaults */
        memset(pp, 0, sizeof *pp);
        pp->used = 1;
-       pp->vport[2] = pp->scissor[2] = 640;
-       pp->vport[3] = pp->scissor[3] = 480;
+       pp->vport.width = pp->scissor.extent.width = 640;
+       pp->vport.height = pp->scissor.extent.height = 480;
+       pp->vport.minDepth = 0.0f;
+       pp->vport.maxDepth = 1.0f;
        pp->prim = VKPRIM_TRIANGLES;
        pp->polymode = VK_POLYGON_MODE_FILL;
        pp->cull = VK_CULL_MODE_BACK_BIT;
        pp->frontface = VK_FRONT_FACE_COUNTER_CLOCKWISE;
+       pp->line_width = 1.0f;
        pp->colorwr = 0xf;      /* RGBA */
        pp->zbuf = 1;
+       pp->zop = VK_COMPARE_OP_LESS;
        pp->depthwr = 1;
        pp->stencil = 0;
        pp->stencilwr = 1;
@@ -642,23 +735,30 @@ void vk_free_pipeln(int pp)
        pipelines[pp].used = 0;
 }
 
-void vk_viewport(int pp, int x, int y, int width, int height)
+void vk_pipeln_rpass(int pp, VkRenderPass rp)
 {
        struct pipeline *p = pipelines + pp;
-       p->vport[0] = x;
-       p->vport[1] = y;
-       p->vport[2] = width;
-       p->vport[3] = height;
+       p->rpass = rp;
        p->vkobj_valid = 0;
 }
 
-void vk_scissor(int pp, int x, int y, int width, int height)
+void vk_pipeln_viewport(int pp, int x, int y, int width, int height)
 {
        struct pipeline *p = pipelines + pp;
-       p->scissor[0] = x;
-       p->scissor[1] = y;
-       p->scissor[2] = width;
-       p->scissor[3] = height;
+       p->vport.x = x;
+       p->vport.y = y;
+       p->vport.width = width;
+       p->vport.height = height;
+       p->vkobj_valid = 0;
+}
+
+void vk_pipeln_scissor(int pp, int x, int y, int width, int height)
+{
+       struct pipeline *p = pipelines + pp;
+       p->scissor.offset.x = x;
+       p->scissor.offset.y = y;
+       p->scissor.extent.width = width;
+       p->scissor.extent.height = height;
        p->vkobj_valid = 0;
 }
 
@@ -698,6 +798,13 @@ void vk_pipeln_frontface(int pp, int ff)
        p->vkobj_valid = 0;
 }
 
+void vk_pipeln_linewidth(int pp, int w)
+{
+       struct pipeline *p = pipelines + pp;
+       p->line_width = w;
+       p->vkobj_valid = 0;
+}
+
 void vk_pipeln_multisample(int pp, int nsamples)
 {
        /* TODO */
@@ -735,6 +842,13 @@ void vk_pipeln_zbuffer(int pp, int enable)
        p->vkobj_valid = 0;
 }
 
+void vk_pipeln_zbuffer_op(int pp, int op)
+{
+       struct pipeline *p = pipelines + pp;
+       p->zop = op;
+       p->vkobj_valid = 0;
+}
+
 void vk_pipeln_stencil(int pp, int enable)
 {
        struct pipeline *p = pipelines + pp;
@@ -777,17 +891,200 @@ void vk_pipeln_blendfunc(int pp, int src, int dst)
 
 VkPipeline vk_pipeln(int pp)
 {
+       int i, idx, num_sdr;
        struct pipeline *p = pipelines + pp;
+       VkPipelineShaderStageCreateInfo ssinf[VKSDR_MAX];
+       VkPipelineVertexInputStateCreateInfo vinp;
+       VkPipelineInputAssemblyStateCreateInfo vasm;
+       VkPipelineViewportStateCreateInfo vp;
+       VkPipelineRasterizationStateCreateInfo rast;
+       VkPipelineMultisampleStateCreateInfo msaa;
+       VkPipelineDepthStencilStateCreateInfo zst;
+       VkPipelineColorBlendAttachmentState bat;
+       VkPipelineColorBlendStateCreateInfo blend;
+       VkPipelineLayoutCreateInfo lay;
+       VkGraphicsPipelineCreateInfo pinf;
+
 
        if(p->vkobj_valid) {
                return p->vkobj;
        }
+
+       if(p->vkobj) {
+               vkDestroyPipeline(vkdev, p->vkobj, 0);
+               p->vkobj = 0;
+       }
+
+       memset(ssinf, 0, sizeof ssinf);
+       idx = 0;
+       for(i=0; i<VKSDR_MAX; i++) {
+               if(p->sdr[idx]) {
+                       ssinf[idx].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+                       ssinf[idx].stage = VKSDR_STAGE(i);
+                       ssinf[idx].module = p->sdr[idx];
+                       ssinf[idx].pName = "main";
+                       idx++;
+               }
+       }
+       num_sdr = idx;
+
+       memset(&vinp, 0, sizeof vinp);
+       vinp.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
+
+       memset(&vasm, 0, sizeof vasm);
+       vasm.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
+       vasm.topology = p->prim;
+
+       memset(&vp, 0, sizeof vp);
+       vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
+       vp.viewportCount = 1;
+       vp.pViewports = &p->vport;
+       vp.scissorCount = 1;
+       vp.pScissors = &p->scissor;
+
+       memset(&rast, 0, sizeof rast);
+       rast.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
+       rast.polygonMode = p->polymode;
+       rast.lineWidth = p->line_width;
+       rast.cullMode = p->cull;
+       rast.frontFace = p->frontface;
+
        /* TODO */
+       memset(&msaa, 0, sizeof msaa);
+       msaa.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
+       msaa.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
+       msaa.minSampleShading = 1.0f;
+
+       memset(&zst, 0, sizeof zst);
+       zst.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
+       zst.depthTestEnable = p->zbuf;
+       zst.depthWriteEnable = p->depthwr;
+       zst.depthCompareOp = p->zop;
+       zst.stencilTestEnable = p->stencil;
+       zst.front.writeMask = p->stencilwr;
+       zst.front.failOp = p->sfail;
+       zst.front.passOp = p->szpass;
+       zst.front.depthFailOp = p->szfail;
+       zst.front.compareOp = p->sop;
+       zst.front.compareMask = p->smask;
+       zst.front.reference = p->sref;
+       zst.back = zst.front;
+
+       memset(&bat, 0, sizeof bat);
+       bat.colorWriteMask = p->colorwr;
+       bat.blendEnable = p->blend;
+       bat.srcColorBlendFactor = p->srcblend;
+       bat.dstColorBlendFactor = p->dstblend;
+       bat.colorBlendOp = VK_BLEND_OP_ADD;     /* TODO */
+       bat.srcAlphaBlendFactor = p->srcblend_a;
+       bat.dstAlphaBlendFactor = p->dstblend_a;
+
+       memset(&blend, 0, sizeof blend);
+       blend.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
+       blend.attachmentCount = 1;
+       blend.pAttachments = &bat;
+
+       /* TODO */
+       memset(&lay, 0, sizeof lay);
+       lay.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+       if(vkCreatePipelineLayout(vkdev, &lay, 0, &p->vkobj_layout) != 0) {
+               return 0;
+       }
+
+       memset(&pinf, 0, sizeof pinf);
+       pinf.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
+       pinf.stageCount = num_sdr;
+       pinf.pStages = ssinf;
+       pinf.pVertexInputState = &vinp;
+       pinf.pInputAssemblyState = &vasm;
+       pinf.pViewportState = &vp;
+       pinf.pRasterizationState = &rast;
+       pinf.pDepthStencilState = &zst;
+       pinf.pMultisampleState = &msaa;
+       pinf.pColorBlendState = &blend;
+       pinf.layout = p->vkobj_layout;
+       pinf.renderPass = p->rpass;
+       pinf.basePipelineIndex = -1;
+
+       if(vkCreateGraphicsPipelines(vkdev, 0, 1, &pinf, 0, &p->vkobj) != 0) {
+               return 0;
+       }
+       p->vkobj_valid = 1;
+       return p->vkobj;
+}
+
+
+VkShaderModule vk_load_shader(const char *fname)
+{
+       FILE *fp;
+       long sz;
+       void *buf;
+       VkShaderModuleCreateInfo sinf;
+       VkShaderModule sdr;
+
+       if(!(fp = fopen(fname, "rb"))) {
+               fprintf(stderr, "failed to open shader: %s: %s\n", fname, strerror(errno));
+               return 0;
+       }
+       fseek(fp, 0, SEEK_END);
+       sz = ftell(fp);
+       fseek(fp, 0, SEEK_SET);
+
+       buf = alloca(sz);
+       if(fread(buf, 1, sz, fp) < sz) {
+               fprintf(stderr, "unexpected EOF while reading shader: %s\n", fname);
+               fclose(fp);
+               return 0;
+       }
+       fclose(fp);
+
+       memset(&sinf, 0, sizeof sinf);
+       sinf.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
+       sinf.codeSize = sz;
+       sinf.pCode = buf;
+
+       if(vkCreateShaderModule(vkdev, &sinf, 0, &sdr) != 0) {
+               fprintf(stderr, "failed to create shader from %s\n", fname);
+               return 0;
+       }
+       return sdr;
+}
+
+void vk_free_shader(VkShaderModule sdr)
+{
+       vkDestroyShaderModule(vkdev, sdr, 0);
+}
+
+VkSemaphore vk_create_sem(void)
+{
+       VkSemaphore sem;
+       VkSemaphoreCreateInfo sinf = {0};
+
+       sinf.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+       if(vkCreateSemaphore(vkdev, &sinf, 0, &sem) != 0) {
+               return 0;
+       }
+       return sem;
+}
+
+void vk_free_sem(VkSemaphore sem)
+{
+       vkDestroySemaphore(vkdev, sem, 0);
+}
+
+
+void vk_rect(VkRect2D *r, int x, int y, int w, int h)
+{
+       r->offset.x = x;
+       r->offset.y = y;
+       r->extent.width = w;
+       r->extent.height = h;
 }
 
 
 #define ARRSZ(arr)     (sizeof arr / sizeof *arr)
 static const char *known_layer_list[] = {
+       "VK_LAYER_KHRONOS_validation",
        "VK_LAYER_GOOGLE_threading",
        "VK_LAYER_LUNARG_parameter_validation",
        "VK_LAYER_LUNARG_object_tracker",
@@ -1099,6 +1396,38 @@ static int create_swapchain(void)
        return 0;
 }
 
+static int create_default_cmdbuf(void)
+{
+       int i, 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)
 {