simple_vulkan

Cross-Platform GPU Compute for Eiffel via Vulkan

v1.0.0 MIT Vulkan 1.3

Overview

simple_vulkan provides GPU compute capabilities through the Vulkan API, enabling high-performance parallel computation on modern GPUs. Designed for compute-intensive tasks like SDF ray marching, it achieves 63 FPS at 4K resolution on supported hardware.

Supports NVIDIA, AMD, and Intel GPUs with automatic device selection that prioritizes discrete GPUs over integrated graphics.

Part of the Simple Eiffel ecosystem.

Quick Start

Prerequisites

  1. Install Vulkan SDK
  2. Set the environment variable:
    set SIMPLE_EIFFEL=D:\prod

Installation

  1. Build the C library (one-time):
    cd D:\prod\simple_vulkan
    build_clib.bat
  2. Add to your ECF file:
    <library name="simple_vulkan" location="$SIMPLE_EIFFEL/simple_vulkan/simple_vulkan.ecf"/>

Basic Usage

local
    vk: SIMPLE_VULKAN
    ctx: VULKAN_CONTEXT
do
    create vk
    ctx := vk.create_context

    if ctx.is_valid then
        print ("GPU: " + ctx.device_name)
        print ("Discrete: " + ctx.is_discrete_gpu.out)
        ctx.dispose
    end
end

Key Features

Cross-Platform GPU

Works on NVIDIA, AMD, and Intel GPUs via Vulkan API.

Automatic Device Selection

Prioritizes discrete GPUs over integrated for maximum performance.

Buffer Management

Create, upload, and download GPU buffers with simple API.

Compute Shaders

Load and execute SPIR-V compute shaders for parallel computation.

Image Output

Create GPU images for rendering results and visualization.

Push Constants

Fast-changing uniforms for real-time applications.

Vendor Detection

Query GPU vendor for vendor-specific optimizations.

API Reference

SIMPLE_VULKAN (Facade)

Main entry point for Vulkan operations.

create_context: VULKAN_CONTEXT

Create a new Vulkan context with automatic GPU selection.

create_buffer (ctx: VULKAN_CONTEXT; size: INTEGER_64; usage: INTEGER): VULKAN_BUFFER

Create a GPU buffer with specified size and usage flags.

load_shader (ctx: VULKAN_CONTEXT; path: STRING): VULKAN_SHADER

Load a SPIR-V compute shader from file.

create_pipeline (ctx: VULKAN_CONTEXT; shader: VULKAN_SHADER): VULKAN_PIPELINE

Create a compute pipeline for shader execution.

VULKAN_CONTEXT

GPU context with device information.

Feature Description
is_valid True if context was created successfully
device_name GPU device name string
is_discrete_gpu True if using discrete GPU
vendor_id GPU vendor ID (NVIDIA=0x10DE, AMD=0x1002, Intel=0x8086)
dispose Release all Vulkan resources

VULKAN_BUFFER

GPU buffer for data storage and transfer.

Feature Description
upload (data, size, offset) Upload data from CPU to GPU buffer
download (data, size, offset) Download data from GPU buffer to CPU
dispose Free GPU memory

VULKAN_PIPELINE

Compute pipeline for shader execution.

Feature Description
bind_buffer (binding, buffer) Bind buffer to shader binding point
dispatch (ctx, x, y, z) Dispatch compute workgroups
wait_idle (ctx) Wait for GPU operations to complete
dispose Release pipeline resources

Buffer Usage Flags

Flag Value Description
Buffer_storage 0x01 Shader storage buffer (SSBO)
Buffer_uniform 0x02 Uniform buffer for constants
Buffer_transfer 0x04 Enable CPU upload/download

Writing Compute Shaders

Compute shaders must be written in GLSL and compiled to SPIR-V format.

Example Shader

#version 450
layout(local_size_x = 64) in;

layout(std430, binding = 0) buffer InputBuffer { float data[]; };
layout(std430, binding = 1) buffer OutputBuffer { float result[]; };

void main() {
    uint idx = gl_GlobalInvocationID.x;
    result[idx] = data[idx] * 2.0;
}

Compile to SPIR-V

%VULKAN_SDK%\Bin\glslc.exe shader.comp -o shader.spv

Complete GPU Compute Example

local
    vk: SIMPLE_VULKAN
    ctx: VULKAN_CONTEXT
    shader: VULKAN_SHADER
    pipeline: VULKAN_PIPELINE
    input_buf, output_buf: VULKAN_BUFFER
do
    create vk
    ctx := vk.create_context

    if ctx.is_valid then
        -- Load compute shader (SPIR-V)
        shader := vk.load_shader (ctx, "compute.spv")

        if shader.is_valid then
            -- Create pipeline
            pipeline := vk.create_pipeline (ctx, shader)

            -- Create and bind buffers
            input_buf := vk.create_buffer (ctx, 4096, vk.Buffer_storage)
            output_buf := vk.create_buffer (ctx, 4096, vk.Buffer_storage)
            pipeline.bind_buffer (0, input_buf).do_nothing
            pipeline.bind_buffer (1, output_buf).do_nothing

            -- Upload data, dispatch, download results
            input_buf.upload (data.item, 4096, 0).do_nothing
            pipeline.dispatch (ctx, 64, 1, 1).do_nothing
            pipeline.wait_idle (ctx)
            output_buf.download (result.item, 4096, 0).do_nothing

            -- Cleanup
            pipeline.dispose
            input_buf.dispose
            output_buf.dispose
            shader.dispose
        end
        ctx.dispose
    end
end

Performance

Tested on NVIDIA GeForce RTX 5070 Ti:

Operation Performance
Context creation <10ms
Buffer operations Near-instant
4K SDF ray marching 63 FPS (3840x2160)