You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

vkCreateDevice调用触发段错误,共享队列族配置问题求助

问题分析与修复方案

你的代码触发段错误主要有三个核心问题,结合你的vulkaninfo输出和代码逻辑,逐一修复如下:

1. 优先级数组的生命周期问题

你在循环内部定义的f32 queue_priority[32][32]是栈上的局部变量,每次循环迭代结束后这块内存就会被销毁,而pQueuePriorities指向的是这块无效内存。当vkCreateDevice访问这些野指针时,直接触发段错误。

修复:把优先级数组移到循环外部,确保其生命周期覆盖vkCreateDevice调用:

// 移到循环外,确保内存有效
f32 queue_priorities[32][32];
memset(queue_priorities, 0, sizeof(queue_priorities)); // 初始化所有优先级为0.0f

2. 队列族索引处理的逻辑错误

  • 数组越界:计算shared_queues的循环中,j < index_count时访问indices[j+1]会越界(j最大为index_count-1,j+1超出数组范围),导致读取垃圾数据,错误计算共享队列数量。
  • 重复创建队列族信息:Vulkan要求每个队列族只需要一个VkDeviceQueueCreateInfo,即使要从该族创建多个队列,也只需在同一个Info中设置queueCount即可,你的代码为同一个队列族创建了多个重复的Info,违反API规范。

修复:先收集并去重需要的队列族索引,再为每个唯一队列族创建单个Info:

// 收集需要的唯一队列族索引,避免重复
u32 unique_queue_families[32];
u32 unique_count = 0;

// 添加图形队列族
unique_queue_families[unique_count++] = context->device.graphics_queue_index;

// 添加显示队列族(如果不与图形共享且未存在)
if (!present_shares_graphics_queue) {
    b8 exists = false;
    for (u32 i = 0; i < unique_count; i++) {
        if (unique_queue_families[i] == context->device.present_queue_index) { exists = true; break; }
    }
    if (!exists) unique_queue_families[unique_count++] = context->device.present_queue_index;
}

// 添加传输队列族(如果不与图形共享且未存在)
if (!transfer_shares_graphics_queue) {
    b8 exists = false;
    for (u32 i = 0; i < unique_count; i++) {
        if (unique_queue_families[i] == context->device.transfer_queue_index) { exists = true; break; }
    }
    if (!exists) unique_queue_families[unique_count++] = context->device.transfer_queue_index;
}

3. 队列创建信息数量错误

你原来的queue_quantity是累加共享队列数得到的,等于index_count,但实际需要传递给vkCreateDevice的是唯一队列族的数量,也就是unique_count,否则驱动会处理多余的无效队列创建信息。

修复:填充队列创建信息时,基于唯一队列族列表:

VkDeviceQueueCreateInfo queue_create_infos[32];
for (u32 i = 0; i < unique_count; i++) {
    u32 family_idx = unique_queue_families[i];
    u32 queue_count = 0;

    // 统计当前队列族需要创建的队列数
    if (family_idx == context->device.graphics_queue_index) queue_count++;
    if (family_idx == context->device.present_queue_index && !present_shares_graphics_queue) queue_count++;
    if (family_idx == context->device.transfer_queue_index && !transfer_shares_graphics_queue) queue_count++;

    // 填充队列创建信息
    queue_create_infos[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
    queue_create_infos[i].pNext = NULL;
    queue_create_infos[i].flags = 0;
    queue_create_infos[i].queueFamilyIndex = family_idx;
    queue_create_infos[i].queueCount = queue_count;
    queue_create_infos[i].pQueuePriorities = queue_priorities[i];
}

// 创建设备时,队列信息数量设为唯一队列族数量
VkDeviceCreateInfo device_create_info = {VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO};
device_create_info.queueCreateInfoCount = unique_count;
device_create_info.pQueueCreateInfos = queue_create_infos;
// 其他字段保持你的原有代码...

额外提示(结合你的硬件情况)

从vulkaninfo输出看,队列族0只有1个队列,但支持图形、传输、显示操作,队列族1有4个队列,支持计算、传输、显示。如果你的程序不需要大量并行计算,完全可以只使用队列族0的单个队列,同时处理图形、传输、显示任务,这样代码会更简洁,也符合硬件资源限制。

内容的提问来源于stack exchange,提问作者mango

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 23:20:29