We’re only one week away from XDC 2026, which will take place in Toronto from the 28th to the 30th of September. I’ll be there one more year together with a sizeable group of Igalia colleagues presenting on a number of different topics related to the open source graphics stack. See the full schedule for more details. I’ll open the afternoon lightning talks round on Monday with a brief presentation about a memory usage problem we recently solved in Vulkan CTS. Last year I also gave an overview of Vulkan CTS and listed a bunch of tips and tricks about it.
You can find the slides in the link above but I noticed I never actually embedded my talk in a blog post for posterity, and I didn’t provide a transcription of the 2025 talk for those more inclined to read than to watch a video. Please excuse me for being so late. You can find both the video and the transcription below. See you in Toronto!
XDC 2025 Recording
▶
">
* {
padding: 0;
margin: 0;
overflow: hidden;
}
html, body {
height: 100%;
}
img, span {
/* All elements take the whole iframe width and are vertically centered. */
position: absolute;
width: 100%;
top: 0;
bottom: 0;
margin: auto;
}
span {
/* This mostly applies to the play button. */
height: 1.5em;
text-align: center;
font-family: sans-serif;
font-size: 500%;
color: white;
}
▶
"
>
Talk slides and transcription
Thanks everyone! Hello, I’m Ricardo from Igalia and I’m going to talk about Vulkan CTS, giving you some general information and some tips and tricks about it.
I’ve been contributing to the Vulkan Conformance Test Suite since 2019. It’s the same project that has OpenGL tests, but I have almost no contributions to the OpenGL part. I’m not the only one at Igalia working on CTS. Our work on this front is being generously funded by Valve. As part of my job, I frequently interact with Mesa contributors and people at Khronos. There’s some overlap between both, specially in this room. So what is my job about?
This.
The project is called VK-GL-CTS and it’s a Vulkan and OpenGL Conformance Test Suite. Most people writing Vulkan drivers have had to deal with VK-GL-CTS at some point. It’s open source, available on Github under the Apache 2 license. You can see it has a lot of commits from many different contributors apart from us, but not much community or activity inside Github, for reasons that I will explain later. This is very common with Khronos projects. Right now it has around 2.8 million Vulkan tests and ~5 million lines of code specific to Vulkan, but when you run a test you also use a lot of code from a common base that’s shared with OpenGL.
To give you some specific details about the Vulkan tests, if you take a look at the top-level README file, it points you to a second README that’s specific to Vulkan. If you follow the quick instructions in that second README and you configure and build the project, you end up with a binary called deqp-vk in some subdirectory of the build directory. That’s the base binary that allows you to run Vulkan tests by passing the -n option and indicating a test name, but you can also use asterisks in the name to form a glob that allows you to run multiple tests that match that pattern. The program will print a summary of the results in the terminal and put a lot more detail about each test in a file called TestResults.qpa. The tests are organized in a tree, with the leaves of that tree being the test cases that can be run, and the nodes leading to that leaf being the parent test groups.
One example is this: a Vulkan test that tries to see if copying between images with some given formats works. dEQP-VK, at the start of the name, is the root node, and there are subgroups to test the core API commands for copying and blitting images, and a subset of those are run for all formats with different image types, like copying from 1D to 2D using the general image layout for both images.
Starting with the first tip: if you dig deeper in the Vulkan CTS README, it mentions a few useful things. One of them is that, when building the project normally, you build many more things than the deqp-vk binary, like stuff for Vulkan Safety Critical, or some additional extra binaries. Of course, if you build calling cmake or ninja, you can indicate that you only want to build deqp-vk. You can always create a shell alias, script or whatever to do that, but if you don’t want to forget about it, there’s a cmake configure option that you can use when building the project to specify the targets you want to build by default, called SELECTED_BUILD_TARGETS. You pass a list of target names separated by spaces. If you specify deqp-vk only, only that binary will be built by default, which it’s much faster than building everything.
Another configuration option that I find particularly useful is DEQP_LOG_NODE_SOURCE. This was added recently to main, so it’s present in the most recent branches, and requires a modern compiler to work. If you enable it, the log file will mention, for every test case that is run, where the test case is being added to the tree. This makes it easier to locate the source code of a particular test. We’ll talk a bit more about that later. If you use this, there’s a small performance penalty when creating the test tree in memory, but it’s probably worth it in many cases. I always use this option.
Another thing: the deqp-vk binary is typically around 400MB big in a Debug build, or more depending on some other build options, so it takes a long time to link it. This is specially problematic when you’re making changes to a single file and rebuilding. Many Linux distributions still use BFD or Gold as the default linkers, which are very slow for deqp-vk, so my advice is to switch to LLD or Mold. For example, in my previous laptop, the default linker took 30 seconds to link deqp-vk. With mold, it went down to <2 seconds. Sometimes you can make them the default linker with update-alternatives but you can also set a link option from LDFLAGS and cmake will pick that up when configuring the project.
Moving on from build tips, I wanted to briefly explain how changes are reviewed and merged to the project. This is related to the community aspect I mentioned before. Every change that lands in the project needs to pass an internal review process inside Khronos. Who’s reviewing and approving changes to CTS? Typically people who have a Vulkan implementation, that is, a Vulkan driver running on some hardware, but software-only implementations also count. Some reviewers work on Mesa. For example, Samuel here reviews a lot of changes to make sure they work on RADV. However, I think it’s fair to say most reviewers do not really look at the source code for the changes. They only want to check if the tests pass on their driver and, if they don’t pass, they block the change until they fix the driver, if it’s a driver bug. A change cannot be blocked forever in those cases, so typically the result is that changes are merged more or less quickly and all drivers work and are fixed at the same time. To help with that process, Khronos has an internal Gitlab instance to track proposals for new tests and issue reports. If you don’t have Khronos access, you can report issues and submit PRs on Github, and someone will eventually review them and move them to the internal tracker.
So, again, if you have a Khronos account, go to Gitlab. If you don’t, use Github. If days or weeks pass and nobody replies on Github, feel free to mention us, specially if your issue comes from Mesa. No guarantees, of course, but it may help move your issue forward. You have some of our handles in the slide.
Some basic stuff about reporting issues. First, please mention hardware and driver, and if possible one specific case that is giving you trouble. Maybe mention a larger set of tests if you think all of them are affected by the same problem. Things that can be reported: Test mistakes, specially if the problem is reported by the validation layers. Also lack of coverage if you think something needs to be tested. A couple of tips about coverage: if you’ve implemented something new and all related tests seem to be passing, try to break something on purpose inside the driver and see if the tests still pass. You may be surprised. Also, if you discover a bug in your driver that is quite simple, obvious and it should be easy to reproduce, maybe it can be converted to a CTS test, so think about that.
Expanding on the topic of reporting issues, sometimes I get the feeling that people assume some minor pain points that they find are simply there and go “well, CTS is like that sometimes”, so I want to mention more things that are fair game and worth reporting. Configuration step takes too long: at some point a version of the layers was being built by default and the dependencies of the layers were being downloaded during the configuration step, instead of a previous step that fetched external dependencies. Tests take too long to run: maybe a pathological case of the shader being too slow to compile (this is happening to our Rpi team), or the test hammering the PCI-e bus due to the chosen memory types (this happened to NVK and we introduced a mechanism to more easily select better memory types, and did some fixes to some tests) And more stuff: tests that take too long to skip, or fail without giving a hint about where, or explaining why (neither in the terminal nor in the logs), not logging enough information, build or link time worsens a lot, etc. You don’t have to assume “CTS is like that”.
More stuff: dealing with test failures. First, if the test logs an image to TestResults.qpa, you can view them with the cherry tool mentioned in the README, but you can also use a self-contained viewer in the scripts subdirectory. It runs entirely in your browser. I have it as a local bookmark in Firefox. It has some limitations. Images in the test log are logged as PNGs. Drawbacks: color depth, 3D images, etc. Ideally this tool would be much more sophisticated. Images would be logged in a format that was more flexible and the tool would allow you to examine layers of an image and raw values with precision and easily by hovering the mouse over a failing pixel, but we don’t have that. You can also run the test in RenderDoc, and you should pass an option for that. Finally, if the failure message does not mention a line and file in the source code where it’s failing, which is trivial, please report it as an issue. In the mean time, the log-node-source option that I mentioned before can help.
If you want to check what a test is doing, here are some hints about navigating the CTS source code. I don’t want to talk too much about this, but some details are worth mentioning. If you log the node source and it points you to a line that mentions addFunctionCase, you only need to check the functions that are being run. Otherwise, the source code contains test cases and instances. Test cases are the leaf nodes of the test tree that we mentioned, and have methods to check the requirements to run the test, to generate the shaders that will be used, and another one to create a test instance. The test instance is the object that runs the actual test, in a method called iterate, and internally they can manage all the resources they need: images, buffers, command buffers, etc. Test Cases in the tree are kept alive since the start of the process and until it finishes while a Test Instance is short-lived: they’re created to run the test, they allocate the resources they need, and they’re destroyed after the test finishes, freeing all resources.
The hard part: finding tests. If I was given a cent every time someone asks me if we have tests that meet certain criteria, I could amass a small fortune. We can always grep the source code searching for extension names, feature names, etc, but things can get really complicated.
Sometimes it’s not only about Feature X or Format Y, or a given API call. We want some specific memory types and alignments, or in combination with some other feature, or some other weird and specific requirements that may not be easy to meet.
Sometimes we look at the source code and find that we do have that coverage. Some other times we have similar coverage but not quite, and it may be easy or hard to add the requested coverage. Of course, sometimes we’re lacking some general coverage and we need to create new tests.
Unfortunately, in many cases the real answer is that we do need to grep the source code as we mentioned before. However, some of this is being changed nowadays and we’re making progress towards making test requirements more explicit and, in a sense, declarative. Ideally, at some point that should let us build a system that could be used to search test cases by features, formats, etc. You can imagine something similar to Sascha Willems’ GPU info database. We could combine it with logging the node source and make it easy to find the source code of those tests.
That’s it. Many thanks! Let me know if you have any questions, or maybe you just want to rant about CTS. If not now, maybe later in the hallway.
Q&A
Q: We sometimes see that a particular test case runs on a queue like the graphics queue. Is it possible to run that test on another queue like the compute queue?
A: That’s being worked on. There’s a very old feature request for CTS to basically be able to run every test that is possible on any other queue that’s available on the device, in general. That’s one thing. It’s a hard problem given the state of the source code but people are working on it right now, and I think we will eventually get there, when we can run the tests on, say, the compute queue. Then that begs more questions like, for conformance purposes, do we have to run all the tests on all the queues supported by the device or not? The answer is not simple. The other possible answer is something that we have been doing for some time, as you know, is that we sometimes create specific variants for some tests that we know are tricky to run on the compute queue or on the transfer queue, and we create variants of those for those specific queues.
Q: Question about lists of packages for the linux distributions to be able to build deqp-vk.
A: I misunderstood part of the question as it was asked but later caught up with the person asking and he was genuinely wondering why deqp-vk was failing to build on some systems following the instructions. As a result of that question, we submitted an update to the documentation to be more precise in the list of required packages to build CTS, so that’s a win!
Q: Request to parametrize the side of the framebuffer in some tests, which is important for tilers like Turnip, to be able to run the test both using system memory and graphics memory.
A: Ack the request and admit that’s a hard one (because it would need changes in a lot of tests).






















































︎
















