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;
}
}
}