JetBrains / skija

Java bindings for Skia
Apache License 2.0
2.63k stars 128 forks source link

A crash is happening with lwjgl #103

Closed Hilal-Anwar closed 3 years ago

Hilal-Anwar commented 3 years ago

FramebufferSize 1440x810, scale 1.0, window 1440x810 #

A fatal error has been detected by the Java Runtime Environment:

#

EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00007ffba78129e0, pid=7984, tid=9208

#

JRE version: OpenJDK Runtime Environment (15.0+31) (build 15-ea+31-1502)

Java VM: OpenJDK 64-Bit Server VM (15-ea+31-1502, mixed mode, sharing, tiered, compressed oops, g1 gc, windows-amd64)

Problematic frame:

C [skija.dll+0xb29e0]

#

No core dump will be written. Minidumps are not enabled by default on client versions of Windows

#

An error report file with more information is saved as:

C:\Users\ABC.ABC-PC\IdeaProjects\SkijaProject\hs_err_pid7984.log

#

If you would like to submit a bug report, please visit:

https://bugreport.java.com/bugreport/crash.jsp

The crash happened outside the Java Virtual Machine in native code.

See problematic frame for where to report the bug.

# hs_err_pid7984.log

tonsky commented 3 years ago

What were you trying to do? In log I see that some font failed to load:

Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j  org.jetbrains.skija.Typeface._nMakeFromFile(Ljava/lang/String;I)J+0
j  org.jetbrains.skija.Typeface.makeFromFile(Ljava/lang/String;I)Lorg/jetbrains/skija/Typeface;+5
j  org.jetbrains.skija.Typeface.makeFromFile(Ljava/lang/String;)Lorg/jetbrains/skija/Typeface;+2
j  scenes.src.Scene.<clinit>()V+5
v  ~StubRoutines::call_stub
j  java.lang.Class.forName0(Ljava/lang/String;ZLjava/lang/ClassLoader;Ljava/lang/Class;)Ljava/lang/Class;+0 java.base@15-ea
j  java.lang.Class.forName(Ljava/lang/String;)Ljava/lang/Class;+11 java.base@15-ea
j  scenes.src.Scenes.newScene(Ljava/lang/String;)Lscenes/src/Scene;+18
j  scenes.src.Scenes.setScene(Ljava/lang/String;)Lscenes/src/Scene;+43
j  scenes.src.Scenes.<clinit>()V+486
v  ~StubRoutines::call_stub
j  lwjgl.src.Window.draw()V+24
j  lwjgl.src.Window.loop()V+112
j  lwjgl.src.Window.run(Lorg/jetbrains/skija/IRect;)V+14
j  lwjgl.src.Main.main([Ljava/lang/String;)V+95
v  ~StubRoutines::call_stub
Hilal-Anwar commented 3 years ago

Thank you very much for replying. I was trying to run the example in https://github.com/JetBrains/skija/blob/master/examples/lwjgl/src/Main.java. I have not cloned the project, but just copied this code and the scene directory in (https://github.com/JetBrains/skija/tree/master/examples/lwjgl) into my project.

package lwjgl.src;

import org.jetbrains.skija.*; import org.jetbrains.skija.impl.Library; import org.jetbrains.skija.impl.Stats; import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFWErrorCallback; import org.lwjgl.glfw.GLFWVidMode; import org.lwjgl.opengl.GL; import scenes.src.Scenes;

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

public class Main { 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 = (int) (vidmode.width() * 0.75);
    int height = (int) (vidmode.height() * 0.75);
    IRect bounds = IRect.makeXYWH(
                     Math.max(0, (vidmode.width() - width) / 2),
                     Math.max(0, (vidmode.height() - height) / 2),
                     width,
                     height);
    new Window().run(bounds);
}

}

class Window { 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();

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

public void run(IRect bounds) {
    refreshRates = getRefreshRates();

    createWindow(bounds);
    loop();

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

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

private void createWindow(IRect bounds) {
    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(bounds.getWidth(), bounds.getHeight(), "Skija LWJGL Demo", NULL, NULL);
    if (window == NULL)
        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, bounds.getLeft(), bounds.getTop());
    updateDimensions();
    xpos = width / 2;
    ypos = height / 2;

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

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

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*/0,
                     /*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.RGB_H));

    canvas = surface.getCanvas();
}

private void draw() {
    Scenes.draw(canvas, width, height, dpi, xpos, ypos);
    context.flush();
    glfwSwapBuffers(window);
}

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) -> {
        Scenes.currentScene().onScroll((float) xoffset * dpi, (float) yoffset * dpi);
    });

    glfwSetKeyCallback(window, (window, key, scancode, action, mods) -> {
        if (action == GLFW_PRESS) {
            switch (key) {
                case GLFW_KEY_LEFT -> Scenes.prevScene();
                case GLFW_KEY_RIGHT -> Scenes.nextScene();
                case GLFW_KEY_UP -> Scenes.currentScene().changeVariant(-1);
                case GLFW_KEY_DOWN -> Scenes.currentScene().changeVariant(1);
                case GLFW_KEY_V -> {
                    Scenes.vsync = !Scenes.vsync;
                    glfwSwapInterval(Scenes.vsync ? 1 : 0);
                }
                case GLFW_KEY_S -> {
                    Scenes.stats = !Scenes.stats;
                    Stats.enabled = Scenes.stats;
                }
                case GLFW_KEY_G -> {
                    System.out.println("Before GC " + Stats.allocated);
                    System.gc();
                }
            }
        }
    });

    initSkia();

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

}

tonsky commented 3 years ago

My guess is that it can’t find font from scenes/fonts. Make sure that you have it and relative path is the same (see Scene.java, Scene::file function)

Hilal-Anwar commented 3 years ago

Yes you are right. I did that change and it is working Thanks bro 😊😊😊❤️❤️❤️. java_NP9jqgtBuQ

Hilal-Anwar commented 3 years ago

Do skija supports graalVm native-image

tonsky commented 3 years ago

Do skija supports graalVm native-image

I’ve never tried it, but it might! The main obstacle is creating window. LWJGL, the library that I use in my examples, does not work in Graal VM. As a result, I have no way to check :(