X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2Fvk.c;h=f5557b3c53f50334a9b5f635ad51e2bcefde672b;hb=51c70e21b25d107c4d86c6ae0c16eac7e0fff22a;hp=ca03b35e7731c586065d98bdd12d8e47f9924605;hpb=296b4bf2b7c4fcc7d9c19381840c62e8b891934f;p=vktest3 diff --git a/src/vk.c b/src/vk.c index ca03b35..f5557b3 100644 --- a/src/vk.c +++ b/src/vk.c @@ -2,6 +2,8 @@ #include #include #include +#include +#include #include #include "vk.h" #include "util.h" @@ -43,9 +45,37 @@ struct framebuf { VkFramebuffer vkobj; }; +struct pipeline { + int used; + 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; + unsigned int sref, smask; + 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 */ +}; + static struct rpass *rpasses; static struct framebuf *framebufs; +static struct pipeline *pipelines; static int create_instance(void); @@ -53,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); @@ -62,12 +93,20 @@ static int have_ext(VkExtensionProperties *ext, int next, const char *name); static Display *dpy; static Window win; static int initflags; +#define MAX_INIT_QUEUE 32 +static struct { + unsigned int flags; + int count; + int qfam; + VkCommandPool cmdpool; +} initq[MAX_INIT_QUEUE]; +static int num_initq; static VkInstance vk; static VkPhysicalDevice vkpdev; -static int vkqfam_idx, vkqfam_maxq; +static VkQueueFamilyProperties *qfam; +static uint32_t num_qfam; static VkDevice vkdev; -static VkQueue vkq; static VkSurfaceKHR vksurf; static VkSurfaceCapabilitiesKHR vksurf_caps; static int vksurf_numfmt, vksurf_selfmt; @@ -77,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; @@ -93,8 +133,32 @@ void vk_init_xwin(Display *d, Window w) win = w; } +void vk_init_queue(unsigned int qflags, int count) +{ + int i; + + for(i=0; i= MAX_INIT_QUEUE) { + fprintf(stderr, "vk_init_queue: too many queues\n"); + return; + } + initq[num_initq].flags = qflags; + initq[num_initq].count = count; + num_initq++; +} + int vk_init(unsigned int flags, unsigned int *usedflags) { + if(!num_initq) { + vk_init_queue(VKQ_GFX | VKQ_PRESENT, 1); + } + initflags = flags; if(create_instance() == -1) return -1; if(create_surface() == -1) return -1; @@ -172,10 +236,177 @@ 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_next_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; + VkBool32 can_pres; + + if(!qfam) return -1; /* not initialized I guess... */ + + for(i=0; i= qfam[fam].queueCount) { + fprintf(stderr, "vk_getq_fam: invalid index %d, family %d has %d queues\n", + n, fam, qfam[fam].queueCount); + return 0; + } + + vkGetDeviceQueue(vkdev, fam, n, &q); + return q; +} + +VkQueue vk_getq(unsigned int flags, int n) +{ + return vk_getq_fam(vk_find_qfamily(flags), n); +} + +static VkCommandPool find_cmdpool(int qfam) +{ + int i; + VkCommandPoolCreateInfo pinf; + + for(i=0; i= 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) { @@ -317,7 +548,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; iused = 1; + 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; + pp->sop = VK_COMPARE_OP_ALWAYS; + pp->smask = 0xffffffff; + pp->blend = 0; + pp->srcblend = pp->srcblend_a = VK_BLEND_FACTOR_ONE; + pp->dstblend = pp->dstblend_a = VK_BLEND_FACTOR_ZERO; + + if(pp == &pipeln) { + darr_push(pipelines, pp); + return darr_size(pipelines) - 1; + } + return pp - pipelines; +} + +void vk_free_pipeln(int pp) +{ + if(!pipelines || pp < 1 || pp >= darr_size(pipelines)) { + return; + } + + if(pipelines[pp].used && pipelines[pp].vkobj) { + vkDestroyPipeline(vkdev, pipelines[pp].vkobj, 0); + } + pipelines[pp].used = 0; +} + +void vk_pipeln_rpass(int pp, VkRenderPass rp) +{ + struct pipeline *p = pipelines + pp; + p->rpass = rp; + p->vkobj_valid = 0; +} + +void vk_pipeln_viewport(int pp, int x, int y, int width, int height) +{ + struct pipeline *p = pipelines + pp; + 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; +} + +void vk_pipeln_shader(int pp, int type, VkShaderModule sdr) +{ + struct pipeline *p = pipelines + pp; + p->sdr[type] = sdr; + p->vkobj_valid = 0; +} + +/* TODO: vertex input */ +void vk_pipeln_prim(int pp, int prim) +{ + struct pipeline *p = pipelines + pp; + p->prim = prim; + p->vkobj_valid = 0; +} + +void vk_pipeln_polymode(int pp, int mode) +{ + struct pipeline *p = pipelines + pp; + p->polymode = mode; + p->vkobj_valid = 0; +} + +void vk_pipeln_cull(int pp, int cull) +{ + struct pipeline *p = pipelines + pp; + p->cull = cull; + p->vkobj_valid = 0; +} + +void vk_pipeln_frontface(int pp, int ff) +{ + struct pipeline *p = pipelines + pp; + p->frontface = 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 */ +} + +void vk_pipeln_colormask(int pp, int r, int g, int b, int a) +{ + struct pipeline *p = pipelines + pp; + p->colorwr = 0; + if(r) p->colorwr |= VK_COLOR_COMPONENT_R_BIT; + if(g) p->colorwr |= VK_COLOR_COMPONENT_G_BIT; + if(b) p->colorwr |= VK_COLOR_COMPONENT_B_BIT; + if(a) p->colorwr |= VK_COLOR_COMPONENT_A_BIT; + p->vkobj_valid = 0; +} + +void vk_pipeln_depthmask(int pp, int z) +{ + struct pipeline *p = pipelines + pp; + p->depthwr = z; + p->vkobj_valid = 0; +} + +void vk_pipeln_stencilmask(int pp, int s) +{ + struct pipeline *p = pipelines + pp; + p->stencilwr = s; + p->vkobj_valid = 0; +} + +void vk_pipeln_zbuffer(int pp, int enable) +{ + struct pipeline *p = pipelines + pp; + p->zbuf = 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; + p->stencil = enable; + p->vkobj_valid = 0; +} + +void vk_pipeln_stencil_op(int pp, int sfail, int zfail, int zpass) +{ + struct pipeline *p = pipelines + pp; + p->sfail = sfail; + p->szfail = zfail; + p->szpass = zpass; + p->vkobj_valid = 0; +} + +void vk_pipeln_stencil_func(int pp, int op, unsigned int ref, unsigned int mask) +{ + struct pipeline *p = pipelines + pp; + p->sop = op; + p->sref = ref; + p->smask = mask; + p->vkobj_valid = 0; +} + +void vk_pipeln_blend(int pp, int enable) +{ + struct pipeline *p = pipelines + pp; + p->blend = enable; + p->vkobj_valid = 0; +} + +void vk_pipeln_blendfunc(int pp, int src, int dst) +{ + struct pipeline *p = pipelines + pp; + p->srcblend = src; + p->dstblend = dst; + p->vkobj_valid = 0; +} + +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; isdr[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); +} + #define ARRSZ(arr) (sizeof arr / sizeof *arr) static const char *known_layer_list[] = { "VK_LAYER_GOOGLE_threading", @@ -557,10 +1184,9 @@ static int create_surface(void) int choose_phys_dev(void) { - uint32_t i, num_pdev, num_qfam, score, best_score, best_dev; + uint32_t i, num_pdev, score, best_score, best_dev; VkPhysicalDevice *pdev; VkPhysicalDeviceProperties pdevprop; - VkQueueFamilyProperties *qfam; VkBool32 can_pres; vkEnumeratePhysicalDevices(vk, &num_pdev, 0); @@ -591,21 +1217,12 @@ int choose_phys_dev(void) } vkpdev = pdev[best_dev]; + if(qfam) free(qfam); + vkGetPhysicalDeviceQueueFamilyProperties(vkpdev, &num_qfam, 0); qfam = malloc_nf(num_qfam * sizeof *qfam); vkGetPhysicalDeviceQueueFamilyProperties(vkpdev, &num_qfam, qfam); - vkqfam_idx = -1; - for(i=0; i 1024) { + fprintf(stderr, "create_device: arbitrary limit of total queues exceeded (%d)\n", totalq); + return -1; + } + prio = alloca(totalq * sizeof *prio); + + for(i=0; i