Segfault in glGenerateMipmap()

I use TextureArrays with GPU instancing to have fewer draw calls. TextureArrays allow me to sample different textures per instance by settings texture index in MaterialPropertyBlocks.


TextureArray is a render texture. I update it (add new textures there) during runtime. I can’t use Graphics.Copy(…) for some reasons.


I need to calculate mipmaps for the TextureArray (RenderTexture.useMipMap is true).


But sometimes I get glitches and crashes on some devices. Seems that it happens only on devices with Mali-G77 and Mali-G78. According to stack traces, the crashes are from Mali drivers from glGenerateMipmap() function.


Does somebody see any problems with my code? Have somebody had similar issues with TextureArrays and mipmaps? Or with new Mali GPUs (g77 and g78)?


Unity3D version - 2020.3.19
Graphics API - OpenGL ES 3.2


Stack trace:

OS Version: Android 12 (SP1A.210812.016.G998BXXU4CVC4)
Report Version: 104

Exception Type: Unknown (SIGSEGV)

Application Specific Information:
Segfault

Thread 0 Crashed:
0   libGLES_mali.so                 0x720e7ec71c        <unknown> + 489869461276
1   libGLES_mali.so                 0x720e7ebc48        <unknown> + 489869458504
2   libGLES_mali.so                 0x720e7e60cc        <unknown> + 489869435084
3   libGLES_mali.so                 0x720e6d9ef8        <unknown> + 489868336888
4   libGLES_mali.so                 0x720e6c98f0        <unknown> + 489868269808
5   libGLES_mali.so                 0x720d720600        <unknown> + 489851848192
6   libGLES_mali.so                 0x720d717a64        <unknown> + 489851812452
7   libGLES_mali.so                 0x720d731574        <unknown> + 489851917684
8   libGLES_mali.so                 0x720d792da8        <unknown> + 489852317096
9   libGLES_mali.so                 0x720d792604        <unknown> + 489852315140
10  libGLES_mali.so                 0x720d744974        glGenerateMipmap
11  libunity.so                     0x71a5a6b5fc        ApiGLES::GenerateMipmap
12  libunity.so                     0x71a5a53754        GfxDeviceGLES::ProcessPendingMipGens
13  libunity.so                     0x71a5a7a558        GfxFramebufferGLES::PrepareImpl
14  libunity.so                     0x71a5a56df8        GfxDeviceGLES::BeforeDrawCall
15  libunity.so                     0x71a5a5d23c        GfxDeviceGLES::DrawNullGeometry
16  libunity.so                     0x71a60c2ec4        GfxDeviceWorker::RunCommand
17  libunity.so                     0x71a60c7684        GfxDeviceWorker::RunExt
18  libunity.so                     0x71a60c764c        GfxDeviceWorker::Run
19  libunity.so                     0x71a60bf888        GfxDeviceWorker::RunGfxDeviceWorker
20  libunity.so                     0x71a581f034        Thread::RunThreadWrapper
21  libc.so                         0x754342dfcc        __pthread_start
22  libc.so                         0x75433cd830        __start_thread

Simplified code:

using System.Collections;
using UnityEngine;
using UnityEngine.Rendering;

public class TextureArrayIssue : MonoBehaviour
{
    private RenderTexture _renderTexture;
    private CommandBuffer _commandBuffer;
    private Material _copyTextureMaterial;
    private static readonly int _copySourceParamId = Shader.PropertyToID("_DR_CopySource");
    
    private void Start()
    {
        _renderTexture = CreateRenderTextureArray();
        _commandBuffer = new CommandBuffer();
        _copyTextureMaterial = new Material(Shader.Find("Unlit/CopyTexture"));
        StartCoroutine(PerformDeferredTextureAdding());
    }

    private static RenderTexture CreateRenderTextureArray()
    {
        var width = 256;
        var height = 256;
        var format = RenderTextureFormat.R8;
        var slices = 128;
        var useMipMap = true;
        var sRGB = false;
        var renderTextureDescriptor = new RenderTextureDescriptor(width, height, format, 0)
        {
            dimension = TextureDimension.Tex2DArray,
            volumeDepth = slices,
            useMipMap = useMipMap,
            sRGB = sRGB,
        };
        var anisoLevel = 1;
        var filterMode = FilterMode.Bilinear;
        var wrapMode = TextureWrapMode.Repeat;
        return new RenderTexture(renderTextureDescriptor)
        {
            anisoLevel = anisoLevel,
            filterMode = filterMode,
            wrapMode = wrapMode,
        };
    }

    // I use this method to add textures in the TextureArray
    public void AddTexture(Texture texture, int slice)
    {
        CustomBlit(texture, _renderTexture, slice);
    }

    private void CustomBlit(Texture srcTexture, RenderTexture dstTextureArray, int dstSlice)
    {
        // Graphics.Blit(texture, _renderTexture, 0, depthSlice) doesn't work properly with Texture2DArrays for Metal
        
        // I use CommandBuffer to batch calls to GPU
        _commandBuffer.SetGlobalTexture(_copySourceParamId, srcTexture);
        _commandBuffer.SetRenderTarget(dstTextureArray.colorBuffer, dstTextureArray.depthBuffer, 
            0, CubemapFace.Unknown, dstSlice);
        _commandBuffer.DrawProcedural(Matrix4x4.identity, _copyTextureMaterial, 0, MeshTopology.Triangles, 3);
    }

    private IEnumerator PerformDeferredTextureAdding()
    {
        while(true)
        {
            if(_commandBuffer.sizeInBytes > 0)
            {
                Graphics.ExecuteCommandBuffer(_commandBuffer);
                _commandBuffer.Clear();
            }

            yield return null;
        }
    }
}

I could reproduce the crash. For that you need a device with Mail G78, OpenGL ES 3.2, and this code:

using UnityEngine;
using UnityEngine.Rendering;

public class UpdateTextureArray : MonoBehaviour
{
    [SerializeField]
    private Texture _srcTexture;
    
    private RenderTexture _renderTexture;

    private void Start()
    {
        RenderTextureDescriptor d = new RenderTextureDescriptor(256, 256, RenderTextureFormat.R8, 0)
        {
            dimension = TextureDimension.Tex2DArray,
            volumeDepth = 128,  // there is no crash if the depth is fewer than 128
            useMipMap = true,   // there is no crash if there are no mip maps
            sRGB = false,
        };
        _renderTexture = new RenderTexture(d)
        {
            anisoLevel = 1,
            filterMode = FilterMode.Bilinear,
            wrapMode = TextureWrapMode.Repeat,
        };
    }
    
    private void LateUpdate()
    {
        Graphics.Blit(_srcTexture, _renderTexture, 0, 0);
    }
}

There are no crashes if any condition is true:

  • use Vulkan (instead of OpenGL ES)
  • use fewer texture array layers (than 128) (but GL_MAX_ARRAY_TEXTURE_LAYERS is 4096 for the devices)
  • don’t use mipmaps for texture array

So I’ve “fixed” the crash by using 127 layers (instead of 128)


SystemInfo.graphicsDeviceVersion: OpenGL ES 3.2 v1.r32p1-01bet2-mbs2v39_0.f99ba4208fd3cd75b7876c6eee932fcf