#include <stdio.h>
#include <string.h>
#include <stdint.h>
+#include <stdarg.h>
#include <vulkan/vulkan.h>
#include "vk.h"
#include "util.h"
#include <vulkan/vulkan_xcb.h>
#endif
+struct rpass {
+ int used;
+ int fmt;
+ int zfmt;
+ int num_colbuf;
+ int num_samples;
+ int clear;
+
+ int vkobj_valid;
+ VkRenderPass vkobj;
+};
+
+#define MAX_FB_IMGV 8
+struct framebuf {
+ int used;
+ int width, height;
+
+ /* if rpasses[rpidx].vkobj != vkrpass, the framebuf is invalid */
+ int rpidx;
+ VkRenderPass vkrpass;
+
+ VkImageView imgv[MAX_FB_IMGV];
+ int num_imgv;
+
+ int vkobj_valid;
+ VkFramebuffer vkobj;
+};
+
+
+static struct rpass *rpasses;
+static struct framebuf *framebufs;
+
+
static int create_instance(void);
static int create_surface(void);
static int choose_phys_dev(void);
return 0;
}
-struct rpass {
- int used;
- int fmt;
- int zfmt;
- int num_colbuf;
- int num_samples;
- /* TODO: stuff about depth-stencil */
- int clear;
-
- int vkobj_valid;
- VkRenderPass vkobj;
-};
-
-static struct rpass *rpasses;
int vk_create_rpass(void)
{
void vk_rpass_msaa(int rp, int nsamp)
{
rpasses[rp].num_samples = nsamp;
+ rpasses[rp].vkobj_valid = 0;
}
void vk_rpass_clear(int rp, int clear)
{
rpasses[rp].clear = clear;
+ rpasses[rp].vkobj_valid = 0;
}
VkRenderPass vk_rpass(int rp)
r = rpasses + rp;
if(!r->vkobj_valid) {
+ if(r->vkobj) {
+ vkDestroyRenderPass(vkdev, r->vkobj, 0);
+ r->vkobj = 0;
+ }
+
zidx = r->num_colbuf;
memset(att, 0, sizeof att);
for(i=0; i<r->num_colbuf; i++) {
return r->vkobj;
}
+
+int vk_create_fb(void)
+{
+ int i;
+ struct framebuf framebuf = {0}, *fb = &framebuf;
+
+ if(!framebufs) {
+ framebufs = darr_alloc(0, sizeof *framebufs);
+ darr_push(framebufs, &framebuf); /* add dummy rpass */
+ }
+
+ for(i=1; i<darr_size(framebufs); i++) {
+ if(!framebufs[i].used) {
+ fb = framebufs + i;
+ }
+ }
+
+ /* init framebuffer defaults */
+ memset(fb, 0, sizeof &fb);
+ fb->used = 1;
+
+ if(fb == &framebuf) {
+ darr_push(framebufs, fb);
+ return darr_size(framebufs) - 1;
+ }
+ return fb - framebufs;
+}
+
+void vk_free_fb(int fb)
+{
+ if(!framebufs || fb < 1 || fb >= darr_size(framebufs)) {
+ return;
+ }
+
+ if(framebufs[fb].used && framebufs[fb].vkobj) {
+ vkDestroyFramebuffer(vkdev, framebufs[fb].vkobj, 0);
+ }
+ framebufs[fb].used = 0;
+}
+
+void vk_fb_size(int fb, int x, int y)
+{
+ framebufs[fb].width = x;
+ framebufs[fb].height = y;
+ framebufs[fb].vkobj_valid = 0;
+}
+
+void vk_fb_rpass(int fb, int rpass)
+{
+ if(rpass < 0 || rpass >= darr_size(rpasses) || !rpasses[rpass].used) {
+ fprintf(stderr, "vk_fb_rpass: %d is not a valid renderpass\n", rpass);
+ return;
+ }
+
+ framebufs[fb].rpidx = rpass;
+ if(rpasses[rpass].vkobj_valid) {
+ framebufs[fb].vkrpass = rpasses[rpass].vkobj;
+ } else {
+ framebufs[fb].vkrpass = 0;
+ }
+ framebufs[fb].vkobj_valid = 0;
+}
+
+void vk_fb_images(int fb, int n, ...)
+{
+ int i;
+ va_list ap;
+
+ if(n > MAX_FB_IMGV) {
+ fprintf(stderr, "vk_fb_images: %d is too many images\n", n);
+ n = MAX_FB_IMGV;
+ }
+
+ va_start(ap, n);
+ for(i=0; i<n; i++) {
+ framebufs[fb].imgv[i] = va_arg(ap, VkImageView);
+ }
+ va_end(ap);
+ framebufs[fb].num_imgv = n;
+ framebufs[fb].vkobj_valid = 0;
+}
+
+VkFramebuffer vk_fb(int fb)
+{
+ VkFramebufferCreateInfo fbinf;
+ VkRenderPass rpass;
+ struct framebuf *f;
+
+ f = framebufs + fb;
+
+ if(!(rpass = vk_rpass(f->rpidx))) {
+ return 0;
+ }
+
+ if(rpass != f->vkrpass || !f->vkobj_valid) {
+ f->vkrpass = rpass;
+ if(f->vkobj) {
+ vkDestroyFramebuffer(vkdev, f->vkobj, 0);
+ f->vkobj = 0;
+ }
+
+ memset(&fbinf, 0, sizeof fbinf);
+ fbinf.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
+ fbinf.renderPass = rpass;
+ fbinf.attachmentCount = f->num_imgv;
+ fbinf.pAttachments = f->imgv;
+ fbinf.width = f->width;
+ fbinf.height = f->height;
+
+ if(vkCreateFramebuffer(vkdev, &fbinf, 0, &f->vkobj) != 0) {
+ fprintf(stderr, "vk_fb: failed to create framebuffer\n");
+ return 0;
+ }
+ f->vkobj_valid = 1;
+ }
+ return f->vkobj;
+}
+
+
#define ARRSZ(arr) (sizeof arr / sizeof *arr)
static const char *known_layer_list[] = {
"VK_LAYER_GOOGLE_threading",