mirror of
https://gitea.nishi.boats/pyrite-dev/milsko
synced 2025-12-31 06:30:52 +00:00
vulkan support [but I finish adding the files]
git-svn-id: http://svn2.nishi.boats/svn/milsko/trunk@88 b9cfdab3-6d41-4d17-bbe4-086880011989
This commit is contained in:
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
*.o
|
||||
*.so
|
||||
examples/example
|
||||
examples/image
|
||||
examples/opengl
|
||||
examples/rotate
|
||||
examples/vulkan
|
||||
3
compile_flags.txt
Normal file
3
compile_flags.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
-D_MILSKO
|
||||
-DUSE_X11
|
||||
-Iinclude
|
||||
BIN
examples/triangle.frag.spv
Normal file
BIN
examples/triangle.frag.spv
Normal file
Binary file not shown.
BIN
examples/triangle.vert.spv
Normal file
BIN
examples/triangle.vert.spv
Normal file
Binary file not shown.
610
examples/vulkan.c
Normal file
610
examples/vulkan.c
Normal file
@@ -0,0 +1,610 @@
|
||||
/* $Id$ */
|
||||
#include <Mw/Milsko.h>
|
||||
#include <Mw/Vulkan.h>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
#include <vulkan/vk_enum_string_helper.h>
|
||||
|
||||
MwWidget window, vulkan;
|
||||
int ow = 300;
|
||||
int oh = 250;
|
||||
|
||||
PFN_vkGetInstanceProcAddr _vkGetInstanceProcAddr;
|
||||
VkInstance instance;
|
||||
VkDevice device;
|
||||
VkPhysicalDevice physicalDevice;
|
||||
VkSurfaceKHR surface;
|
||||
VkQueue graphicsQueue;
|
||||
VkQueue presentQueue;
|
||||
|
||||
VkSwapchainKHR swapchain;
|
||||
VkImage* swapchainImages;
|
||||
VkImageView* swapchainImageView;
|
||||
uint32_t swapchainImageViewCount;
|
||||
uint32_t currentImageIndex;
|
||||
uint32_t frameNumber;
|
||||
|
||||
VkFence* fences;
|
||||
VkSemaphore* renderFinishedSemaphores;
|
||||
VkSemaphore* imageAvaliableSemaphores;
|
||||
|
||||
VkFramebuffer* framebuffers;
|
||||
|
||||
VkPipeline pipeline;
|
||||
VkCommandBuffer* cmdBuffers;
|
||||
VkRenderPass renderPass;
|
||||
|
||||
VkResult res;
|
||||
|
||||
VkSwapchainCreateInfoKHR swapchainCreateInfo = {};
|
||||
|
||||
#define MAX_FRAMES_IN_FLIGHT swapchainImageViewCount
|
||||
|
||||
// convienence macro for loading a vulkan function pointer into memory
|
||||
#define LOAD_VK_FUNCTION(name) \
|
||||
PFN_##name _##name = (PFN_##name)_vkGetInstanceProcAddr(instance, #name); \
|
||||
assert(_##name);
|
||||
|
||||
void tick(MwWidget handle, void* user_data, void* call_data) {
|
||||
(void)handle;
|
||||
(void)user_data;
|
||||
(void)call_data;
|
||||
|
||||
VkCommandBufferBeginInfo beginInfo = {};
|
||||
VkRenderPassBeginInfo renderPassInfo = {};
|
||||
VkSubmitInfo submitInfo = {};
|
||||
VkPresentInfoKHR presentInfo = {};
|
||||
|
||||
VkClearValue clearColor = {{{0.0f, 0.0f, 0.0f, 1.0f}}};
|
||||
uint32_t vertexCount = 3;
|
||||
uint32_t instanceCount = 1;
|
||||
|
||||
VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT};
|
||||
|
||||
LOAD_VK_FUNCTION(vkCreateFence);
|
||||
LOAD_VK_FUNCTION(vkWaitForFences);
|
||||
LOAD_VK_FUNCTION(vkResetFences);
|
||||
LOAD_VK_FUNCTION(vkResetCommandBuffer);
|
||||
LOAD_VK_FUNCTION(vkBeginCommandBuffer);
|
||||
LOAD_VK_FUNCTION(vkEndCommandBuffer);
|
||||
LOAD_VK_FUNCTION(vkQueueSubmit);
|
||||
LOAD_VK_FUNCTION(vkAcquireNextImageKHR);
|
||||
LOAD_VK_FUNCTION(vkQueuePresentKHR);
|
||||
LOAD_VK_FUNCTION(vkCreateSwapchainKHR);
|
||||
|
||||
LOAD_VK_FUNCTION(vkCmdBeginRenderPass);
|
||||
LOAD_VK_FUNCTION(vkCmdEndRenderPass);
|
||||
LOAD_VK_FUNCTION(vkCmdDraw);
|
||||
LOAD_VK_FUNCTION(vkCmdBindPipeline);
|
||||
|
||||
if((res = _vkWaitForFences(device, 1, &fences[frameNumber], VK_TRUE, UINT64_MAX)) != VK_SUCCESS) {
|
||||
printf("error waiting on fence: %s\n", string_VkResult(res));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if((res = _vkResetFences(device, 1, &fences[frameNumber])) != VK_SUCCESS) {
|
||||
printf("error resetting fence: %s\n", string_VkResult(res));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
swapchainRetry:
|
||||
if((res = _vkAcquireNextImageKHR(device, swapchain, UINT64_MAX, imageAvaliableSemaphores[frameNumber], NULL, ¤tImageIndex)) != VK_SUCCESS) {
|
||||
if(res == VK_ERROR_OUT_OF_DATE_KHR) {
|
||||
if(_vkCreateSwapchainKHR(device, &swapchainCreateInfo, NULL, &swapchain) != VK_SUCCESS) {
|
||||
printf("failed to create swapchain: %s\n", string_VkResult(res));
|
||||
exit(0);
|
||||
};
|
||||
goto swapchainRetry;
|
||||
}
|
||||
};
|
||||
|
||||
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
beginInfo.pNext = NULL;
|
||||
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
beginInfo.pInheritanceInfo = NULL;
|
||||
|
||||
if((res = _vkResetCommandBuffer(cmdBuffers[frameNumber], 0)) != VK_SUCCESS) {
|
||||
printf("error beginning command buffer record: %s\n", string_VkResult(res));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if((res = _vkBeginCommandBuffer(cmdBuffers[frameNumber], &beginInfo)) != VK_SUCCESS) {
|
||||
printf("error beginning command buffer record: %s\n", string_VkResult(res));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||
renderPassInfo.pNext = NULL;
|
||||
renderPassInfo.renderPass = renderPass;
|
||||
renderPassInfo.framebuffer = framebuffers[frameNumber];
|
||||
renderPassInfo.renderArea.offset = (VkOffset2D){0, 0};
|
||||
renderPassInfo.renderArea.extent = (VkExtent2D){(uint32_t)ow, (uint32_t)oh};
|
||||
renderPassInfo.clearValueCount = 1;
|
||||
renderPassInfo.pClearValues = &clearColor;
|
||||
|
||||
_vkCmdBeginRenderPass(cmdBuffers[frameNumber], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
|
||||
_vkCmdBindPipeline(cmdBuffers[frameNumber], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
||||
|
||||
_vkCmdDraw(cmdBuffers[frameNumber], vertexCount, instanceCount, 0, 0);
|
||||
|
||||
_vkCmdEndRenderPass(cmdBuffers[frameNumber]);
|
||||
|
||||
if((res = _vkEndCommandBuffer(cmdBuffers[frameNumber])) != VK_SUCCESS) {
|
||||
printf("error recording command buffer: %s\n", string_VkResult(res));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submitInfo.pNext = NULL;
|
||||
submitInfo.waitSemaphoreCount = 1;
|
||||
submitInfo.pWaitSemaphores = &imageAvaliableSemaphores[frameNumber];
|
||||
submitInfo.pWaitDstStageMask = waitStages;
|
||||
submitInfo.commandBufferCount = 1;
|
||||
submitInfo.pCommandBuffers = &cmdBuffers[frameNumber];
|
||||
submitInfo.signalSemaphoreCount = 1;
|
||||
submitInfo.pSignalSemaphores = &renderFinishedSemaphores[frameNumber];
|
||||
|
||||
if((res = _vkQueueSubmit(graphicsQueue, 1, &submitInfo, fences[frameNumber])) != VK_SUCCESS) {
|
||||
printf("error submitting command buffer: %s\n", string_VkResult(res));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
||||
|
||||
presentInfo.waitSemaphoreCount = 1;
|
||||
presentInfo.pWaitSemaphores = &renderFinishedSemaphores[frameNumber];
|
||||
presentInfo.swapchainCount = 1;
|
||||
presentInfo.pSwapchains = &swapchain;
|
||||
presentInfo.pImageIndices = ¤tImageIndex;
|
||||
|
||||
presentInfo.pResults = NULL; // Optional
|
||||
|
||||
_vkQueuePresentKHR(presentQueue, &presentInfo);
|
||||
|
||||
// frameNumber = currentImageIndex;
|
||||
frameNumber = (frameNumber + 1) % (MAX_FRAMES_IN_FLIGHT);
|
||||
}
|
||||
|
||||
void vulkan_setup(MwWidget handle) {
|
||||
FILE* vertFile;
|
||||
FILE* fragFile;
|
||||
void* vertBuf;
|
||||
void* fragBuf;
|
||||
size_t vertFileSize;
|
||||
size_t fragFileSize;
|
||||
size_t amountRead;
|
||||
|
||||
uint32_t i;
|
||||
VkViewport viewport = {};
|
||||
VkRect2D scissor = {};
|
||||
VkCommandPool cmdPool = {};
|
||||
VkResult res = 0;
|
||||
VkShaderModule fragShaderModule;
|
||||
VkShaderModule vertShaderModule;
|
||||
VkPipelineLayout pipelineLayout = {};
|
||||
VkAttachmentDescription colorAttachment = {};
|
||||
VkAttachmentReference colorAttachmentRef = {};
|
||||
VkSubpassDescription subpass = {};
|
||||
|
||||
VkRenderPassCreateInfo renderPassInfo = {};
|
||||
VkShaderModuleCreateInfo vertInfo = {};
|
||||
VkShaderModuleCreateInfo fragInfo = {};
|
||||
VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
|
||||
VkPipelineShaderStageCreateInfo vertShaderStageInfo = {};
|
||||
VkPipelineShaderStageCreateInfo fragShaderStageInfo = {};
|
||||
VkPipelineShaderStageCreateInfo shaderStages[2] = {};
|
||||
VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
|
||||
VkPipelineInputAssemblyStateCreateInfo inputAssembly = {};
|
||||
VkPipelineViewportStateCreateInfo viewportState = {};
|
||||
VkPipelineRasterizationStateCreateInfo rasterizer = {};
|
||||
VkPipelineMultisampleStateCreateInfo multisampling = {};
|
||||
VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
|
||||
VkPipelineColorBlendStateCreateInfo colorBlending = {};
|
||||
VkGraphicsPipelineCreateInfo pipelineInfo = {};
|
||||
VkFramebufferCreateInfo framebufferInfo = {};
|
||||
VkCommandBufferAllocateInfo allocInfo = {};
|
||||
VkCommandPoolCreateInfo poolInfo = {};
|
||||
VkImageViewCreateInfo imageViewCreateInfo = {};
|
||||
VkSemaphoreCreateInfo semaphoreInfo = {};
|
||||
VkFenceCreateInfo fenceInfo = {};
|
||||
|
||||
_vkGetInstanceProcAddr = MwVulkanGetInstanceProcAddr(handle);
|
||||
instance = MwVulkanGetInstance(handle);
|
||||
device = MwVulkanGetLogicalDevice(handle);
|
||||
physicalDevice = MwVulkanGetPhysicalDevice(handle);
|
||||
graphicsQueue = MwVulkanGetGraphicsQueue(handle);
|
||||
presentQueue = MwVulkanGetPresentQueue(handle);
|
||||
surface = MwVulkanGetSurface(handle);
|
||||
|
||||
LOAD_VK_FUNCTION(vkCreateShaderModule);
|
||||
LOAD_VK_FUNCTION(vkCreatePipelineLayout);
|
||||
LOAD_VK_FUNCTION(vkCreateGraphicsPipelines);
|
||||
LOAD_VK_FUNCTION(vkCreateCommandPool);
|
||||
LOAD_VK_FUNCTION(vkCreateFramebuffer);
|
||||
LOAD_VK_FUNCTION(vkAllocateCommandBuffers);
|
||||
LOAD_VK_FUNCTION(vkCreateFence);
|
||||
LOAD_VK_FUNCTION(vkCreateSemaphore);
|
||||
LOAD_VK_FUNCTION(vkCreateSwapchainKHR);
|
||||
LOAD_VK_FUNCTION(vkGetSwapchainImagesKHR);
|
||||
LOAD_VK_FUNCTION(vkCreateImageView);
|
||||
LOAD_VK_FUNCTION(vkCreateRenderPass);
|
||||
|
||||
// create a swapchain
|
||||
swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
||||
swapchainCreateInfo.surface = surface;
|
||||
swapchainCreateInfo.minImageCount = 3;
|
||||
swapchainCreateInfo.imageFormat = VK_FORMAT_B8G8R8A8_SRGB;
|
||||
swapchainCreateInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
|
||||
swapchainCreateInfo.imageExtent = (VkExtent2D){.width = ow, .height = oh},
|
||||
swapchainCreateInfo.imageArrayLayers = 1,
|
||||
swapchainCreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
|
||||
VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
||||
VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
// th is how we specify no transformation.
|
||||
swapchainCreateInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
|
||||
swapchainCreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||
swapchainCreateInfo.presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
|
||||
// we don't care about the color of pixels that are obscured.
|
||||
swapchainCreateInfo.clipped = VK_TRUE;
|
||||
swapchainCreateInfo.oldSwapchain = NULL;
|
||||
|
||||
if(MwVulkanGetGraphicsQueueIndex(handle) != MwVulkanGetPresentQueueIndex(handle)) {
|
||||
swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
||||
swapchainCreateInfo.queueFamilyIndexCount = 2;
|
||||
|
||||
uint32_t indices[] = {
|
||||
MwVulkanGetGraphicsQueueIndex(handle),
|
||||
MwVulkanGetPresentQueueIndex(handle),
|
||||
};
|
||||
swapchainCreateInfo.pQueueFamilyIndices = indices;
|
||||
} else {
|
||||
swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
swapchainCreateInfo.queueFamilyIndexCount = 0;
|
||||
swapchainCreateInfo.pQueueFamilyIndices = NULL;
|
||||
}
|
||||
|
||||
if(_vkCreateSwapchainKHR(device, &swapchainCreateInfo, NULL, &swapchain) != VK_SUCCESS) {
|
||||
printf("failed to create swapchain: %s\n", string_VkResult(res));
|
||||
exit(0);
|
||||
};
|
||||
|
||||
imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
imageViewCreateInfo.format = swapchainCreateInfo.imageFormat;
|
||||
imageViewCreateInfo.components.r = VK_COMPONENT_SWIZZLE_R;
|
||||
imageViewCreateInfo.components.g = VK_COMPONENT_SWIZZLE_G;
|
||||
imageViewCreateInfo.components.b = VK_COMPONENT_SWIZZLE_B;
|
||||
imageViewCreateInfo.components.a = VK_COMPONENT_SWIZZLE_A;
|
||||
imageViewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
imageViewCreateInfo.subresourceRange.baseMipLevel = 0;
|
||||
imageViewCreateInfo.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
|
||||
imageViewCreateInfo.subresourceRange.baseArrayLayer = 0;
|
||||
imageViewCreateInfo.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
|
||||
|
||||
if(_vkGetSwapchainImagesKHR(device, swapchain, &swapchainImageViewCount, NULL) != VK_SUCCESS) {
|
||||
printf("failed to get swapchain images: %s\n", string_VkResult(res));
|
||||
exit(0);
|
||||
}
|
||||
swapchainImages = malloc(sizeof(VkImage) * MAX_FRAMES_IN_FLIGHT);
|
||||
swapchainImageView = malloc(sizeof(VkImageView) * MAX_FRAMES_IN_FLIGHT);
|
||||
_vkGetSwapchainImagesKHR(device, swapchain, &swapchainImageViewCount, swapchainImages);
|
||||
for(i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
|
||||
imageViewCreateInfo.image = swapchainImages[i];
|
||||
if(_vkCreateImageView(device, &imageViewCreateInfo, NULL, &swapchainImageView[i]) != VK_SUCCESS) {
|
||||
printf("failed to get swapchain images: %s\n", string_VkResult(res));
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Create a Render Pass.
|
||||
colorAttachment.flags = 0;
|
||||
colorAttachment.format = swapchainCreateInfo.imageFormat;
|
||||
colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
colorAttachmentRef.attachment = 0;
|
||||
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
|
||||
subpass.flags = 0;
|
||||
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||
subpass.inputAttachmentCount = 0;
|
||||
subpass.pInputAttachments = NULL;
|
||||
subpass.colorAttachmentCount = 1;
|
||||
subpass.pColorAttachments = &colorAttachmentRef;
|
||||
subpass.pResolveAttachments = NULL;
|
||||
subpass.pDepthStencilAttachment = NULL;
|
||||
subpass.preserveAttachmentCount = 0;
|
||||
subpass.pPreserveAttachments = NULL;
|
||||
|
||||
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||
renderPassInfo.pNext = NULL;
|
||||
renderPassInfo.flags = 0;
|
||||
renderPassInfo.attachmentCount = 1;
|
||||
renderPassInfo.pAttachments = &colorAttachment;
|
||||
renderPassInfo.subpassCount = 1;
|
||||
renderPassInfo.pSubpasses = &subpass;
|
||||
renderPassInfo.dependencyCount = 0;
|
||||
renderPassInfo.pDependencies = NULL;
|
||||
|
||||
if((res = _vkCreateRenderPass(device, &renderPassInfo, NULL, &renderPass)) != VK_SUCCESS) {
|
||||
printf("error creating the render pass: %s\n", string_VkResult(res));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Create the Vertex Shader Module.
|
||||
vertFile = fopen("triangle.vert.spv", "rb");
|
||||
fragFile = fopen("triangle.frag.spv", "rb");
|
||||
|
||||
fseek(vertFile, 0L, SEEK_END);
|
||||
vertFileSize = ftell(vertFile);
|
||||
rewind(vertFile);
|
||||
vertBuf = malloc(vertFileSize);
|
||||
memset(vertBuf, 0, vertFileSize);
|
||||
amountRead = fread(vertBuf, 1, vertFileSize, vertFile);
|
||||
printf("triangle.vert.spv: read %ld bytes\n", amountRead);
|
||||
|
||||
vertInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||
vertInfo.pNext = NULL;
|
||||
vertInfo.flags = 0;
|
||||
vertInfo.codeSize = amountRead;
|
||||
vertInfo.pCode = vertBuf;
|
||||
|
||||
if(_vkCreateShaderModule(device, &vertInfo, NULL, &vertShaderModule) != VK_SUCCESS) {
|
||||
printf("failed to create the shader module: %s\n", string_VkResult(res));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Create the Fragment Shader Module.
|
||||
fseek(fragFile, 0L, SEEK_END);
|
||||
fragFileSize = ftell(fragFile);
|
||||
rewind(fragFile);
|
||||
fragBuf = malloc(fragFileSize);
|
||||
memset(fragBuf, 0, fragFileSize);
|
||||
amountRead = fread(fragBuf, 1, fragFileSize, fragFile);
|
||||
printf("triangle.frag.spv: read %ld bytes\n", amountRead);
|
||||
|
||||
fragInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||
fragInfo.pNext = NULL;
|
||||
fragInfo.flags = 0;
|
||||
fragInfo.codeSize = amountRead;
|
||||
fragInfo.pCode = fragBuf;
|
||||
|
||||
if(_vkCreateShaderModule(device, &fragInfo, NULL, &fragShaderModule) != VK_SUCCESS) {
|
||||
printf("error creating the shader module: %s\n", string_VkResult(res));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Create Pipeline Layout.
|
||||
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||
pipelineLayoutInfo.pNext = NULL;
|
||||
pipelineLayoutInfo.flags = 0;
|
||||
pipelineLayoutInfo.setLayoutCount = 0;
|
||||
pipelineLayoutInfo.pSetLayouts = NULL;
|
||||
pipelineLayoutInfo.pushConstantRangeCount = 0;
|
||||
|
||||
if((res = _vkCreatePipelineLayout(device, &pipelineLayoutInfo, NULL, &pipelineLayout)) != VK_SUCCESS) {
|
||||
printf("error creating the pipeline layout: %s\n", string_VkResult(res));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
vertShaderStageInfo.pNext = NULL;
|
||||
vertShaderStageInfo.flags = 0;
|
||||
vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
vertShaderStageInfo.module = vertShaderModule;
|
||||
vertShaderStageInfo.pName = "main";
|
||||
vertShaderStageInfo.pSpecializationInfo = NULL;
|
||||
|
||||
fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
fragShaderStageInfo.pNext = NULL;
|
||||
fragShaderStageInfo.flags = 0;
|
||||
fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
fragShaderStageInfo.module = fragShaderModule;
|
||||
fragShaderStageInfo.pName = "main";
|
||||
fragShaderStageInfo.pSpecializationInfo = NULL;
|
||||
|
||||
shaderStages[0] = vertShaderStageInfo;
|
||||
shaderStages[1] = fragShaderStageInfo;
|
||||
|
||||
vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||
vertexInputInfo.pNext = NULL;
|
||||
vertexInputInfo.flags = 0;
|
||||
vertexInputInfo.vertexBindingDescriptionCount = 0;
|
||||
vertexInputInfo.pVertexBindingDescriptions = NULL;
|
||||
vertexInputInfo.vertexAttributeDescriptionCount = 0;
|
||||
vertexInputInfo.pVertexAttributeDescriptions = NULL;
|
||||
|
||||
inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
||||
inputAssembly.pNext = NULL;
|
||||
inputAssembly.flags = 0;
|
||||
inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||
inputAssembly.primitiveRestartEnable = VK_FALSE;
|
||||
|
||||
viewport.x = 0.0f;
|
||||
viewport.y = 0.0f;
|
||||
viewport.width = (float)ow;
|
||||
viewport.height = (float)oh;
|
||||
viewport.minDepth = 0.0f;
|
||||
viewport.maxDepth = 1.0f;
|
||||
|
||||
scissor.offset = (VkOffset2D){0, 0};
|
||||
scissor.extent = (VkExtent2D){(uint32_t)viewport.width, (uint32_t)viewport.height};
|
||||
|
||||
viewportState = (VkPipelineViewportStateCreateInfo){};
|
||||
viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
||||
viewportState.viewportCount = 1;
|
||||
viewportState.pViewports = &viewport;
|
||||
viewportState.scissorCount = 1;
|
||||
viewportState.pScissors = &scissor;
|
||||
|
||||
rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
||||
rasterizer.pNext = NULL;
|
||||
rasterizer.flags = 0;
|
||||
rasterizer.depthClampEnable = VK_FALSE;
|
||||
rasterizer.rasterizerDiscardEnable = VK_FALSE;
|
||||
rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
|
||||
rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
|
||||
rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;
|
||||
rasterizer.depthBiasEnable = VK_FALSE;
|
||||
rasterizer.depthBiasConstantFactor = 0.0;
|
||||
rasterizer.depthBiasClamp = 0.0;
|
||||
rasterizer.depthBiasSlopeFactor = 0.0;
|
||||
rasterizer.lineWidth = 1.0f;
|
||||
|
||||
multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
||||
multisampling.pNext = NULL;
|
||||
multisampling.flags = 0;
|
||||
multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||
multisampling.sampleShadingEnable = VK_FALSE;
|
||||
multisampling.minSampleShading = 0.0;
|
||||
multisampling.pSampleMask = NULL;
|
||||
multisampling.alphaToCoverageEnable = VK_FALSE;
|
||||
multisampling.alphaToOneEnable = VK_FALSE;
|
||||
|
||||
colorBlendAttachment.blendEnable = VK_FALSE;
|
||||
colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
|
||||
colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
|
||||
colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
|
||||
colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
|
||||
colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
||||
|
||||
colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
||||
colorBlending.pNext = NULL;
|
||||
colorBlending.flags = 0;
|
||||
colorBlending.logicOpEnable = VK_FALSE;
|
||||
colorBlending.logicOp = VK_LOGIC_OP_COPY;
|
||||
colorBlending.attachmentCount = 1;
|
||||
colorBlending.pAttachments = &colorBlendAttachment;
|
||||
colorBlending.blendConstants[0] = 0.0f;
|
||||
colorBlending.blendConstants[1] = 0.0f;
|
||||
colorBlending.blendConstants[2] = 0.0f;
|
||||
colorBlending.blendConstants[3] = 0.0f;
|
||||
|
||||
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
||||
pipelineInfo.pNext = NULL;
|
||||
pipelineInfo.flags = 0;
|
||||
pipelineInfo.stageCount = 2;
|
||||
pipelineInfo.pStages = shaderStages;
|
||||
pipelineInfo.pVertexInputState = &vertexInputInfo;
|
||||
pipelineInfo.pInputAssemblyState = &inputAssembly;
|
||||
pipelineInfo.pTessellationState = NULL;
|
||||
pipelineInfo.pViewportState = &viewportState;
|
||||
pipelineInfo.pRasterizationState = &rasterizer;
|
||||
pipelineInfo.pMultisampleState = &multisampling;
|
||||
pipelineInfo.pDepthStencilState = NULL;
|
||||
pipelineInfo.pColorBlendState = &colorBlending;
|
||||
pipelineInfo.pDynamicState = NULL;
|
||||
pipelineInfo.layout = pipelineLayout;
|
||||
pipelineInfo.renderPass = renderPass;
|
||||
pipelineInfo.subpass = 0;
|
||||
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
|
||||
pipelineInfo.basePipelineIndex = 0;
|
||||
|
||||
if((res = _vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, NULL, &pipeline)) != VK_SUCCESS) {
|
||||
printf("failed to create graphics pipeline: %s\n", string_VkResult(res));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
framebuffers = malloc(sizeof(VkFramebuffer) * MAX_FRAMES_IN_FLIGHT);
|
||||
|
||||
framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||
framebufferInfo.pNext = NULL;
|
||||
framebufferInfo.flags = 0;
|
||||
framebufferInfo.renderPass = renderPass;
|
||||
framebufferInfo.attachmentCount = 1;
|
||||
framebufferInfo.width = ow;
|
||||
framebufferInfo.height = oh;
|
||||
framebufferInfo.layers = 1;
|
||||
for(i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
|
||||
framebufferInfo.pAttachments = &swapchainImageView[i];
|
||||
if((res = _vkCreateFramebuffer(device, &framebufferInfo, NULL, &framebuffers[i])) != VK_SUCCESS) {
|
||||
printf("error creating the frame buffer: %s\n", string_VkResult(res));
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Create Command Pool.
|
||||
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||
poolInfo.pNext = NULL;
|
||||
poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
||||
poolInfo.queueFamilyIndex = MwVulkanGetGraphicsQueueIndex(handle);
|
||||
|
||||
if((res = _vkCreateCommandPool(device, &poolInfo, NULL, &cmdPool)) != VK_SUCCESS) {
|
||||
printf("error creating the command pool: %s\n", string_VkResult(res));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Create Command Buffer to record draw commands.
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
allocInfo.pNext = NULL;
|
||||
allocInfo.commandPool = cmdPool;
|
||||
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
allocInfo.commandBufferCount = 1;
|
||||
|
||||
cmdBuffers = malloc(sizeof(VkCommandBuffer) * MAX_FRAMES_IN_FLIGHT);
|
||||
|
||||
for(i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
|
||||
if((res = _vkAllocateCommandBuffers(device, &allocInfo, &cmdBuffers[i])) != VK_SUCCESS) {
|
||||
printf("error allocating the command buffers: %s\n", string_VkResult(res));
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||
fenceInfo.pNext = 0;
|
||||
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||
|
||||
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||
semaphoreInfo.pNext = 0;
|
||||
semaphoreInfo.flags = VK_SEMAPHORE_TYPE_BINARY;
|
||||
|
||||
imageAvaliableSemaphores = malloc(sizeof(VkSemaphore) * MAX_FRAMES_IN_FLIGHT);
|
||||
renderFinishedSemaphores = malloc(sizeof(VkSemaphore) * MAX_FRAMES_IN_FLIGHT);
|
||||
fences = malloc(sizeof(VkFence) * MAX_FRAMES_IN_FLIGHT);
|
||||
|
||||
for(i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
|
||||
if(_vkCreateSemaphore(device, &semaphoreInfo, NULL, &imageAvaliableSemaphores[i]) != VK_SUCCESS) {
|
||||
printf("error creating fence: %s\n", string_VkResult(res));
|
||||
exit(0);
|
||||
}
|
||||
if(_vkCreateSemaphore(device, &semaphoreInfo, NULL, &renderFinishedSemaphores[i]) != VK_SUCCESS) {
|
||||
printf("error creating fence: %s\n", string_VkResult(res));
|
||||
exit(0);
|
||||
}
|
||||
if(_vkCreateFence(device, &fenceInfo, NULL, &fences[i]) != VK_SUCCESS) {
|
||||
printf("error creating fence: %s\n", string_VkResult(res));
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
window = MwVaCreateWidget(MwWindowClass, "main", NULL, 0, 0, 400, 450,
|
||||
MwNtitle, "hello world",
|
||||
NULL);
|
||||
|
||||
MwVulkanEnableExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||
vulkan = MwCreateWidget(MwVulkanClass, "vulkan", window, 50, 50, ow, oh);
|
||||
|
||||
MwAddUserHandler(window, MwNtickHandler, tick, NULL);
|
||||
|
||||
vulkan_setup(vulkan);
|
||||
|
||||
MwLoop(window);
|
||||
}
|
||||
39
include/Mw/Vulkan.h
Normal file
39
include/Mw/Vulkan.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/* $Id$ */
|
||||
#ifndef __MW_VULKAN_H__
|
||||
#define __MW_VULKAN_H__
|
||||
|
||||
#if !defined(_WIN32) && !defined(__linux__) && !defined(__FreeBSD__)
|
||||
#error Vulkan is unsupported on the requested platform.
|
||||
#endif
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#include <Mw/MachDep.h>
|
||||
#include <Mw/TypeDefs.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
MWDECL MwClass MwVulkanClass;
|
||||
|
||||
// Add an extension to the list of extensions to enable prior to initialization.
|
||||
// This must be called before MwCreateWidget.
|
||||
MWDECL void MwVulkanEnableExtension(const char* ext_name);
|
||||
|
||||
MWDECL PFN_vkGetInstanceProcAddr MwVulkanGetInstanceProcAddr(MwWidget handle);
|
||||
MWDECL VkInstance MwVulkanGetInstance(MwWidget handle);
|
||||
MWDECL VkSurfaceKHR MwVulkanGetSurface(MwWidget handle);
|
||||
MWDECL VkPhysicalDevice MwVulkanGetPhysicalDevice(MwWidget handle);
|
||||
MWDECL VkDevice MwVulkanGetLogicalDevice(MwWidget handle);
|
||||
MWDECL int MwVulkanGetGraphicsQueueIndex(MwWidget handle);
|
||||
MWDECL int MwVulkanGetPresentQueueIndex(MwWidget handle);
|
||||
MWDECL VkQueue MwVulkanGetGraphicsQueue(MwWidget handle);
|
||||
MWDECL VkQueue MwVulkanGetPresentQueue(MwWidget handle);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
385
src/vulkan.c
Normal file
385
src/vulkan.c
Normal file
@@ -0,0 +1,385 @@
|
||||
/* $Id$ */
|
||||
#include "Mw/Vulkan.h"
|
||||
#include "Mw/TypeDefs.h"
|
||||
#include <Mw/Milsko.h>
|
||||
#include <Mw/TypeDefs.h>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define VK_USE_PLATFORM_WIN32_KHR 1
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
#define VK_USE_PLATFORM_XLIB_KHR 1
|
||||
#endif
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
#include <vulkan/vk_enum_string_helper.h>
|
||||
#ifdef __linux__
|
||||
#include <vulkan/vulkan_xlib.h>
|
||||
#endif
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "stb_ds.h"
|
||||
|
||||
// convienence macro for handling vulkan errors
|
||||
#define VK_CMD(func) \
|
||||
vk_res = func; \
|
||||
if(vk_res != VK_SUCCESS) { \
|
||||
printf("VULKAN ERROR AT %s:%d: %s\n", __FILE__, __LINE__, string_VkResult(vk_res)); \
|
||||
exit(0); \
|
||||
}
|
||||
|
||||
// convienence macro for loading a vulkan function pointer into memory
|
||||
#define LOAD_VK_FUNCTION(name) \
|
||||
PFN_##name _##name = (PFN_##name)o->vkGetInstanceProcAddr(o->vkInstance, #name); \
|
||||
assert(_##name);
|
||||
|
||||
bool enableValidationLayers = true;
|
||||
|
||||
const char** enabledExtensions;
|
||||
unsigned int enabledExtensionCount = 0;
|
||||
|
||||
typedef struct vulkan {
|
||||
void* vulkanLibrary;
|
||||
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;
|
||||
VkInstance vkInstance;
|
||||
VkSurfaceKHR vkSurface;
|
||||
|
||||
VkPhysicalDevice vkPhysicalDevice;
|
||||
VkDevice vkLogicalDevice;
|
||||
VkQueue vkGraphicsQueue;
|
||||
VkQueue vkPresentQueue;
|
||||
uint32_t vkGraphicsFamilyIDX;
|
||||
uint32_t vkPresentFamilyIDX;
|
||||
|
||||
const char** vkInstanceExtensions;
|
||||
const char** vkDeviceExtensions;
|
||||
const char** vkLayers;
|
||||
int vkInstanceExtensionCount;
|
||||
int vkDeviceExtensionCount;
|
||||
int vkLayerCount;
|
||||
} vulkan_t;
|
||||
|
||||
static void vulkan_instance_setup(MwWidget handle, vulkan_t* o);
|
||||
static void vulkan_surface_setup(MwWidget handle, vulkan_t* o);
|
||||
static void vulkan_devices_setup(MwWidget handle, vulkan_t* o);
|
||||
|
||||
static void create(MwWidget handle) {
|
||||
vulkan_t* o = malloc(sizeof(*o));
|
||||
|
||||
// !! important to call it in this order
|
||||
vulkan_instance_setup(handle, o);
|
||||
vulkan_surface_setup(handle, o);
|
||||
vulkan_devices_setup(handle, o);
|
||||
|
||||
handle->internal = o;
|
||||
MwSetDefault(handle);
|
||||
}
|
||||
|
||||
static void destroy(MwWidget handle) {
|
||||
vulkan_t* o = (vulkan_t*)handle->internal;
|
||||
free(o);
|
||||
}
|
||||
|
||||
static void vulkan_instance_setup(MwWidget handle, vulkan_t* o) {
|
||||
// todo: Some sort of function for being able to set the vulkan version?
|
||||
uint32_t vulkan_version = VK_VERSION_1_0;
|
||||
uint32_t api_version = VK_API_VERSION_1_0;
|
||||
uint32_t extension_count = 0;
|
||||
uint32_t layer_count = 0;
|
||||
unsigned long i, n = 0;
|
||||
|
||||
PFN_vkEnumerateInstanceExtensionProperties
|
||||
_vkEnumerateInstanceExtensionProperties;
|
||||
PFN_vkEnumerateInstanceLayerProperties _vkEnumerateInstanceLayerProperties;
|
||||
PFN_vkCreateInstance _vkCreateInstance;
|
||||
|
||||
VkApplicationInfo app_info;
|
||||
VkInstanceCreateInfo instance_create_info;
|
||||
|
||||
VkExtensionProperties* ext_props;
|
||||
VkLayerProperties* layer_props;
|
||||
|
||||
VkResult vk_res;
|
||||
|
||||
// TODO: support for whatever win32's equivalants to dlopen/dlsym are
|
||||
o->vulkanLibrary = dlopen("libvulkan.so", RTLD_LAZY | RTLD_GLOBAL);
|
||||
o->vkGetInstanceProcAddr = dlsym(o->vulkanLibrary, "vkGetInstanceProcAddr");
|
||||
assert(o->vkGetInstanceProcAddr);
|
||||
|
||||
// Load in any other function pointers we need.
|
||||
_vkEnumerateInstanceExtensionProperties = dlsym(o->vulkanLibrary, "vkEnumerateInstanceExtensionProperties");
|
||||
assert(_vkEnumerateInstanceExtensionProperties);
|
||||
_vkEnumerateInstanceLayerProperties = dlsym(o->vulkanLibrary, "vkEnumerateInstanceLayerProperties");
|
||||
assert(_vkEnumerateInstanceLayerProperties);
|
||||
_vkCreateInstance = dlsym(o->vulkanLibrary, "vkCreateInstance");
|
||||
assert(_vkCreateInstance);
|
||||
|
||||
// setup enabled extensions
|
||||
arrput(enabledExtensions, VK_KHR_SURFACE_EXTENSION_NAME);
|
||||
#if defined(_WIN32)
|
||||
arrput(enabledExtensions, VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
||||
#elif defined(__linux__) || defined(__FreeBSD__)
|
||||
arrput(enabledExtensions, VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
||||
#endif
|
||||
|
||||
// passing null gives us all the extensions provided by the current vulkan implementation
|
||||
VK_CMD(_vkEnumerateInstanceExtensionProperties(NULL, &extension_count, NULL));
|
||||
ext_props = malloc(sizeof(VkExtensionProperties) * extension_count);
|
||||
VK_CMD(_vkEnumerateInstanceExtensionProperties(NULL, &extension_count, ext_props));
|
||||
o->vkInstanceExtensions = malloc(sizeof(const char*) * (arrlen(enabledExtensions) + 1));
|
||||
|
||||
for(i = 0; i < extension_count; i++) {
|
||||
for(n = 0; n < arrlen(enabledExtensions); n++) {
|
||||
if(strcmp(ext_props[i].extensionName, enabledExtensions[n]) == 0) {
|
||||
o->vkInstanceExtensions[o->vkInstanceExtensionCount] = ext_props[i].extensionName;
|
||||
o->vkInstanceExtensionCount++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("enabled %d instance extensions\n", o->vkInstanceExtensionCount);
|
||||
|
||||
app_info = (VkApplicationInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
||||
.pNext = NULL,
|
||||
.pApplicationName = "",
|
||||
.applicationVersion = vulkan_version,
|
||||
.pEngineName = "",
|
||||
.engineVersion = vulkan_version,
|
||||
.apiVersion = api_version,
|
||||
};
|
||||
|
||||
VK_CMD(_vkEnumerateInstanceLayerProperties(&layer_count, NULL));
|
||||
layer_props = malloc(sizeof(VkLayerProperties) * layer_count);
|
||||
VK_CMD(_vkEnumerateInstanceLayerProperties(&layer_count, layer_props));
|
||||
o->vkLayers = malloc(256 * (layer_count + 2));
|
||||
for(i = 0; i < layer_count; i++) {
|
||||
if(enableValidationLayers) {
|
||||
if(strcmp(layer_props[i].layerName, "VK_LAYER_KHRONOS_validation") == 0) {
|
||||
printf("layer: %s\n", layer_props[i].layerName);
|
||||
memset(&o->vkLayers[i], 0, 255);
|
||||
memcpy(&o->vkLayers[i], layer_props[i].layerName, 254);
|
||||
o->vkLayerCount++;
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
o->vkLayers[i++] = NULL;
|
||||
|
||||
instance_create_info = (VkInstanceCreateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
||||
.flags = 0,
|
||||
.pApplicationInfo = &app_info,
|
||||
.enabledExtensionCount = o->vkInstanceExtensionCount,
|
||||
.enabledLayerCount = 0,
|
||||
.ppEnabledExtensionNames = o->vkInstanceExtensions,
|
||||
.ppEnabledLayerNames = o->vkLayers,
|
||||
};
|
||||
instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||
|
||||
VK_CMD(_vkCreateInstance(&instance_create_info, NULL, &o->vkInstance));
|
||||
}
|
||||
|
||||
static void vulkan_surface_setup(MwWidget handle, vulkan_t* o) {
|
||||
int vk_res;
|
||||
#ifdef _WIN32
|
||||
LOAD_VK_FUNCTION(vkCreateWin32SurfaceKHR);
|
||||
|
||||
VkWin32SurfaceCreateInfoKHR createInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR,
|
||||
.pNext = NULL,
|
||||
.flags = 0,
|
||||
.hinstance = handle->lowlevel->hInstance,
|
||||
.hwnd = handle->lowlevel->hWnd,
|
||||
};
|
||||
|
||||
VK_CMD(_vkCreateWin32SurfaceKHR(o->vkInstance, &createInfo, NULL,
|
||||
&o->vkSurface));
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
LOAD_VK_FUNCTION(vkCreateXlibSurfaceKHR);
|
||||
|
||||
VkXlibSurfaceCreateInfoKHR createInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR,
|
||||
.pNext = NULL,
|
||||
.flags = 0,
|
||||
.dpy = handle->lowlevel->display,
|
||||
.window = handle->lowlevel->window,
|
||||
};
|
||||
VK_CMD(_vkCreateXlibSurfaceKHR(o->vkInstance, &createInfo, NULL, &o->vkSurface));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void vulkan_devices_setup(MwWidget handle, vulkan_t* o) {
|
||||
int vk_res;
|
||||
unsigned long i, n;
|
||||
uint32_t deviceCount;
|
||||
VkPhysicalDevice* devices;
|
||||
uint32_t queueFamilyCount;
|
||||
VkQueueFamilyProperties* family_props;
|
||||
float queuePriority = 1.0f;
|
||||
VkDeviceQueueCreateInfo queueCreateInfos[2];
|
||||
VkDeviceCreateInfo createInfo;
|
||||
VkExtensionProperties* ext_props;
|
||||
uint32_t extension_count;
|
||||
VkBool32 has_graphics = false;
|
||||
VkBool32 has_present = false;
|
||||
int queueCreateCount = 0;
|
||||
|
||||
LOAD_VK_FUNCTION(vkEnumeratePhysicalDevices);
|
||||
LOAD_VK_FUNCTION(vkGetPhysicalDeviceQueueFamilyProperties);
|
||||
LOAD_VK_FUNCTION(vkCreateDevice);
|
||||
LOAD_VK_FUNCTION(vkGetDeviceQueue);
|
||||
LOAD_VK_FUNCTION(vkGetPhysicalDeviceSurfaceSupportKHR);
|
||||
|
||||
PFN_vkEnumerateDeviceExtensionProperties _vkEnumerateDeviceExtensionProperties = (PFN_vkEnumerateDeviceExtensionProperties)
|
||||
o->vkGetInstanceProcAddr(o->vkInstance, "vkEnumerateDeviceExtensionProperties");
|
||||
assert(_vkEnumerateDeviceExtensionProperties);
|
||||
|
||||
// create the physical device
|
||||
VK_CMD(_vkEnumeratePhysicalDevices(o->vkInstance, &deviceCount, NULL));
|
||||
devices = malloc(sizeof(VkPhysicalDevice) * deviceCount);
|
||||
VK_CMD(_vkEnumeratePhysicalDevices(o->vkInstance, &deviceCount, devices));
|
||||
|
||||
for(i = 0; i < deviceCount; i++) {
|
||||
_vkGetPhysicalDeviceQueueFamilyProperties(devices[i], &queueFamilyCount, NULL);
|
||||
family_props = malloc(sizeof(VkQueueFamilyProperties) * queueFamilyCount);
|
||||
_vkGetPhysicalDeviceQueueFamilyProperties(devices[i], &queueFamilyCount, family_props);
|
||||
o->vkGraphicsFamilyIDX = 0;
|
||||
o->vkPresentFamilyIDX = 0;
|
||||
for(n = 0; n < queueFamilyCount; n++) {
|
||||
if(family_props[n].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
|
||||
has_graphics = true;
|
||||
o->vkGraphicsFamilyIDX = n;
|
||||
};
|
||||
|
||||
_vkGetPhysicalDeviceSurfaceSupportKHR(devices[i], n, o->vkSurface,
|
||||
&has_present);
|
||||
if(has_present) {
|
||||
o->vkPresentFamilyIDX = n;
|
||||
}
|
||||
if(has_graphics && has_present) {
|
||||
o->vkPhysicalDevice = devices[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(family_props);
|
||||
}
|
||||
if(!has_graphics && !has_present) {
|
||||
// rare, yes, but idk maybe some shitty drivers will present this dillema idk.
|
||||
printf("There were no devices with either a graphics or presentation queue. Exiting!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// create the logical device
|
||||
queueCreateInfos[queueCreateCount] = (VkDeviceQueueCreateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
|
||||
.pNext = NULL,
|
||||
.flags = 0,
|
||||
.queueFamilyIndex = o->vkGraphicsFamilyIDX,
|
||||
.queueCount = 1,
|
||||
.pQueuePriorities = &queuePriority,
|
||||
};
|
||||
if(o->vkGraphicsFamilyIDX == o->vkPresentFamilyIDX) {
|
||||
queueCreateInfos[queueCreateCount++] = (VkDeviceQueueCreateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
|
||||
.pNext = NULL,
|
||||
.flags = 0,
|
||||
.queueFamilyIndex = o->vkPresentFamilyIDX,
|
||||
.queueCount = 1,
|
||||
.pQueuePriorities = &queuePriority,
|
||||
};
|
||||
}
|
||||
|
||||
VK_CMD(_vkEnumerateDeviceExtensionProperties(o->vkPhysicalDevice, NULL, &extension_count, NULL));
|
||||
ext_props = malloc(sizeof(VkExtensionProperties) * extension_count);
|
||||
VK_CMD(_vkEnumerateDeviceExtensionProperties(o->vkPhysicalDevice, NULL, &extension_count, ext_props));
|
||||
o->vkDeviceExtensions = malloc(sizeof(const char*) * (arrlen(enabledExtensions) + 1));
|
||||
|
||||
for(i = 0; i < extension_count; i++) {
|
||||
for(n = 0; n < arrlen(enabledExtensions); n++) {
|
||||
if(strcmp(ext_props[i].extensionName, enabledExtensions[n]) == 0) {
|
||||
o->vkDeviceExtensions[o->vkDeviceExtensionCount] = ext_props[i].extensionName;
|
||||
o->vkDeviceExtensionCount++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("enabled %d device extensions\n", o->vkDeviceExtensionCount);
|
||||
|
||||
createInfo = (VkDeviceCreateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
||||
.pNext = NULL,
|
||||
.flags = 0,
|
||||
.queueCreateInfoCount = queueCreateCount,
|
||||
.pQueueCreateInfos = queueCreateInfos,
|
||||
.pEnabledFeatures = NULL,
|
||||
.enabledExtensionCount = o->vkDeviceExtensionCount,
|
||||
.ppEnabledExtensionNames = o->vkDeviceExtensions,
|
||||
.enabledLayerCount = 0,
|
||||
.ppEnabledLayerNames = NULL,
|
||||
};
|
||||
|
||||
VK_CMD(_vkCreateDevice(o->vkPhysicalDevice, &createInfo, NULL, &o->vkLogicalDevice) != VK_SUCCESS);
|
||||
|
||||
_vkGetDeviceQueue(o->vkLogicalDevice, o->vkGraphicsFamilyIDX, 0, &o->vkGraphicsQueue);
|
||||
if(o->vkGraphicsFamilyIDX == o->vkPresentFamilyIDX) {
|
||||
o->vkPresentQueue = o->vkGraphicsQueue;
|
||||
} else {
|
||||
_vkGetDeviceQueue(o->vkLogicalDevice, o->vkPresentFamilyIDX, 0, &o->vkPresentQueue);
|
||||
}
|
||||
// free(devices);
|
||||
}
|
||||
|
||||
void MwVulkanEnableExtension(const char* name) {
|
||||
arrput(enabledExtensions, name);
|
||||
}
|
||||
|
||||
PFN_vkGetInstanceProcAddr MwVulkanGetInstanceProcAddr(MwWidget handle) {
|
||||
return ((vulkan_t*)handle->internal)->vkGetInstanceProcAddr;
|
||||
};
|
||||
VkInstance MwVulkanGetInstance(MwWidget handle) {
|
||||
return ((vulkan_t*)handle->internal)->vkInstance;
|
||||
};
|
||||
VkSurfaceKHR MwVulkanGetSurface(MwWidget handle) {
|
||||
return ((vulkan_t*)handle->internal)->vkSurface;
|
||||
};
|
||||
VkPhysicalDevice MwVulkanGetPhysicalDevice(MwWidget handle) {
|
||||
return ((vulkan_t*)handle->internal)->vkPhysicalDevice;
|
||||
};
|
||||
VkDevice MwVulkanGetLogicalDevice(MwWidget handle) {
|
||||
return ((vulkan_t*)handle->internal)->vkLogicalDevice;
|
||||
};
|
||||
VkQueue MwVulkanGetGraphicsQueue(MwWidget handle) {
|
||||
return ((vulkan_t*)handle->internal)->vkGraphicsQueue;
|
||||
};
|
||||
VkQueue MwVulkanGetPresentQueue(MwWidget handle) {
|
||||
return ((vulkan_t*)handle->internal)->vkPresentQueue;
|
||||
};
|
||||
|
||||
int MwVulkanGetGraphicsQueueIndex(MwWidget handle) {
|
||||
return ((vulkan_t*)handle->internal)->vkGraphicsFamilyIDX;
|
||||
}
|
||||
|
||||
int MwVulkanGetPresentQueueIndex(MwWidget handle) {
|
||||
return ((vulkan_t*)handle->internal)->vkPresentFamilyIDX;
|
||||
}
|
||||
|
||||
MwClassRec MwVulkanClassRec = {
|
||||
create, /* create */
|
||||
destroy, /* destroy */
|
||||
NULL, /* draw */
|
||||
NULL /* click */
|
||||
};
|
||||
MwClass MwVulkanClass = &MwVulkanClassRec;
|
||||
Reference in New Issue
Block a user