-
-
Save skrollilehti/a46444dd722e11482fcf3d7a564f5d2e to your computer and use it in GitHub Desktop.
Graphics API comparison
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <X11/Xlib.h> | |
#define GL_GLEXT_PROTOTYPES | |
#include <GL/glx.h> | |
#include <GL/gl.h> | |
#include <GL/glext.h> | |
const char *vertex_src = | |
"#version 330 core\n" | |
"layout(location=0) in vec2 position;\n" | |
"layout(location=1) in vec3 color;\n" | |
"out vec3 v_color;\n" | |
"void main()\n" | |
"{\n" | |
" v_color = color;\n" | |
" gl_Position = vec4(position, 0.0, 1.0);\n" | |
"}\n"; | |
const char *fragment_src = | |
"#version 330 core\n" | |
"in vec3 v_color;\n" | |
"out vec4 frag_color;\n" | |
"void main()\n" | |
"{\n" | |
" frag_color = vec4(v_color, 1.0);\n" | |
"}\n"; | |
float vertex_data[] = | |
{ | |
-0.5f, -0.7f, 1.0f, 0.0f, 0.0f, | |
0.5f, -0.7f, 0.0f, 1.0f, 0.0f, | |
0.0f, 0.7f, 0.0f, 0.0f, 1.0f | |
}; | |
int main() | |
{ | |
Display *display = XOpenDisplay(0); | |
Window root = DefaultRootWindow(display); | |
glXQueryExtension(display, NULL, NULL); | |
int fb_attribs[] = { GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, | |
GLX_RENDER_TYPE, GLX_RGBA_BIT, | |
GLX_DOUBLEBUFFER, 1, | |
0 }; | |
int n_configs = 0; | |
GLXFBConfig *fb_configs = glXChooseFBConfig(display, DefaultScreen(display), fb_attribs, &n_configs); | |
XVisualInfo *vi = glXGetVisualFromFBConfig(display, fb_configs[0]); | |
XSetWindowAttributes attr; | |
attr.colormap = XCreateColormap(display, root, vi->visual, AllocNone); | |
Window window = XCreateWindow(display, root, 0, 0, 1280, 720, 0, | |
vi->depth, InputOutput, vi->visual, CWColormap, &attr); | |
GLXWindow glxwnd = glXCreateWindow(display, fb_configs[0], window, 0); | |
int ctx_attribs[] = { GLX_RENDER_TYPE, GLX_RGBA_TYPE, | |
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, | |
GLX_CONTEXT_MAJOR_VERSION_ARB, 3, | |
GLX_CONTEXT_MINOR_VERSION_ARB, 3, | |
0 }; | |
PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribs = | |
(PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddressARB((const GLubyte *)"glXCreateContextAttribsARB"); | |
GLXContext context = glXCreateContextAttribs(display, fb_configs[0], 0, True, ctx_attribs); | |
XFree(vi); | |
XFree(fb_configs); | |
XMapWindow(display, window); | |
glXMakeContextCurrent(display, glxwnd, glxwnd, context); | |
unsigned vertex_shader = glCreateShader(GL_VERTEX_SHADER); | |
glShaderSource(vertex_shader, 1, &vertex_src, NULL); | |
glCompileShader(vertex_shader); | |
unsigned fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); | |
glShaderSource(fragment_shader, 1, &fragment_src, NULL); | |
glCompileShader(fragment_shader); | |
unsigned shprog = glCreateProgram(); | |
glAttachShader(shprog, vertex_shader); | |
glAttachShader(shprog, fragment_shader); | |
glLinkProgram(shprog); | |
unsigned vbo; | |
glGenBuffers(1, &vbo); | |
glBindBuffer(GL_ARRAY_BUFFER, vbo); | |
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW); | |
unsigned vao; | |
glGenVertexArrays(1, &vao); | |
glBindVertexArray(vao); | |
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void *)0); | |
glEnableVertexAttribArray(0); | |
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void *)(2*sizeof(float))); | |
glEnableVertexAttribArray(1); | |
glUseProgram(shprog); | |
while(1) | |
{ | |
int pending = XPending(display); | |
while(pending--) | |
{ | |
XEvent event; | |
XNextEvent(display, &event); | |
} | |
glClear(GL_COLOR_BUFFER_BIT); | |
glDrawArrays(GL_TRIANGLES, 0, 3); | |
glXSwapBuffers(display, glxwnd); | |
} | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <X11/Xlib.h> | |
#include <GL/glx.h> | |
#include <GL/gl.h> | |
int main() | |
{ | |
Display *display = XOpenDisplay(0); | |
Window root = DefaultRootWindow(display); | |
glXQueryExtension(display, NULL, NULL); | |
int attribs[] = { GLX_RGBA, GLX_DOUBLEBUFFER, 0 }; | |
XVisualInfo *vi = glXChooseVisual(display, DefaultScreen(display), attribs); | |
XSetWindowAttributes attr; | |
attr.colormap = XCreateColormap(display, root, vi->visual, AllocNone); | |
Window window = XCreateWindow(display, root, 0, 0, 1280, 720, 0, | |
vi->depth, InputOutput, vi->visual, CWColormap, &attr); | |
GLXContext context = glXCreateContext(display, vi, 0, True); | |
XFree(vi); | |
XMapWindow(display, window); | |
glXMakeCurrent(display, window, context); | |
while(1) | |
{ | |
int pending = XPending(display); | |
while(pending--) | |
{ | |
XEvent event; | |
XNextEvent(display, &event); | |
} | |
glClear(GL_COLOR_BUFFER_BIT); | |
glBegin(GL_TRIANGLES); | |
glColor3f(1.0f, 0.0f, 0.0f); | |
glVertex3f(-0.5f, -0.7f, 0.0f); | |
glColor3f(0.0f, 1.0f, 0.0f); | |
glVertex3f(0.5f, -0.7f, 0.0f); | |
glColor3f(0.0f, 0.0f, 1.0f); | |
glVertex3f(0.0f, 0.7f, 0.0f); | |
glEnd(); | |
glXSwapBuffers(display, window); | |
} | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdlib.h> | |
#include <string.h> | |
#include <X11/Xlib.h> | |
#define VK_USE_PLATFORM_XLIB_KHR | |
#include <vulkan/vulkan.h> | |
const uint32_t shader_binary[] = | |
{ | |
119734787, 66816, 1900544, 35, 0, 131089, 1, 196622, 0, 1, 589839, 0, 19, | |
1852399981, 0, 13, 15, 17, 11, 458767, 4, 31, 1852399981, 0, 29, 30, 196624, | |
31, 7, 262149, 1, 1684631414, 0, 196613, 2, 7630441, 262149, 3, 1634692198, | |
116, 262149, 4, 845374838, 0, 262149, 5, 862152054, 0, 262149, 6, 878929270, | |
0, 393221, 7, 1348430951, 1700164197, 2019914866, 0, 393222, 7, 0, | |
1348430951, 1953067887, 7237481, 458758, 7, 1, 1348430951, 1953393007, | |
1702521171, 0, 458758, 7, 2, 1130327143, 1148217708, 1635021673, 6644590, | |
327685, 13, 1769172848, 1852795252, 0, 262149, 15, 1869377379, 114, 262149, | |
17, 1868783478, 7499628, 262149, 18, 1684631414, 10536, 262149, 19, | |
1852399981, 10536, 262149, 1, 1684631414, 0, 262149, 3, 1634692198, 116, | |
262149, 5, 862152054, 0, 262149, 6, 878929270, 0, 262149, 29, 1868783478, | |
7499628, 327685, 30, 1734439526, 1819239263, 29295, 262149, 31, 1852399981, | |
10536, 196679, 7, 2, 327752, 7, 0, 11, 0, 327752, 7, 1, 11, 1, 262215, 9, 6, | |
16, 327752, 7, 2, 11, 3, 262215, 13, 30, 0, 262215, 15, 30, 1, 262215, 17, | |
30, 0, 262215, 29, 30, 0, 262215, 30, 30, 0, 131091, 1, 262165, 2, 32, 1, | |
196630, 3, 32, 262167, 4, 3, 2, 262167, 5, 3, 3, 262167, 6, 3, 4, 262187, 2, | |
8, 1, 262172, 9, 3, 8, 327710, 7, 6, 3, 9, 262176, 10, 3, 7, 262203, 10, 11, | |
3, 262176, 12, 1, 4, 262203, 12, 13, 1, 262176, 14, 1, 5, 262203, 14, 15, 1, | |
262176, 16, 3, 5, 262203, 16, 17, 3, 196641, 18, 1, 262187, 3, 23, 0, | |
262187, 3, 24, 1065353216, 262187, 2, 26, 0, 262176, 27, 3, 6, 262203, 14, | |
29, 1, 262203, 27, 30, 3, 327734, 1, 19, 0, 18, 131320, 20, 262205, 5, 21, | |
15, 196670, 17, 21, 262205, 4, 22, 13, 393296, 6, 25, 22, 23, 24, 327745, | |
27, 28, 11, 26, 196670, 28, 25, 65789, 65592, 327734, 1, 31, 0, 18, 131320, | |
32, 262205, 5, 33, 29, 327760, 6, 34, 33, 24, 196670, 30, 34, 65789, 65592 | |
}; | |
float vertex_data[] = | |
{ | |
-0.5f, 0.7f, 1.0f, 0.0f, 0.0f, | |
0.5f, 0.7f, 0.0f, 1.0f, 0.0f, | |
0.0f, -0.7f, 0.0f, 0.0f, 1.0f | |
}; | |
int main() | |
{ | |
Display *display = XOpenDisplay(0); | |
Window root = DefaultRootWindow(display); | |
Window window = XCreateWindow(display, root, 0, 0, 1280, 720, 0, | |
CopyFromParent, InputOutput, CopyFromParent, 0, NULL); | |
const char *extensions[] = { "VK_KHR_surface", "VK_KHR_xlib_surface" }; | |
VkApplicationInfo app_info = | |
{ | |
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, | |
.apiVersion = (1<<22)|(2<<12) | |
}; | |
VkInstanceCreateInfo instance_create_info = | |
{ | |
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, | |
.pApplicationInfo = &app_info, | |
.enabledExtensionCount = 2, | |
.ppEnabledExtensionNames = extensions | |
}; | |
VkInstance instance; | |
vkCreateInstance(&instance_create_info, 0, &instance); | |
VkXlibSurfaceCreateInfoKHR surface_create_info = | |
{ | |
.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, | |
.dpy = display, | |
.window = window | |
}; | |
VkSurfaceKHR surface; | |
vkCreateXlibSurfaceKHR(instance, &surface_create_info, 0, &surface); | |
unsigned n_phys_devices = 0; | |
vkEnumeratePhysicalDevices(instance, &n_phys_devices, 0); | |
VkPhysicalDevice *phys_devices = malloc(n_phys_devices*sizeof(VkPhysicalDevice)); | |
vkEnumeratePhysicalDevices(instance, &n_phys_devices, phys_devices); | |
VkPhysicalDevice physical_device; | |
unsigned gfx_queue_index = 0; | |
for(unsigned i=0; i<n_phys_devices; ++i) | |
{ | |
physical_device = phys_devices[i]; | |
unsigned n_queue_families = 0; | |
vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &n_queue_families, 0); | |
VkQueueFamilyProperties *queue_family_props = malloc(n_queue_families*sizeof(VkQueueFamilyProperties)); | |
vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &n_queue_families, queue_family_props); | |
for(; gfx_queue_index<n_queue_families; ++gfx_queue_index) | |
if((queue_family_props[gfx_queue_index].queueFlags&VK_QUEUE_GRAPHICS_BIT)) | |
break; | |
free(queue_family_props); | |
if(gfx_queue_index>=n_queue_families) | |
continue; | |
VkBool32 supported = VK_FALSE; | |
vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, gfx_queue_index, surface, &supported); | |
if(supported) | |
break; | |
} | |
free(phys_devices); | |
float queue_priority = 1.0f; | |
VkDeviceQueueCreateInfo queue_create_info = | |
{ | |
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, | |
.queueFamilyIndex = gfx_queue_index, | |
.queueCount = 1, | |
.pQueuePriorities = &queue_priority | |
}; | |
const char *dev_extensions[] = { "VK_KHR_swapchain" }; | |
VkDeviceCreateInfo device_create_info = | |
{ | |
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, | |
.queueCreateInfoCount = 1, | |
.pQueueCreateInfos = &queue_create_info, | |
.enabledExtensionCount = 1, | |
.ppEnabledExtensionNames = dev_extensions | |
}; | |
VkDevice device; | |
vkCreateDevice(physical_device, &device_create_info, 0, &device); | |
VkQueue graphics_queue; | |
vkGetDeviceQueue(device, gfx_queue_index, 0, &graphics_queue); | |
VkSwapchainCreateInfoKHR swapchain_info = | |
{ | |
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, | |
.surface = surface, | |
.minImageCount = 2, | |
.imageExtent.width = 1280, | |
.imageExtent.height = 720, | |
.imageArrayLayers = 1, | |
.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, | |
.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE, | |
.clipped = VK_TRUE | |
}; | |
VkSurfaceCapabilitiesKHR surface_caps; | |
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, surface, &surface_caps); | |
swapchain_info.preTransform = surface_caps.currentTransform; | |
swapchain_info.compositeAlpha = surface_caps.supportedCompositeAlpha&~(surface_caps.supportedCompositeAlpha-1); | |
uint32_t n_formats = 0; | |
vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &n_formats, 0); | |
VkSurfaceFormatKHR *surface_formats = malloc(n_formats*sizeof(VkSurfaceFormatKHR)); | |
vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &n_formats, surface_formats); | |
for(unsigned i=0; i<n_formats; ++i) | |
{ | |
const VkSurfaceFormatKHR *format = surface_formats+i; | |
if(format->format!=VK_FORMAT_R8G8B8_SRGB && format->format!=VK_FORMAT_B8G8R8_SRGB) | |
{ | |
swapchain_info.imageFormat = format->format; | |
swapchain_info.imageColorSpace = format->colorSpace; | |
break; | |
} | |
} | |
free(surface_formats); | |
uint32_t n_present_modes = 0; | |
vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &n_present_modes, 0); | |
VkPresentModeKHR *present_modes = malloc(n_present_modes*sizeof(VkPresentModeKHR)); | |
vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &n_present_modes, present_modes); | |
swapchain_info.presentMode = present_modes[0]; | |
for(unsigned i=0; i<n_present_modes; ++i) | |
if(present_modes[i]==VK_PRESENT_MODE_FIFO_KHR) | |
{ | |
swapchain_info.presentMode = VK_PRESENT_MODE_FIFO_KHR; | |
break; | |
} | |
free(present_modes); | |
VkSwapchainKHR swapchain; | |
vkCreateSwapchainKHR(device, &swapchain_info, NULL, &swapchain); | |
VkAttachmentDescription attachment = | |
{ | |
.format = swapchain_info.imageFormat, | |
.samples = VK_SAMPLE_COUNT_1_BIT, | |
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, | |
.storeOp = VK_ATTACHMENT_STORE_OP_STORE, | |
.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD, | |
.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE, | |
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, | |
.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR | |
}; | |
VkAttachmentReference color_ref = | |
{ | |
.attachment = 0, | |
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL | |
}; | |
VkSubpassDescription subpass = | |
{ | |
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, | |
.colorAttachmentCount = 1, | |
.pColorAttachments = &color_ref | |
}; | |
VkSubpassDependency dependency = | |
{ | |
.srcSubpass = 0, | |
.dstSubpass = VK_SUBPASS_EXTERNAL, | |
.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, | |
.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT, | |
.dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, | |
.dstAccessMask = 0, | |
}; | |
VkRenderPassCreateInfo render_pass_info = | |
{ | |
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, | |
.attachmentCount = 1, | |
.pAttachments = &attachment, | |
.subpassCount = 1, | |
.pSubpasses = &subpass, | |
.dependencyCount = 1, | |
.pDependencies = &dependency | |
}; | |
VkRenderPass render_pass; | |
vkCreateRenderPass(device, &render_pass_info, NULL, &render_pass); | |
uint32_t n_swap_images = 0; | |
vkGetSwapchainImagesKHR(device, swapchain, &n_swap_images, 0); | |
VkImage *swap_images = malloc(n_swap_images*sizeof(VkImage)); | |
vkGetSwapchainImagesKHR(device, swapchain, &n_swap_images, swap_images); | |
VkImageView *swap_views = malloc(n_swap_images*sizeof(VkImageView)); | |
VkFramebuffer *framebuffers = malloc(n_swap_images*sizeof(VkFramebuffer)); | |
for(unsigned i=0; i<n_swap_images; ++i) | |
{ | |
VkImageViewCreateInfo view_info = | |
{ | |
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, | |
.image = swap_images[i], | |
.viewType = VK_IMAGE_VIEW_TYPE_2D, | |
.format = swapchain_info.imageFormat, | |
.components = | |
{ | |
.r = VK_COMPONENT_SWIZZLE_R, | |
.g = VK_COMPONENT_SWIZZLE_G, | |
.b = VK_COMPONENT_SWIZZLE_B, | |
.a = VK_COMPONENT_SWIZZLE_A, | |
}, | |
.subresourceRange = | |
{ | |
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | |
.baseMipLevel = 0, | |
.levelCount = 1, | |
.baseArrayLayer = 0, | |
.layerCount = 1 | |
} | |
}; | |
vkCreateImageView(device, &view_info, NULL, &swap_views[i]); | |
VkFramebufferCreateInfo framebuffer_info = | |
{ | |
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, | |
.renderPass = render_pass, | |
.attachmentCount = 1, | |
.pAttachments = &swap_views[i], | |
.width = 1280, | |
.height = 720, | |
.layers = 1 | |
}; | |
vkCreateFramebuffer(device, &framebuffer_info, NULL, &framebuffers[i]); | |
} | |
unsigned frames_in_flight = (n_swap_images>=3 ? 3 : n_swap_images); | |
VkCommandPool *command_pools = malloc(frames_in_flight*sizeof(VkCommandPool)); | |
VkCommandBuffer *command_buffers = malloc(frames_in_flight*sizeof(VkCommandBuffer)); | |
for(unsigned i=0; i<frames_in_flight; ++i) | |
{ | |
VkCommandPoolCreateInfo pool_info = | |
{ | |
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, | |
.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, | |
.queueFamilyIndex = gfx_queue_index | |
}; | |
vkCreateCommandPool(device, &pool_info, NULL, &command_pools[i]); | |
VkCommandBufferAllocateInfo alloc_info = | |
{ | |
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, | |
.commandPool = command_pools[i], | |
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, | |
.commandBufferCount = 1 | |
}; | |
vkAllocateCommandBuffers(device, &alloc_info, &command_buffers[i]); | |
} | |
VkSemaphore *semaphores = malloc(frames_in_flight*2*sizeof(VkSemaphore)); | |
for(unsigned i=0; i<frames_in_flight*2; ++i) | |
{ | |
VkSemaphoreCreateInfo semaphore_info = | |
{ | |
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO | |
}; | |
vkCreateSemaphore(device, &semaphore_info, NULL, &semaphores[i]); | |
} | |
VkFence *fences = malloc(frames_in_flight*sizeof(VkFence)); | |
for(unsigned i=0; i<frames_in_flight; ++i) | |
{ | |
VkFenceCreateInfo fence_info = | |
{ | |
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, | |
.flags = VK_FENCE_CREATE_SIGNALED_BIT | |
}; | |
vkCreateFence(device, &fence_info, NULL, &fences[i]); | |
} | |
VkShaderModuleCreateInfo module_info = | |
{ | |
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, | |
.codeSize = sizeof(shader_binary), | |
.pCode = shader_binary | |
}; | |
VkShaderModule module; | |
vkCreateShaderModule(device, &module_info, NULL, &module); | |
VkPipelineLayoutCreateInfo layout_info = | |
{ | |
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO | |
}; | |
VkPipelineLayout layout; | |
vkCreatePipelineLayout(device, &layout_info, NULL, &layout); | |
VkPipelineShaderStageCreateInfo stage_infos[2] = | |
{ | |
{ | |
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | |
.stage = VK_SHADER_STAGE_VERTEX_BIT, | |
.module = module, | |
.pName = "main" | |
}, | |
{ | |
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, | |
.stage = VK_SHADER_STAGE_FRAGMENT_BIT, | |
.module = module, | |
.pName = "main" | |
} | |
}; | |
VkVertexInputBindingDescription vertex_input_binding = | |
{ | |
.binding = 0, | |
.stride = 5*sizeof(float), | |
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX | |
}; | |
VkVertexInputAttributeDescription vertex_attribs[2] = | |
{ | |
{ | |
.location = 0, | |
.binding = 0, | |
.format = VK_FORMAT_R32G32_SFLOAT, | |
.offset = 0 | |
}, | |
{ | |
.location = 1, | |
.binding = 0, | |
.format = VK_FORMAT_R32G32B32_SFLOAT, | |
.offset = 2*sizeof(float) | |
} | |
}; | |
VkPipelineVertexInputStateCreateInfo vertex_input_state = | |
{ | |
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, | |
.vertexBindingDescriptionCount = 1, | |
.pVertexBindingDescriptions = &vertex_input_binding, | |
.vertexAttributeDescriptionCount = 2, | |
.pVertexAttributeDescriptions = vertex_attribs | |
}; | |
VkPipelineInputAssemblyStateCreateInfo input_assembly_info = | |
{ | |
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, | |
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, | |
.primitiveRestartEnable = VK_FALSE | |
}; | |
VkPipelineViewportStateCreateInfo viewport_info = | |
{ | |
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, | |
.viewportCount = 1, | |
.pViewports = NULL, | |
.scissorCount = 1, | |
.pScissors = NULL | |
}; | |
VkPipelineRasterizationStateCreateInfo raster_info = | |
{ | |
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, | |
.depthClampEnable = VK_FALSE, | |
.rasterizerDiscardEnable = VK_FALSE, | |
.polygonMode = VK_POLYGON_MODE_FILL, | |
.cullMode = VK_CULL_MODE_NONE, | |
.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE, | |
.depthBiasEnable = VK_FALSE, | |
.depthBiasConstantFactor = 0.0f, | |
.depthBiasClamp = 0.0f, | |
.depthBiasSlopeFactor = 0.0f, | |
.lineWidth = 1.0f | |
}; | |
VkPipelineMultisampleStateCreateInfo multisample_info = | |
{ | |
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, | |
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, | |
.sampleShadingEnable = VK_FALSE, | |
.minSampleShading = 1.0f, | |
.pSampleMask = 0, | |
.alphaToCoverageEnable = VK_FALSE, | |
.alphaToOneEnable = VK_FALSE | |
}; | |
VkPipelineDepthStencilStateCreateInfo depth_stencil_info = | |
{ | |
.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, | |
.depthTestEnable = VK_FALSE, | |
.depthWriteEnable = VK_FALSE, | |
.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL, | |
.depthBoundsTestEnable = VK_FALSE, | |
.stencilTestEnable = VK_FALSE, | |
.front = | |
{ | |
.failOp = VK_STENCIL_OP_KEEP, | |
.passOp = VK_STENCIL_OP_KEEP, | |
.depthFailOp = VK_STENCIL_OP_KEEP, | |
.compareOp = VK_COMPARE_OP_EQUAL, | |
.compareMask = 0xFFFFFFFFU, | |
.writeMask = 0xFFFFFFFFU, | |
.reference = 0 | |
} | |
}; | |
depth_stencil_info.front = depth_stencil_info.back; | |
VkPipelineColorBlendAttachmentState blend_attachment = | |
{ | |
.blendEnable = VK_FALSE, | |
.srcColorBlendFactor = VK_BLEND_FACTOR_ONE, | |
.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO, | |
.colorBlendOp = VK_BLEND_OP_ADD, | |
.srcAlphaBlendFactor = blend_attachment.srcColorBlendFactor, | |
.dstAlphaBlendFactor = blend_attachment.dstColorBlendFactor, | |
.alphaBlendOp = blend_attachment.colorBlendOp, | |
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | | |
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT | |
}; | |
VkPipelineColorBlendStateCreateInfo blend_info = | |
{ | |
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, | |
.attachmentCount = 1, | |
.pAttachments = &blend_attachment | |
}; | |
VkDynamicState dynamic_states[2] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; | |
VkPipelineDynamicStateCreateInfo dynamic_info = | |
{ | |
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, | |
.dynamicStateCount = 2, | |
.pDynamicStates = dynamic_states | |
}; | |
VkGraphicsPipelineCreateInfo pipeline_info = | |
{ | |
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, | |
.stageCount = 2, | |
.pStages = stage_infos, | |
.pVertexInputState = &vertex_input_state, | |
.pInputAssemblyState = &input_assembly_info, | |
.pViewportState = &viewport_info, | |
.pRasterizationState = &raster_info, | |
.pMultisampleState = &multisample_info, | |
.pDepthStencilState = &depth_stencil_info, | |
.pColorBlendState = &blend_info, | |
.pDynamicState = &dynamic_info, | |
.layout = layout, | |
.renderPass = render_pass, | |
.subpass = 0 | |
}; | |
VkPipeline pipeline; | |
vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipeline_info, NULL, &pipeline); | |
VkBufferCreateInfo buffer_info = | |
{ | |
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | |
.size = sizeof(vertex_data), | |
.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, | |
.sharingMode = VK_SHARING_MODE_EXCLUSIVE | |
}; | |
VkBuffer vertex_buffer; | |
vkCreateBuffer(device, &buffer_info, NULL, &vertex_buffer); | |
VkPhysicalDeviceMemoryProperties mem_props; | |
vkGetPhysicalDeviceMemoryProperties(physical_device, &mem_props); | |
VkMemoryRequirements requirements; | |
vkGetBufferMemoryRequirements(device, vertex_buffer, &requirements); | |
VkMemoryAllocateInfo alloc_info = | |
{ | |
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, | |
.allocationSize = requirements.size | |
}; | |
const VkMemoryPropertyFlags mem_flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | | |
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; | |
for(unsigned i=0; i<mem_props.memoryTypeCount; ++i) | |
if((requirements.memoryTypeBits&(1<<i)) && (mem_props.memoryTypes[i].propertyFlags&mem_flags)==mem_flags) | |
{ | |
alloc_info.memoryTypeIndex = i; | |
break; | |
} | |
VkDeviceMemory memory; | |
vkAllocateMemory(device, &alloc_info, NULL, &memory); | |
vkBindBufferMemory(device, vertex_buffer, memory, 0); | |
void *mapped_address; | |
vkMapMemory(device, memory, 0, VK_WHOLE_SIZE, 0, &mapped_address); | |
memcpy(mapped_address, vertex_data, sizeof(vertex_data)); | |
XMapWindow(display, window); | |
int first_frame = 1; | |
unsigned frame_index = 0; | |
while(1) | |
{ | |
int pending = XPending(display); | |
while(pending--) | |
{ | |
XEvent event; | |
XNextEvent(display, &event); | |
} | |
uint32_t image_index; | |
vkAcquireNextImageKHR(device, swapchain, UINT64_MAX, semaphores[frame_index*2], 0, &image_index); | |
vkWaitForFences(device, 1, &fences[frame_index], VK_TRUE, UINT64_MAX); | |
vkResetCommandPool(device, command_pools[frame_index], 0); | |
vkResetFences(device, 1, &fences[frame_index]); | |
VkCommandBuffer cmd_buf = command_buffers[frame_index]; | |
VkCommandBufferBeginInfo buffer_begin_info = | |
{ | |
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, | |
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT | |
}; | |
vkBeginCommandBuffer(cmd_buf, &buffer_begin_info); | |
if(first_frame) | |
{ | |
VkBufferMemoryBarrier barrier = | |
{ | |
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, | |
.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT, | |
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT, | |
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | |
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | |
.buffer = vertex_buffer, | |
.offset = 0, | |
.size = VK_WHOLE_SIZE | |
}; | |
vkCmdPipelineBarrier(cmd_buf, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, 0, 0, | |
1, &barrier, 0, NULL); | |
first_frame = 0; | |
} | |
VkClearValue clear_value = { .color.float32 = { 0.0f, 0.0f, 0.0f, 1.0f } }; | |
VkRenderPassBeginInfo pass_begin_info = | |
{ | |
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, | |
.renderPass = render_pass, | |
.framebuffer = framebuffers[image_index], | |
.clearValueCount = 1, | |
.pClearValues = &clear_value, | |
.renderArea = | |
{ | |
.offset.x = 0, | |
.offset.y = 0, | |
.extent.width = 1280, | |
.extent.height = 720, | |
} | |
}; | |
vkCmdBeginRenderPass(cmd_buf, &pass_begin_info, VK_SUBPASS_CONTENTS_INLINE); | |
vkCmdBindPipeline(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); | |
VkDeviceSize vbuf_offset = 0; | |
vkCmdBindVertexBuffers(cmd_buf, 0, 1, &vertex_buffer, &vbuf_offset); | |
VkViewport viewport = | |
{ | |
.width = 1280, | |
.height = 720, | |
.minDepth = 0.0f, | |
.maxDepth = 1.0f | |
}; | |
vkCmdSetViewport(cmd_buf, 0, 1, &viewport); | |
VkRect2D scissor = | |
{ | |
.extent.width = 1280, | |
.extent.height = 720 | |
}; | |
vkCmdSetScissor(cmd_buf, 0, 1, &scissor); | |
vkCmdDraw(cmd_buf, 3, 1, 0, 0); | |
vkCmdEndRenderPass(cmd_buf); | |
vkEndCommandBuffer(cmd_buf); | |
VkPipelineStageFlags wait_stages = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; | |
VkSubmitInfo submit_info = | |
{ | |
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, | |
.waitSemaphoreCount = 1, | |
.pWaitSemaphores = semaphores+frame_index*2, | |
.pWaitDstStageMask = &wait_stages, | |
.commandBufferCount = 1, | |
.pCommandBuffers = &cmd_buf, | |
.signalSemaphoreCount = 1, | |
.pSignalSemaphores = semaphores+frame_index*2+1 | |
}; | |
vkQueueSubmit(graphics_queue, 1, &submit_info, fences[frame_index]); | |
VkPresentInfoKHR present_info = | |
{ | |
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, | |
.waitSemaphoreCount = 1, | |
.pWaitSemaphores = semaphores+frame_index*2+1, | |
.swapchainCount = 1, | |
.pSwapchains = &swapchain, | |
.pImageIndices = &image_index | |
}; | |
vkQueuePresentKHR(graphics_queue, &present_info); | |
frame_index = (frame_index+1)%frames_in_flight; | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment