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;
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;
}
vk_finish();
+ vk_free_buf(vbpos);
+ vk_free_buf(vbcol);
+
for(i=0; i<num_swap_img; i++) {
vk_free_fb(fb[i]);
}
void app_display(void)
{
- int imgid;
+ int i, imgid;
VkCommandBuffer cmdbuf;
struct frame *frm;
imgid = vk_next_swap_image(frm->sem_getimg);
cmdbuf = frm->cmdbuf;
+ /* record the command buffer: begin-rpass, bind-pipeline, draw, end-rpass */
{
VkCommandBufferBeginInfo cmdbegin = {0};
VkRenderPassBeginInfo rpbegin = {0};
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);
#ifdef _WIN32
#include <windows.h>
+#include <malloc.h>
#include <vulkan/vulkan_win32.h>
#else
+#include <alloca.h>
/*#include <vulkan/vulkan_xlib.h>*/
#include <X11/Xlib-xcb.h>
#include <vulkan/vulkan_xcb.h>
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;
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);
static VkPhysicalDevice vkpdev;
static VkQueueFamilyProperties *qfam;
static uint32_t num_qfam;
+static VkPhysicalDeviceMemoryProperties vkmemprop;
static VkDevice vkdev;
static VkSurfaceKHR vksurf;
static VkSurfaceCapabilitiesKHR vksurf_caps;
if(rpasses[rp].used && rpasses[rp].vkobj) {
vkDestroyRenderPass(vkdev, rpasses[rp].vkobj, 0);
+ rpasses[rp].vkobj = 0;
}
rpasses[rp].used = 0;
}
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; i<VKATTR_MAX; i++) {
+ attr = p->vattr + 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;
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;
VkPipelineColorBlendStateCreateInfo blend;
VkPipelineLayoutCreateInfo lay;
VkGraphicsPipelineCreateInfo pinf;
+ VkVertexInputBindingDescription bdesc[VKATTR_MAX];
+ VkVertexInputAttributeDescription adesc[VKATTR_MAX];
if(p->vkobj_valid) {
}
num_sdr = idx;
+ num_vattr = 0;
+ for(i=0; i<VKATTR_MAX; i++) {
+ if(p->vattr[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;
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; i<darr_size(buffers); i++) {
+ if(!buffers[i].used) {
+ b = buffers + i;
+ }
+ }
+
+ /* init buffer defaults */
+ memset(b, 0, sizeof *b);
+ b->used = 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; i<vkmemprop.memoryTypeCount; i++) {
+ if((mask & (1 << i)) && (flags & vkmemprop.memoryTypes[i].propertyFlags) == flags) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+VkBuffer vk_buf(int bb)
+{
+ struct buffer *b = buffers + bb;
+ VkBufferCreateInfo binf;
+ VkMemoryRequirements mreq;
+ VkMemoryAllocateInfo alloc;
+
+ if(!b->vkobj_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)
{
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; i<count; i++) {
+ bb = va_arg(ap, int);
+ barr[i] = vk_buf(bb);
+ offsarr[i] = 0;
+ }
+ va_end(ap);
+
+ vkCmdBindVertexBuffers(cmdbuf, 0, count, barr, offsarr);
+}
+
void vk_rect(VkRect2D *r, int x, int y, int w, int h)
{
r->offset.x = x;
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;
};
#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,
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
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);
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);
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);