CommandBuffer.SetGlobalTexture(...) works weird

Greetings to all. Faced with such a problem.

I’m developing a puzzle game. It was necessary to add an outline effect (so that the puzzles on the game table would not be lost). It worked.

Then it was necessary to make two passes for the post-effect separately for connected puzzles and not (single puzzles are lost under groups). Failed.
Reason: after correctly rendering the post-effect mask, I cannot access the result via SetGlobalTexture(…), since the result of the last effect on camera is written into two textures.
Below are the code snippets to show that the problem is not in it.

The post-effect is produced through the Command Buffer, which are located inside the wrapper class:

public class PassGroup
    {
        public UnityEngine.Rendering.CommandBuffer buffer;
         /**/
        public PassGroup(Service Parent, Material DrawMat, string BufferName, string TempTextureName, string FinalTextureName)
        {
            parent = Parent;
            drawMat = DrawMat;
           
            tempTextureID = Shader.PropertyToID(TempTextureName);
            finalTextureID = Shader.PropertyToID(FinalTextureName);
            finalName = FinalTextureName;
           
            buffer = new UnityEngine.Rendering.CommandBuffer { name = BufferName };
           
            propertyBlock = new MaterialPropertyBlock();
        }

        /* */
       
        void UpdateBuffer()
        {
            buffer.Clear();
            if (Requests.Count == 0) return;
            buffer.GetTemporaryRT(tempTextureID, Screen.width, Screen.height, 8, FilterMode.Point);
            buffer.SetRenderTarget(tempTextureID);
            buffer.ClearRenderTarget(false, true, Color.clear);
            buffer.DisableKeyword(drawMat, STEREO_L);
            buffer.DrawMeshInstanced(QuadMesh, 0, drawMat, -1, Matrixes, Requests.Count, propertyBlock);
            buffer.SetGlobalTexture(finalTextureID, tempTextureID); //Problem HERE
            buffer.ReleaseTemporaryRT(tempTextureID);
        }
    }

Code of service that creates PassGroups:

public class Service
    {
        /**/
        PassGroup NotMerged, Grouped;
        public List<CommandBuffer> buffers => new(){ NotMerged.buffer, Grouped.buffer };
/*
Important moment. CommandBuffer are supplied first NotMerged, then Grouped. Now outlines grouped.
When i swap them, grouped will not outline, but NotMerged will.
*/
        public Service(Material Mask, Mesh quadMesh)
        {
            puzzleMesh = quadMesh;
           
            NotMerged = new PassGroup(this, Mask, "Single puzzles outline", "_SingleObjects_Temp", "_SingleObjects");
            Grouped = new PassGroup(this, Mask, "Groups outline", "_GroupObjects_Temp", "_GroupObjects");
           
           /**/
        }
}

In attachment i append step-by-step research of Frame debugger with mine comments.

buffer.SetGlobalTexture(“_SingleObjects”, “_SingleObjects_Temp”); - this instruction don’t work in my build-up.
Problem not with shaders, because after swap commandBuffers on camera outline just going to single objects, groups ignored.

Win 11, Unity 2022.3.10F1, Build-in render pipeline, Editor environment.





            buffer.SetGlobalTexture(finalTextureID, tempTextureID); //Problem HERE
            buffer.ReleaseTemporaryRT(tempTextureID);

If I am not mistaken, you are returning the temporary render target right after setting it as a global texture. So when the global texture is used, it will point to a texture in the free-list of the pool. Or even worse, it could have been reused by some other code or even deleted.

To be fair, I didn’t know about the existence of the “ReleaseTemporaryRT” method before I ran into the problem. With one postprocessing pass without calling ReleaseTemporaryRT, it works stably in production.

But ok. I tried 2 scenarios:

  1. Comment out the line.
buffer.DrawMeshInstanced(QuadMesh, 0, drawMat, -1, Matrixes, Requests.Count, propertyBlock);
buffer.SetGlobalTexture(finalTextureID, tempTextureID);
//buffer.ReleaseTemporaryRT(tempTextureID);

The result is obvious - the problem remains.

  1. Move the row before setting RenderTexture as global.
buffer.DrawMeshInstanced(QuadMesh, 0, drawMat, -1, Matrixes, Requests.Count, propertyBlock);
buffer.ReleaseTemporaryRT(tempTextureID);
buffer.SetGlobalTexture(finalTextureID, tempTextureID);

The effect does not work, and the warning goes to the console: “CommandBuffer: temporary render texture _SingleObjects_Temp not found while executing Single puzzles outline (SetGlobalTexture)” (same with groups).