One API. Every GPU.

NeoVeldrid is a low-level, high-performance graphics library for .NET. Build 2D and 3D games, simulations, and tools with a single portable API across Vulkan, Direct3D 11, OpenGL, and OpenGL ES.

A maintained fork of Veldrid, powered by Silk.NET. Open source under the MIT license.

Vulkan, Direct3D 11, OpenGL, OpenGL ES
Multi-Backend

Write your rendering code once. It runs on Vulkan, Direct3D 11, OpenGL, and OpenGL ES without any changes.

Windows, Linux, macOS
Cross-Platform

Windows, Linux, and macOS from a single codebase. All native dependencies ship as NuGet packages.

High Performance

A thin, low-cost abstraction close to the metal. Allocation-free rendering loop. Multi-threaded command recording.

Modern GPU Features

Programmable shaders, compute, structured buffers, array textures, multisampling. Write GLSL once, cross-compile via SPIR-V.

Pure .NET

Install a NuGet package and start coding. No native SDKs, no manual library copying, no build scripts.

Flexible

Headless rendering, GPU compute, multi-window, ImGui integration. Games, tools, simulations, or offline processing.

Up and running in seconds

Create a window and a GPU device in two lines. NeoVeldrid picks the best available backend for the platform automatically.

  • Vulkan, D3D11, OpenGL, or OpenGL ES
  • Windows, Linux, macOS
  • No native SDKs to install
var window = NeoVeldridStartup.CreateWindow(new WindowCreateInfo
{
    WindowWidth = 960,
    WindowHeight = 540,
    WindowTitle = "My App"
});

var device = NeoVeldridStartup.CreateGraphicsDevice(window);
var factory = device.ResourceFactory;
var commandList = factory.CreateCommandList();
GPU resources, the .NET way

Create vertex buffers, index buffers, and uniforms with a clean, typed API. Upload data directly from arrays and structs.

float[] quadVertices = {
//    X      Y     U     V
    -0.5f,  0.5f, 0.0f, 0.0f, // top-left
     0.5f,  0.5f, 1.0f, 0.0f, // top-right
     0.5f, -0.5f, 1.0f, 1.0f, // bottom-right
    -0.5f, -0.5f, 0.0f, 1.0f, // bottom-left
};

ushort[] quadIndices = { 0, 1, 2, 0, 2, 3 };

var vertexBuffer = factory.CreateBuffer(
    new BufferDescription(quadVertices.SizeInBytes(), BufferUsage.VertexBuffer)
);
var indexBuffer = factory.CreateBuffer(
    new BufferDescription(quadIndices.SizeInBytes(), BufferUsage.IndexBuffer)
);

device.UpdateBuffer(vertexBuffer, 0, quadVertices);
device.UpdateBuffer(indexBuffer, 0, quadIndices);
Portable shaders

Write your shaders in GLSL once. NeoVeldrid.SPIRV handles the rest - compiling to SPIR-V and cross-compiling to whatever the current backend needs. No separate shader files per platform.

var vertexCode = File.ReadAllText("my-shader.vert.glsl");
var fragmentCode = File.ReadAllText("my-shader.frag.glsl");

var shaders = factory.CreateFromSpirv(
    new ShaderDescription(ShaderStages.Vertex, Encoding.UTF8.GetBytes(vertexCode), "main"),
    new ShaderDescription(ShaderStages.Fragment, Encoding.UTF8.GetBytes(fragmentCode), "main")
);
Full control over the GPU pipeline

Blend state, depth testing, rasterization, shaders - everything is explicit and declarative. No hidden state machines, no surprises.

var pipeline = factory.CreateGraphicsPipeline(new GraphicsPipelineDescription
{
    BlendState = BlendStateDescription.SingleOverrideBlend,
    DepthStencilState = DepthStencilStateDescription.DepthOnlyLessEqual,
    RasterizerState = RasterizerStateDescription.Default,
    PrimitiveTopology = PrimitiveTopology.TriangleList,
    ShaderSet = new ShaderSetDescription(new[] { vertexLayout }, shaders),
    Outputs = device.SwapchainFramebuffer.OutputDescription
});
Allocation-free rendering

The core rendering loop allocates zero garbage-collected memory. Record commands, submit, swap. That's it.

while (window.Exists)
{
    window.PumpEvents();

    commandList.Begin();
    commandList.SetFramebuffer(device.SwapchainFramebuffer);
    commandList.ClearColorTarget(0, RgbaFloat.CornflowerBlue);
    commandList.SetPipeline(pipeline);
    commandList.SetVertexBuffer(0, vertexBuffer);
    commandList.SetIndexBuffer(indexBuffer, IndexFormat.UInt16);
    commandList.DrawIndexed(6);
    commandList.End();

    device.SubmitCommands(commandList);
    device.SwapBuffers();
}
GPU compute, same API

Run compute shaders alongside your graphics work. Same command list, same resource model, same submission pipeline.

var computePipeline = factory.CreateComputePipeline(
    new ComputePipelineDescription(computeShader, resourceLayout, 16, 16, 1)
);

commandList.Begin();
commandList.SetPipeline(computePipeline);
commandList.SetComputeResourceSet(0, resourceSet);
commandList.Dispatch(groupCountX, groupCountY, 1);
commandList.End();

device.SubmitCommands(commandList);
Textures and samplers

Create 2D textures, upload pixel data, sample them in shaders. Supports compressed formats, mipmaps, array textures, and multisampling.

var texture = factory.CreateTexture(TextureDescription.Texture2D(
    width, height, mipLevels: 1, arrayLayers: 1,
    PixelFormat.R8_G8_B8_A8_UNorm, TextureUsage.Sampled)
);

device.UpdateTexture(texture, pixelData, 0, 0, 0, width, height, 1, 0, 0);

var textureView = factory.CreateTextureView(texture);
var sampler = factory.CreateSampler(SamplerDescription.Linear);
Coming from Veldrid?

NeoVeldrid preserves full API compatibility. Update your NuGet packages, rename the namespace, and you're done. No code changes needed.

Migration Guide
Ready to get started?

Follow the tutorial to create your first NeoVeldrid application in minutes.

Get Started