调整交换链图像的大小时(由于窗口大小已更改),我出现一些白色闪烁。我真的不明白为什么是这个问题的根源。 仅在将VK_PRESENT_MODE_FIFO_KHR当前模式与我的Intel(R)UHD Graphics 630集成GPU一起使用时才出现此问题,而GeForce GTX 1050则没有此问题。我发现根据GPU的不同行为对Vulkan真的很好奇
也许我想要实现的理想解决方案是拥有一个交换链,该交换链始终保持屏幕的大小,并且在可能的情况下仅对可见部分进行翻转?
这是我的swapchain调整大小代码(远非最佳,因为我重做一些可以避免的操作)。
bool resize_swapchain(VK_Renderer* renderer,Window* window) {
assert(renderer);
VkResult res;
clear_swapchain(renderer);
// Build the swapchain
// Get the list of VkFormats that are supported:
get_enumeration(vkGetPhysicalDeviceSurfaceFormatsKHR,VkSurfaceFormatKHR,surface_formats,"Failed to get physical device surface formats.\n","Found %d surface formats.\n",renderer->physical_device,renderer->surface);
// If the format list includes just one entry of VK_FORMAT_UNDEFINED,// the surface has no preferred format. Otherwise,at least one
// supported format will be returned.
if (surface_formats.size() == 1 && surface_formats[0].format == VK_FORMAT_UNDEFINED) {
renderer->surface_format = VK_FORMAT_B8G8R8A8_UNORM;
} else {
renderer->surface_format = surface_formats[0].format;
}
VkSurfaceCapabilitiesKHR surface_capabilities;
res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(renderer->physical_device,renderer->surface,&surface_capabilities);
if (res != VK_SUCCESS) {
log(globals.logger,Log_Level::error,"Failed to get physical device surface capabilities.\n");
clear_swapchain(renderer);
return false;
}
get_enumeration(vkGetPhysicalDeviceSurfacePresentModesKHR,VkPresentModeKHR,present_modes,"Failed to get physical device surface present modes.\n","Found %d present modes.\n",renderer->surface);
// width and height are either both 0xFFFFFFFF,or both not 0xFFFFFFFF.
if (surface_capabilities.currentExtent.width == 0xFFFFFFFF) {
// If the surface size is undefined,the size is set to
// the size of the images requested.
renderer->swapchain_extent.width = window->size.x;
renderer->swapchain_extent.height = window->size.y;
if (renderer->swapchain_extent.width < surface_capabilities.minImageExtent.width) {
renderer->swapchain_extent.width = surface_capabilities.minImageExtent.width;
} else if (renderer->swapchain_extent.width > surface_capabilities.maxImageExtent.width) {
renderer->swapchain_extent.width = surface_capabilities.maxImageExtent.width;
}
if (renderer->swapchain_extent.height < surface_capabilities.minImageExtent.height) {
renderer->swapchain_extent.height = surface_capabilities.minImageExtent.height;
} else if (renderer->swapchain_extent.height > surface_capabilities.maxImageExtent.height) {
renderer->swapchain_extent.height = surface_capabilities.maxImageExtent.height;
}
} else {
// If the surface size is defined,the swap chain size must match
renderer->swapchain_extent = surface_capabilities.currentExtent;
}
// The FIFO present mode is guaranteed by the spec to be supported
#if defined(FL_PROFILING_MODE)
VkPresentModeKHR swapchain_present_mode = VK_PRESENT_MODE_IMMEDIATE_KHR;
#else
VkPresentModeKHR swapchain_present_mode = VK_PRESENT_MODE_FIFO_KHR;
#endif
// Determine the number of VkImage's to use in the swap chain.
// We need to acquire only 1 presentable image at at time.
// Asking for minImageCount images ensures that we can acquire
// 1 presentable image as long as we present it before attempting
// to acquire another.
uint32_t desired_number_of_swapchain_images = surface_capabilities.minImageCount;
VkSurfaceTransformflagBitsKHR surface_transform;
if (surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) {
surface_transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
} else {
surface_transform = surface_capabilities.currentTransform;
}
// Find a supported composite alpha mode - one of these is guaranteed to be set
VkCompositeAlphaflagBitsKHR composite_alpha_flag = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
// TODO change the order if we want to be able to blend the window of our application with the Windows Desktop
VkCompositeAlphaflagBitsKHR composite_alpha_flags[4] = {
VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,};
for (uint32_t i = 0; i < sizeof(composite_alpha_flags); i++) {
if (surface_capabilities.supportedCompositeAlpha & composite_alpha_flags[i]) {
composite_alpha_flag = composite_alpha_flags[i];
break;
}
}
VkSwapchainCreateInfoKHR swapchain_info = {};
swapchain_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
swapchain_info.pNext = nullptr;
swapchain_info.surface = renderer->surface;
swapchain_info.minImageCount = desired_number_of_swapchain_images;
swapchain_info.imageFormat = renderer->surface_format;
swapchain_info.imageExtent.width = renderer->swapchain_extent.width;
swapchain_info.imageExtent.height = renderer->swapchain_extent.height;
swapchain_info.preTransform = surface_transform;
swapchain_info.compositeAlpha = composite_alpha_flag;
swapchain_info.imageArrayLayers = 1;
swapchain_info.presentMode = swapchain_present_mode;
swapchain_info.oldSwapchain = nullptr;
swapchain_info.clipped = true;
swapchain_info.imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
swapchain_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
swapchain_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
swapchain_info.queueFamilyIndexCount = 0;
swapchain_info.pQueueFamilyIndices = nullptr;
uint32_t queue_family_indices[2] = {(uint32_t)renderer->graphics_queue_family_index,(uint32_t)renderer->present_queue_family_index};
if (renderer->graphics_queue_family_index != renderer->present_queue_family_index) {
// If the graphics and present queues are from different queue families,// we either have to explicitly transfer ownership of images between
// the queues,or we have to create the swapchain with imageSharingMode
// as VK_SHARING_MODE_CONCURRENT
swapchain_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
swapchain_info.queueFamilyIndexCount = 2;
swapchain_info.pQueueFamilyIndices = queue_family_indices;
// TODO @Speedup We may want optimize this by using VK_SHARING_MODE_EXCLUSIVE and be explicit about transfert ownership
}
res = vkCreateSwapchainKHR(renderer->device,&swapchain_info,nullptr,&renderer->swapchain);
if (res != VK_SUCCESS) {
log(globals.logger,"Failed to create the swapchain.\n");
clear_swapchain(renderer);
return false;
}
log(globals.logger,Log_Level::verbose,"Swapchain created with size (%d,%d).\n",swapchain_info.imageExtent.width,swapchain_info.imageExtent.height);
get_enumeration(vkGetSwapchainImagesKHR,VkImage,swapchain_images,"Failed to get swapchain images.\n","Found %d swapchain images.\n",renderer->device,renderer->swapchain);
renderer->swapchain_buffers.resize(swapchain_images.size());
for (uint32_t i = 0; i < swapchain_images.size(); i++) {
renderer->swapchain_buffers[i].image = swapchain_images[i];
}
for (uint32_t i = 0; i < swapchain_images.size(); i++) {
VkImageViewCreateInfo color_image_view = {};
color_image_view.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
color_image_view.pNext = nullptr;
color_image_view.flags = 0;
color_image_view.image = renderer->swapchain_buffers[i].image;
color_image_view.viewType = VK_IMAGE_VIEW_TYPE_2D;
color_image_view.format = renderer->surface_format;
color_image_view.components.r = VK_COMPONENT_SWIZZLE_R;
color_image_view.components.g = VK_COMPONENT_SWIZZLE_G;
color_image_view.components.b = VK_COMPONENT_SWIZZLE_B;
color_image_view.components.a = VK_COMPONENT_SWIZZLE_A;
color_image_view.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
color_image_view.subresourceRange.baseMipLevel = 0;
color_image_view.subresourceRange.levelCount = 1;
color_image_view.subresourceRange.baseArrayLayer = 0;
color_image_view.subresourceRange.layerCount = 1;
res = vkCreateImageView(renderer->device,&color_image_view,&renderer->swapchain_buffers[i].view);
if (res != VK_SUCCESS) {
log(globals.logger,"Failed to create image view.\n");
clear_swapchain(renderer);
return false;
}
log(globals.logger,"Image view %d created.\n",i);
}
// Build the depth buffer
VkImageCreateInfo image_info = {};
const VkFormat depth_format = VK_FORMAT_D32_SFLOAT;
VkFormatProperties format_properties;
bool found_memory_type_index;
vkGetPhysicalDeviceFormatProperties(renderer->physical_device,depth_format,&format_properties);
if (format_properties.linearTilingFeatures & VK_FORMAT_FEATURE_DEpth_STENCIL_ATTACHMENT_BIT) {
image_info.tiling = VK_IMAGE_TILING_LINEAR;
} else if (format_properties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEpth_STENCIL_ATTACHMENT_BIT) {
image_info.tiling = VK_IMAGE_TILING_OPTIMAL;
} else {
// @TODO choose an other format?
log(globals.logger,"VK_FORMAT_D32_SFLOAT Unsupported.\n");
clear_swapchain(renderer);
return false;
}
image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
image_info.pNext = nullptr;
image_info.imageType = VK_IMAGE_TYPE_2D;
image_info.format = depth_format;
image_info.extent.width = renderer->swapchain_extent.width;
image_info.extent.height = renderer->swapchain_extent.height;
image_info.extent.depth = 1;
image_info.mipLevels = 1;
image_info.arrayLayers = 1;
image_info.samples = renderer->sample_count_flag;
image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
image_info.usage = VK_IMAGE_USAGE_DEpth_STENCIL_ATTACHMENT_BIT;
image_info.queueFamilyIndexCount = 0;
image_info.pQueueFamilyIndices = nullptr;
image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
image_info.flags = 0;
VkMemoryAllocateInfo memory_allocation_info = {};
memory_allocation_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
memory_allocation_info.pNext = nullptr;
memory_allocation_info.allocationSize = 0;
memory_allocation_info.memoryTypeIndex = 0;
VkImageViewCreateInfo view_info = {};
view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
view_info.pNext = nullptr;
view_info.image = nullptr;
view_info.format = depth_format;
view_info.components.r = VK_COMPONENT_SWIZZLE_R;
view_info.components.g = VK_COMPONENT_SWIZZLE_G;
view_info.components.b = VK_COMPONENT_SWIZZLE_B;
view_info.components.a = VK_COMPONENT_SWIZZLE_A;
view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEpth_BIT;
view_info.subresourceRange.baseMipLevel = 0;
view_info.subresourceRange.levelCount = 1;
view_info.subresourceRange.baseArrayLayer = 0;
view_info.subresourceRange.layerCount = 1;
view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
view_info.flags = 0;
VkMemoryRequirements memory_requirements;
renderer->depth_buffer.format = depth_format;
/* Create image */
res = vkCreateImage(renderer->device,&image_info,&renderer->depth_buffer.image);
if (res != VK_SUCCESS) {
log(globals.logger,"Failed to create the depth image.\n");
clear_swapchain(renderer);
return false;
}
vkGetImageMemoryRequirements(renderer->device,renderer->depth_buffer.image,&memory_requirements);
memory_allocation_info.allocationSize = memory_requirements.size;
/* Use the memory properties to determine the type of memory required */
found_memory_type_index = memory_type_from_properties(renderer,memory_requirements.memoryTypeBits,VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,&memory_allocation_info.memoryTypeIndex);
if (!found_memory_type_index) {
log(globals.logger,"Failed to find memory type to allocate the depth image.\n");
clear_swapchain(renderer);
return false;
}
/* Allocate memory */
res = vkAllocateMemory(renderer->device,&memory_allocation_info,&renderer->depth_buffer.memory);
if (res != VK_SUCCESS) {
log(globals.logger,"Failed to create memory for depth image.\n");
clear_swapchain(renderer);
return false;
}
/* Bind memory */
res = vkBindImageMemory(renderer->device,renderer->depth_buffer.memory,0);
if (res != VK_SUCCESS) {
log(globals.logger,"Failed to bind the depth image memory.\n");
clear_swapchain(renderer);
return false;
}
/* Create image view */
view_info.image = renderer->depth_buffer.image;
res = vkCreateImageView(renderer->device,&view_info,&renderer->depth_buffer.view);
if (res != VK_SUCCESS) {
log(globals.logger,"Failed to create the depth image view.\n");
clear_swapchain(renderer);
return false;
}
log(globals.logger,"Depth buffer created.\n");
for (size_t i = 0; i < renderer->scenes.size(); i++) {
swapchain_resized(renderer->scenes[i],renderer->swapchain_extent.width,renderer->swapchain_extent.height);
}
return true;
}
编辑:也许我的问题与我如何将渲染图像提交到交换链或图像获取有关。
for (size_t i = 0; i < scene->meshes.size(); i++) {
draw_mesh(scene->meshes[i]);
}
// End the Render pass
vkCmdEndRenderPass(scene->renderer->graphical_command_buffer);
// End command buffer
{
res = vkEndCommandBuffer(scene->renderer->graphical_command_buffer);
}
// Execute queue command buffer
{
/* Queue the command buffer for execution */
const VkCommandBuffer command_buffers[] = {scene->renderer->graphical_command_buffer};
VkFenceCreateInfo fence_create_info;
VkFence draw_fence;
fence_create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
fence_create_info.pNext = nullptr;
fence_create_info.flags = 0;
vkCreateFence(scene->renderer->device,&fence_create_info,&draw_fence);
VkPipelinestageflags pipe_stage_flags = VK_PIpelINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkSubmitInfo submit_info[1] = {};
submit_info[0].pNext = nullptr;
submit_info[0].sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info[0].waitSemaphoreCount = 1;
submit_info[0].pWaitSemaphores = &scene->image_acquired_semaphore;
submit_info[0].pWaitDstStageMask = &pipe_stage_flags;
submit_info[0].commandBufferCount = 1;
submit_info[0].pCommandBuffers = command_buffers;
submit_info[0].signalSemaphoreCount = 0;
submit_info[0].pSignalSemaphores = nullptr;
/* Queue the command buffer for execution */
res = vkQueueSubmit(scene->renderer->graphics_queue,1,submit_info,draw_fence);
assert(res == VK_SUCCESS);
/* Now present the image in the window */
VkPresentInfoKHR present;
present.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
present.pNext = nullptr;
present.swapchainCount = 1;
present.pSwapchains = &scene->renderer->swapchain;
present.pImageIndices = &scene->current_buffer;
present.pWaitSemaphores = nullptr;
present.waitSemaphoreCount = 0;
present.pResults = nullptr;
/* Make sure command buffer is finished before presenting */
do {
res = vkWaitForFences(scene->renderer->device,&draw_fence,VK_TRUE,scene->renderer->draw_fence_timeout_us);
} while (res == VK_TIMEOUT);
assert(res == VK_SUCCESS);
res = vkQueuePresentKHR(scene->renderer->present_queue,&present);
assert(res == VK_SUCCESS);
vkDestroyFence(scene->renderer->device,draw_fence,nullptr);
}
在vulkan-tutorial.com上,我们还应该使用swapchain(https://vulkan-tutorial.com/Drawing_a_triangle/Swap_chain_recreation)重新创建命令缓冲区,这真的是强制性的吗?