Hey Stu!
I had some time this week to investigate this further, and I think I figured out what’s going on.
The issue happens on FNiagaraRibbonAggregationStepCS (NiagaraRibbonAggregationStep.usf), and it’s because of a mismatch between the FRibbonAccumulationValues struct size on the shader (NiagaraRibbonCommon.ush) and the stride size on the TransientAccumulation buffers.
The shader structure is correct. Each ribbon renderer determines the correct stride at GetAccumulationStructSize and sets the right permutation vector defs. However, if you have two consecutive ribbon renderers with different strides, and the size of the first allocated transient buffer happens to be enough to fit the data of the second, they won’t get re-initialized, and the stride will be wrong.
Example:
Ribbon Renderer A: Using full ribbon IDs, stride: 24
Ribbon Renderer B: Not using them, stride: 20
After A, TransientAccumulation is enough to fit B, so it won’t Initialize (InitOrUpdateBuffers); its stride size remains at 24. In AMD cards, you’ll get the wrong transient buffer offsets for B, and your ribbons will explode 
One work-around is this:
`// At FNiagaraRibbonGPUInitComputeBuffers, InitOrUpdateBuffers
const uint32 AccumulationBufferStructSize = GetAccumulationStructSize(bWantsMultiRibbon, bWantsTessellation, bWantsTessellationTwist) * sizeof(float);
if (TransientAccumulation[0].NumBytes < (AccumulationBufferStructSize * NeededSize)
// FIX: Account for stride differences
|| (TransientAccumulation[0].Buffer->GetStride() != AccumulationBufferStructSize))
{
…
}`I’ve tested this in our AMD workstation, and everything seems to be working fine now. You can also test it in a vanilla distribution by verifying that things break using the original repro above, and then applying this patch.
I’m going to run some diagnostics on my NVidia workstation, I wonder if NVidia handles this buffer’s memory differently.