texture.Apply when using raw texture pointers is doing crazy things in the profiler

RawTextureData is supposed to be the faster leaner version of making texture.
But here is what i’m getting when apply(false) is called:
7579939--939487--upload_2021-10-17_11-43-3.png
then i commented out this line
7579939--939493--upload_2021-10-17_11-43-23.png
and bam smooth and low
7579939--939490--upload_2021-10-17_11-43-14.png
this is captured on the switch, deep profiler
so is this a bug in profiler? Raw being pretty bad? me calling apply wrong?

here is the script

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.VFX;

[DefaultExecutionOrder(-9999)]
public class VFXBatchController : MonoBehaviour
{
    Texture2D _tex; // RGB for position, A for lifetime
    static readonly int countID = Shader.PropertyToID("count");
    static readonly int offsetID = Shader.PropertyToID("offset");
    static readonly int positionsID = Shader.PropertyToID("positionslifetimes");
    const int MAXCOUNT = 1000;
    [Serializable]
    public struct VFX
    {
        public int groupID;
        public VisualEffect vfx;
    }
    public VFX[] vfx;

    void OnEnable() { _tex = new Texture2D(MAXCOUNT, 1, GraphicsFormat.R32G32B32A32_SFloat, TextureCreationFlags.None); }

    Vector4 _tmp = new Vector4();

    void Update()
    {
        var positionsLifetimes = _tex.GetRawTextureData<Vector4>();
        int offset = 0;
        for (int vfxIndex = 0; vfxIndex < vfx.Length; vfxIndex++)
        {
            vfx[vfxIndex].vfx.SetInt(offsetID, offset);
            var countEmitter = VFXBatchEmitter.emitters.ContainsKey(vfx[vfxIndex].groupID) ? VFXBatchEmitter.emitters[vfx[vfxIndex].groupID].Count : 0;
            vfx[vfxIndex].vfx.SetInt(countID, countEmitter);
            if (countEmitter == 0)
                continue;
            var emitters = VFXBatchEmitter.emitters[vfx[vfxIndex].groupID];
            for (var emitterIndex = 0; emitterIndex < countEmitter; emitterIndex++)
            {
                var emitter = emitters[emitterIndex];
                if (emitter.lifetime > 0)
                {
                    var tp = emitter.transform.position;
                    _tmp.Set(tp.x, tp.y, tp.z, emitter.lifetime);
                    positionsLifetimes[offset + emitterIndex] = _tmp;
                }
            }
            offset += countEmitter;
        }
        _tex.Apply(false);
        for (int i = 0; i < vfx.Length; i++)
        {
            vfx[i].vfx.SetTexture(positionsID, _tex);
        }
    }
}

RawTextureData (and Get/SetPixelData) gives you access to the underlying CPU data of the texture.
Calling Texture.Apply is what actually (re)uploads the CPU data to the GPU. This is an expensive operation.

For your use case you should be better off using a ComputeBuffer instead of a Texture.

ComputeBuffer.BeginWrite can give you a NativeArray pointing to CPU writable GPU memory which should be faster.
(this does depend on the hardware, although this should still be the fastest upload path)
Depending on your use case you could also use BeginWrite to do only a partial update of the buffer each frame.

Thanks @NicoLeyman I was wondering about compute buffer, I’m currently using a texture to send data to vfx graph as you can see. How would I have to change the graphs to support compute buffers instead? And any code example on how to write the data to it?

Also are you saying that using texture.Apply after settings up rawtexturedata nullifies the benefit of rawtexturedata in term of performance?

RawTextureData and Get/Set PixelData are the fastest ways to access the CPU side data of a Texture. To get your changes onto the GPU you will have to call Texture.Apply which is slow because it does a CPU to GPU transfer.

I’m not very familiar with VFX graph but it should be possible to access compute buffers from VFX graph as that should be what it’s using under the hood as well. Best to look at the VFX graph docs for that.

I’ll file report regarding the ComputeBuffer documentation as it’s a bit lacking.

Thanks for the details, I’ll see what the VFX graph entry points are.

Had a look myself since I was curious and it turns out GraphicsBuffer is supposed to be a more versatile replacement of ComputeBuffer. Thus VFX Graph supports only GraphicsBuffer: Sample Buffer | Visual Effect Graph | 13.0.0

Not in 8.3 it seems, which is the version I use.
What’s missing in the documentation is the version that a feature (page) was added, Like the unreal doc.

7587154--940666--upload_2021-10-20_3-9-52.png