skip to Main Content

I have a program which loads images frequently. It displays image in a sort-of grid and loads them as the user scrolls down and they come into view. This works well except for the seemingly random crashes that occur. It doesn’t seem to matter whether I’m loading a specific image, loading a lot of images or only a couple, or anything else, it’ll just randomly crash trying to load an image.

Oddly enough, it crashes without throwing a Visual Studio exception. So I used procdump to generate a dump file which lead me to find out that it exited with exception code ‘0xC0000409’, which corresponds to a Status Stack Buffer Overrun exception and that it was being caused by nvoglv64.dll at my call to TexImage2D.

Notably, this only happens when loading textures on a secondary context and thread. When I load textures on the main thread and context, it seems perfectly stable. That said there is virtually no difference in logic between how textures are loaded when I do it on the main thread vs. on the separate thread.

I get literally 3 results, 1 of those in english when I google this issue, I have no idea where to even start debugging this, so any help would be appreciated.

I’m not entirely sure what code to include, but relevant loading code is below, this gets called as fast as possible for each texture there is to load.

public static void Load( int FileIndex )
{
    BindlessTexture Texture = new();

    Texture.Handle = GL.GenTexture();
    GL.BindTexture(TextureTarget.Texture2D, Texture.Handle);

    Image<Rgba32> ImageData = Image.Load<Rgba32>(Library.Paths[FileIndex]);
    ImageData.Mutate(X => X.Flip(FlipMode.Vertical));

    byte[] PixelData = new byte[4 * ImageData.Width * ImageData.Height];
    ImageData.CopyPixelDataTo(PixelData);

    GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMagFilter.Linear);
    GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
    GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToBorderArb);
    GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToBorderArb);
    GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureBorderColor, new float[4]);

    GL.TexImage2D(
        TextureTarget.Texture2D,
        0,
        PixelInternalFormat.Rgba,
        ImageData.Width,
        ImageData.Height,
        0,
        PixelFormat.Rgba,
        PixelType.UnsignedByte,
        PixelData
    );

    PixelData = null;
    ImageData.Dispose();
    GL.BindTexture(TextureTarget.Texture2D, 0);

    Texture.BindlessHandle = GL.Arb.GetTextureHandle(Texture.Handle);

    lock ( Library.BindlessTextures ) //I don't think either thread will collide but just in case?
    lock ( Library.BindlessTextureHandles )
    {
        Library.BindlessTextures[FileIndex] = Texture;
        Library.BindlessTextureHandles[FileIndex] = Texture.BindlessHandle;
    }

    TexturesToFinalize.Enqueue(FileIndex);
}

While the exception doesn’t here, maybe it’s worth including that once a texture is loaded and its handle is created, its made resident on the main thread, and then marshalled over to a mapped SSBO with the code below:

public void FinalizeLoadingTextures()
{
    while ( TextureLoader.TexturesToFinalize.Count != 0 )
    {
        int FileIndex = TextureLoader.TexturesToFinalize.Dequeue();
        BindlessTexture Texture = Library.BindlessTextures[FileIndex];

        if ( Texture is not null )
        {

            GL.Arb.MakeTextureHandleResident(Texture.BindlessHandle);
            Marshal.WriteInt64(Library.BindlessTextureHandleBufferPointer, FileIndex * 8, Texture.BindlessHandle);

        }
    }

}

2

Answers


  1. Chosen as BEST ANSWER

    Yeah I just had to admit defeat on this one and move the OpenGL texture creation code to the main thread and context. Loading the pixel data remains on the texture thread so the application doesn't block but anything OpenGL is kept on the same thread.


  2. This could be because of windows Timeout detection and recovery (TDR). If you open Event Viewer and go to Windows Logs > Applications and look for the crash logs or open the crash log via your debugger, nvoglv64.dll trowing 0xC0000409 is often due to a TDR restarting the GPU or stopping the program that is using the GPU.

    Here is NVIDIA’s page on the problem and possible solutions

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search