/* $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 #include #include #include #ifdef HAS_VK_ENUM_STRING_HELPER #include #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); }