#include "opengl/texture-gl.h"
#include "opengl/shader-gl.h"
+#include "vulkan/shader-vk.h"
#include "vulkan/mesh-vk.h"
#include "vulkan/texture-vk.h"
void (*gfx_zbuffer)(bool enable);
void (*gfx_cull_face)(Gfx_cull_face cf);
void (*gfx_reshape)(int width, int height);
+void (*gfx_wireframe)(bool enable);
bool gfx_init(Gfx_API api)
{
case GFX_GL:
return new ShaderProgramGL;
case GFX_VK:
- // return new ShaderProgramVK;
- return 0;
+ return new ShaderProgramVK;
}
return 0;
}
case GFX_GL:
return new ShaderGL;
case GFX_VK:
- // return new ShaderVK;
- return 0;
+ return new ShaderVK;
}
return 0;
}
return (char *)"vk_shaders";
}
return (char *)"";
-}
\ No newline at end of file
+}
extern void (*gfx_zbuffer)(bool enable);
extern void (*gfx_cull_face)(Gfx_cull_face cf);
extern void (*gfx_reshape)(int width, int height);
+extern void (*gfx_wireframe)(bool enable);
bool gfx_init(Gfx_API api);
void gfx_cleanup();
Shader *gfx_create_shader();
char *gfx_get_shader_path();
-#endif // GFXAPI_H_
\ No newline at end of file
+#endif // GFXAPI_H_
break;
// case 'F':
- // fog_density = fog_density < 1 - 0.0009 ? fog_density + 0.0001 : 1;
- // break;
+ // fog_density = fog_density < 1 - 0.0009 ? fog_density + 0.0001 : 1;
+ // break;
// case 'U':
- // fog_density = fog_density > 0.0001 ? fog_density - 0.0001 : 0;
- // break;
+ // fog_density = fog_density > 0.0001 ? fog_density - 0.0001 : 0;
+ // break;
+
+ case 'P':
+ gfx_wireframe(true);
+ break;
+
+ case 'F':
+ gfx_wireframe(false);
+ break;
default:
break;
static void viewport(int x, int y, int width, int height);
static void zbuffer(bool enable);
static void cull_face(Gfx_cull_face cf);
-static void reshape(int width, int height) {};
+static void reshape(int width, int height) {}
+static void wireframe(bool enable);
bool init_opengl()
{
gfx_zbuffer = zbuffer;
gfx_cull_face = cull_face;
gfx_reshape = reshape;
+ gfx_wireframe = wireframe;
// glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
return true;
break;
}
}
+
+static void wireframe(bool enabled)
+{
+ if(enabled)
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ else
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+}
bool Renderer::create()
{
//debug
- if(!(nprog = sdr_man->create_shader_program("debug.v.glsl", "debug.f.glsl"))) {
- fprintf(stderr, "Failed to load debug shaders.\n");
- }
+ // if(!(nprog = sdr_man->create_shader_program("debug.v.glsl", "debug.f.glsl"))) {
+ // fprintf(stderr, "Failed to load debug shaders.\n");
+ // }
if(!(sprog = sdr_man->create_shader_program("default.v.glsl", "default.f.glsl"))) {
return false;
{
path = std::string(gfx_get_shader_path());
+ if(!vname || !fname)
+ return 0;
+
Shader *vsdr = load_shader(vname, SDR_VERTEX);
if(!vsdr)
return 0;
--- /dev/null
+#include "vkutil.h"
+#include "shader-vk.h"
+
+/* static variables */
+static vku_buffer ubo;
+
+ShaderVK::ShaderVK()
+{
+}
+
+ShaderVK::~ShaderVK()
+{
+ destroy();
+}
+
+bool ShaderVK::create(char *buf, unsigned int bsz, const char *fname)
+{
+ return true;
+}
+
+bool ShaderVK::load(const char *fname, SType type)
+{
+ return true;
+}
+
+void ShaderVK::destroy()
+{
+}
+
+ShaderProgramVK::ShaderProgramVK()
+{
+}
+
+ShaderProgramVK::~ShaderProgramVK()
+{
+}
+
+bool ShaderProgramVK::create()
+{
+ return true;
+}
+
+bool ShaderProgramVK::link()
+{
+ return true;
+}
+
+bool ShaderProgramVK::use() const
+{
+ return true;
+}
+
+void ShaderProgramVK::destroy()
+{
+}
+
+void ShaderProgramVK::attach_shader(Shader *shader)
+{
+}
+
+int ShaderProgramVK::get_uniform_location(const char *name) const
+{
+ return 0;
+}
+
+void ShaderProgramVK::set_uniformi(int location, int value)
+{
+}
+
+void ShaderProgramVK::set_uniformi(int location, int x, int y)
+{
+}
+
+void ShaderProgramVK::set_uniformi(int location, int x, int y, int z)
+{
+}
+
+void ShaderProgramVK::set_uniformi(int location, int x, int y, int z, int w)
+{
+}
+
+
+void ShaderProgramVK::set_uniformf(int location, float value)
+{
+}
+
+void ShaderProgramVK::set_uniformf(int location, float x, float y)
+{
+}
+
+void ShaderProgramVK::set_uniformf(int location, float x, float y, float z)
+{
+}
+
+void ShaderProgramVK::set_uniformf(int location, float x, float y, float z, float w)
+{
+}
+
+void ShaderProgramVK::set_uniform_matrix(int location, const Mat4 &mat)
+{
+}
\ No newline at end of file
--- /dev/null
+#ifndef SHADER_VK_H_
+#define SHADER_VK_H_
+
+#include <string>
+#include "shader.h"
+
+class ShaderVK : public Shader
+{
+protected:
+ SType type;
+ std::string name;
+
+ virtual bool create(char *buf, unsigned int bsz, const char *fname) override;
+
+public:
+ ShaderVK();
+ virtual ~ShaderVK();
+
+ virtual bool load(const char *fname, SType type);
+ virtual void destroy() override;
+};
+
+class ShaderProgramVK : public ShaderProgram
+{
+protected:
+ /*ubo*/
+
+public:
+ ShaderProgramVK();
+ virtual ~ShaderProgramVK();
+
+ virtual bool create() override;
+ virtual bool use() const override;
+ virtual bool link() override;
+ virtual void destroy() override;
+ virtual void attach_shader(Shader *shader) override;
+
+ virtual int get_uniform_location(const char *name) const override;
+
+ virtual void set_uniformi(int location, int value) override;
+ virtual void set_uniformi(int location, int x, int y) override;
+ virtual void set_uniformi(int location, int x, int y, int z) override;
+ virtual void set_uniformi(int location, int x, int y, int z, int w) override;
+
+ virtual void set_uniformf(int location, float value) override;
+ virtual void set_uniformf(int location, float x, float y) override;
+ virtual void set_uniformf(int location, float x, float y, float z) override;
+ virtual void set_uniformf(int location, float x, float y, float z, float w) override;
+
+ virtual void set_uniform_matrix(int location, const Mat4 &mat) override;
+};
+#endif // SHADER_VK_H_
\ No newline at end of file
/* static functions */
static void error_callback(int error, const char *descr);
+static void clear(float r, float g, float b);
+static void viewport(int x, int y, int width, int height);
+static void zbuffer(bool enable);
+static void cull_face(Gfx_cull_face cf);
static void reshape(int width, int height);
bool init_vulkan()
return false;
}
+ if(!(vkswapchain = vku_create_swapchain(vksurface, win_w, win_h, 2,
+ VK_PRESENT_MODE_FIFO_KHR, 0))) {
+ fprintf(stderr, "Failed to create swapchain.\n");
+ return false;
+ }
+
+ vkswapchain_images = vku_get_swapchain_images(vkswapchain, &vknum_swapchain_images);
+ if(!vkswapchain_images) {
+ fprintf(stderr, "Failed to get swapchain images.\n");
+ return false;
+ }
+
+ vkswapchain_views = vku_create_image_views(vkswapchain_images, vknum_swapchain_images);
+ if(!vkswapchain_views) {
+ fprintf(stderr, "Failed to create swapchain image views.\n");
+ delete [] vkswapchain_images;
+ return false;
+ }
+
+ if(!vku_create_renderpass()) {
+ fprintf(stderr, "Failed to create renderpass'\n");
+ return false;
+ }
+
+ if(!vku_create_framebuffers(vkswapchain_views, vknum_swapchain_images, win_w, win_h)) {
+ fprintf(stderr, "Failed to create framebuffers.\n");
+ return false;
+ }
+
+ gfx_clear = clear;
+ gfx_viewport = viewport;
+ gfx_zbuffer = zbuffer;
+ gfx_cull_face = cull_face;
gfx_reshape = reshape;
return true;
void cleanup_vulkan()
{
+ if(win) {
+ glfwDestroyWindow(win);
+ }
+ glfwTerminate();
+
//TODOs according to the book:
// 1- make sure all threads have been terminated (when I add threads)
// 2- destroy objects in *reverse* order
+ vkDestroyRenderPass(vkdev, vkrpass, 0);
vkDestroySurfaceKHR(vkinst, vksurface, 0);
vku_cleanup();
}
vkswapchain = sc;
- free(vkswapchain_images);
+ delete [] vkswapchain_images;
vkswapchain_images = vku_get_swapchain_images(sc, 0);
vknext_swapchain_image = vku_get_next_image(vkswapchain);
-}
\ No newline at end of file
+}
+
+static void clear(float r, float g, float b)
+{
+}
+
+static void viewport(int x, int y, int width, int height)
+{
+}
+
+static void zbuffer(bool enable)
+{
+}
+
+static void cull_face(Gfx_cull_face cf)
+{
+}
/* global variables */
+VkPipeline *vkgraphics_pipeline;
+VkFramebuffer *vkfbufs;
+VkRenderPass vkrpass;
VkSwapchainKHR vkswapchain;
VkImage *vkswapchain_images;
+VkImageView *vkswapchain_views;
+int vknum_swapchain_images;
int vknext_swapchain_image;
VkSurfaceKHR vksurface;
VkInstance vkinst;
vkext_count = 0;
vkEnumerateInstanceExtensionProperties(0, &vkext_count, 0);
if(vkext_count) {
- if(!(vkext = (VkExtensionProperties *)malloc(vkext_count * sizeof *vkext))) {
- perror("failed to allocate instance extension list");
- return false;
- }
+ vkext = new VkExtensionProperties[vkext_count];
vkEnumerateInstanceExtensionProperties(0, &vkext_count, vkext);
printf("instance extensions:\n");
vkdevext_count = 0;
vkEnumerateDeviceExtensionProperties(phys_devices[sel_dev], 0, &vkdevext_count, 0);
if(vkdevext_count) {
- if(!(vkdevext = (VkExtensionProperties *)malloc(vkdevext_count * sizeof *vkdevext))) {
- perror("failed to allocate device extension list");
- return false;
- }
+ vkdevext = new VkExtensionProperties[vkdevext_count];
vkEnumerateDeviceExtensionProperties(phys_devices[sel_dev], 0, &vkdevext_count, vkdevext);
printf("selected device extensions:\n");
fprintf(stderr, "failed to enumerate vulkan physical devices\n");
return false;
}
- phys_devices = (VkPhysicalDevice *)malloc(num_devices * sizeof *phys_devices);
+ phys_devices = new VkPhysicalDevice[num_devices];
if(vkEnumeratePhysicalDevices(vkinst, &num_devices, phys_devices) != 0) {
fprintf(stderr, "failed to enumerate vulkan physical devices\n");
return false;
if(qprop_count <= 0) {
continue;
}
- qprop = (VkQueueFamilyProperties *)malloc(qprop_count * sizeof *qprop);
+ qprop = new VkQueueFamilyProperties[qprop_count];
vkGetPhysicalDeviceQueueFamilyProperties(phys_devices[i], &qprop_count, qprop);
for(unsigned int j=0; j<qprop_count; j++) {
sel_qfamily = j;
}
}
- free(qprop);
+ delete [] qprop;
}
if(sel_dev < 0 || sel_qfamily < 0) {
vkinst = 0;
}
- free(phys_devices);
+ delete [] phys_devices;
phys_devices = 0;
}
if(vkGetSwapchainImagesKHR(vkdev, sc, &nimg, 0) != 0) {
return 0;
}
- if(!(images = (VkImage *)malloc(nimg * sizeof *images))) {
- return 0;
- }
+ images = new VkImage[nimg];
vkGetSwapchainImagesKHR(vkdev, sc, &nimg, images);
if(count) *count = (int)nimg;
return images;
}
+VkImageView *vku_create_image_views(VkImage *images, int count)
+{
+ VkImageView *iviews;
+
+ iviews = new VkImageView[count];
+ for(int i=0; i<count; i++) {
+ VkImageViewCreateInfo inf;
+ memset(&inf, 0, sizeof inf);
+
+ inf.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+ inf.image = images[i];
+ inf.viewType = VK_IMAGE_VIEW_TYPE_2D;
+ inf.format = VK_FORMAT_B8G8R8A8_UNORM; //TODO
+ inf.components.r = inf.components.g = inf.components.b =
+ inf.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
+ inf.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ inf.subresourceRange.levelCount = 1;
+ inf.subresourceRange.layerCount = 1;
+
+ if(vkCreateImageView(vkdev, &inf, 0, iviews) != 0) {
+ fprintf(stderr, "Failed to create image views.\n");
+ delete iviews;
+ return 0;
+ }
+ }
+
+ return iviews;
+}
+
int vku_get_next_image(VkSwapchainKHR sc)
{
uint32_t next;
vkQueuePresentKHR(vkq, &inf);
}
+bool vku_create_renderpass()
+{
+ VkAttachmentDescription attachments[2];
+ memset(&attachments, 0, 2 * sizeof *attachments);
+
+ /* color */
+ attachments[0].format = VK_FORMAT_B8G8R8A8_UNORM;
+ attachments[0].samples = VK_SAMPLE_COUNT_1_BIT;
+ attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+ attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+ attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+ attachments[0].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+ attachments[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+
+ /* depth */
+ attachments[1].format = VK_FORMAT_D32_SFLOAT_S8_UINT; //TODO
+ attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
+ attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+ attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+ attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+ attachments[1].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+ attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+
+ VkAttachmentReference color_ref;
+ color_ref.attachment = 0;
+ color_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+
+ VkAttachmentReference depth_ref;
+ depth_ref.attachment = 1;
+ depth_ref.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+
+ VkSubpassDescription subpass_desc;
+ memset(&subpass_desc, 0, sizeof subpass_desc);
+
+ subpass_desc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+ subpass_desc.colorAttachmentCount = 1;
+ subpass_desc.pColorAttachments = &color_ref;
+ subpass_desc.pDepthStencilAttachment = &depth_ref;
+
+ VkRenderPassCreateInfo inf;
+ memset(&inf, 0, sizeof inf);
+
+ inf.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
+ inf.attachmentCount = 2;
+ inf.pAttachments = attachments;
+ inf.subpassCount = 1;
+ inf.pSubpasses = &subpass_desc;
+
+ if(vkCreateRenderPass(vkdev, &inf, 0, &vkrpass) != VK_SUCCESS) {
+ return false;
+ }
+
+ return true;
+}
+
+bool vku_create_framebuffers(VkImageView *image_views, int count, int w, int h)
+{
+ delete vkfbufs;
+ vkfbufs = new VkFramebuffer[count];
+
+ VkFramebufferCreateInfo inf;
+ memset(&inf, 0, sizeof inf);
+
+ inf.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
+ inf.renderPass = vkrpass;
+ inf.attachmentCount = count;
+ inf.pAttachments = image_views;
+ inf.width = w;
+ inf.height = h;
+ inf.layers = 1;
+
+ for(int i=0; i<count; i++) {
+ if(vkCreateFramebuffer(vkdev, &inf, 0, &vkfbufs[i]) != VK_SUCCESS) {
+ fprintf(stderr, "Failed to create framebuffer for image view: %d\n", i);
+ delete vkfbufs;
+ return false;
+ }
+ }
+ return true;
+}
+
struct vku_buffer *vku_create_buffer(int sz, unsigned int usage)
{
struct vku_buffer *buf;
VkBufferCreateInfo binfo;
- if(!(buf = (vku_buffer *)malloc(sizeof *buf))) {
- perror("failed to allocate vk_buffer structure");
- return 0;
- }
+ buf = new vku_buffer;
memset(&binfo, 0, sizeof binfo);
binfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
{
if(buf) {
vkDestroyBuffer(vkdev, buf->buf, 0);
- free(buf);
+ delete buf;
}
}
return errmsg.c_str();
}
+bool vku_create_graphics_pipeline(VkPipelineLayout *layout)
+{
+ VkGraphicsPipelineCreateInfo inf;
+ memset(&inf, 0, sizeof inf);
+
+ inf.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
+ inf.layout = *layout;
+ inf.renderPass = vkrpass;
+
+ /* states */
+
+ /* how primitives are assembled */
+ VkPipelineInputAssemblyStateCreateInfo ias;
+ memset(&ias, 0, sizeof ias);
+ ias.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
+ ias.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+
+ /* rasterisation */
+ VkPipelineRasterizationStateCreateInfo rsi;
+ memset(&rsi, 0, sizeof rsi);
+ rsi.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
+ rsi.polygonMode = VK_POLYGON_MODE_FILL;
+ rsi.cullMode = VK_CULL_MODE_BACK_BIT;
+ rsi.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
+ rsi.lineWidth = 1.0f;
+
+ /* blend factors */
+ VkPipelineColorBlendAttachmentState bas[1];
+ memset(&bas[0], 0, sizeof bas[0]);
+
+ VkPipelineColorBlendStateCreateInfo cbs;
+ memset(&cbs, 0, sizeof cbs);
+ cbs.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
+ cbs.attachmentCount = 1;
+ cbs.pAttachments = bas;
+
+ /* number of viewport and scissors in this pipeline */
+ VkPipelineViewportStateCreateInfo vs;
+ memset(&vs, 0, sizeof vs);
+ vs.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
+ vs.viewportCount = 1;
+ vs.scissorCount = 1;
+
+ /* dynamic states: that can be changed later */
+ std::vector<VkDynamicState> ds_enabled;
+ ds_enabled.push_back(VK_DYNAMIC_STATE_VIEWPORT);
+ //ds_enabled.push_back(VK_DYNAMIC_STATE_SCISSOR);
+ VkPipelineDynamicStateCreateInfo ds;
+ ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
+ ds.pDynamicStates = ds_enabled.data();
+ ds.dynamicStateCount = static_cast<uint32_t>(ds_enabled.size());
+
+ /* depth tests */
+ VkPipelineDepthStencilStateCreateInfo dsi;
+ memset(&dsi, 0, sizeof dsi);
+ dsi.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
+ dsi.depthTestEnable = VK_TRUE;
+ dsi.depthWriteEnable = VK_TRUE;
+ dsi.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
+ dsi.back.failOp = VK_STENCIL_OP_KEEP;
+ dsi.back.passOp = VK_STENCIL_OP_KEEP;
+ dsi.back.compareOp = VK_COMPARE_OP_ALWAYS;
+ dsi.front = dsi.back;
+
+ /* multisampling - must be set even if not used */
+ VkPipelineMultisampleStateCreateInfo msi;
+ memset(&msi, 0, sizeof msi);
+ msi.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
+ msi.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
+
+ //TODO in progress
+ return true;
+}
+
static const char *get_device_name_str(VkPhysicalDeviceType type)
{
switch(type) {
#define VKUTIL_H_
#include <vulkan/vulkan.h>
+#include <vector>
+extern VkPipeline *vkgraphics_pipeline;
+extern VkDescriptorSet *vkdescset;
+extern VkFramebuffer *vkfbufs;
+extern VkRenderPass vkrpass;
extern VkSwapchainKHR vkswapchain;
extern VkImage *vkswapchain_images;
+extern VkImageView *vkswapchain_views;
+extern int vknum_swapchain_images;
extern VkSurfaceKHR vksurface;
extern VkInstance vkinst;
extern VkPhysicalDevice vkpdev;
void vku_begin_cmdbuf(VkCommandBuffer buf, unsigned int flags);
void vku_end_cmdbuf(VkCommandBuffer buf);
void vku_reset_cmdbuf(VkCommandBuffer buf);
-
void vku_submit_cmdbuf(VkQueue q, VkCommandBuffer buf, VkFence done_fence);
/* swapchain */
VkSwapchainKHR vku_create_swapchain(VkSurfaceKHR surf, int xsz, int ysz, int n,
VkPresentModeKHR pmode, VkSwapchainKHR prev);
VkImage *vku_get_swapchain_images(VkSwapchainKHR sc, int *count);
+VkImageView *vku_create_image_views(VkImage *images, int count);
int vku_get_next_image(VkSwapchainKHR sc);
void vku_present(VkSwapchainKHR sc, int img_idx);
+/* rederpass */
+bool vku_create_renderpass();
+
+/* framebuffer */
+bool vku_create_framebuffers(VkImageView *image_views, int count, int w, int h);
+
/* buffers */
vku_buffer *vku_create_buffer(int sz, unsigned int usage);
void vku_destroy_buffer(vku_buffer *buf);
-
void vku_cmd_copybuf(VkCommandBuffer cmdbuf, VkBuffer dest, int doffs,
VkBuffer src, int soffs, int size);
/* other */
const char *vku_get_vulkan_error_str(VkResult error);
-#endif // VKUTIL_H_
\ No newline at end of file
+/* pipeline */
+bool vku_create_graphics_pipeline(VkPipelineLayout *layout);
+
+/* descriptor set */
+//bool vku_create_descriptor_set()
+
+#endif // VKUTIL_H_