从交换链呈现会引发段错误
Presenting from swapchain induces segfault
目前正在尝试创建一个主循环来呈现来自交换链的图像:
void loop(struct Context *ctx, void(*loopfn)(struct Context*)) {
VkQueue queue;
vkGetDeviceQueue(ctx->objects.device, 0, 0, &queue);
while (!glfwWindowShouldClose(ctx->window)) {
VkResult fenceStatus = vkGetFenceStatus(ctx->objects.device, ctx->objects.fence);
if (fenceStatus == VK_SUCCESS) {
// Reset fence and command buffer
if (vkQueuePresentKHR(queue, &ctx->objects.presentInfo) != VK_SUCCESS) {
fprintf(stderr, "Failed to present image\n");
break;
}
loopfn(ctx);
} else if (fenceStatus == VK_ERROR_DEVICE_LOST) {
fprintf(stderr, "Device lost\n");
break;
}
}
}
void loopfn(struct Context *ctx) {
// Clear color image
}
int main() {
struct Context *ctx = init(500, 500, "Test");
if (!ctx)
return -1;
loop(ctx, loopfn);
deinit(ctx);
return 0;
}
但是,我似乎以不正确的方式使用了交换链扩展,这转化为来自验证层的以下错误消息,紧接着是分段错误:
UNASSIGNED-CoreValidation-DrawState-SwapchainInvalidImage(ERROR / SPEC): msgNum: 0 - vkQueuePresentKHR: Swapchain image index too large (0). There are only 0 images in this swapchain.
Objects: 1
[0] 0x7, type: 1000001000, name: (null)
Validation(ERROR): msg_code: 0: [ UNASSIGNED-CoreValidation-DrawState-SwapchainInvalidImage ] Object: 0x7 (Type = 27) | vkQueuePresentKHR: Swapchain image index too large (0). There are only 0 images in this swapchain.
我的 init
函数很长,我不知道把它放在这里是否会有用,但我实际上正在做的(但不起作用)是:
创建交换链如下:
VkSwapchainCreateInfoKHR swapchainInfo =
{ .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR
, .pNext = NULL
, .flags = 0x00000000
, .surface = ctx->objects.surface
, .minImageCount = surfaceCapabilities.minImageCount
, .imageFormat = pSurfaceFormats[0].format
, .imageColorSpace = pSurfaceFormats[0].colorSpace
, .imageExtent = surfaceCapabilities.currentExtent
, .imageArrayLayers = 1
, .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT
, .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE
, .queueFamilyIndexCount = 1
, .pQueueFamilyIndices = NULL
, .preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR
, .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR
, .presentMode = VK_PRESENT_MODE_MAILBOX_KHR
, .clipped = VK_TRUE
, .oldSwapchain = VK_NULL_HANDLE
};
if (vkCreateSwapchainKHR(ctx->objects.device, &swapchainInfo, NULL, &ctx->objects.swapchain) != VK_SUCCESS)
goto failure;
正在创建彩色图像和深度图像。两个 VkImageCreateInfo
结构都有一个指向以下结构的指针作为它们的 pNext
值:
VkImageSwapchainCreateInfoKHR swapchainImageInfo =
{ .sType = VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR
, .pNext = NULL
, .swapchain = ctx->objects.swapchain
};
为两个图像分配内存,然后尝试将它们绑定到交换链,如下所示:
VkBindImageMemorySwapchainInfoKHR colorSwapchainBindInfo =
{ .sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR
, .pNext = NULL
, .swapchain = ctx->objects.swapchain
, .imageIndex = 0
};
VkBindImageMemoryInfo colorMemBindInfo =
{ .sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO
, .pNext = &colorSwapchainBindInfo
, .image = ctx->objects.colorImage
, .memory = ctx->objects.colorMemory
, .memoryOffset = 0
};
// Pretty much the same thing for the depth image
VkBindImageMemoryInfo memBindInfos[] = { colorMemBindInfo, depthMemBindInfo };
if (vkBindImageMemory2(ctx->objects.device, 2, memBindInfos) != VK_SUCCESS)
goto failure;
执行两个所需的图像布局转换(从 VK_IMAGE_LAYOUT_UNDEFINED
到 VK_IMAGE_LAYOUT_GENERAL
)
- 创建两个需要的图像视图,一个帧缓冲区和一个
VkPresentInfoKHR
结构
我想知道我做错了什么以及如何解决它。随时询问任何额外的精度。
编辑: 我使用的实例扩展是 VK_KHR_surface
和 VK_KHR_xcb_surface
.
uint32_t count;
const char **extensions = glfwGetRequiredInstanceExtensions(&count);
VkInstanceCreateInfo instanceInfo =
{ .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO
, .pNext = NULL
, .flags = 0x00000000
, .pApplicationInfo = NULL
, .enabledLayerCount = 0
, .ppEnabledLayerNames = NULL
, .enabledExtensionCount = count
, .ppEnabledExtensionNames = extensions
};
我使用的唯一设备扩展是 VK_KHR_swapchain
:
const char *deviceExtensions[] = { "VK_KHR_swapchain" };
VkDeviceCreateInfo deviceInfo =
{ .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO
, .pNext = NULL
, .flags = 0x00000000
, .queueCreateInfoCount = 1
, .pQueueCreateInfos = &queueInfo
, .enabledLayerCount = 0
, .ppEnabledLayerNames = NULL
, .enabledExtensionCount = sizeof(deviceExtensions) / sizeof(deviceExtensions[0])
, .ppEnabledExtensionNames = deviceExtensions
, .pEnabledFeatures = NULL
};
对,所以这是一个 XY 问题。似乎您使用的 Vulkan 功能不适合您的情况。即 VkImageSwapchainCreateInfoKHR
和 VkBindImageMemorySwapchainInfoKHR
。根据他们的描述,它们仅对 GPU 组有用。但根据您的评论,您只想以旧的无聊方式使用交换链。
Swapchain 需要以特殊方式创建自己的镜像。这通常是对 Vulkan Swapchain 抽象的底层系统(例如 X、Wayland、GDI 或 DXGI)的限制。因此,您不会尝试自己创建这些图像(也不会尝试将内存绑定到它们),而是让 vkCreateSwapchain
为您完成。
顺便说一句,Vulkan 交换链对深度图像没有用处。全是彩图。
因此,当交换链 vkCreate
d 时,您可以使用 vkGetSwapchainImagesKHR
获得它为您创建的图像。用法类似于:
uint32_t count;
VkResult errco = vkGetSwapchainImagesKHR( dev, swpch, &count, nullptr );
if( errco ) throw "error";
std::vector<VkImage> swapchainImages( count );
errco = vkGetSwapchainImagesKHR( dev, swpch, &count, swapchainImages.data() );
if( errco ) throw "error";
注意:理论上您获得的图像可能比使用 vkCreateSwapchain
请求的图像更多。
这些图像与 vkCreateImage
定期获得的 VkImage
一样好,除了两点:
- 你不能
vkDestroyImage
他们;当您调用 vkDestroySwapchainKHR
. 时,它们会被销毁
- 它们已经绑定了内存(因此您不需要,也不允许将内存绑定到这些图像)。
介绍到此为止,解决眼前的问题。
.queueFamilyIndexCount = 1
.pQueueFamilyIndices = NULL
这会在 vkCreateSwapchainKHR 处造成段错误。
目前正在尝试创建一个主循环来呈现来自交换链的图像:
void loop(struct Context *ctx, void(*loopfn)(struct Context*)) {
VkQueue queue;
vkGetDeviceQueue(ctx->objects.device, 0, 0, &queue);
while (!glfwWindowShouldClose(ctx->window)) {
VkResult fenceStatus = vkGetFenceStatus(ctx->objects.device, ctx->objects.fence);
if (fenceStatus == VK_SUCCESS) {
// Reset fence and command buffer
if (vkQueuePresentKHR(queue, &ctx->objects.presentInfo) != VK_SUCCESS) {
fprintf(stderr, "Failed to present image\n");
break;
}
loopfn(ctx);
} else if (fenceStatus == VK_ERROR_DEVICE_LOST) {
fprintf(stderr, "Device lost\n");
break;
}
}
}
void loopfn(struct Context *ctx) {
// Clear color image
}
int main() {
struct Context *ctx = init(500, 500, "Test");
if (!ctx)
return -1;
loop(ctx, loopfn);
deinit(ctx);
return 0;
}
但是,我似乎以不正确的方式使用了交换链扩展,这转化为来自验证层的以下错误消息,紧接着是分段错误:
UNASSIGNED-CoreValidation-DrawState-SwapchainInvalidImage(ERROR / SPEC): msgNum: 0 - vkQueuePresentKHR: Swapchain image index too large (0). There are only 0 images in this swapchain.
Objects: 1
[0] 0x7, type: 1000001000, name: (null)
Validation(ERROR): msg_code: 0: [ UNASSIGNED-CoreValidation-DrawState-SwapchainInvalidImage ] Object: 0x7 (Type = 27) | vkQueuePresentKHR: Swapchain image index too large (0). There are only 0 images in this swapchain.
我的 init
函数很长,我不知道把它放在这里是否会有用,但我实际上正在做的(但不起作用)是:
创建交换链如下:
VkSwapchainCreateInfoKHR swapchainInfo = { .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR , .pNext = NULL , .flags = 0x00000000 , .surface = ctx->objects.surface , .minImageCount = surfaceCapabilities.minImageCount , .imageFormat = pSurfaceFormats[0].format , .imageColorSpace = pSurfaceFormats[0].colorSpace , .imageExtent = surfaceCapabilities.currentExtent , .imageArrayLayers = 1 , .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT , .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE , .queueFamilyIndexCount = 1 , .pQueueFamilyIndices = NULL , .preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR , .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR , .presentMode = VK_PRESENT_MODE_MAILBOX_KHR , .clipped = VK_TRUE , .oldSwapchain = VK_NULL_HANDLE }; if (vkCreateSwapchainKHR(ctx->objects.device, &swapchainInfo, NULL, &ctx->objects.swapchain) != VK_SUCCESS) goto failure;
正在创建彩色图像和深度图像。两个
VkImageCreateInfo
结构都有一个指向以下结构的指针作为它们的pNext
值:VkImageSwapchainCreateInfoKHR swapchainImageInfo = { .sType = VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR , .pNext = NULL , .swapchain = ctx->objects.swapchain };
为两个图像分配内存,然后尝试将它们绑定到交换链,如下所示:
VkBindImageMemorySwapchainInfoKHR colorSwapchainBindInfo = { .sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR , .pNext = NULL , .swapchain = ctx->objects.swapchain , .imageIndex = 0 }; VkBindImageMemoryInfo colorMemBindInfo = { .sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO , .pNext = &colorSwapchainBindInfo , .image = ctx->objects.colorImage , .memory = ctx->objects.colorMemory , .memoryOffset = 0 }; // Pretty much the same thing for the depth image VkBindImageMemoryInfo memBindInfos[] = { colorMemBindInfo, depthMemBindInfo }; if (vkBindImageMemory2(ctx->objects.device, 2, memBindInfos) != VK_SUCCESS) goto failure;
执行两个所需的图像布局转换(从
VK_IMAGE_LAYOUT_UNDEFINED
到VK_IMAGE_LAYOUT_GENERAL
)- 创建两个需要的图像视图,一个帧缓冲区和一个
VkPresentInfoKHR
结构
我想知道我做错了什么以及如何解决它。随时询问任何额外的精度。
编辑: 我使用的实例扩展是 VK_KHR_surface
和 VK_KHR_xcb_surface
.
uint32_t count;
const char **extensions = glfwGetRequiredInstanceExtensions(&count);
VkInstanceCreateInfo instanceInfo =
{ .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO
, .pNext = NULL
, .flags = 0x00000000
, .pApplicationInfo = NULL
, .enabledLayerCount = 0
, .ppEnabledLayerNames = NULL
, .enabledExtensionCount = count
, .ppEnabledExtensionNames = extensions
};
我使用的唯一设备扩展是 VK_KHR_swapchain
:
const char *deviceExtensions[] = { "VK_KHR_swapchain" };
VkDeviceCreateInfo deviceInfo =
{ .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO
, .pNext = NULL
, .flags = 0x00000000
, .queueCreateInfoCount = 1
, .pQueueCreateInfos = &queueInfo
, .enabledLayerCount = 0
, .ppEnabledLayerNames = NULL
, .enabledExtensionCount = sizeof(deviceExtensions) / sizeof(deviceExtensions[0])
, .ppEnabledExtensionNames = deviceExtensions
, .pEnabledFeatures = NULL
};
对,所以这是一个 XY 问题。似乎您使用的 Vulkan 功能不适合您的情况。即 VkImageSwapchainCreateInfoKHR
和 VkBindImageMemorySwapchainInfoKHR
。根据他们的描述,它们仅对 GPU 组有用。但根据您的评论,您只想以旧的无聊方式使用交换链。
Swapchain 需要以特殊方式创建自己的镜像。这通常是对 Vulkan Swapchain 抽象的底层系统(例如 X、Wayland、GDI 或 DXGI)的限制。因此,您不会尝试自己创建这些图像(也不会尝试将内存绑定到它们),而是让 vkCreateSwapchain
为您完成。
顺便说一句,Vulkan 交换链对深度图像没有用处。全是彩图。
因此,当交换链 vkCreate
d 时,您可以使用 vkGetSwapchainImagesKHR
获得它为您创建的图像。用法类似于:
uint32_t count;
VkResult errco = vkGetSwapchainImagesKHR( dev, swpch, &count, nullptr );
if( errco ) throw "error";
std::vector<VkImage> swapchainImages( count );
errco = vkGetSwapchainImagesKHR( dev, swpch, &count, swapchainImages.data() );
if( errco ) throw "error";
注意:理论上您获得的图像可能比使用 vkCreateSwapchain
请求的图像更多。
这些图像与 vkCreateImage
定期获得的 VkImage
一样好,除了两点:
- 你不能
vkDestroyImage
他们;当您调用vkDestroySwapchainKHR
. 时,它们会被销毁
- 它们已经绑定了内存(因此您不需要,也不允许将内存绑定到这些图像)。
介绍到此为止,解决眼前的问题。
.queueFamilyIndexCount = 1
.pQueueFamilyIndices = NULL
这会在 vkCreateSwapchainKHR 处造成段错误。