Vulkan prototype slowly progressing
April 08, 2016
So, the Vulkan prototype is progress... But I'm running into many problems working with the drivers and the associated tools. Here's some examples of the problems I'm finding.
RenderDoc crashing
RenderDoc is the best tool for debugging Vulkan at the moment... But every time I tried to capture a log, it just crashed! The crash report didn't contain any useful information. All I could do was guess at the problem.
Fortunately, RenderDoc has one really great feature... It's open-source! So, I just downloaded the code and ran from Visual Studio (it compiled first time).
RenderDoc is still very unstable for Vulkan. But now that I have my own compiled version, that's not really a big issue. I can just debug any crashes and make changes as required. All of the other GPU debugging tools I've ever used (PIX, console tools, GPA, nsight, etc) have been unstable, as well. But they were all closed source. So whenever I got an error, my only choices were to either use another debugging, or guess at the problem. With this in mind, (open-source + very unstable) is probably better than (closed-source + mostly stable).
My issue was related to "binding" decorations in SPIR-V. RenderDoc requires that all resources have binding decorations. I found this was also an issue for run-time XLE code. Even though the GLSL compiler is capable of generating SPIR-V code without binding decorations, it seems like all practical uses require them.
My shaders weren't getting "bindings" for any resources, and this was the cause of RenderDoc's crashes!
HLSL cross compiler and "bindings"
Part of the issue is related to the HLSL cross compiler. In some cases, the cross compiler can attach "location" values, but it never attaches "binding" values for textures or constant buffers.
Fortunately, the HLSL cross compiler is also open-source... So I can create a fork with the modifications I need. That seems to be required in this case. I could try to attach the binding information later in the pipeline (eg, by modifying the output GLSL, or by inserting instructions into the SPIR-V bytecode)... But changing and improving the cross compiler seems like the best option.
We ideally also want to specify the "descriptor set" in the GLSL code. Unfortunately, HLSL 5 doesn't have an equivalent concept. That is going to require some more effort.
HLSL shader prototype with Vulkan
April 05, 2016
As part of the Vulkan prototype, I'm experimenting with compiling HLSL shaders to SPIR-V.
The Vulkan API doesn't have a high level shader language attached. Instead, it works with a new intermediate bytecode format, called SPIR-V. This works with the LLVM compiler system, so in theory we plug in different front ends to allow various high level languages to compile to SPIR-V.
That sounds great for the future... But right now, there doesn't seem to be a great path for generating the SPIR-V bytecode.
All of the XLE shaders are HLSL... So how do we use them with Vulkan? Let's consider the options.
Preprocessor framework
One option is to convert the shader code to GLSL using a preprocessor framework. HLSL and GLSL are closely related... But they vary significantly in the way the shader interface is declared (eg, shader resources, vertex elements, built in values, etc).
We can get around this by using a system of preprocessor macros and complex #includes. We would end up with native HLSL and GLSL code that does the same thing. The core shader code that does the math and lighting (etc) should be fairly compatible between languages... It's just the interface that is an issue.
However this kind of approach it's a bit awkward, and difficult maintain in the long term. And it might mean dropping support for some of the more unusual D3D features I'm using (such as for dynamic linking).
Also, it looks like GLSL might not be around a very long time. It could possibly go the way of OpenGL in the medium term. So it doesn't make sense to invest a lot of time into GLSL, just to have to be replaced with something else later.
Cross compile
Another option is to try to convert the HLSL output to SPIR-V by way of a cross compiler.
Starting to experiment with Vulkan
April 04, 2016
So, it's a simple story -- boy meets API, yada, yada, yada...
I've started to build some initial experiments with the Vulkan API. Version 1.0 of the API was just released -- and there's an SDK from Valve (called LunarG) around.
Initial impressions
My first impressions are very positive! Many of the design ideals and structures of the API are familiar from my days working with consoles (particularly the Sony consoles). This type of API has not been available on open platforms (like Windows) before -- so for people who don't have experience with consoles, it might give an idea of what it's like.
I'm also really happy how much of the surrounding resources have been made open-source... The samples, shader compilation tool-chain, etc... It's all very effective use of github.
Khronos have drawn attention to how much input they've gotten from the game engine development community. And it shows in the results. This is the kind of API that an experienced engine developer wants to see.
I think it's also a model that is much more viable for cross platform development than anything we've seen before. OpenGL had a lot of problems, and DirectX was so tied to the Windows platform. But this feels like something that is truly viable across many platforms (including low end and high end).
I'm really impressed with how a third party group has managed to build an API that balances the needs of engine developers with the needs of hardware designers. I think Khronos has really shown how this kind of thing should be done -- and it seems like a good model for other APIs (sound, physics hardware, etc).
Long term viability
Vulkan feels like an API that could stick around for awhile. OpenGL has been on it's last legs for a long time... And DirectX always needs constant refreshes to survive. But Vulkan feels like it will be here for awhile. Due to it's cross-platform and long term viability, it's really undermined DirectX and Apple's Metal.
I felt the same about C++11, when I started using it. The new C++14 is a huge step forward from the old C++98 days. Many of the design patterns we C++ programmers always wanted to use are not much more viable in C++14. Stroustrup said that C++14 "completes" C++11 -- but really, I think it "completes" C++ as a whole.
Comparing different methods for order independent transparency
March 31, 2016
There are has been a lot research on order independent transparency recently. There are a few screenshots comparing the following methods:
- Sorted -- this mode sorts back-to-front per fragment. It's very expensive, but serves as a reference.
- Stochastic -- as per nVidia's Stochastic Transparency research. This uses MSAA hardware to estimate the optical depth covering a given sample.
- Depth weighted -- as per nVidia's other white paper, "A Phenomenological Scattering Model for Order-Independent Transparency." This is very cheap, and uses a fixed equation based on fragment depth to weight samples.
Sorted
Stochastic
Depth Weighted
Unordered
Environment Rendering Screenshots
March 30, 2016
Here are a few screenshots of environment rendering in XLE. I don't have a lot of art I can take screenshots of, so I can't show a very polished scene... But you can see some of the rendering features.
Look for:
- shallow water surface animation
- order independent blending for foliage
- volumetric fog (& related effects)
- dynamic imposters for distant trees
- high res terrain geometry
- terrain decoration spawn
- "contact hardening" shadows
- infinite terrain shadows
(see older screenshots here)