From 057106c985b6bc8986af8f66e9fad6237a6ed4b7 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Sat, 21 Sep 2024 23:59:48 +0300 Subject: [PATCH] vertex buffers --- sdr/sdr.v.glsl | 19 ++--- src/app.c | 35 +++++++- src/vk.c | 252 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/vk.h | 41 ++++++++- 4 files changed, 328 insertions(+), 19 deletions(-) diff --git a/sdr/sdr.v.glsl b/sdr/sdr.v.glsl index 3a60cbe..10807fa 100644 --- a/sdr/sdr.v.glsl +++ b/sdr/sdr.v.glsl @@ -5,22 +5,13 @@ out gl_PerVertex { vec4 gl_Position; }; -layout(location = 0) out vec3 color; - -vec2 vpos[3] = vec2[]( - vec2(0.0, -0.5), - vec2(0.5, 0.5), - vec2(-0.5, 0.5) -); +layout(location = 0) in vec4 attr_vertex; +layout(location = 1) in vec4 attr_color; -vec3 vcol[3] = vec3[]( - vec3(1.0, 0.0, 0.0), - vec3(0.0, 1.0, 0.0), - vec3(0.0, 0.0, 1.0) -); +layout(location = 0) out vec3 color; void main() { - gl_Position = vec4(vpos[gl_VertexIndex], 0.0, 1.0); - color = vcol[gl_VertexIndex]; + gl_Position = attr_vertex; + color = attr_color.rgb; } diff --git a/src/app.c b/src/app.c index 41779d6..cd50cf6 100644 --- a/src/app.c +++ b/src/app.c @@ -22,11 +22,27 @@ static VkSemaphore sem_draw; static VkQueue queue; static VkShaderModule vsdr, psdr; +static float verts[] = { + 0, -0.5, 0, 1, + 0.5, 0.5, 0, 1, + -0.5, 0.5, 0, 1 +}; + +static float colors[] = { + 1, 0, 0, 1, + 0, 1, 0, 1, + 0, 0, 1, 1 +}; + +static int vbpos, vbcol; + int app_init(void) { int i, qfam; unsigned int flags; VkCommandPool cmdpool; + VkVertexInputBindingDescription vinpdesc[2]; + VkVertexInputAttributeDescription vattrdesc[2]; if(vk_init(VKINIT_DEPTH, &flags) == -1) { return -1; @@ -85,6 +101,16 @@ int app_init(void) vk_pipeln_zbuffer(pipeln, 0); vk_pipeln_frontface(pipeln, VK_FRONT_FACE_CLOCKWISE); + vk_pipeln_vattr(pipeln, 0, 0, 0, 0, VKATTR_VEC4); + vk_pipeln_vattr(pipeln, 1, 1, 0, 0, VKATTR_VEC4); + + vbpos = vk_create_buf(VKBUF_VERTEX); + vk_buf_size(vbpos, sizeof verts); + vk_buf_data(vbpos, 0, sizeof verts, verts); + vbcol = vk_create_buf(VKBUF_VERTEX); + vk_buf_size(vbcol, sizeof colors); + vk_buf_data(vbcol, 0, sizeof colors, colors); + sem_draw = vk_create_sem(); return 0; } @@ -95,6 +121,9 @@ void app_cleanup(void) vk_finish(); + vk_free_buf(vbpos); + vk_free_buf(vbcol); + for(i=0; isem_getimg); cmdbuf = frm->cmdbuf; + /* record the command buffer: begin-rpass, bind-pipeline, draw, end-rpass */ { VkCommandBufferBeginInfo cmdbegin = {0}; VkRenderPassBeginInfo rpbegin = {0}; @@ -152,7 +182,8 @@ void app_display(void) rpbegin.clearValueCount = 1; vkCmdBeginRenderPass(cmdbuf, &rpbegin, VK_SUBPASS_CONTENTS_INLINE); - vkCmdBindPipeline(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, vk_pipeln(pipeln)); + vkcmd_bind_gfxpipeln(cmdbuf, pipeln); + vkcmd_bind_vbuf(cmdbuf, 2, vbpos, vbcol); vkCmdDraw(cmdbuf, 3, 1, 0, 0); vkCmdEndRenderPass(cmdbuf); vkEndCommandBuffer(cmdbuf); diff --git a/src/vk.c b/src/vk.c index c6c5c4b..0895ee6 100644 --- a/src/vk.c +++ b/src/vk.c @@ -11,8 +11,10 @@ #ifdef _WIN32 #include +#include #include #else +#include /*#include */ #include #include @@ -46,11 +48,18 @@ struct framebuf { VkFramebuffer vkobj; }; +struct vertex_attrib { + int used; + VkVertexInputBindingDescription bind; + VkVertexInputAttributeDescription attr; +}; + struct pipeline { int used; VkViewport vport; VkRect2D scissor; VkShaderModule sdr[VKSDR_MAX]; + struct vertex_attrib vattr[VKATTR_MAX]; VkPrimitiveTopology prim; VkPolygonMode polymode; float line_width; @@ -73,10 +82,20 @@ struct pipeline { VkPipelineLayout vkobj_layout; /* TODO probably best to split this */ }; +struct buffer { + int used; + unsigned int size; + VkBufferUsageFlags usage; + VkBuffer vkobj; + int vkobj_valid; + VkDeviceMemory devmem; +}; + static struct rpass *rpasses; static struct framebuf *framebufs; static struct pipeline *pipelines; +static struct buffer *buffers; static int create_instance(void); @@ -112,6 +131,7 @@ static VkInstance vk; static VkPhysicalDevice vkpdev; static VkQueueFamilyProperties *qfam; static uint32_t num_qfam; +static VkPhysicalDeviceMemoryProperties vkmemprop; static VkDevice vkdev; static VkSurfaceKHR vksurf; static VkSurfaceCapabilitiesKHR vksurf_caps; @@ -483,6 +503,7 @@ void vk_free_rpass(int rp) if(rpasses[rp].used && rpasses[rp].vkobj) { vkDestroyRenderPass(vkdev, rpasses[rp].vkobj, 0); + rpasses[rp].vkobj = 0; } rpasses[rp].used = 0; } @@ -802,7 +823,57 @@ void vk_pipeln_shader(int pp, int type, VkShaderModule sdr) p->vkobj_valid = 0; } -/* TODO: vertex input */ +void vk_pipeln_vattr(int pp, int loc, int bind, int offs, int stride, int fmt) +{ + int i, idx = -1; + struct pipeline *p = pipelines + pp; + struct vertex_attrib *attr; + + for(i=0; ivattr + i; + if(attr->used) { + if(attr->attr.location == loc) { + idx = i; + break; + } + } else { + if(idx == -1) { + idx = i; + } + } + } + + if(idx == -1) return; + + attr = p->vattr + idx; + attr->used = 1; + attr->attr.location = loc; + attr->attr.binding = attr->bind.binding = bind; + attr->attr.offset = offs; + switch(fmt) { + case VKATTR_FLOAT: + attr->attr.format = VK_FORMAT_R32_SFLOAT; + if(stride <= 0) stride = sizeof(float); + break; + case VKATTR_VEC2: + attr->attr.format = VK_FORMAT_R32G32_SFLOAT; + if(stride <= 0) stride = 2 * sizeof(float); + break; + case VKATTR_VEC3: + attr->attr.format = VK_FORMAT_R32G32B32_SFLOAT; + if(stride <= 0) stride = 3 * sizeof(float); + break; + case VKATTR_VEC4: + attr->attr.format = VK_FORMAT_R32G32B32A32_SFLOAT; + if(stride <= 0) stride = 4 * sizeof(float); + break; + default: + break; + } + attr->bind.stride = stride; + attr->bind.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; /* TODO support instancing */ +} + void vk_pipeln_prim(int pp, int prim) { struct pipeline *p = pipelines + pp; @@ -924,7 +995,7 @@ void vk_pipeln_blendfunc(int pp, int src, int dst) VkPipeline vk_pipeln(int pp) { - int i, idx, num_sdr; + int i, idx, num_sdr, num_vattr; struct pipeline *p = pipelines + pp; VkPipelineShaderStageCreateInfo ssinf[VKSDR_MAX]; VkPipelineVertexInputStateCreateInfo vinp; @@ -937,6 +1008,8 @@ VkPipeline vk_pipeln(int pp) VkPipelineColorBlendStateCreateInfo blend; VkPipelineLayoutCreateInfo lay; VkGraphicsPipelineCreateInfo pinf; + VkVertexInputBindingDescription bdesc[VKATTR_MAX]; + VkVertexInputAttributeDescription adesc[VKATTR_MAX]; if(p->vkobj_valid) { @@ -961,8 +1034,21 @@ VkPipeline vk_pipeln(int pp) } num_sdr = idx; + num_vattr = 0; + for(i=0; ivattr[i].used) { + bdesc[num_vattr] = p->vattr[i].bind; + adesc[num_vattr] = p->vattr[i].attr; + num_vattr++; + } + } + memset(&vinp, 0, sizeof vinp); vinp.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vinp.pVertexBindingDescriptions = bdesc; + vinp.vertexBindingDescriptionCount = num_vattr; + vinp.pVertexAttributeDescriptions = adesc; + vinp.vertexAttributeDescriptionCount = num_vattr; memset(&vasm, 0, sizeof vasm); vasm.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; @@ -1046,6 +1132,139 @@ VkPipeline vk_pipeln(int pp) return p->vkobj; } +int vk_create_buf(unsigned int type) +{ + int i; + struct buffer buf = {0}, *b = &buf; + + if(!buffers) { + buffers = darr_alloc(0, sizeof *buffers); + darr_push(buffers, &buf); /* add dummy buffer */ + } + + for(i=1; iused = 1; + b->usage = (VkBufferUsageFlags)type; + + if(b == &buf) { + darr_push(buffers, b); + return darr_size(buffers) - 1; + } + return b - buffers; +} + +void vk_free_buf(int bb) +{ + if(!buffers || bb < 1 || bb >= darr_size(buffers)) { + return; + } + + if(buffers[bb].used && buffers[bb].vkobj) { + if(buffers[bb].devmem) { + vkFreeMemory(vkdev, buffers[bb].devmem, 0); + buffers[bb].devmem = 0; + } + vkDestroyBuffer(vkdev, buffers[bb].vkobj, 0); + buffers[bb].vkobj = 0; + } + buffers[bb].used = 0; +} + +void vk_buf_usage(int bb, unsigned int type) +{ + struct buffer *b = buffers + bb; + b->usage = type; + b->vkobj_valid = 0; +} + +void vk_buf_size(int bb, unsigned int size) +{ + struct buffer *b = buffers + bb; + b->size = size; + b->vkobj_valid = 0; +} + +static int find_memtype(unsigned int mask, VkMemoryPropertyFlagBits flags) +{ + int i; + for(i=0; ivkobj_valid) { + if(b->vkobj) { + vkDestroyBuffer(vkdev, b->vkobj, 0); + b->vkobj = 0; + } + + memset(&binf, 0, sizeof binf); + binf.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + binf.usage = b->usage; + binf.size = b->size; + binf.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + if(vkCreateBuffer(vkdev, &binf, 0, &b->vkobj) != 0) { + fprintf(stderr, "failed to create buffer\n"); + return 0; + } + + vkGetBufferMemoryRequirements(vkdev, b->vkobj, &mreq); + + memset(&alloc, 0, sizeof alloc); + alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + alloc.allocationSize = mreq.size; + alloc.memoryTypeIndex = find_memtype(mreq.memoryTypeBits, VKMEM_HOSTVIS | VKMEM_HOSTCOH); + if(vkAllocateMemory(vkdev, &alloc, 0, &b->devmem) != 0) { + fprintf(stderr, "failed to allocate %ld bytes of device memory\n", mreq.size); + vkDestroyBuffer(vkdev, b->vkobj, 0); + b->vkobj = 0; + return 0; + } + vkBindBufferMemory(vkdev, b->vkobj, b->devmem, 0); + + b->vkobj_valid = 1; + } + + return b->vkobj; +} + +void *vk_buf_map(int bb, int offs, int sz) +{ + void *ptr; + vk_buf(bb); /* force lazy construction completion */ + vkMapMemory(vkdev, buffers[bb].devmem, offs, sz, 0, &ptr); + return ptr; +} + +void vk_buf_unmap(int bb) +{ + vkUnmapMemory(vkdev, buffers[bb].devmem); +} + +void vk_buf_data(int bb, int offs, int sz, void *data) +{ + void *ptr = vk_buf_map(bb, offs, sz); + memcpy(ptr, data, sz); + vk_buf_unmap(bb); +} VkShaderModule vk_load_shader(const char *fname) { @@ -1131,6 +1350,32 @@ void vk_wait_fence(VkFence fence, long timeout) vkResetFences(vkdev, 1, &fence); } +void vkcmd_bind_gfxpipeln(VkCommandBuffer cmdbuf, int pp) +{ + vkCmdBindPipeline(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, vk_pipeln(pp)); +} + +void vkcmd_bind_vbuf(VkCommandBuffer cmdbuf, int count, ...) +{ + int i, bb; + va_list ap; + VkBuffer *barr; + VkDeviceSize *offsarr; + + barr = alloca(count * sizeof *barr); + offsarr = alloca(count * sizeof *offsarr); + + va_start(ap, count); + for(i=0; ioffset.x = x; @@ -1413,6 +1658,9 @@ static int create_device(void) devinf.pNext = init_rayext_list(); } + /* retreive memory properties for the selected device */ + vkGetPhysicalDeviceMemoryProperties(vkpdev, &vkmemprop); + if(vkCreateDevice(vkpdev, &devinf, 0, &vkdev) != 0) { fprintf(stderr, "failed to create vulkan device\n"); return -1; diff --git a/src/vk.h b/src/vk.h index e987e96..18d1de0 100644 --- a/src/vk.h +++ b/src/vk.h @@ -46,6 +46,15 @@ enum { }; #define VKSDR_STAGE(x) (1 << (x)) +#define VKATTR_MAX 8 + +enum { + VKATTR_FLOAT, + VKATTR_VEC2, + VKATTR_VEC3, + VKATTR_VEC4 +}; + /* primitives */ enum { VKPRIM_POINTS = VK_PRIMITIVE_TOPOLOGY_POINT_LIST, @@ -53,6 +62,23 @@ enum { VKPRIM_TRIANGLES = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST }; +/* buffer types */ +enum { + VKBUF_VERTEX = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, + VKBUF_INDEX = VK_BUFFER_USAGE_INDEX_BUFFER_BIT, + VKBUF_UNIFORM = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT +}; + +/* memory type bits */ +enum { + VKMEM_DEVLOCAL = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + VKMEM_HOSTVIS = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, + VKMEM_HOSTCOH = VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + VKMEM_HOSTCACHED = VK_MEMORY_PROPERTY_HOST_CACHED_BIT, + VKMEM_LAZY = VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT, + VKMEM_PROT = VK_MEMORY_PROPERTY_PROTECTED_BIT +}; + #ifdef _WIN32 void vk_init_win(HINSTANCE hinst, HWND win); #else @@ -104,7 +130,7 @@ void vk_pipeln_rpass(int pp, VkRenderPass rp); void vk_pipeln_viewport(int pp, int x, int y, int width, int height); void vk_pipeln_scissor(int pp, int x, int y, int width, int height); void vk_pipeln_shader(int pp, int type, VkShaderModule sdr); -/* TODO: vertex input */ +void vk_pipeln_vattr(int pp, int loc, int bind, int offs, int stride, int fmt); void vk_pipeln_prim(int pp, int prim); void vk_pipeln_polymode(int pp, int mode); void vk_pipeln_cull(int pp, int cull); @@ -123,6 +149,15 @@ void vk_pipeln_blend(int pp, int enable); void vk_pipeln_blendfunc(int pp, int src, int dst); VkPipeline vk_pipeln(int pp); +int vk_create_buf(unsigned int type); +void vk_free_buf(int bb); +void vk_buf_usage(int bb, unsigned int type); +void vk_buf_size(int bb, unsigned int size); +VkBuffer vk_buf(int bb); +void *vk_buf_map(int bb, int offs, int sz); +void vk_buf_unmap(int bb); +void vk_buf_data(int bb, int offs, int sz, void *data); + VkShaderModule vk_load_shader(const char *fname); void vk_free_shader(VkShaderModule sdr); @@ -133,6 +168,10 @@ VkFence vk_create_fence(int state); void vk_free_fence(VkFence fence); void vk_wait_fence(VkFence fence, long timeout); /* -1 = inf */ +/* command helpers */ +void vkcmd_bind_gfxpipeln(VkCommandBuffer cmdbuf, int pp); +void vkcmd_bind_vbuf(VkCommandBuffer cmdbuf, int count, ...); + /* random helpers */ void vk_rect(VkRect2D *r, int x, int y, int w, int h); -- 1.7.10.4