mirror of
https://gitea.nishi.boats/pyrite-dev/milsko
synced 2025-12-31 14:40:49 +00:00
git-svn-id: http://svn2.nishi.boats/svn/milsko/trunk@252 b9cfdab3-6d41-4d17-bbe4-086880011989
659 lines
24 KiB
C
659 lines
24 KiB
C
/* $Id$ */
|
|
|
|
/**
|
|
* this example is quite minimal, you may need to modify it if your graphics card is more esoteric
|
|
*
|
|
* ioixd maintains this file. nishi doesn't know vulkan at all
|
|
*/
|
|
|
|
#include "Mw/Error.h"
|
|
#include <Mw/Milsko.h>
|
|
#include <Mw/Widget/Vulkan.h>
|
|
|
|
#include <vulkan/vulkan.h>
|
|
#include <vulkan/vulkan_core.h>
|
|
#ifdef HAS_VK_ENUM_STRING_HELPER
|
|
#include <vulkan/vk_enum_string_helper.h>
|
|
#else
|
|
char buffer[512];
|
|
|
|
char* string_VkResult(VkResult res) {
|
|
sprintf(buffer, "%d", res);
|
|
|
|
return &buffer[0];
|
|
}
|
|
#endif
|
|
|
|
MwWidget window, vulkan;
|
|
int ow = 300;
|
|
int oh = 250;
|
|
|
|
PFN_vkGetInstanceProcAddr _vkGetInstanceProcAddr;
|
|
VkInstance instance;
|
|
VkDevice device;
|
|
VkPhysicalDevice physicalDevice;
|
|
VkSurfaceKHR surface;
|
|
VkQueue graphicsQueue;
|
|
VkQueue presentQueue;
|
|
uint32_t* graphicsQueueIndex;
|
|
uint32_t* presentQueueIndex;
|
|
|
|
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 = VK_NULL_HANDLE;
|
|
VkResult res = 0;
|
|
VkShaderModule fragShaderModule;
|
|
VkShaderModule vertShaderModule;
|
|
VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
|
|
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 = {};
|
|
|
|
MwErrorEnum err = MwEsuccess;
|
|
_vkGetInstanceProcAddr = MwVulkanGetField(handle, MwVulkanField_GetInstanceProcAddr, &err);
|
|
if(err != MwEsuccess) {
|
|
printf("Error getting vkGetInstanceProcAddr!\n%s\n", MwGetLastError());
|
|
}
|
|
instance = MwVulkanGetField(handle, MwVulkanField_Instance, &err);
|
|
if(err != MwEsuccess) {
|
|
printf("Error getting vulkan instance!\n%s\n", MwGetLastError());
|
|
}
|
|
device = MwVulkanGetField(handle, MwVulkanField_LogicalDevice, &err);
|
|
if(err != MwEsuccess) {
|
|
printf("Error getting VkDevice!\n%s\n", MwGetLastError());
|
|
}
|
|
physicalDevice = MwVulkanGetField(handle, MwVulkanField_PhysicalDevice, &err);
|
|
if(err != MwEsuccess) {
|
|
printf("Error getting physical device!\n%s\n", MwGetLastError());
|
|
}
|
|
graphicsQueue = MwVulkanGetField(handle, MwVulkanField_GraphicsQueue, &err);
|
|
if(err != MwEsuccess) {
|
|
printf("Error getting graphics queue!\n%s\n", MwGetLastError());
|
|
}
|
|
presentQueue = MwVulkanGetField(handle, MwVulkanField_PresentQueue, &err);
|
|
if(err != MwEsuccess) {
|
|
printf("Error getting present queue!\n%s\n", MwGetLastError());
|
|
}
|
|
surface = MwVulkanGetField(handle, MwVulkanField_Surface, &err);
|
|
if(err != MwEsuccess) {
|
|
printf("Error getting surface!\n%s\n", MwGetLastError());
|
|
}
|
|
presentQueueIndex = MwVulkanGetField(handle, MwVulkanField_PresentQueueIndex, &err);
|
|
if(err != MwEsuccess) {
|
|
printf("Error getting present queue index!\n%s\n", MwGetLastError());
|
|
}
|
|
graphicsQueueIndex = MwVulkanGetField(handle, MwVulkanField_GraphicsQueueIndex, &err);
|
|
if(err != MwEsuccess) {
|
|
printf("Error getting graphics queue index!\n%s\n", MwGetLastError());
|
|
}
|
|
|
|
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(*graphicsQueueIndex != *presentQueueIndex) {
|
|
swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
|
swapchainCreateInfo.queueFamilyIndexCount = 2;
|
|
|
|
uint32_t indices[] = {
|
|
*graphicsQueueIndex,
|
|
*presentQueueIndex,
|
|
};
|
|
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 %zu 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 %zu 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 = *graphicsQueueIndex;
|
|
|
|
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() {
|
|
if(!MwVulkanSupported()) {
|
|
printf("Vulkan not found or unsupported on target platform.\n");
|
|
return 1;
|
|
}
|
|
|
|
window = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 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);
|
|
}
|