void draw() { VkResult err; VkSemaphore presentCompleteSemaphore; VkSemaphoreCreateInfo presentCompleteSemaphoreCreateInfo = vkTools::initializers::semaphoreCreateInfo(VK_FENCE_CREATE_SIGNALED_BIT); err = vkCreateSemaphore(device, &presentCompleteSemaphoreCreateInfo, nullptr, &presentCompleteSemaphore); assert(!err); // Get next image in the swap chain (back/front buffer) err = swapChain.acquireNextImage(presentCompleteSemaphore, ¤tBuffer); assert(!err); VkSubmitInfo submitInfo = vkTools::initializers::submitInfo(); submitInfo.waitSemaphoreCount = 1; submitInfo.pWaitSemaphores = &presentCompleteSemaphore; submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer]; // Submit draw command buffer err = vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE); assert(!err); err = swapChain.queuePresent(queue, currentBuffer); assert(!err); vkDestroySemaphore(device, presentCompleteSemaphore, nullptr); submitPostPresentBarrier(swapChain.buffers[currentBuffer].image); err = vkQueueWaitIdle(queue); assert(!err); }
//Destroyer VulkanBase::~VulkanBase() { // Wait until all operations are complete to destroy stuff CHECK_RESULT(vkQueueWaitIdle(queue)); swapchain.clean(); //vkFreeCommandBuffers(device, commandPool, commandBuffersVector.size(), commandBuffersVector.data()); vkDestroyCommandPool(device, commandPool, nullptr); // Destroy synchronization elements vkDestroySemaphore(device, imageAcquiredSemaphore, nullptr); vkDestroySemaphore(device, renderingCompletedSemaphore, nullptr); vkDestroyFence(device, presentFence, nullptr); // Destroy logical device vkDestroyDevice(device, nullptr); #ifdef _DEBUG if (enableValidation) { vkDebug::freeDebugCallback(instance); } #endif // _DEBUG vkDestroyInstance(instance,nullptr); }
void draw() { VkResult err; // Get next image in the swap chain (back/front buffer) err = swapChain.acquireNextImage(semaphores.presentComplete, ¤tBuffer); assert(!err); submitPostPresentBarrier(swapChain.buffers[currentBuffer].image); // Command buffer to be sumitted to the queue submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer]; // Submit to queue err = vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE); assert(!err); submitPrePresentBarrier(swapChain.buffers[currentBuffer].image); err = swapChain.queuePresent(queue, currentBuffer, semaphores.renderComplete); assert(!err); err = vkQueueWaitIdle(queue); assert(!err); }
void Anvil::Queue::wait_idle() { lock(); { vkQueueWaitIdle(m_queue); } unlock(); }
static void vulkan_raster_font_flush(vulkan_raster_t *font) { const struct vk_draw_triangles call = { font->vk->pipelines.font, &font->texture_optimal, font->vk->samplers.mipmap_linear, &font->vk->mvp, sizeof(font->vk->mvp), &font->range, font->vertices, }; if(font->needs_update) { VkCommandBuffer staging; VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; VkCommandBufferAllocateInfo cmd_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO }; VkCommandBufferBeginInfo begin_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; cmd_info.commandPool = font->vk->staging_pool; cmd_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; cmd_info.commandBufferCount = 1; vkAllocateCommandBuffers(font->vk->context->device, &cmd_info, &staging); begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; vkBeginCommandBuffer(staging, &begin_info); vulkan_copy_staging_to_dynamic(font->vk, staging, &font->texture_optimal, &font->texture); vkEndCommandBuffer(staging); #ifdef HAVE_THREADS slock_lock(font->vk->context->queue_lock); #endif submit_info.commandBufferCount = 1; submit_info.pCommandBuffers = &staging; vkQueueSubmit(font->vk->context->queue, 1, &submit_info, VK_NULL_HANDLE); vkQueueWaitIdle(font->vk->context->queue); #ifdef HAVE_THREADS slock_unlock(font->vk->context->queue_lock); #endif vkFreeCommandBuffers(font->vk->context->device, font->vk->staging_pool, 1, &staging); font->needs_update = false; } vulkan_draw_triangles(font->vk, &call); }
XCamReturn VKDevice::compute_queue_wait_idle () { XCAM_FAIL_RETURN ( ERROR, XCAM_IS_VALID_VK_ID (_compute_queue), XCAM_RETURN_ERROR_PARAM, "VKDevice compute queue wait idle failed, queue_id is null"); XCAM_VK_CHECK_RETURN ( ERROR, vkQueueWaitIdle (_compute_queue), XCAM_RETURN_ERROR_VULKAN, "VKDevice compute queue wait idle failed"); return XCAM_RETURN_NO_ERROR; }
void Renderer::_EndSingleTimeCommands(VkCommandPool pool, VkCommandBuffer commandBuffer) { ErrorCheck(vkEndCommandBuffer(commandBuffer)); VkSubmitInfo submit_info {}; submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit_info.commandBufferCount = 1; submit_info.pCommandBuffers = &commandBuffer; ErrorCheck(vkQueueSubmit(_queue, 1, &submit_info, VK_NULL_HANDLE)); ErrorCheck(vkQueueWaitIdle(_queue)); vkFreeCommandBuffers(_device, pool, 1, &commandBuffer); }
void VkApp::endSingleTimeCommands(VkCommandBuffer commandBuffer){ vkEndCommandBuffer(commandBuffer); VkSubmitInfo submitInfo = {}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &commandBuffer; vkQueueSubmit(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE); vkQueueWaitIdle(graphicsQueue); vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer); }
void flush_command_buffer() { VkResult err; if (_vulkan_command_buffer == VK_NULL_HANDLE) { return; } err = vkEndCommandBuffer(_vulkan_command_buffer); assert(!err); const VkCommandBuffer command_buffers[] = { _vulkan_command_buffer }; VkFence nullFence = VK_NULL_HANDLE; /* typedef struct VkSubmitInfo { VkStructureType sType; const void* pNext; uint32_t waitSemaphoreCount; const VkSemaphore* pWaitSemaphores; const VkPipelineStageFlags* pWaitDstStageMask; uint32_t commandBufferCount; const VkCommandBuffer* pCommandBuffers; uint32_t signalSemaphoreCount; const VkSemaphore* pSignalSemaphores; } VkSubmitInfo; */ VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO, NULL, 0, NULL, NULL, 1, command_buffers, 0, NULL }; err = vkQueueSubmit(_vulkan_queue, 1, &submit_info, nullFence); assert(!err); err = vkQueueWaitIdle(_vulkan_queue); assert(!err); vkFreeCommandBuffers(_vulkan_device, _vulkan_command_pool, 1, command_buffers); _vulkan_command_buffer = VK_NULL_HANDLE; }
void VulkanWindow::Finalize() { if ( VkResult result = vkQueueWaitIdle ( mVulkanRenderer.GetQueue() ) ) { std::cerr << "vkQueueWaitIdle failed: " << GetVulkanResultString ( result ); } if ( VkResult result = vkDeviceWaitIdle ( mVulkanRenderer.GetDevice() ) ) { std::cerr << "vkDeviceWaitIdle failed: " << GetVulkanResultString ( result ); } FinalizeFrameBuffers(); FinalizeDepthStencil(); FinalizeImageViews(); FinalizeSwapchain(); FinalizeSurface(); }
void GrManagerImpl::flushCommandBuffer(CommandBufferPtr cmdb, Bool wait) { CommandBufferImpl& impl = *cmdb->m_impl; VkCommandBuffer handle = impl.getHandle(); VkSubmitInfo submit = {}; submit.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; FencePtr fence = newFence(); LockGuard<Mutex> lock(m_globalMtx); PerFrame& frame = m_perFrame[m_frame % MAX_FRAMES_IN_FLIGHT]; // Do some special stuff for the last command buffer VkPipelineStageFlags waitFlags; if(impl.renderedToDefaultFramebuffer()) { submit.pWaitSemaphores = &frame.m_acquireSemaphore->getHandle(); waitFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; submit.pWaitDstStageMask = &waitFlags; submit.waitSemaphoreCount = 1; // Create the semaphore to signal ANKI_ASSERT(!frame.m_renderSemaphore && "Only one begin/end render pass is allowed with the default fb"); frame.m_renderSemaphore = m_semaphores.newInstance(fence); submit.signalSemaphoreCount = 1; submit.pSignalSemaphores = &frame.m_renderSemaphore->getHandle(); frame.m_presentFence = fence; } submit.commandBufferCount = 1; submit.pCommandBuffers = &handle; frame.m_cmdbsSubmitted.pushBack(getAllocator(), cmdb); ANKI_TRACE_START_EVENT(VK_QUEUE_SUBMIT); ANKI_VK_CHECKF(vkQueueSubmit(m_queue, 1, &submit, fence->getHandle())); ANKI_TRACE_STOP_EVENT(VK_QUEUE_SUBMIT); if(wait) { vkQueueWaitIdle(m_queue); } }
static void vulkan_raster_font_free_font(void *data, bool is_threaded) { vulkan_raster_t *font = (vulkan_raster_t*)data; if (!font) return; if (font->font_driver && font->font_data) font->font_driver->free(font->font_data); vkQueueWaitIdle(font->vk->context->queue); vulkan_destroy_texture( font->vk->context->device, &font->texture); vulkan_destroy_texture( font->vk->context->device, &font->texture_optimal); free(font); }
void VkHelper::endSingleTimeCommandBuffer(VkDevice device, VkCommandPool cmdPool, VkQueue queue, VkCommandBuffer cmdBuffer) { if (vkEndCommandBuffer(cmdBuffer) != VK_SUCCESS) std::runtime_error("ERROR: Command buffer end failed."); VkSubmitInfo submitInfo{}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.pNext = VK_NULL_HANDLE; submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &cmdBuffer; if (vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE) != VK_SUCCESS) std::runtime_error("ERROR: Submission to the queue failed."); vkQueueWaitIdle(queue); vkFreeCommandBuffers(device, cmdPool, 1, &cmdBuffer); }
void VulkanBase::flushSetupCommandBuffer() { if (setupCmdBuffer == VK_NULL_HANDLE) return; vkTools::checkResult(vkEndCommandBuffer(setupCmdBuffer)); VkSubmitInfo submitInfo = {}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &setupCmdBuffer; vkTools::checkResult(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); vkTools::checkResult(vkQueueWaitIdle(queue)); vkFreeCommandBuffers(device, cmdPool, 1, &setupCmdBuffer); setupCmdBuffer = VK_NULL_HANDLE; }
void VulkanExampleBase::windowResize() { if (!prepared) { return; } prepared = false; // Recreate swap chain width = destWidth; height = destHeight; createSetupCommandBuffer(); setupSwapChain(); // Recreate the frame buffers vkDestroyImageView(device, depthStencil.view, nullptr); vkDestroyImage(device, depthStencil.image, nullptr); vkFreeMemory(device, depthStencil.mem, nullptr); setupDepthStencil(); for (uint32_t i = 0; i < frameBuffers.size(); i++) { vkDestroyFramebuffer(device, frameBuffers[i], nullptr); } setupFrameBuffer(); flushSetupCommandBuffer(); // Command buffers need to be recreated as they may store // references to the recreated frame buffer destroyCommandBuffers(); createCommandBuffers(); buildCommandBuffers(); vkQueueWaitIdle(queue); vkDeviceWaitIdle(device); // Notify derived class windowResized(); viewChanged(); prepared = true; }
void draw() { VkResult err; // Get next image in the swap chain (back/front buffer) err = swapChain.acquireNextImage(semaphores.presentComplete, ¤tBuffer); assert(!err); submitPostPresentBarrier(swapChain.buffers[currentBuffer].image); VkPipelineStageFlags pipelineStages = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; VkSubmitInfo submitInfo = vkTools::initializers::submitInfo(); submitInfo.waitSemaphoreCount = 1; submitInfo.pWaitSemaphores = &semaphores.presentComplete; submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer]; submitInfo.pWaitDstStageMask = &pipelineStages; submitInfo.signalSemaphoreCount = 1; submitInfo.pSignalSemaphores = &semaphores.submitSignal; // Submit to the graphics queue err = vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE); assert(!err); submitPrePresentBarrier(swapChain.buffers[currentBuffer].image); // Present the current buffer to the swap chain // This will display the image err = swapChain.queuePresent(queue, currentBuffer, semaphores.submitSignal); assert(!err); // Compute VkSubmitInfo computeSubmitInfo = vkTools::initializers::submitInfo(); computeSubmitInfo.commandBufferCount = 1; computeSubmitInfo.pCommandBuffers = &computeCmdBuffer; err = vkQueueSubmit(computeQueue, 1, &computeSubmitInfo, VK_NULL_HANDLE); assert(!err); err = vkQueueWaitIdle(computeQueue); assert(!err); }
assert(!err); } } void draw() { VkResult err; VkSemaphore presentCompleteSemaphore; VkSemaphoreCreateInfo presentCompleteSemaphoreCreateInfo = vkTools::initializers::semaphoreCreateInfo(VK_FLAGS_NONE); err = vkCreateSemaphore(device, &presentCompleteSemaphoreCreateInfo, nullptr, &presentCompleteSemaphore); assert(!err); // Get next image in the swap chain (back/front buffer) err = swapChain.acquireNextImage(presentCompleteSemaphore, ¤tBuffer); assert(!err); // Gather command buffers to be sumitted to the queue std::vector<VkCommandBuffer> submitCmdBuffers = { offScreenCmdBuffer, drawCmdBuffers[currentBuffer], }; VkSubmitInfo submitInfo = vkTools::initializers::submitInfo(); submitInfo.waitSemaphoreCount = 1; submitInfo.pWaitSemaphores = &presentCompleteSemaphore; submitInfo.commandBufferCount = submitCmdBuffers.size(); submitInfo.pCommandBuffers = submitCmdBuffers.data(); // Submit draw command buffer err = vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE); assert(!err); submitPrePresentBarrier(swapChain.buffers[currentBuffer].image); err = swapChain.queuePresent(queue, currentBuffer); assert(!err); vkDestroySemaphore(device, presentCompleteSemaphore, nullptr); submitPostPresentBarrier(swapChain.buffers[currentBuffer].image);
void VulkanExampleBase::flushCommandBuffer(VkCommandBuffer commandBuffer, VkQueue queue, bool free) { if (commandBuffer == VK_NULL_HANDLE) { return; } vkTools::checkResult(vkEndCommandBuffer(commandBuffer)); VkSubmitInfo submitInfo = {}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &commandBuffer; vkTools::checkResult(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); vkTools::checkResult(vkQueueWaitIdle(queue)); if (free) { vkFreeCommandBuffers(device, cmdPool, 1, &commandBuffer); } }
void VulkanWindow::OnResizeViewport ( int32_t aX, int32_t aY, uint32_t aWidth, uint32_t aHeight ) { VkSurfaceCapabilitiesKHR surface_capabilities{}; VkResult result {vkGetPhysicalDeviceSurfaceCapabilitiesKHR ( mVulkanRenderer.GetPhysicalDevice(), mVkSurfaceKHR, &surface_capabilities ) }; if ( result == VK_SUCCESS && std::memcmp ( &surface_capabilities, &mVkSurfaceCapabilitiesKHR, sizeof ( VkSurfaceCapabilitiesKHR ) ) != 0 ) { if ( VK_SUCCESS != ( result = vkQueueWaitIdle ( mVulkanRenderer.GetQueue() ) ) ) { std::ostringstream stream; stream << "vkQueueWaitIdle failed: " << GetVulkanResultString ( result ); throw std::runtime_error ( stream.str().c_str() ); } if ( VK_SUCCESS != ( result = vkDeviceWaitIdle ( mVulkanRenderer.GetDevice() ) ) ) { std::ostringstream stream; stream << "vkDeviceWaitIdle failed: " << GetVulkanResultString ( result ); throw std::runtime_error ( stream.str().c_str() ); } FinalizeFrameBuffers(); FinalizeDepthStencil(); FinalizeImageViews(); InitializeSwapchain(); InitializeImageViews(); InitializeDepthStencil(); InitializeFrameBuffers(); } mVkViewport.x = static_cast<float> ( aX ); mVkViewport.y = static_cast<float> ( aY ); mVkViewport.width = static_cast<float> ( aWidth ); mVkViewport.height = static_cast<float> ( aHeight ); // Clip Scissors to surface extents mVkScissor.offset.x = ( aX < 0 ) ? 0 : aX; mVkScissor.offset.y = ( aY < 0 ) ? 0 : aY; mVkScissor.extent.width = ( aX + aWidth > mVkSurfaceCapabilitiesKHR.currentExtent.width ) ? mVkSurfaceCapabilitiesKHR.currentExtent.width : aX + aWidth; mVkScissor.extent.height = ( aY + aHeight > mVkSurfaceCapabilitiesKHR.currentExtent.height ) ? mVkSurfaceCapabilitiesKHR.currentExtent.height : aY + aHeight; }
void VulkanExampleBase::flushSetupCommandBuffer() { VkResult err; if (setupCmdBuffer == VK_NULL_HANDLE) return; err = vkEndCommandBuffer(setupCmdBuffer); assert(!err); VkSubmitInfo submitInfo = {}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &setupCmdBuffer; err = vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE); assert(!err); err = vkQueueWaitIdle(queue); assert(!err); vkFreeCommandBuffers(device, cmdPool, 1, &setupCmdBuffer); setupCmdBuffer = VK_NULL_HANDLE; }
int sample_main(int argc, char *argv[]) { VkResult U_ASSERT_ONLY res; struct sample_info info = {}; char sample_title[] = "Copy/Blit Image"; VkImageCreateInfo image_info; VkImage bltSrcImage; VkImage bltDstImage; VkMemoryRequirements memReq; VkMemoryAllocateInfo memAllocInfo; VkDeviceMemory dmem; unsigned char *pImgMem; process_command_line_args(info, argc, argv); init_global_layer_properties(info); init_instance_extension_names(info); init_device_extension_names(info); init_instance(info, sample_title); init_enumerate_device(info); init_window_size(info, 640, 640); init_connection(info); init_window(info); init_swapchain_extension(info); VkSurfaceCapabilitiesKHR surfCapabilities; res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(info.gpus[0], info.surface, &surfCapabilities); if (!(surfCapabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT)) { std::cout << "Surface cannot be destination of blit - abort \n"; exit(-1); } init_device(info); init_command_pool(info); init_command_buffer(info); execute_begin_command_buffer(info); init_device_queue(info); init_swap_chain(info, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); /* VULKAN_KEY_START */ VkFormatProperties formatProps; vkGetPhysicalDeviceFormatProperties(info.gpus[0], info.format, &formatProps); assert( (formatProps.linearTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT) && "Format cannot be used as transfer source"); VkSemaphore presentCompleteSemaphore; VkSemaphoreCreateInfo presentCompleteSemaphoreCreateInfo; presentCompleteSemaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; presentCompleteSemaphoreCreateInfo.pNext = NULL; presentCompleteSemaphoreCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; res = vkCreateSemaphore(info.device, &presentCompleteSemaphoreCreateInfo, NULL, &presentCompleteSemaphore); assert(res == VK_SUCCESS); // Get the index of the next available swapchain image: res = vkAcquireNextImageKHR(info.device, info.swap_chain, UINT64_MAX, presentCompleteSemaphore, VK_NULL_HANDLE, &info.current_buffer); // TODO: Deal with the VK_SUBOPTIMAL_KHR and VK_ERROR_OUT_OF_DATE_KHR // return codes assert(res == VK_SUCCESS); // Create an image, map it, and write some values to the image image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; image_info.pNext = NULL; image_info.imageType = VK_IMAGE_TYPE_2D; image_info.format = info.format; image_info.extent.width = info.width; image_info.extent.height = info.height; image_info.extent.depth = 1; image_info.mipLevels = 1; image_info.arrayLayers = 1; image_info.samples = NUM_SAMPLES; image_info.queueFamilyIndexCount = 0; image_info.pQueueFamilyIndices = NULL; image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; image_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT; image_info.flags = 0; image_info.tiling = VK_IMAGE_TILING_LINEAR; image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; res = vkCreateImage(info.device, &image_info, NULL, &bltSrcImage); memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; memAllocInfo.pNext = NULL; vkGetImageMemoryRequirements(info.device, bltSrcImage, &memReq); bool pass = memory_type_from_properties(info, memReq.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &memAllocInfo.memoryTypeIndex); assert(pass); memAllocInfo.allocationSize = memReq.size; res = vkAllocateMemory(info.device, &memAllocInfo, NULL, &dmem); res = vkBindImageMemory(info.device, bltSrcImage, dmem, 0); set_image_layout(info, bltSrcImage, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); res = vkEndCommandBuffer(info.cmd); assert(res == VK_SUCCESS); VkFence cmdFence; init_fence(info, cmdFence); VkPipelineStageFlags pipe_stage_flags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; VkSubmitInfo submit_info = {}; submit_info.pNext = NULL; submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit_info.waitSemaphoreCount = 1; submit_info.pWaitSemaphores = &presentCompleteSemaphore; submit_info.pWaitDstStageMask = &pipe_stage_flags; submit_info.commandBufferCount = 1; submit_info.pCommandBuffers = &info.cmd; submit_info.signalSemaphoreCount = 0; submit_info.pSignalSemaphores = NULL; /* Queue the command buffer for execution */ res = vkQueueSubmit(info.queue, 1, &submit_info, cmdFence); assert(res == VK_SUCCESS); /* Make sure command buffer is finished before mapping */ do { res = vkWaitForFences(info.device, 1, &cmdFence, VK_TRUE, FENCE_TIMEOUT); } while (res == VK_TIMEOUT); assert(res == VK_SUCCESS); vkDestroyFence(info.device, cmdFence, NULL); res = vkMapMemory(info.device, dmem, 0, memReq.size, 0, (void **)&pImgMem); // Checkerboard of 8x8 pixel squares for (int row = 0; row < info.height; row++) { for (int col = 0; col < info.width; col++) { unsigned char rgb = (((row & 0x8) == 0) ^ ((col & 0x8) == 0)) * 255; pImgMem[0] = rgb; pImgMem[1] = rgb; pImgMem[2] = rgb; pImgMem[3] = 255; pImgMem += 4; } } // Flush the mapped memory and then unmap it Assume it isn't coherent since // we didn't really confirm VkMappedMemoryRange memRange; memRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; memRange.pNext = NULL; memRange.memory = dmem; memRange.offset = 0; memRange.size = memReq.size; res = vkFlushMappedMemoryRanges(info.device, 1, &memRange); vkUnmapMemory(info.device, dmem); vkResetCommandBuffer(info.cmd, 0); execute_begin_command_buffer(info); set_image_layout(info, bltSrcImage, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); bltDstImage = info.buffers[info.current_buffer].image; // init_swap_chain will create the images as color attachment optimal // but we want transfer dst optimal set_image_layout(info, bltDstImage, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); // Do a 32x32 blit to all of the dst image - should get big squares VkImageBlit region; region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; region.srcSubresource.mipLevel = 0; region.srcSubresource.baseArrayLayer = 0; region.srcSubresource.layerCount = 1; region.srcOffsets[0].x = 0; region.srcOffsets[0].y = 0; region.srcOffsets[0].z = 0; region.srcOffsets[1].x = 32; region.srcOffsets[1].y = 32; region.srcOffsets[1].z = 1; region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; region.dstSubresource.mipLevel = 0; region.dstSubresource.baseArrayLayer = 0; region.dstSubresource.layerCount = 1; region.dstOffsets[0].x = 0; region.dstOffsets[0].y = 0; region.dstOffsets[0].z = 0; region.dstOffsets[1].x = info.width; region.dstOffsets[1].y = info.height; region.dstOffsets[1].z = 1; vkCmdBlitImage(info.cmd, bltSrcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, bltDstImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion, VK_FILTER_LINEAR); // Do a image copy to part of the dst image - checks should stay small VkImageCopy cregion; cregion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; cregion.srcSubresource.mipLevel = 0; cregion.srcSubresource.baseArrayLayer = 0; cregion.srcSubresource.layerCount = 1; cregion.srcOffset.x = 0; cregion.srcOffset.y = 0; cregion.srcOffset.z = 0; cregion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; cregion.dstSubresource.mipLevel = 0; cregion.dstSubresource.baseArrayLayer = 0; cregion.dstSubresource.layerCount = 1; cregion.dstOffset.x = 256; cregion.dstOffset.y = 256; cregion.dstOffset.z = 0; cregion.extent.width = 128; cregion.extent.height = 128; cregion.extent.depth = 1; vkCmdCopyImage(info.cmd, bltSrcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, bltDstImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &cregion); VkImageMemoryBarrier prePresentBarrier = {}; prePresentBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; prePresentBarrier.pNext = NULL; prePresentBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; prePresentBarrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; prePresentBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; prePresentBarrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; prePresentBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; prePresentBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; prePresentBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; prePresentBarrier.subresourceRange.baseMipLevel = 0; prePresentBarrier.subresourceRange.levelCount = 1; prePresentBarrier.subresourceRange.baseArrayLayer = 0; prePresentBarrier.subresourceRange.layerCount = 1; prePresentBarrier.image = info.buffers[info.current_buffer].image; vkCmdPipelineBarrier(info.cmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, NULL, 0, NULL, 1, &prePresentBarrier); res = vkEndCommandBuffer(info.cmd); VkFenceCreateInfo fenceInfo; VkFence drawFence; fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fenceInfo.pNext = NULL; fenceInfo.flags = 0; vkCreateFence(info.device, &fenceInfo, NULL, &drawFence); submit_info.pNext = NULL; submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit_info.waitSemaphoreCount = 0; submit_info.pWaitSemaphores = NULL; submit_info.pWaitDstStageMask = NULL; submit_info.commandBufferCount = 1; submit_info.pCommandBuffers = &info.cmd; submit_info.signalSemaphoreCount = 0; submit_info.pSignalSemaphores = NULL; /* Queue the command buffer for execution */ res = vkQueueSubmit(info.queue, 1, &submit_info, drawFence); assert(res == VK_SUCCESS); res = vkQueueWaitIdle(info.queue); assert(res == VK_SUCCESS); /* Now present the image in the window */ VkPresentInfoKHR present; present.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; present.pNext = NULL; present.swapchainCount = 1; present.pSwapchains = &info.swap_chain; present.pImageIndices = &info.current_buffer; present.pWaitSemaphores = NULL; present.waitSemaphoreCount = 0; present.pResults = NULL; /* Make sure command buffer is finished before presenting */ do { res = vkWaitForFences(info.device, 1, &drawFence, VK_TRUE, FENCE_TIMEOUT); } while (res == VK_TIMEOUT); assert(res == VK_SUCCESS); res = vkQueuePresentKHR(info.queue, &present); assert(res == VK_SUCCESS); wait_seconds(1); /* VULKAN_KEY_END */ if (info.save_images) write_ppm(info, "copyblitimage"); vkDestroySemaphore(info.device, presentCompleteSemaphore, NULL); vkDestroyFence(info.device, drawFence, NULL); vkDestroyImage(info.device, bltSrcImage, NULL); vkFreeMemory(info.device, dmem, NULL); destroy_swap_chain(info); destroy_command_buffer(info); destroy_command_pool(info); destroy_device(info); destroy_window(info); destroy_instance(info); return 0; }
void VulkanContext::WaitUntilQueueIdle() { // Should almost never be used vkQueueWaitIdle(gfx_queue_); }
/** * Create Vulkan buffers for the index and vertex buffer using a vertex layout * * @note Only does staging if a valid command buffer and transfer queue are passed * * @param meshBuffer Pointer to the mesh buffer containing buffer handles and memory * @param layout Vertex layout for the vertex buffer * @param createInfo Structure containing information for mesh creation time (center, scaling, etc.) * @param useStaging If true, buffers are staged to device local memory * @param copyCmd (Required for staging) Command buffer to put the copy commands into * @param copyQueue (Required for staging) Queue to put copys into */ void createBuffers( vkMeshLoader::MeshBuffer *meshBuffer, std::vector<vkMeshLoader::VertexLayout> layout, vkMeshLoader::MeshCreateInfo *createInfo, bool useStaging, VkCommandBuffer copyCmd, VkQueue copyQueue) { glm::vec3 scale; glm::vec2 uvscale; glm::vec3 center; if (createInfo == nullptr) { scale = glm::vec3(1.0f); uvscale = glm::vec2(1.0f); center = glm::vec3(0.0f); } else { scale = createInfo->scale; uvscale = createInfo->uvscale; center = createInfo->center; } std::vector<float> vertexBuffer; for (size_t m = 0; m < m_Entries.size(); m++) { for (size_t i = 0; i < m_Entries[m].Vertices.size(); i++) { // Push vertex data depending on layout for (auto& layoutDetail : layout) { // Position if (layoutDetail == vkMeshLoader::VERTEX_LAYOUT_POSITION) { vertexBuffer.push_back(m_Entries[m].Vertices[i].m_pos.x * scale.x + center.x); vertexBuffer.push_back(m_Entries[m].Vertices[i].m_pos.y * scale.y + center.y); vertexBuffer.push_back(m_Entries[m].Vertices[i].m_pos.z * scale.z + center.z); } // Normal if (layoutDetail == vkMeshLoader::VERTEX_LAYOUT_NORMAL) { vertexBuffer.push_back(m_Entries[m].Vertices[i].m_normal.x); vertexBuffer.push_back(-m_Entries[m].Vertices[i].m_normal.y); vertexBuffer.push_back(m_Entries[m].Vertices[i].m_normal.z); } // Texture coordinates if (layoutDetail == vkMeshLoader::VERTEX_LAYOUT_UV) { vertexBuffer.push_back(m_Entries[m].Vertices[i].m_tex.s * uvscale.s); vertexBuffer.push_back(m_Entries[m].Vertices[i].m_tex.t * uvscale.t); } // Color if (layoutDetail == vkMeshLoader::VERTEX_LAYOUT_COLOR) { vertexBuffer.push_back(m_Entries[m].Vertices[i].m_color.r); vertexBuffer.push_back(m_Entries[m].Vertices[i].m_color.g); vertexBuffer.push_back(m_Entries[m].Vertices[i].m_color.b); } // Tangent if (layoutDetail == vkMeshLoader::VERTEX_LAYOUT_TANGENT) { vertexBuffer.push_back(m_Entries[m].Vertices[i].m_tangent.x); vertexBuffer.push_back(m_Entries[m].Vertices[i].m_tangent.y); vertexBuffer.push_back(m_Entries[m].Vertices[i].m_tangent.z); } // Bitangent if (layoutDetail == vkMeshLoader::VERTEX_LAYOUT_BITANGENT) { vertexBuffer.push_back(m_Entries[m].Vertices[i].m_binormal.x); vertexBuffer.push_back(m_Entries[m].Vertices[i].m_binormal.y); vertexBuffer.push_back(m_Entries[m].Vertices[i].m_binormal.z); } // Dummy layout components for padding if (layoutDetail == vkMeshLoader::VERTEX_LAYOUT_DUMMY_FLOAT) { vertexBuffer.push_back(0.0f); } if (layoutDetail == vkMeshLoader::VERTEX_LAYOUT_DUMMY_VEC4) { vertexBuffer.push_back(0.0f); vertexBuffer.push_back(0.0f); vertexBuffer.push_back(0.0f); vertexBuffer.push_back(0.0f); } } } } meshBuffer->vertices.size = vertexBuffer.size() * sizeof(float); dim.min *= scale; dim.max *= scale; dim.size *= scale; std::vector<uint32_t> indexBuffer; for (uint32_t m = 0; m < m_Entries.size(); m++) { uint32_t indexBase = static_cast<uint32_t>(indexBuffer.size()); for (uint32_t i = 0; i < m_Entries[m].Indices.size(); i++) { indexBuffer.push_back(m_Entries[m].Indices[i] + indexBase); } vkMeshLoader::MeshDescriptor descriptor{}; descriptor.indexBase = indexBase; descriptor.indexCount = static_cast<uint32_t>(m_Entries[m].Indices.size()); descriptor.vertexCount = static_cast<uint32_t>(m_Entries[m].Vertices.size()); meshBuffer->meshDescriptors.push_back(descriptor); } meshBuffer->indices.size = indexBuffer.size() * sizeof(uint32_t); meshBuffer->indexCount = static_cast<uint32_t>(indexBuffer.size()); // Use staging buffer to move vertex and index buffer to device local memory if (useStaging && copyQueue != VK_NULL_HANDLE && copyCmd != VK_NULL_HANDLE) { // Create staging buffers struct { VkBuffer buffer; VkDeviceMemory memory; } vertexStaging, indexStaging; // Vertex buffer vulkanDevice->createBuffer( VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, meshBuffer->vertices.size, &vertexStaging.buffer, &vertexStaging.memory, vertexBuffer.data()); // Index buffer vulkanDevice->createBuffer( VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, meshBuffer->indices.size, &indexStaging.buffer, &indexStaging.memory, indexBuffer.data()); // Create device local target buffers // Vertex buffer vulkanDevice->createBuffer( VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, meshBuffer->vertices.size, &meshBuffer->vertices.buf, &meshBuffer->vertices.mem); // Index buffer vulkanDevice->createBuffer( VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, meshBuffer->indices.size, &meshBuffer->indices.buf, &meshBuffer->indices.mem); // Copy from staging buffers VkCommandBufferBeginInfo cmdBufInfo = vkTools::initializers::commandBufferBeginInfo(); VK_CHECK_RESULT(vkBeginCommandBuffer(copyCmd, &cmdBufInfo)); VkBufferCopy copyRegion = {}; copyRegion.size = meshBuffer->vertices.size; vkCmdCopyBuffer( copyCmd, vertexStaging.buffer, meshBuffer->vertices.buf, 1, ©Region); copyRegion.size = meshBuffer->indices.size; vkCmdCopyBuffer( copyCmd, indexStaging.buffer, meshBuffer->indices.buf, 1, ©Region); VK_CHECK_RESULT(vkEndCommandBuffer(copyCmd)); VkSubmitInfo submitInfo = {}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = ©Cmd; VK_CHECK_RESULT(vkQueueSubmit(copyQueue, 1, &submitInfo, VK_NULL_HANDLE)); VK_CHECK_RESULT(vkQueueWaitIdle(copyQueue)); vkDestroyBuffer(vulkanDevice->logicalDevice, vertexStaging.buffer, nullptr); vkFreeMemory(vulkanDevice->logicalDevice, vertexStaging.memory, nullptr); vkDestroyBuffer(vulkanDevice->logicalDevice, indexStaging.buffer, nullptr); vkFreeMemory(vulkanDevice->logicalDevice, indexStaging.memory, nullptr); } else { // Generate vertex buffer vulkanDevice->createBuffer( VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, meshBuffer->vertices.size, &meshBuffer->vertices.buf, &meshBuffer->vertices.mem, vertexBuffer.data()); // Generate index buffer vulkanDevice->createBuffer( VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, meshBuffer->indices.size, &meshBuffer->indices.buf, &meshBuffer->indices.mem, indexBuffer.data()); } }
VkCtx( VkPhysicalDevice physdev, VkDevice device, VkQueue queue, VkCommandBuffer cmdbuf ) : m_device( device ) , m_queue( queue ) , m_context( s_gpuCtxCounter.fetch_add( 1, std::memory_order_relaxed ) ) , m_head( 0 ) , m_tail( 0 ) , m_oldCnt( 0 ) { assert( m_context != 255 ); VkPhysicalDeviceProperties prop; vkGetPhysicalDeviceProperties( physdev, &prop ); const float period = prop.limits.timestampPeriod; VkQueryPoolCreateInfo poolInfo = {}; poolInfo.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; poolInfo.queryCount = QueryCount; poolInfo.queryType = VK_QUERY_TYPE_TIMESTAMP; vkCreateQueryPool( device, &poolInfo, nullptr, &m_query ); VkCommandBufferBeginInfo beginInfo = {}; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; VkSubmitInfo submitInfo = {}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &cmdbuf; vkBeginCommandBuffer( cmdbuf, &beginInfo ); vkCmdResetQueryPool( cmdbuf, m_query, 0, QueryCount ); vkEndCommandBuffer( cmdbuf ); vkQueueSubmit( queue, 1, &submitInfo, VK_NULL_HANDLE ); vkQueueWaitIdle( queue ); vkBeginCommandBuffer( cmdbuf, &beginInfo ); vkCmdWriteTimestamp( cmdbuf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, m_query, 0 ); vkEndCommandBuffer( cmdbuf ); vkQueueSubmit( queue, 1, &submitInfo, VK_NULL_HANDLE ); vkQueueWaitIdle( queue ); int64_t tcpu = Profiler::GetTime(); int64_t tgpu; vkGetQueryPoolResults( device, m_query, 0, 1, sizeof( tgpu ), &tgpu, sizeof( tgpu ), VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT ); vkBeginCommandBuffer( cmdbuf, &beginInfo ); vkCmdResetQueryPool( cmdbuf, m_query, 0, 1 ); vkEndCommandBuffer( cmdbuf ); vkQueueSubmit( queue, 1, &submitInfo, VK_NULL_HANDLE ); vkQueueWaitIdle( queue ); Magic magic; auto& token = s_token.ptr; auto& tail = token->get_tail_index(); auto item = token->enqueue_begin<tracy::moodycamel::CanAlloc>( magic ); MemWrite( &item->hdr.type, QueueType::GpuNewContext ); MemWrite( &item->gpuNewContext.cpuTime, tcpu ); MemWrite( &item->gpuNewContext.gpuTime, tgpu ); memset( &item->gpuNewContext.thread, 0, sizeof( item->gpuNewContext.thread ) ); MemWrite( &item->gpuNewContext.period, period ); MemWrite( &item->gpuNewContext.context, m_context ); MemWrite( &item->gpuNewContext.accuracyBits, uint8_t( 0 ) ); #ifdef TRACY_ON_DEMAND s_profiler.DeferItem( *item ); #endif tail.store( magic + 1, std::memory_order_release ); }
void loadTexture(const char* filename, VkFormat format, bool forceLinearTiling) { VkFormatProperties formatProperties; VkResult err; gli::textureCube texCube(gli::load(filename)); assert(!texCube.empty()); cubeMap.width = texCube[0].dimensions().x; cubeMap.height = texCube[0].dimensions().y; // Get device properites for the requested texture format vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &formatProperties); VkImageCreateInfo imageCreateInfo = vkTools::initializers::imageCreateInfo(); imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; imageCreateInfo.format = format; imageCreateInfo.extent = { cubeMap.width, cubeMap.height, 1 }; imageCreateInfo.mipLevels = 1; imageCreateInfo.arrayLayers = 1; imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; imageCreateInfo.tiling = VK_IMAGE_TILING_LINEAR; imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT; imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; imageCreateInfo.flags = 0; VkMemoryAllocateInfo memAllocInfo = vkTools::initializers::memoryAllocateInfo(); VkMemoryRequirements memReqs; struct { VkImage image; VkDeviceMemory memory; } cubeFace[6]; // Allocate command buffer for image copies and layouts VkCommandBuffer cmdBuffer; VkCommandBufferAllocateInfo cmdBufAlllocatInfo = vkTools::initializers::commandBufferAllocateInfo( cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1); err = vkAllocateCommandBuffers(device, &cmdBufAlllocatInfo, &cmdBuffer); assert(!err); VkCommandBufferBeginInfo cmdBufInfo = vkTools::initializers::commandBufferBeginInfo(); err = vkBeginCommandBuffer(cmdBuffer, &cmdBufInfo); assert(!err); // Load separate cube map faces into linear tiled textures for (uint32_t face = 0; face < 6; ++face) { err = vkCreateImage(device, &imageCreateInfo, nullptr, &cubeFace[face].image); assert(!err); vkGetImageMemoryRequirements(device, cubeFace[face].image, &memReqs); memAllocInfo.allocationSize = memReqs.size; getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &memAllocInfo.memoryTypeIndex); err = vkAllocateMemory(device, &memAllocInfo, nullptr, &cubeFace[face].memory); assert(!err); err = vkBindImageMemory(device, cubeFace[face].image, cubeFace[face].memory, 0); assert(!err); VkImageSubresource subRes = {}; subRes.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; VkSubresourceLayout subResLayout; void *data; vkGetImageSubresourceLayout(device, cubeFace[face].image, &subRes, &subResLayout); assert(!err); err = vkMapMemory(device, cubeFace[face].memory, 0, memReqs.size, 0, &data); assert(!err); memcpy(data, texCube[face][subRes.mipLevel].data(), texCube[face][subRes.mipLevel].size()); vkUnmapMemory(device, cubeFace[face].memory); // Image barrier for linear image (base) // Linear image will be used as a source for the copy vkTools::setImageLayout( cmdBuffer, cubeFace[face].image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); } // Transfer cube map faces to optimal tiling // Setup texture as blit target with optimal tiling imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; imageCreateInfo.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; imageCreateInfo.arrayLayers = 6; err = vkCreateImage(device, &imageCreateInfo, nullptr, &cubeMap.image); assert(!err); vkGetImageMemoryRequirements(device, cubeMap.image, &memReqs); memAllocInfo.allocationSize = memReqs.size; getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memAllocInfo.memoryTypeIndex); err = vkAllocateMemory(device, &memAllocInfo, nullptr, &cubeMap.deviceMemory); assert(!err); err = vkBindImageMemory(device, cubeMap.image, cubeMap.deviceMemory, 0); assert(!err); // Image barrier for optimal image (target) // Optimal image will be used as destination for the copy // Set initial layout for all array layers of the optimal (target) tiled texture VkImageSubresourceRange subresourceRange = {}; subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; subresourceRange.baseMipLevel = 0; subresourceRange.levelCount = 1; subresourceRange.layerCount = 6; vkTools::setImageLayout( cmdBuffer, cubeMap.image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, subresourceRange); // Copy cube map faces one by one for (uint32_t face = 0; face < 6; ++face) { // Copy region for image blit VkImageCopy copyRegion = {}; copyRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; copyRegion.srcSubresource.baseArrayLayer = 0; copyRegion.srcSubresource.mipLevel = 0; copyRegion.srcSubresource.layerCount = 1; copyRegion.srcOffset = { 0, 0, 0 }; copyRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; copyRegion.dstSubresource.baseArrayLayer = face; copyRegion.dstSubresource.mipLevel = 0; copyRegion.dstSubresource.layerCount = 1; copyRegion.dstOffset = { 0, 0, 0 }; copyRegion.extent.width = cubeMap.width; copyRegion.extent.height = cubeMap.height; copyRegion.extent.depth = 1; // Put image copy into command buffer vkCmdCopyImage( cmdBuffer, cubeFace[face].image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, cubeMap.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Region); } // Change texture image layout to shader read after all faces have been copied cubeMap.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; vkTools::setImageLayout( cmdBuffer, cubeMap.image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, cubeMap.imageLayout, subresourceRange); err = vkEndCommandBuffer(cmdBuffer); assert(!err); VkFence nullFence = { VK_NULL_HANDLE }; // Submit command buffer to graphis queue VkSubmitInfo submitInfo = vkTools::initializers::submitInfo(); submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &cmdBuffer; err = vkQueueSubmit(queue, 1, &submitInfo, nullFence); assert(!err); err = vkQueueWaitIdle(queue); assert(!err); // Create sampler VkSamplerCreateInfo sampler = vkTools::initializers::samplerCreateInfo(); sampler.magFilter = VK_FILTER_LINEAR; sampler.minFilter = VK_FILTER_LINEAR; sampler.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; sampler.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; sampler.addressModeV = sampler.addressModeU; sampler.addressModeW = sampler.addressModeU; sampler.mipLodBias = 0.0f; sampler.maxAnisotropy = 8; sampler.compareOp = VK_COMPARE_OP_NEVER; sampler.minLod = 0.0f; sampler.maxLod = 0.0f; sampler.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; err = vkCreateSampler(device, &sampler, nullptr, &cubeMap.sampler); assert(!err); // Create image view VkImageViewCreateInfo view = vkTools::initializers::imageViewCreateInfo(); view.image = VK_NULL_HANDLE; view.viewType = VK_IMAGE_VIEW_TYPE_CUBE; view.format = format; view.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }; view.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; view.subresourceRange.layerCount = 6; view.image = cubeMap.image; err = vkCreateImageView(device, &view, nullptr, &cubeMap.view); assert(!err); // Cleanup for (auto& face : cubeFace) { vkDestroyImage(device, face.image, nullptr); vkFreeMemory(device, face.memory, nullptr); } }
VkResult setup(VkDevice device, VkCommandPool command_pool, SwapChain& swap_chain, uint32_t *width, uint32_t *height) { VkCommandBuffer setup_command_buffer = VK_NULL_HANDLE; // command buffer used for setup VkCommandBufferAllocateInfo command_buffer_allocate_info; command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; command_buffer_allocate_info.pNext = nullptr; command_buffer_allocate_info.commandPool = command_pool; command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; command_buffer_allocate_info.commandBufferCount = 1; vkAllocateCommandBuffers(device, &command_buffer_allocate_info, &setup_command_buffer); VkCommandBufferBeginInfo command_buffer_begin_info = {}; command_buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; command_buffer_begin_info.pNext = nullptr; command_buffer_begin_info.flags = 0; command_buffer_begin_info.pInheritanceInfo = nullptr; vkBeginCommandBuffer(setup_command_buffer, &command_buffer_begin_info); // SWAP CHAIN uint32_t present_mode_count = 0; vkGetPhysicalDeviceSurfacePresentModesKHR(swap_chain.gpu, swap_chain.surface, &present_mode_count, nullptr); std::vector<VkPresentModeKHR> present_modes(present_mode_count); vkGetPhysicalDeviceSurfacePresentModesKHR(swap_chain.gpu, swap_chain.surface, &present_mode_count, present_modes.data()); // Try to use mailbox mode // Low latency and non-tearing VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; for (uint32_t i = 0; i < present_mode_count; i++) { if (present_modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR; break; } if ((swapchainPresentMode != VK_PRESENT_MODE_MAILBOX_KHR) && (present_modes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR)) { swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; } } VkSurfaceCapabilitiesKHR surface_cap; vkGetPhysicalDeviceSurfaceCapabilitiesKHR(swap_chain.gpu, swap_chain.surface, &surface_cap); VkExtent2D swapchainExtent = {}; // width and height are either both -1, or both not -1. if (surface_cap.currentExtent.width == -1) { // If the surface size is undefined, the size is set to // the size of the images requested. swapchainExtent.width = *width; swapchainExtent.height = *height; } else { // If the surface size is defined, the swap chain size must match swapchainExtent = surface_cap.currentExtent; *width = surface_cap.currentExtent.width; *height = surface_cap.currentExtent.height; } // Determine the number of images uint32_t desired_number_of_swapchain_images = surface_cap.minImageCount + 1; if ((surface_cap.maxImageCount > 0) && (desired_number_of_swapchain_images > surface_cap.maxImageCount)) { desired_number_of_swapchain_images = surface_cap.maxImageCount; } VkSurfaceTransformFlagsKHR pre_transform; if (check_flag(surface_cap.supportedTransforms, VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)) { pre_transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; } else { pre_transform = surface_cap.currentTransform; } /* VkSwapchainCreateInfoKHR swapchain_creation_info = {}; swapchain_creation_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; swapchain_creation_info.pNext = NULL; swapchain_creation_info.surface = surface; swapchain_creation_info.minImageCount = desired_number_of_swapchain_images; swapchain_creation_info.imageFormat = colorFormat; swapchain_creation_info.imageColorSpace = colorSpace; swapchain_creation_info.imageExtent = { swapchainExtent.width, swapchainExtent.height }; swapchain_creation_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; swapchain_creation_info.preTransform = (VkSurfaceTransformFlagBitsKHR)preTransform; swapchain_creation_info.imageArrayLayers = 1; swapchain_creation_info.queueFamilyIndexCount = VK_SHARING_MODE_EXCLUSIVE; swapchain_creation_info.queueFamilyIndexCount = 0; swapchain_creation_info.pQueueFamilyIndices = NULL; swapchain_creation_info.presentMode = swapchainPresentMode; swapchain_creation_info.oldSwapchain = VK_NULL_HANDLE; swapchain_creation_info.clipped = true; swapchain_creation_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; vkCreateSwapchainKHR(device, &swapchain_creation_info, nullptr, &swap_chain.swap_chain); std::vector<VkImage> swap_chain_images(desired_number_of_swapchain_images); vkGetSwapchainImagesKHR(device, swapChain, &desired_number_of_swapchain_images, swap_chain_images.data()); */ /* assert(!err); buffers = (SwapChainBuffer*)malloc(sizeof(SwapChainBuffer)*imageCount); assert(buffers); //buffers.resize(imageCount); for (uint32_t i = 0; i < imageCount; i++) { VkImageViewCreateInfo colorAttachmentView = {}; colorAttachmentView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; colorAttachmentView.pNext = NULL; colorAttachmentView.format = colorFormat; colorAttachmentView.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }; colorAttachmentView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; colorAttachmentView.subresourceRange.baseMipLevel = 0; colorAttachmentView.subresourceRange.levelCount = 1; colorAttachmentView.subresourceRange.baseArrayLayer = 0; colorAttachmentView.subresourceRange.layerCount = 1; colorAttachmentView.viewType = VK_IMAGE_VIEW_TYPE_2D; colorAttachmentView.flags = 0; buffers[i].image = swapchainImages[i]; vkTools::setImageLayout( cmdBuffer, buffers[i].image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); colorAttachmentView.image = buffers[i].image; err = vkCreateImageView(device, &colorAttachmentView, nullptr, &buffers[i].view); assert(!err); } */ vkEndCommandBuffer(setup_command_buffer); VkSubmitInfo submit_info = {}; submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit_info.pNext = nullptr; submit_info.waitSemaphoreCount = 0; submit_info.pWaitSemaphores = nullptr; submit_info.pWaitDstStageMask = nullptr; submit_info.commandBufferCount = 1; submit_info.pCommandBuffers = &setup_command_buffer; submit_info.signalSemaphoreCount = 0; submit_info.pSignalSemaphores = nullptr; vkQueueSubmit(swap_chain.present_queue, 1, &submit_info, VK_NULL_HANDLE); vkQueueWaitIdle(swap_chain.present_queue); vkFreeCommandBuffers(device, command_pool, 1, &setup_command_buffer); return VK_SUCCESS; }
int main(int argc, char *argv[]) { VkResult U_ASSERT_ONLY res; bool U_ASSERT_ONLY pass; struct sample_info info = {}; char sample_title[] = "Draw Cube"; process_command_line_args(info, argc, argv); init_global_layer_properties(info); info.instance_extension_names.push_back(VK_KHR_SURFACE_EXTENSION_NAME); #ifdef _WIN32 info.instance_extension_names.push_back( VK_KHR_WIN32_SURFACE_EXTENSION_NAME); #else info.instance_extension_names.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME); #endif info.device_extension_names.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); init_instance(info, sample_title); init_enumerate_device(info); init_window_size(info, 500, 500); init_connection(info); init_window(info); init_swapchain_extension(info); init_device(info); init_command_pool(info); init_command_buffer(info); execute_begin_command_buffer(info); init_device_queue(info); init_swap_chain(info); init_depth_buffer(info); init_uniform_buffer(info); init_descriptor_and_pipeline_layouts(info, false); init_renderpass(info, DEPTH_PRESENT); init_shaders(info, vertShaderText, fragShaderText); init_framebuffers(info, DEPTH_PRESENT); init_vertex_buffer(info, g_vb_solid_face_colors_Data, sizeof(g_vb_solid_face_colors_Data), sizeof(g_vb_solid_face_colors_Data[0]), false); init_descriptor_pool(info, false); init_descriptor_set(info, false); init_pipeline_cache(info); init_pipeline(info, DEPTH_PRESENT); /* VULKAN_KEY_START */ VkClearValue clear_values[2]; clear_values[0].color.float32[0] = 0.2f; clear_values[0].color.float32[1] = 0.2f; clear_values[0].color.float32[2] = 0.2f; clear_values[0].color.float32[3] = 0.2f; clear_values[1].depthStencil.depth = 1.0f; clear_values[1].depthStencil.stencil = 0; VkSemaphore presentCompleteSemaphore; VkSemaphoreCreateInfo presentCompleteSemaphoreCreateInfo; presentCompleteSemaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; presentCompleteSemaphoreCreateInfo.pNext = NULL; presentCompleteSemaphoreCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; res = vkCreateSemaphore(info.device, &presentCompleteSemaphoreCreateInfo, NULL, &presentCompleteSemaphore); assert(res == VK_SUCCESS); // Get the index of the next available swapchain image: res = vkAcquireNextImageKHR(info.device, info.swap_chain, UINT64_MAX, presentCompleteSemaphore, NULL, &info.current_buffer); // TODO: Deal with the VK_SUBOPTIMAL_KHR and VK_ERROR_OUT_OF_DATE_KHR // return codes assert(res == VK_SUCCESS); /* Allocate a uniform buffer that will take query results. */ VkBuffer query_result_buf; VkDeviceMemory query_result_mem; VkBufferCreateInfo buf_info = {}; buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; buf_info.pNext = NULL; buf_info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; buf_info.size = 4 * sizeof(uint64_t); buf_info.queueFamilyIndexCount = 0; buf_info.pQueueFamilyIndices = NULL; buf_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; buf_info.flags = 0; res = vkCreateBuffer(info.device, &buf_info, NULL, &query_result_buf); assert(res == VK_SUCCESS); VkMemoryRequirements mem_reqs; vkGetBufferMemoryRequirements(info.device, query_result_buf, &mem_reqs); VkMemoryAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; alloc_info.pNext = NULL; alloc_info.memoryTypeIndex = 0; alloc_info.allocationSize = mem_reqs.size; pass = memory_type_from_properties(info, mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &alloc_info.memoryTypeIndex); assert(pass); res = vkAllocateMemory(info.device, &alloc_info, NULL, &query_result_mem); assert(res == VK_SUCCESS); res = vkBindBufferMemory(info.device, query_result_buf, query_result_mem, 0); assert(res == VK_SUCCESS); VkQueryPool query_pool; VkQueryPoolCreateInfo query_pool_info; query_pool_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; query_pool_info.pNext = NULL; query_pool_info.queryType = VK_QUERY_TYPE_OCCLUSION; query_pool_info.flags = 0; query_pool_info.queryCount = 2; query_pool_info.pipelineStatistics = 0; res = vkCreateQueryPool(info.device, &query_pool_info, NULL, &query_pool); assert(res == VK_SUCCESS); vkCmdResetQueryPool(info.cmd, query_pool, 0 /*startQuery*/, 2 /*queryCount*/); VkRenderPassBeginInfo rp_begin; rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; rp_begin.pNext = NULL; rp_begin.renderPass = info.render_pass; rp_begin.framebuffer = info.framebuffers[info.current_buffer]; rp_begin.renderArea.offset.x = 0; rp_begin.renderArea.offset.y = 0; rp_begin.renderArea.extent.width = info.width; rp_begin.renderArea.extent.height = info.height; rp_begin.clearValueCount = 2; rp_begin.pClearValues = clear_values; vkCmdBeginRenderPass(info.cmd, &rp_begin, VK_SUBPASS_CONTENTS_INLINE); vkCmdBindPipeline(info.cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, info.pipeline); vkCmdBindDescriptorSets(info.cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, info.pipeline_layout, 0, NUM_DESCRIPTOR_SETS, info.desc_set.data(), 0, NULL); const VkDeviceSize offsets[1] = {0}; vkCmdBindVertexBuffers(info.cmd, 0, 1, &info.vertex_buffer.buf, offsets); VkViewport viewport; viewport.height = (float)info.height; viewport.width = (float)info.width; viewport.minDepth = (float)0.0f; viewport.maxDepth = (float)1.0f; viewport.x = 0; viewport.y = 0; vkCmdSetViewport(info.cmd, 0, NUM_VIEWPORTS, &viewport); VkRect2D scissor; scissor.extent.width = info.width; scissor.extent.height = info.height; scissor.offset.x = 0; scissor.offset.y = 0; vkCmdSetScissor(info.cmd, 0, NUM_SCISSORS, &scissor); vkCmdBeginQuery(info.cmd, query_pool, 0 /*slot*/, 0 /*flags*/); vkCmdEndQuery(info.cmd, query_pool, 0 /*slot*/); vkCmdBeginQuery(info.cmd, query_pool, 1 /*slot*/, 0 /*flags*/); vkCmdDraw(info.cmd, 12 * 3, 1, 0, 0); vkCmdEndRenderPass(info.cmd); vkCmdEndQuery(info.cmd, query_pool, 1 /*slot*/); vkCmdCopyQueryPoolResults( info.cmd, query_pool, 0 /*firstQuery*/, 2 /*queryCount*/, query_result_buf, 0 /*dstOffset*/, sizeof(uint64_t) /*stride*/, VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT); VkImageMemoryBarrier prePresentBarrier = {}; prePresentBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; prePresentBarrier.pNext = NULL; prePresentBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; prePresentBarrier.dstAccessMask = 0; prePresentBarrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; prePresentBarrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; prePresentBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; prePresentBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; prePresentBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; prePresentBarrier.subresourceRange.baseMipLevel = 0; prePresentBarrier.subresourceRange.levelCount = 1; prePresentBarrier.subresourceRange.baseArrayLayer = 0; prePresentBarrier.subresourceRange.layerCount = 1; prePresentBarrier.image = info.buffers[info.current_buffer].image; vkCmdPipelineBarrier(info.cmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, NULL, 0, NULL, 1, &prePresentBarrier); res = vkEndCommandBuffer(info.cmd); const VkCommandBuffer cmd_bufs[] = {info.cmd}; VkFenceCreateInfo fenceInfo; VkFence drawFence; fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fenceInfo.pNext = NULL; fenceInfo.flags = 0; vkCreateFence(info.device, &fenceInfo, NULL, &drawFence); VkPipelineStageFlags pipe_stage_flags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; VkSubmitInfo submit_info[1] = {}; submit_info[0].pNext = NULL; submit_info[0].sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit_info[0].waitSemaphoreCount = 1; submit_info[0].pWaitSemaphores = &presentCompleteSemaphore; submit_info[0].pWaitDstStageMask = &pipe_stage_flags; submit_info[0].commandBufferCount = 1; submit_info[0].pCommandBuffers = cmd_bufs; submit_info[0].signalSemaphoreCount = 0; submit_info[0].pSignalSemaphores = NULL; /* Queue the command buffer for execution */ res = vkQueueSubmit(info.queue, 1, submit_info, drawFence); assert(res == VK_SUCCESS); res = vkQueueWaitIdle(info.queue); assert(res == VK_SUCCESS); uint64_t samples_passed[4]; samples_passed[0] = 0; samples_passed[1] = 0; res = vkGetQueryPoolResults( info.device, query_pool, 0 /*firstQuery*/, 2 /*queryCount*/, sizeof(samples_passed) /*dataSize*/, samples_passed, sizeof(uint64_t) /*stride*/, VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT); assert(res == VK_SUCCESS); std::cout << "vkGetQueryPoolResults data" << "\n"; std::cout << "samples_passed[0] = " << samples_passed[0] << "\n"; std::cout << "samples_passed[1] = " << samples_passed[1] << "\n"; /* Read back query result from buffer */ uint64_t *samples_passed_ptr; res = vkMapMemory(info.device, query_result_mem, 0, mem_reqs.size, 0, (void **)&samples_passed_ptr); assert(res == VK_SUCCESS); std::cout << "vkCmdCopyQueryPoolResults data" << "\n"; std::cout << "samples_passed[0] = " << samples_passed_ptr[0] << "\n"; std::cout << "samples_passed[1] = " << samples_passed_ptr[1] << "\n"; vkUnmapMemory(info.device, query_result_mem); /* Now present the image in the window */ VkPresentInfoKHR present; present.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; present.pNext = NULL; present.swapchainCount = 1; present.pSwapchains = &info.swap_chain; present.pImageIndices = &info.current_buffer; present.pWaitSemaphores = NULL; present.waitSemaphoreCount = 0; present.pResults = NULL; /* Make sure command buffer is finished before presenting */ do { res = vkWaitForFences(info.device, 1, &drawFence, VK_TRUE, FENCE_TIMEOUT); } while (res == VK_TIMEOUT); assert(res == VK_SUCCESS); res = vkQueuePresentKHR(info.queue, &present); assert(res == VK_SUCCESS); wait_seconds(1); /* VULKAN_KEY_END */ if (info.save_images) write_ppm(info, "occlusion_query"); vkDestroyBuffer(info.device, query_result_buf, NULL); vkFreeMemory(info.device, query_result_mem, NULL); vkDestroySemaphore(info.device, presentCompleteSemaphore, NULL); vkDestroyQueryPool(info.device, query_pool, NULL); vkDestroyFence(info.device, drawFence, NULL); destroy_pipeline(info); destroy_pipeline_cache(info); destroy_descriptor_pool(info); destroy_vertex_buffer(info); destroy_framebuffers(info); destroy_shaders(info); destroy_renderpass(info); destroy_descriptor_and_pipeline_layouts(info); destroy_uniform_buffer(info); destroy_depth_buffer(info); destroy_swap_chain(info); destroy_command_buffer(info); destroy_command_pool(info); destroy_device(info); destroy_window(info); destroy_instance(info); return 0; }
void loadTextureArray(std::string filename, VkFormat format) { #if defined(__ANDROID__) // Textures are stored inside the apk on Android (compressed) // So they need to be loaded via the asset manager AAsset* asset = AAssetManager_open(androidApp->activity->assetManager, filename.c_str(), AASSET_MODE_STREAMING); assert(asset); size_t size = AAsset_getLength(asset); assert(size > 0); void *textureData = malloc(size); AAsset_read(asset, textureData, size); AAsset_close(asset); gli::texture2DArray tex2DArray(gli::load((const char*)textureData, size)); #else gli::texture2DArray tex2DArray(gli::load(filename)); #endif assert(!tex2DArray.empty()); textureArray.width = tex2DArray.dimensions().x; textureArray.height = tex2DArray.dimensions().y; layerCount = tex2DArray.layers(); // Get device properites for the requested texture format VkFormatProperties formatProperties; vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &formatProperties); VkImageCreateInfo imageCreateInfo = vkTools::initializers::imageCreateInfo(); imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; imageCreateInfo.format = format; imageCreateInfo.extent = { textureArray.width, textureArray.height, 1 }; imageCreateInfo.mipLevels = 1; imageCreateInfo.arrayLayers = 1; imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; imageCreateInfo.tiling = VK_IMAGE_TILING_LINEAR; imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT; imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; imageCreateInfo.flags = 0; VkMemoryAllocateInfo memAllocInfo = vkTools::initializers::memoryAllocateInfo(); VkMemoryRequirements memReqs; struct Layer { VkImage image; VkDeviceMemory memory; }; std::vector<Layer> arrayLayer; arrayLayer.resize(layerCount); // Allocate command buffer for image copies and layouts VkCommandBuffer cmdBuffer; VkCommandBufferAllocateInfo cmdBufAlllocatInfo = vkTools::initializers::commandBufferAllocateInfo( cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1); VkResult err = vkAllocateCommandBuffers(device, &cmdBufAlllocatInfo, &cmdBuffer); assert(!err); VkCommandBufferBeginInfo cmdBufInfo = vkTools::initializers::commandBufferBeginInfo(); err = vkBeginCommandBuffer(cmdBuffer, &cmdBufInfo); assert(!err); // Load separate cube map faces into linear tiled textures for (uint32_t i = 0; i < layerCount; ++i) { err = vkCreateImage(device, &imageCreateInfo, nullptr, &arrayLayer[i].image); assert(!err); vkGetImageMemoryRequirements(device, arrayLayer[i].image, &memReqs); memAllocInfo.allocationSize = memReqs.size; getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &memAllocInfo.memoryTypeIndex); err = vkAllocateMemory(device, &memAllocInfo, nullptr, &arrayLayer[i].memory); assert(!err); err = vkBindImageMemory(device, arrayLayer[i].image, arrayLayer[i].memory, 0); assert(!err); VkImageSubresource subRes = {}; subRes.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; VkSubresourceLayout subResLayout; void *data; vkGetImageSubresourceLayout(device, arrayLayer[i].image, &subRes, &subResLayout); assert(!err); err = vkMapMemory(device, arrayLayer[i].memory, 0, memReqs.size, 0, &data); assert(!err); memcpy(data, tex2DArray[i].data(), tex2DArray[i].size()); vkUnmapMemory(device, arrayLayer[i].memory); // Image barrier for linear image (base) // Linear image will be used as a source for the copy vkTools::setImageLayout( cmdBuffer, arrayLayer[i].image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); } // Transfer cube map faces to optimal tiling // Setup texture as blit target with optimal tiling imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; imageCreateInfo.arrayLayers = layerCount; err = vkCreateImage(device, &imageCreateInfo, nullptr, &textureArray.image); assert(!err); vkGetImageMemoryRequirements(device, textureArray.image, &memReqs); memAllocInfo.allocationSize = memReqs.size; getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memAllocInfo.memoryTypeIndex); err = vkAllocateMemory(device, &memAllocInfo, nullptr, &textureArray.deviceMemory); assert(!err); err = vkBindImageMemory(device, textureArray.image, textureArray.deviceMemory, 0); assert(!err); // Image barrier for optimal image (target) // Set initial layout for all array layers of the optimal (target) tiled texture VkImageSubresourceRange subresourceRange = {}; subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; subresourceRange.baseMipLevel = 0; subresourceRange.levelCount = 1; subresourceRange.layerCount = layerCount; vkTools::setImageLayout( cmdBuffer, textureArray.image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, subresourceRange); // Copy cube map faces one by one for (uint32_t i = 0; i < layerCount; ++i) { // Copy region for image blit VkImageCopy copyRegion = {}; copyRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; copyRegion.srcSubresource.baseArrayLayer = 0; copyRegion.srcSubresource.mipLevel = 0; copyRegion.srcSubresource.layerCount = 1; copyRegion.srcOffset = { 0, 0, 0 }; copyRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; copyRegion.dstSubresource.baseArrayLayer = i; copyRegion.dstSubresource.mipLevel = 0; copyRegion.dstSubresource.layerCount = 1; copyRegion.dstOffset = { 0, 0, 0 }; copyRegion.extent.width = textureArray.width; copyRegion.extent.height = textureArray.height; copyRegion.extent.depth = 1; // Put image copy into command buffer vkCmdCopyImage( cmdBuffer, arrayLayer[i].image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, textureArray.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Region); } // Change texture image layout to shader read after all layers have been copied textureArray.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; vkTools::setImageLayout( cmdBuffer, textureArray.image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, textureArray.imageLayout, subresourceRange); err = vkEndCommandBuffer(cmdBuffer); assert(!err); VkFence nullFence = { VK_NULL_HANDLE }; // Submit command buffer to graphis queue VkSubmitInfo submitInfo = vkTools::initializers::submitInfo(); submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &cmdBuffer; err = vkQueueSubmit(queue, 1, &submitInfo, nullFence); assert(!err); err = vkQueueWaitIdle(queue); assert(!err); // Create sampler VkSamplerCreateInfo sampler = vkTools::initializers::samplerCreateInfo(); sampler.magFilter = VK_FILTER_LINEAR; sampler.minFilter = VK_FILTER_LINEAR; sampler.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; sampler.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; sampler.addressModeV = sampler.addressModeU; sampler.addressModeW = sampler.addressModeU; sampler.mipLodBias = 0.0f; sampler.maxAnisotropy = 8; sampler.compareOp = VK_COMPARE_OP_NEVER; sampler.minLod = 0.0f; sampler.maxLod = 0.0f; sampler.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; err = vkCreateSampler(device, &sampler, nullptr, &textureArray.sampler); assert(!err); // Create image view VkImageViewCreateInfo view = vkTools::initializers::imageViewCreateInfo(); view.image = VK_NULL_HANDLE; view.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; view.format = format; view.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }; view.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; view.subresourceRange.layerCount = layerCount; view.image = textureArray.image; err = vkCreateImageView(device, &view, nullptr, &textureArray.view); assert(!err); // Cleanup for (auto& layer : arrayLayer) { vkDestroyImage(device, layer.image, nullptr); vkFreeMemory(device, layer.memory, nullptr); } }
void vkeGameRendererDynamic::update(){ VulkanAppContext *ctxt = VulkanAppContext::GetInstance(); VulkanDC *dc = VulkanDC::Get(); VulkanDC::Device *device = dc->getDefaultDevice(); VkCommandBuffer cmd = VK_NULL_HANDLE; VulkanDC::Device::Queue::CommandBufferID cmdID = INIT_COMMAND_ID + 300; static float sTime = 0.0f; static uint32_t *uniforms = NULL; uint32_t sz = (sizeof(VkeNodeUniform) * 100) + (64 * 64); static bool ismapped(false); nv_math::mat4f tempMatrix; const float r2d = 180 / (3.14159265359); static float xTheta(0.0f); //if (!ismapped){ VKA_CHECK_ERROR(vkMapMemory(getDefaultDevice(), m_uniforms_staging, 0, sz, 0, (void **)&uniforms), "Could not map buffer memory.\n"); //ismapped = true; //} for (uint32_t i = 0; i < 64; ++i){ size_t pointerOffset = (sizeof(VkeNodeUniform) * 100) + (64 * i); nv_math::mat4f *matPtr = (nv_math::mat4f*)(((uint8_t*)uniforms) + pointerOffset); m_flight_paths[i]->update(matPtr, sTime); } m_node_data->update((VkeNodeUniform*)uniforms); m_camera->setViewport(0, 0, (float)m_width, (float)m_height); m_camera->update(); VkMappedMemoryRange memRange = { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE }; memRange.memory = m_uniforms_staging; memRange.offset = 0; memRange.size = sz; vkFlushMappedMemoryRanges(device->getVKDevice(), 1, &memRange); vkUnmapMemory(device->getVKDevice(), m_uniforms_staging); if (!m_is_first_frame){ VkSubmitInfo subInfo; memset(&subInfo, 0, sizeof(subInfo)); subInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; subInfo.commandBufferCount = 1; subInfo.pCommandBuffers = &m_update_commands[m_current_buffer_index]; vkQueueSubmit(dc->getDefaultQueue()->getVKQueue(), 1, &subInfo, VK_NULL_HANDLE); vkQueueWaitIdle(dc->getDefaultQueue()->getVKQueue()); #if defined(WIN32) subInfo.waitSemaphoreCount = 1; subInfo.pWaitSemaphores = &m_present_done; subInfo.signalSemaphoreCount = 0; subInfo.pSignalSemaphores = &m_render_done; #endif subInfo.pCommandBuffers = &m_primary_commands[m_current_buffer_index]; vkQueueSubmit(dc->getDefaultQueue()->getVKQueue(), 1, &subInfo, VK_NULL_HANDLE); } else{ m_is_first_frame = false; } present(); m_current_buffer_index++; m_current_buffer_index %= 2; sTime += 0.16; generateDrawCommands(); }
void VlkRenderer::do_the_thing(util::Path& dir) { // Please keep in mind that this function is only for testing and so might be messy. // Enumerate available physical devices auto devices = vk_do_ritual(vkEnumeratePhysicalDevices, this->instance); if (devices.empty()) { throw Error(MSG(err) << "No Vulkan devices available."); } std::vector<std::pair<VkPhysicalDevice, SurfaceSupportDetails>> support_per_dev; for (auto dev : devices) { auto support = VlkGraphicsDevice::find_device_surface_support(dev, surface); if (support) { support_per_dev.emplace_back(dev, *support); } } if (support_per_dev.empty()) { throw Error(MSG(err) << "No valid Vulkan device available."); } // TODO rate devices based on capabilities // Given an instance and surface, selects the best (fastest, most capable, etc.) graphics device // which supports rendering onto that particular surface and constructs the object. auto const& info = support_per_dev[0]; // Create a logical device with a single queue for both graphics and present if (info.second.maybe_present_fam) { throw 0; } VlkGraphicsDevice dev(info.first, { info.second.graphics_fam } ); VlkDrawableDisplay display(dev.get_device(), info.second); // TODO reinit swapchain on window resize auto vert = resources::ShaderSource( resources::shader_lang_t::spirv, resources::shader_stage_t::vertex, util::Path(dir) / "assets/shaders/vert.spv" ); auto frag = resources::ShaderSource( resources::shader_lang_t::spirv, resources::shader_stage_t::fragment, util::Path(dir) / "assets/shaders/frag.spv" ); VlkShaderProgram prog(dev.get_device(), { vert, frag } ); VkPipelineVertexInputStateCreateInfo cr_vert_in = {}; cr_vert_in.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; // all init'd to 0 VkPipelineInputAssemblyStateCreateInfo cr_in_asm = {}; cr_in_asm.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; cr_in_asm.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; cr_in_asm.primitiveRestartEnable = VK_FALSE; VkViewport viewport = {}; viewport.x = 0.0f; viewport.y = 0.0f; viewport.width = display.extent.width; viewport.height = display.extent.height; viewport.minDepth = 0.0f; viewport.maxDepth = 1.0f; VkRect2D scissor = {}; scissor.offset = { 0, 0 }; scissor.extent = display.extent; VkPipelineViewportStateCreateInfo cr_view = {}; cr_view.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; cr_view.viewportCount = 1; cr_view.pViewports = &viewport; cr_view.scissorCount = 1; cr_view.pScissors = &scissor; VkPipelineRasterizationStateCreateInfo cr_raster = {}; cr_raster.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; cr_raster.depthClampEnable = VK_FALSE; cr_raster.rasterizerDiscardEnable = VK_FALSE; cr_raster.polygonMode = VK_POLYGON_MODE_FILL; cr_raster.lineWidth = 1.0f; cr_raster.cullMode = VK_CULL_MODE_BACK_BIT; cr_raster.frontFace = VK_FRONT_FACE_CLOCKWISE; cr_raster.depthBiasEnable = VK_FALSE; VkPipelineMultisampleStateCreateInfo cr_msaa = {}; cr_msaa.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; cr_msaa.sampleShadingEnable = VK_FALSE; cr_msaa.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; VkPipelineColorBlendAttachmentState blend_state = {}; blend_state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; blend_state.blendEnable = VK_TRUE; blend_state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; blend_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; blend_state.colorBlendOp = VK_BLEND_OP_ADD; blend_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; blend_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; blend_state.alphaBlendOp = VK_BLEND_OP_ADD; VkPipelineColorBlendStateCreateInfo cr_blend = {}; cr_blend.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; cr_blend.logicOpEnable = VK_FALSE; cr_blend.attachmentCount = 1; cr_blend.pAttachments = &blend_state; VkPipelineLayoutCreateInfo cr_layout = {}; cr_layout.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; // empty object VkPipelineLayout layout; VK_CALL_CHECKED(vkCreatePipelineLayout, dev.get_device(), &cr_layout, nullptr, &layout); /// RENDERPASS VkAttachmentDescription color_attachment = {}; color_attachment.format = display.format; color_attachment.samples = VK_SAMPLE_COUNT_1_BIT; color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; color_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; color_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; color_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; color_attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; VkAttachmentReference color_attachment_ref = {}; color_attachment_ref.attachment = 0; color_attachment_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; VkSubpassDescription subpass = {}; subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; subpass.colorAttachmentCount = 1; subpass.pColorAttachments = &color_attachment_ref; VkSubpassDependency dep = {}; dep.srcSubpass = VK_SUBPASS_EXTERNAL; dep.dstSubpass = 0; dep.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; dep.srcAccessMask = 0; dep.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; dep.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; VkRenderPassCreateInfo cr_render_pass = {}; cr_render_pass.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; cr_render_pass.attachmentCount = 1; cr_render_pass.pAttachments = &color_attachment; cr_render_pass.subpassCount = 1; cr_render_pass.pSubpasses = &subpass; cr_render_pass.dependencyCount = 1; cr_render_pass.pDependencies = &dep; VkRenderPass render_pass; VK_CALL_CHECKED(vkCreateRenderPass, dev.get_device(), &cr_render_pass, nullptr, &render_pass); /// RENDERPASS VkGraphicsPipelineCreateInfo cr_pipeline = {}; cr_pipeline.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; cr_pipeline.stageCount = 2; cr_pipeline.pStages = prog.pipeline_stage_infos.data(); cr_pipeline.pVertexInputState = &cr_vert_in; cr_pipeline.pInputAssemblyState = &cr_in_asm; cr_pipeline.pViewportState = &cr_view; cr_pipeline.pRasterizationState = &cr_raster; cr_pipeline.pMultisampleState = &cr_msaa; cr_pipeline.pDepthStencilState = nullptr; cr_pipeline.pColorBlendState = &cr_blend; cr_pipeline.pDynamicState = nullptr; cr_pipeline.layout = layout; cr_pipeline.renderPass = render_pass; cr_pipeline.subpass = 0; cr_pipeline.basePipelineHandle = VK_NULL_HANDLE; cr_pipeline.basePipelineIndex = -1; VkPipeline pipeline; VK_CALL_CHECKED(vkCreateGraphicsPipelines, dev.get_device(), VK_NULL_HANDLE, 1, &cr_pipeline, nullptr, &pipeline); std::vector<VkFramebuffer> fbufs; for (auto view : display.image_views) { VkFramebufferCreateInfo cr_fbuf = {}; cr_fbuf.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; cr_fbuf.renderPass = render_pass; cr_fbuf.attachmentCount = 1; cr_fbuf.pAttachments = &view; cr_fbuf.width = display.extent.width; cr_fbuf.height = display.extent.height; cr_fbuf.layers = 1; VkFramebuffer fbuf; VK_CALL_CHECKED(vkCreateFramebuffer, dev.get_device(), &cr_fbuf, nullptr, &fbuf); fbufs.push_back(fbuf); } VkCommandPoolCreateInfo cr_pool = {}; cr_pool.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; cr_pool.queueFamilyIndex = info.second.graphics_fam; cr_pool.flags = 0; VkCommandPool pool; VK_CALL_CHECKED(vkCreateCommandPool, dev.get_device(), &cr_pool, nullptr, &pool); std::vector<VkCommandBuffer> cmd_bufs(fbufs.size()); VkCommandBufferAllocateInfo cr_cmd_bufs = {}; cr_cmd_bufs.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; cr_cmd_bufs.commandPool = pool; cr_cmd_bufs.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; cr_cmd_bufs.commandBufferCount = static_cast<uint32_t>(cmd_bufs.size()); VK_CALL_CHECKED(vkAllocateCommandBuffers, dev.get_device(), &cr_cmd_bufs, cmd_bufs.data()); for (size_t i = 0; i < cmd_bufs.size(); i++) { auto cmd_buf = cmd_bufs[i]; auto fbuf = fbufs[i]; VkCommandBufferBeginInfo begin_info = {}; begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; begin_info.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; begin_info.pInheritanceInfo = nullptr; vkBeginCommandBuffer(cmd_buf, &begin_info); VkRenderPassBeginInfo cmd_render = {}; cmd_render.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; cmd_render.renderPass = render_pass; cmd_render.framebuffer = fbuf; cmd_render.renderArea.offset = { 0, 0 }; cmd_render.renderArea.extent = display.extent; VkClearValue clear_color = {{{ 0.0f, 0.0f, 0.0f, 1.0f }}}; cmd_render.clearValueCount = 1; cmd_render.pClearValues = &clear_color; vkCmdBeginRenderPass(cmd_buf, &cmd_render, VK_SUBPASS_CONTENTS_INLINE); vkCmdBindPipeline(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); vkCmdDraw(cmd_buf, 3, 1, 0, 0); vkCmdEndRenderPass(cmd_buf); VK_CALL_CHECKED(vkEndCommandBuffer, cmd_buf); VkSemaphoreCreateInfo cr_sem = {}; cr_sem.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; VkSemaphore sem_image_ready; VkSemaphore sem_render_done; VK_CALL_CHECKED(vkCreateSemaphore, dev.get_device(), &cr_sem, nullptr, &sem_image_ready); VK_CALL_CHECKED(vkCreateSemaphore, dev.get_device(), &cr_sem, nullptr, &sem_render_done); uint32_t img_idx = 0; VK_CALL_CHECKED(vkAcquireNextImageKHR, dev.get_device(), display.swapchain, std::numeric_limits<uint64_t>::max(), sem_image_ready, VK_NULL_HANDLE, &img_idx); VkSubmitInfo submit = {}; submit.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit.waitSemaphoreCount = 1; submit.pWaitSemaphores = &sem_image_ready; VkPipelineStageFlags mask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; submit.pWaitDstStageMask = &mask; submit.commandBufferCount = 1; submit.pCommandBuffers = &cmd_bufs[img_idx]; submit.signalSemaphoreCount = 1; submit.pSignalSemaphores = &sem_render_done; VK_CALL_CHECKED(vkQueueSubmit, dev.get_queue(0), 1, &submit, VK_NULL_HANDLE); VkPresentInfoKHR present_info = {}; present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; present_info.waitSemaphoreCount = 1; present_info.pWaitSemaphores = &sem_render_done; present_info.swapchainCount = 1; present_info.pSwapchains = &display.swapchain; present_info.pImageIndices = &img_idx; present_info.pResults = nullptr; vkQueuePresentKHR(dev.get_queue(0), &present_info); vkQueueWaitIdle(dev.get_queue(0)); vkDeviceWaitIdle(dev.get_device()); } }