← 返回作品展示

Vulkanite — 自研 GPU 驱动框架

VulkanSPIR-VCGPU 架构

Vulkanite 是一个从零实现的 Vulkan 1.3 兼容 GPU 用户态驱动框架,涵盖 SPIR-V 着色器编译管线、命令缓冲区调度、描述符集管理与显存分配器。项目深入 GPU 驱动底层,展示了对现代图形 API 和 GPU 架构的深刻理解。

一、驱动架构概览

Vulkanite 采用分层架构:应用层(Vulkan API 入口)→ 命令流层(命令缓冲编码)→ 编译器层(SPIR-V → 原生 ISA)→ 内存管理层(显存分配与虚拟化)→ 内核接口层(ioctl 与内核驱动通信)。

typedef struct VulkaniteDriver {
    VkPhysicalDeviceProperties properties;
    VkPhysicalDeviceMemoryProperties memory_props;
    VkPhysicalDeviceFeatures features;

    // 命令缓冲区环形队列
    CommandRingBuffer* cmd_ring;

    // 着色器编译器
    SpirvCompiler* compiler;

    // 显存分配器
    GpuMemoryAllocator* vram_alloc;

    // 描述符堆
    DescriptorHeap* desc_heap;

    // 内核驱动文件描述符
    int drm_fd;
} VulkaniteDriver;

二、SPIR-V 着色器编译管线

实现完整的 SPIR-V 二进制解析器,将 SPIR-V 模块转换为 GPU 原生 ISA。支持顶点着色器、片段着色器和计算着色器的编译,包含死代码消除、常量折叠和循环展开等优化 Pass。

typedef struct SpirvCompiler {
    SpirvModule* module;
    IsaEmitter* emitter;
    RegisterAllocator* reg_alloc;
} SpirvCompiler;

// SPIR-V OpCode 到原生 ISA 的转换
static void translate_spirv_instruction(
    SpirvCompiler* compiler, SpvOp opcode,
    const uint32_t* operands, uint32_t operand_count)
{
    switch (opcode) {
    case SpvOpFMul:
        emit_fmul(compiler->emitter,
            operands[0], operands[1], operands[2]);
        break;
    case SpvOpFAdd:
        emit_fadd(compiler->emitter,
            operands[0], operands[1], operands[2]);
        break;
    case SpvOpVectorShuffle:
        emit_vector_shuffle(compiler->emitter,
            operands, operand_count);
        break;
    case SpvOpImageSampleImplicitLod:
        emit_texture_sample(compiler->emitter,
            operands, operand_count);
        break;
    }
}

三、命令缓冲区调度器

实现 Vulkan 命令缓冲区的录制与提交。命令缓冲区被编码为 GPU 可执行的命令流,通过环形缓冲区提交到 GPU 命令处理器。支持主命令缓冲区和辅助命令缓冲区的复用。

typedef struct CommandRingBuffer {
    uint32_t* base;           // 映射的 GPU 可见内存
    uint32_t size;            // 环形缓冲区大小(字节)
    uint32_t write_ptr;       // CPU 写入位置
    volatile uint32_t* read_ptr;  // GPU 读取位置(GPU 可写)
} CommandRingBuffer;

VkResult vkBeginCommandBuffer(VkCommandBuffer cmd_buf,
    const VkCommandBufferBeginInfo* begin_info)
{
    CommandBuffer* cb = (CommandBuffer*)cmd_buf;
    cb->state = COMMAND_BUFFER_RECORDING;
    cb->cmd_stream = create_command_stream(64 * 1024);

    if (begin_info->flags & VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) {
        cb->flags |= CB_ONE_TIME_SUBMIT;
    }
    return VK_SUCCESS;
}

VkResult vkQueueSubmit(VkQueue queue, uint32_t count,
    const VkSubmitInfo* submits, VkFence fence)
{
    for (uint32_t i = 0; i < count; i++) {
        CommandBuffer* cb = (CommandBuffer*)submits[i].pCommandBuffers[0];
        encode_indirect_buffer_packet(queue->cmd_ring, cb->cmd_stream);
    }
    ring_doorbell(queue->doorbell_offset);
    return VK_SUCCESS;
}

四、显存分配器

实现基于 Buddy Allocator 的显存管理,支持不同内存类型(VRAM、GART、系统内存)的分配策略。使用稀疏纹理技术支持超大纹理的虚拟化管理。

typedef struct GpuMemoryAllocator {
    BuddyAllocator vram_buddy;    // 专用显存
    BuddyAllocator gart_buddy;    // GART 可交换内存
    uint64_t total_vram;
    uint64_t available_vram;
} GpuMemoryAllocator;

VkResult vkAllocateMemory(VkDevice device,
    const VkMemoryAllocateInfo* alloc_info,
    VkDeviceMemory* memory)
{
    GpuMemoryAllocator* alloc = device->vram_alloc;
    uint64_t size = alloc_info->allocationSize;
    uint32_t type_index = alloc_info->memoryTypeIndex;

    uint64_t offset;
    if (type_index == MEMORY_TYPE_VRAM) {
        offset = buddy_alloc(&alloc->vram_buddy, size, 4096);
    } else {
        offset = buddy_alloc(&alloc->gart_buddy, size, 4096);
    }

    *memory = create_device_memory(device, offset, size, type_index);
    return VK_SUCCESS;
}

五、描述符集管理

实现 Vulkan 描述符集的分配与更新,支持 Uniform Buffer、Storage Buffer、Sampled Image 和 Storage Image 等描述符类型。使用描述符堆减少分配开销。

Vulkanite 展示了 GPU 驱动开发的核心技术栈,从 SPIR-V 编译到命令调度再到显存管理,是理解现代 GPU 工作原理的绝佳实践项目。

← 返回作品展示