Forward+ Rendering doesn't work in Direct3D11

I tried to use Forward+ rendering path in PC, it works well in Direct3D12 and Vulkan API, while doesn’t work in Direct3D11.

Tested in 2021.3.2f, URP 12.1.6

What does not work exactly?

The Additional lights calculate doesn’t work. The screenshots are captured in URP’s default sample, which contains a spot additional light.
Actually, it seems to result from the Constant Buffer “AdditionalLightsZBins” and “AdditionalLightsTiles”.In DX11, they are all set to 0 in GPU(CPU works well), which miscalculate additional lights.

I suggest making a bug report on this

Curious how you enabled this - have been keeping my eyes peeled for it but can’t find the option (or how to expose it).

Add the define symbol to your project.
Symbol : URP_ENABLE_CLUSTERED_UI
8151401--1058924--symbol.png

1 Like

How does this enable Forward+?

Check my last reply.

I just found another bug on URP12 forward+ :frowning:
Open the spot light, it goes well. Close the spot light, the light still bright the scene :frowning:

The DirectX 11 issues have been fixed for 2022.2 :slight_smile: It should be available when a16 goes out. Not sure about the spot light issue, but I’m not able to reproduce it on the latest version.

Is the API problem caused by the C++ Code of Unity engine? I mean, Is there a way to fix this in earliler Unity versions?:slight_smile:

The DirectX 11 issues were caused by accidentally doing a partial update of the F+ constant buffers, which hit an unsupported use case in the C++ code. The fix was to do a full update instead, which is entirely on the C# side. So it should be possible to do a similar fix in earlier versions, but given the experimental status and that it’s hidden behind a scripting define, we won’t be fixing it in earlier versions.

1 Like

hey @peterbay any chance you could give more info on this potential DX11 fix in earlier version? (2021.1 here) I tried a bunch of things and couldn’t get it to fix. I tried different sizes in SetData(), SetGlobalConstantBuffer(), GraphicsBuffer instead of ComputeBuffer, persistent NativeArrays like in F+ v2 (but m_TileLightMasks length varies in v1)

Here’s a refresher of F+ v1:

internal static int maxZBins => 1024 * 4;
internal static int maxTileVec4s => 4096;

NativeArray<ZBin> m_ZBins;
NativeArray<uint> m_TileLightMasks;

m_ZBinBuffer = new ComputeBuffer(UniversalRenderPipeline.maxZBins / 4, UnsafeUtility.SizeOf<float4>(), ComputeBufferType.Constant, ComputeBufferMode.Dynamic);
m_TileBuffer = new ComputeBuffer(UniversalRenderPipeline.maxTileVec4s, UnsafeUtility.SizeOf<float4>(), ComputeBufferType.Constant, ComputeBufferMode.Dynamic);

m_ZBins = new NativeArray<ZBin>(binCount, Allocator.TempJob); // seems constant to 4096
m_TileLightMasks = new NativeArray<uint>(((m_TileResolution.x * m_TileResolution.y * (wordsPerTile) + 3) / 4) * 4, Allocator.TempJob); // this one varies a lot

m_ZBinBuffer.SetData(m_ZBins.Reinterpret<float4>(UnsafeUtility.SizeOf<ZBin>()), 0, 0, m_ZBins.Length / 4);
m_TileBuffer.SetData(m_TileLightMasks.Reinterpret<float4>(UnsafeUtility.SizeOf<uint>()), 0, 0, m_TileLightMasks.Length / 4);

cmd.SetGlobalConstantBuffer(m_ZBinBuffer, "AdditionalLightsZBins", 0, m_ZBins.Length * 4);
cmd.SetGlobalConstantBuffer(m_TileBuffer, "AdditionalLightsTiles", 0, m_TileLightMasks.Length * 4);

Thanks

@sabojako The trick is to use the overload of ComputeBuffer.SetData that only takes the native array. I.e. it should look like:

m_ZBinBuffer.SetData(m_ZBins.Reinterpret<float4>(UnsafeUtility.SizeOf<ZBin>()));
m_TileBuffer.SetData(m_TileLightMasks.Reinterpret<float4>(UnsafeUtility.SizeOf<uint>()));

Otherwise it maps to a partial buffer update, which doesn’t work for DX11. When using this overload, the NativeArray must have the same size as the ComputeBuffer. I.e. UniversalRenderPipeline.maxZBins for m_ZBins and UniversalRenderPipeline.maxTileVec4s/4 for m_TileLightMasks.

1 Like

Thanks @peterbay ! I managed to get it working by using proper array lengths and SetData(NativeArray). I had to use GraphicsBuffer tho. ComputeBuffer doesn’t wanna work even with the full update SetData, so maybe double check it is fixed too?

Np! :smile: Ahh right, I forgot that I also replaced it with GraphicsBuffer on my end. Not entirely sure what’s going on there.