← back

Intro to Vulkan, Part One

Live long and prosper?

A cross-platform graphics API? that sounds great, I can draw poorly on all 3 platforms now!

There’s been a change in the tutorial for Vulkan, there are now two! One that’s based more in a C API layer way and a more modern C++ RAII one. You can find them both here:

Vulkan Tutorial vulkan-tutorial.com The original tutorial. C-API focused, the long-standing community starting point. Khronos Vulkan® Tutorial docs.vulkan.org/tutorial/latest/00_Introduction.html The newer official Khronos version, built around Vulkan-Hpp and RAII. This is the one I'm following.

I’ve mostly gone through the new tutorial for rendering a triangle (extremely hard I know).

It seems like it’s significantly more bearable than the older vulkan tutorial with the cost of some poor practices supposedly according to the internet, but hey, gotta start somewhere!

So far out of the general pipeline there’s a few terms and logical things I’ve learned.

Instances

These guys are kinda your entry point into Vulkan, every application typically has one and it’s where your per-application state lives (Vulkan goes out of its way to have no global state).

You’ll use it to tell the driver about your app (name, engine, API version) and to declare any instance-level extensions and validation layers you want turned on. From here you can start enumerating physical devices!

Validation Layers

These guys are mainly used for debugging by surfacing errors, warnings, and perf hints from the underlying C API. You configure what kind of messages you want with bit flags (severity, type, etc), but the messages themselves come back as actual readable diagnostics, not raw bit codes. It’s usually disabled by default for performance reasons. Usually the less code running means faster output, right?

Ideally, you’d wanna base these off your NDEBUG macro settings if you’re using C++, which for all intents and purposes I’m assuming so because that’s what I’m using though feel free to apply this to whatever language equivalent you may have.

There’s a lot of different validation layers out there. Heads up though: you may see older tutorials talk about enabling layers at both the instance and device level, but device-level layers got deprecated back in Vulkan 1.1. Nowadays you just enable layers at the instance level and they apply across the board, which is one less thing to think about.

Queues

From what I understand here, these aren’t really “queues” in the data structure sense you’re probably picturing, they’re more like submission channels to the GPU. You hand work over to a queue and the GPU chews through it.

Queues come in families, and each family is what advertises which operations its queues can actually do (graphics, compute, transfer, present, etc). So the capability stuff lives at the family level, not on individual queues.

Physical Devices

These guys are your devices that are capable of using the API effectively. This interfaces directly checking the capabilities and support of any device you have connected on your system. It can be integrated, discrete, AMD, Intel, Nvidia, whatever you’ve got, you’ll use this interface to query it and see what it’s capable of using!

Logical Devices

Logically (teehee), these devices are used to interface with physical devices! They’re built similarly to instance creation, and these are where you’ll link queues.

Note

You’ll typically never need more than 1 queue per family according to the documentation. The common path seems to be a multi-threaded pattern is to record command buffers across a bunch of threads and then submit them all through a single queue apparently.

Beyond that, the flow goes: you record commands into a command buffer, then submit that command buffer to a queue. The logical device is the handle you use to create the queues, command pools, and buffers in the first place.

Surfaces

Devices both logical & physical are nice and all, but you kind of have to have something to send/present the image made on the GPU, for this we have a surface!

This abstract concept is an effective connection between the instance and the native windowing system that effectively bridges the gap between the two systems, obviously with it being a platform-agnostic design, this is kinda pivotal to have.

Warning

Not all surfaces are the same however, you’ll have to check this support per queue family on the physical device before going to create your logical device.

Swap Chain

Surfaces are nice and all, but you kinda need more than one image floating around or you’ll get tearing on screen, that’s where swap chains come in!

A swap chain is basically a pool of images (usually 2 or 3) that you cycle through, you draw on one while the display reads from another, then swap once you’re done.

You also pick a present mode when setting it up, which decides the actual swap behavior (v-sync, triple-buffering, tearing-allowed, etc).

To Be Continued!

That’s where I’m at right now, we’ll go further along in part two and hopefully we’ll have a fully rendered triangle!

← all posts more in graphics →