HumbleUI/Skija

LWJGL, JRE Exception: Access Violation @ DirectContext.makeGL

Closed this issue · 2 comments

I tried recreating the skija + lwjgl example, but I can't get it running:
Everytime I start the project the JRE Crashes, showing an EXCEPTION_ACCESS_VIOLATION error.
If I step through the program it crashes at the DirectContext.makeGL() call.

Before that, I was able to create a GL window and GL context. Clearing the window also worked fine.
So I assume the openGL part of the project is working fine.

Maybe I made an obvious error, when I added the libraries to my project.
(I did not follow the gradle/maven etc. guide. I added them manually)
I'm pretty new to programming in Java, so it's likely I made a very stupid and obvious error.
Maybe somebody else can help me figure out, what might be the issue here.

Project Setup:
Platform: Windows 10 x64
JRE: Azul Zulu 17
IDE: IntelliJ
LWJGL: 3.3.1 (Minimal openGL)
Skija: 0.109.1 (Release version)

Code:
(My code is basicly identical to the Skija, lwjgl example)

import java.nio.IntBuffer;
import java.util.*;

import org.lwjgl.glfw.*;
import org.lwjgl.opengl.*;
import org.lwjgl.system.MemoryStack;

import static org.lwjgl.glfw.Callbacks.*;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.system.MemoryUtil.*;

import io.github.humbleui.skija.*;
import io.github.humbleui.skija.impl.*;

class Window
{
    //GL
    public long window;
    public int width;
    public int height;
    public float dpi = 1f;
    public int xpos = 0;
    public int ypos = 0;
    public boolean vsync = true;
    public boolean stats = true;
    private int[] refreshRates;
    private String os = System.getProperty("os.name").toLowerCase();

    //SKIA
    private DirectContext context;
    private BackendRenderTarget renderTarget;
    private Surface surface;
    private Canvas canvas;

    //-----------------------------------------------------------------------------------------------------//
    //Create Window
    //-----------------------------------------------------------------------------------------------------//
    private void createWindow(int x, int y, int width, int height)
    {
        glfwDefaultWindowHints(); // optional, the current window hints are already the default
        glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // the window will stay hidden after creation
        glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); // the window will be resizable

        window = glfwCreateWindow(width, height, "Skija LWJGL Demo", 0, 0);
        if (window == 0)
        {
            throw new RuntimeException("Failed to create the GLFW window");
        }

        glfwSetKeyCallback(window, (window, key, scancode, action, mods) ->
        {
            if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE)
            {
                glfwSetWindowShouldClose(window, true);
            }
        });

        glfwSetWindowPos(window, x, y);
        updateDimensions();
        xpos = width / 2;
        ypos = height / 2;

        glfwMakeContextCurrent(window);
        glfwSwapInterval(vsync ? 1 : 0); // Enable v-sync
        glfwShowWindow(window);
    }

    //-----------------------------------------------------------------------------------------------------//
    //Get Refresh Rates
    //-----------------------------------------------------------------------------------------------------//
    private int[] getRefreshRates()
    {
        var monitors = glfwGetMonitors();
        int[] res = new int[monitors.capacity()];
        for (int i=0; i < monitors.capacity(); ++i)
        {
            res[i] = glfwGetVideoMode(monitors.get(i)).refreshRate();
        }
        return res;
    }

    //-----------------------------------------------------------------------------------------------------//
    //Run
    //-----------------------------------------------------------------------------------------------------//
    public void run(int x, int y, int width, int height)
    {
        refreshRates = getRefreshRates();

        createWindow(x, y, width, height);
        loop();

        glfwFreeCallbacks(window);
        glfwDestroyWindow(window);
        glfwTerminate();
        glfwSetErrorCallback(null).free();
    }

    //-----------------------------------------------------------------------------------------------------//
    //Update Dimensions
    //-----------------------------------------------------------------------------------------------------//
    private void updateDimensions()
    {
        int[] width = new int[1];
        int[] height = new int[1];
        glfwGetFramebufferSize(window, width, height);

        float[] xscale = new float[1];
        float[] yscale = new float[1];
        glfwGetWindowContentScale(window, xscale, yscale);
        assert xscale[0] == yscale[0] : "Horizontal dpi=" + xscale[0] + ", vertical dpi=" + yscale[0];

        this.width = (int) (width[0] / xscale[0]);
        this.height = (int) (height[0] / yscale[0]);
        this.dpi = xscale[0];
        System.out.println("FramebufferSize " + width[0] + "x" + height[0] + ", scale " + this.dpi + ", window " + this.width + "x" + this.height);
    }

    //-----------------------------------------------------------------------------------------------------//
    //Initialize Skia
    //-----------------------------------------------------------------------------------------------------//
    private void initSkia()
    {
        Stats.enabled = true;

        if (surface != null)
        {
            surface.close();
        }
        if (renderTarget != null)
        {
            renderTarget.close();
        }

        renderTarget = BackendRenderTarget.makeGL(
                (int) (width * dpi),
                (int) (height * dpi),
                /*samples*/16,
                /*stencil*/8,
                /*fbId*/0,
                FramebufferFormat.GR_GL_RGBA8);

        surface = Surface.makeFromBackendRenderTarget(
                context,
                renderTarget,
                SurfaceOrigin.BOTTOM_LEFT,
                SurfaceColorFormat.RGBA_8888,
                ColorSpace.getDisplayP3(),  // TODO load monitor profile
                new SurfaceProps(PixelGeometry.BGR_H));

        canvas = surface.getCanvas();
    }

    //-----------------------------------------------------------------------------------------------------//
    //Draw
    //-----------------------------------------------------------------------------------------------------//
    private void draw()
    {
        //var canvas = surface.getCanvas();
        //canvas.clear(0);
        //Paint paint = new Paint();
        //paint.setColor4f(new Color4f(1f, 1f, 1f, 1f), ColorSpace.getSRGB());
        //paint.setAntiAlias(true);
        //canvas.drawCircle(640f, 360f, 150f, paint);
        context.flush();
        glfwSwapBuffers(window);
    }

    //-----------------------------------------------------------------------------------------------------//
    //Loop
    //-----------------------------------------------------------------------------------------------------//
    private void loop()
    {
        GL.createCapabilities();
        if ("false".equals(System.getProperty("skija.staticLoad")))
        {
            Library.load();
        }
        context = DirectContext.makeGL();

        GLFW.glfwSetWindowSizeCallback(window, (window, width, height) ->
        {
            updateDimensions();
            initSkia();
            draw();
        });

        glfwSetCursorPosCallback(window, (window, xpos, ypos) ->
        {
            if(os.contains("mac") || os.contains("darwin"))
            {
                this.xpos = (int) xpos;
                this.ypos = (int) ypos;
            }
            else
            {
                this.xpos = (int) (xpos / dpi);
                this.ypos = (int) (ypos / dpi);
            }
        });

        glfwSetMouseButtonCallback(window, (window, button, action, mods) ->
        {
            System.out.println("Button " + button + " " + (action == 0 ? "released" : "pressed"));
        });

        glfwSetScrollCallback(window, (window, xoffset, yoffset) ->
        {
            System.out.println("Scroll " + xoffset + "/" + yoffset);
        });

        glfwSetKeyCallback(window, (window, key, scancode, action, mods) ->
        {
            if (action == GLFW_PRESS)
            {
                switch (key)
                {
                    case GLFW_KEY_V:
                        vsync = !vsync;
                        glfwSwapInterval(vsync ? 1 : 0);
                        System.out.println("Vsync " + (vsync ? "ON" : "OFF"));
                        break;
                    case GLFW_KEY_G:
                        System.out.println("Before GC " + Stats.allocated);
                        System.gc();
                        break;
                }
            }
        });

        initSkia();

        while (!glfwWindowShouldClose(window))
        {
            draw();
            glfwPollEvents();
        }
    }
}

public class SkiaMain
{
    public static void main(String [] args) throws Exception
    {
        GLFWErrorCallback.createPrint(System.err).set();
        if (!glfwInit())
        {
            throw new IllegalStateException("Unable to initialize GLFW");
        }

        GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
        int width = 1280;
        int height = 720;
        new Window().run(Math.max(0, (vidmode.width() - width) / 2), Math.max(0, (vidmode.height() - height) / 2), width, height);
    }
}

Error log:
Maybe somebody else can get some usefule information from this:
error.log

Well, whatever went wrong, I have no idea.
But I just got Gradle to actually do its job and setup my dependencies correctly and now it works.
I still wish I knew what caused the issue, but I guess I will never know.
I consider this Issue closed (even though its not really resolved).

tonsky commented

I’m glad it worked out!