Using Vulkan in Unity shaders

Kept you waiting, huh?

It’s been a long time, S… since my last post, mostly due to an enormous amount of work I made during this period.

Ever wondered that you can utilize some Vulkan features for your good, but Unity seemingly doesn’t support them in HLSL? Right, that’s what I stumbled across too.

So, for instance you need to use push constants for faster draw calls, may be you are issuing them from a native plugin or something. How do you actually do that?

Using vk:: namespace in HLSL

// Mandatory.
#pragma use_dxc

struct TestPushConstant_t
{
    uint64_t m_nBufferDeviceAddress;  // GlobalsTest_t
};

[[vk::push_constant]] TestPushConstant_t g_PushConstants;

At first, I was wondering will Unity’s version of DXC actually emit correct code when I load a push constant? And turns out it does! So you are at least safe. Now you can use push constants and push them with vkPushConstants via your native plugin or something.

Ramping up the stakes:

In my case I needed raw buffer access with VK_KHR_buffer_device_address. You see, address space of the sparse buffer on Vulkan devices typically much larger than 4GB, but, the storage buffer address space is limited by uint32, which means we have only 4GB AT MAX available to address with SSBO. Even if our device can address much more than that.

We do that in HLSL like that:

float4 vTest = vk::RawBufferLoad<float4>(our64bitbufferPtr + 16);

This is totally valid construction in new HLSL compiled with DXC and will emit proper SPIR-V, but with Unity… You will get a compiler error that RawBufferLoad is undefined. One work around is to patch DxcCreateInstance (or wrap it into another DLL) and add -fspv-target-env=vulkan1.2 to it.

Let’s just update Unity’s DXC version

Download latest DXC release from https://github.com/microsoft/DirectXShaderCompiler/releases. And just throw the files into Editors\2022.3.27f1\Editor\Data\Tools\ folder replacing original files. Don’t forget to make backup of them and close all instances of editor before you replace them.

Will that even work? Turns out it will!

So this means two things:

  1. You can replace Dxcompiler with your own compiled dll, the source code of which is open.
  2. You can update Unity’s dxc with the newer one.

After replacing dxcompiler Unity is absolutely fine with me using RawBufferLoad.

Documentation

https://docs.vulkan.org/guide/latest/hlsl.html

https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/SPIR-V.rst#vulkan-specific-features

Cheers! Happy hacking.

Leave a Reply

Your email address will not be published. Required fields are marked *