0

I'm making a frontend for the Mupen64Plus emulator with support for custom scripts that can draw over its video output. However, my implementation seems to segfault on Windows (it doesn't on Linux, for some reason.)

This MVE mimics the system I use for rendering graphics. To compile it you'll need to install Silk.NET.OpenGL, Silk.NET.SDL, and SkiaSharp off of NuGet.

  • The video plugin controls most of the render loop. Its actions are represented by the call to Render().
  • The lines that follow represent what happens when the video plugin requests to swap buffers:
    • OpenGL output is flushed
    • It switches to a separate context to render Skia's output
    • Skia's output is flushed
    • OpenGL is rendered

It will trigger an access violation on line 72 on Windows.

using System.Diagnostics;
using Silk.NET.OpenGL;
using Silk.NET.SDL;
using SkiaSharp;

Sdl sdl = Sdl.GetApi();

unsafe
{
    sdl.SetHint(Sdl.HintVideodriver, "x11");
    if (sdl.Init(Sdl.InitVideo | Sdl.InitEvents) != 0)
        SdlAbort();

    sdl.GLSetAttribute(GLattr.ContextMajorVersion, 4);
    sdl.GLSetAttribute(GLattr.ContextMinorVersion, 1);
    sdl.GLSetAttribute(GLattr.ContextProfileMask, (int) GLprofile.Compatibility);

    sdl.GLSetAttribute(GLattr.RedSize, 8);
    sdl.GLSetAttribute(GLattr.GreenSize, 8);
    sdl.GLSetAttribute(GLattr.BlueSize, 8);
    sdl.GLSetAttribute(GLattr.AlphaSize, 8);
    sdl.GLSetAttribute(GLattr.Doublebuffer, 1);
    sdl.GLSetAttribute(GLattr.StencilSize, 8);

    Window* window = sdl.CreateWindow("Test", Sdl.WindowposCentered, Sdl.WindowposCentered, 800, 600, (uint) WindowFlags.Opengl);
    void* mainCtx = sdl.GLCreateContext(window);
    GL mainGL = GL.GetApi(x => (IntPtr) sdl.GLGetProcAddress(x));

    void* skiaCtx = sdl.GLCreateContext(window);
    if (sdl.GLMakeCurrent(window, skiaCtx) != 0)
        SdlAbort();

    using var grContext = GRContext.CreateGl();
    Debug.Assert(grContext != null);
    using var surface =
        SKSurface.Create(grContext,
            new GRBackendRenderTarget(800, 600, 0, 8, new GRGlFramebufferInfo(0, (uint) GLEnum.Rgba8)),
            SKColorType.Rgba8888);
    Debug.Assert(surface != null);

    if (sdl.GLMakeCurrent(window, mainCtx) != 0)
        SdlAbort();

    Init(mainGL);

    bool shouldClose = false;
    while (true)
    {
        Event evt = new();
        while (sdl.PollEvent(ref evt) != 0)
        {
            switch ((EventType) evt.Type)
            {
                case EventType.Windowevent:
                    switch ((WindowEventID) evt.Window.Event)
                    {
                        case WindowEventID.Close:
                            shouldClose = true;
                            break;
                    }

                    break;
            }
        }

        Render(mainGL);
        mainGL.Flush();
        if (sdl.GLMakeCurrent(window, skiaCtx) != 0)
            SdlAbort();
        Render2(surface.Canvas);
        surface.Flush();
        if (sdl.GLMakeCurrent(window, mainCtx) != 0)
            SdlAbort();
        sdl.GLSwapWindow(window);

        if (shouldClose)
            break;
    }
    sdl.GLDeleteContext(mainCtx);
    sdl.DestroyWindow(window);

    sdl.QuitSubSystem(Sdl.InitVideo | Sdl.InitEvents);
}

void SdlAbort()
{
    throw new Exception($"SDL: {sdl.GetErrorS()}");
}

void Init(GL gl)
{

}

void Render(GL gl)
{
    gl.ClearColor(0.0f, 0.0f, 1.0f, 1.0f);
    gl.Clear(ClearBufferMask.ColorBufferBit);
}

void Render2(SKCanvas canvas)
{
    using var lime = new SKPaint
    {
        Color = SKColors.Lime
    };
    canvas.DrawCircle(300, 300, 100, lime);
}

What causes these kinds of segfaults, and what should I do to avoid them?

itzjackyscode
  • 970
  • 9
  • 27

0 Answers0