Java-Programme mit LWJGL verursachen zahlreiche Probleme mit Metal unter macOSJava

Java-Forum
Anonymous
 Java-Programme mit LWJGL verursachen zahlreiche Probleme mit Metal unter macOS

Post by Anonymous »

Ich habe eine einfache, größtenteils funktionierende OpenGL-Anwendung in Java (Version 21) mit LWJGL auf meinem MacBook geschrieben. Das Programm selbst funktioniert einwandfrei, allerdings kam es zu zahlreichen Abstürzen im Zusammenhang mit Metal oder der Speicherverwaltung. Apple scheint OpenGL mit Metal zu emulieren, was erklären würde, warum LWJGL, eine Bindung für OpenGL, Vulkan und verwandte Bibliotheken, Metal-bezogene Fehler auslöst. Hier sind einige Beispiele von dem, was ich gesehen habe:

Code: Select all

-[IOGPUMetalCommandBuffer validate]:214: failed assertion 'commit command buffer with uncommitted encoder'
Dieser Fehler trat auf, als ich zum ersten Mal Bildtexturen mit anpassbaren Parametern richtig funktionieren ließ. Die Textur wird geladen, angezeigt und wendet alle Konfigurationen an, die für das Texture-Objekt bereitgestellt wurden. Wenn das Programm jedoch zu lange geöffnet bleibt, würde diese bestimmte Behauptung fehlschlagen.

Code: Select all

-[AGXG13XFamilyCommandBuffer renderCommandEncoderWithDescriptor:]:964: failed assertion 'A command encoder is already encoding to this command buffer'
Nachdem das Programm mit minimalen Änderungen erneut ausgeführt wurde (ich bin mir nicht einmal sicher, ob ich überhaupt etwas geändert habe), stürzte es erneut ab, dieses Mal mit der oben genannten Fehlermeldung. Irgendwie hat Code ohne oder mit nur sehr wenigen Änderungen, der mit denselben verfügbaren Ressourcen wie zuvor ausgeführt wird, eine andere Behauptung ausgelöst.

Code: Select all

/Library/Java/JavaVirtualMachines/jdk-21.jdk/Contents/Home/bin/java -XstartOnFirstThread -javaagent:[idea runtime and lwjgl stuff from my .m2 dir] net.bunsoft.bunworks.examples.Main
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x0000000133f158d8, pid=21546, tid=51971
#
# JRE version: Java(TM) SE Runtime [url=viewtopic.php?t=25360]Environment[/url] (21.0.2+13) (build 21.0.2+13-LTS-58)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (21.0.2+13-LTS-58, mixed mode, sharing, tiered, compressed oops, compressed class ptrs, g1 gc, bsd-aarch64)
# Problematic frame:
# C  [AppleMetalOpenGLRenderer+0x158d8]  std::__1::pair std::__1::__hash_table::__emplace_unique_key_args(GLRResource* const&, GLRResource*&)+0x5c
#
# No core dump will be written. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# An error report file with more information is saved as:
# /Users/audrey/Documents/Code/jBunworks/hs_err_pid21546.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.
#

Process finished with exit code 134 (interrupted by signal 6:SIGABRT)
Dieses Problem beschäftigt mich, seit ich zum ersten Mal ein Fenster mit GLFW geöffnet habe. Es tritt jedes Mal auf, wenn ich die Fenstergröße ändere. Ich weiß nicht warum, zumal es nicht zu einem Absturz kommt, wenn das Fenster im Vollbildmodus angezeigt wird. Manchmal, nachdem dieser Absturz aufgetreten ist, führt ein Neustart des Programms stattdessen sofort zum Absturz.
Dies ist die Methode, die ich verwende, um eine OpenGL-Textur zu generieren:

Code: Select all

    protected void generate() {
glBindTexture(GL_TEXTURE_2D, id);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
}
Die ID wird bei der Erstellung des Texture-Objekts generiert. Es wird jedes Mal neu generiert, wenn ein neues Bild hochgeladen, der Wrap-Modus oder der Filtermodus geändert wird.
Dies sind alle relevanten Klassen (

Code: Select all

GraphicsDevice
und RenderTarget-Code wurden der Kürze halber entfernt):

Code: Select all

package net.bunsoft.bunworks.render;

import net.bunsoft.bunworks.core.ResourceHelper;
import org.lwjgl.system.MemoryUtil;
import org.lwjgl.system.MemoryStack;

import java.nio.ByteBuffer;
import java.nio.IntBuffer;

import static org.lwjgl.opengl.GL13C.GL_TEXTURE0;
import static org.lwjgl.opengl.GL13C.glActiveTexture;
import static org.lwjgl.opengl.GL30C.glGenerateMipmap;
import static org.lwjgl.stb.STBImage.*;
import static org.lwjgl.opengl.GL11C.*;

public class Texture {
protected int id;

protected ByteBuffer image;
protected int width;
protected int height;
protected int nChannels;

private int wrapMode;
private int minFilter;
private int magFilter;

public Texture() {
id = glGenTextures();
wrapMode = GL_REPEAT;
minFilter = GL_LINEAR_MIPMAP_LINEAR;
magFilter = GL_LINEAR;

generate();
}

public Texture(int width, int height, int nChannels) {
this();

this.width = width;
this.height = height;
this.nChannels = nChannels;

image = ByteBuffer.allocate(width * height * nChannels);
generate();
}

public Texture(String path) {
this();
loadImage(path);
}

public void loadImage(String path) {
byte[] bytes = ResourceHelper.loadBytes(path);
ByteBuffer buf = MemoryUtil.memAlloc(bytes.length);
buf.put(bytes).flip();

try (MemoryStack stack = MemoryStack.stackPush()) {
IntBuffer pw = stack.mallocInt(1);
IntBuffer ph = stack.mallocInt(1);
IntBuffer pc = stack.mallocInt(1);

image = stbi_load_from_memory(buf, pw, ph, pc, 0);
width = pw.get();
height = ph.get();
nChannels = pc.get();

if (image == null) {
System.err.println("Failed to load texture image "  + path);
}
} finally {
MemoryUtil.memFree(buf);
}

generate();
}

public void use(int texUnit) {
glActiveTexture(GL_TEXTURE0 + texUnit);
glBindTexture(GL_TEXTURE_2D, id);
}

public void resize(int w, int h) {
width = w;
height = h;

image = ByteBuffer.allocate(width * height * nChannels);
generate();
}

public int getWrapMode() {
return wrapMode;
}

public void setWrapMode(int wrapMode) {
this.wrapMode = wrapMode;
generate();
}

public int getMinFilter() {
return minFilter;
}

public int getMagFilter() {
return magFilter;
}

public void setFilter(int min, int mag) {
minFilter = min;
magFilter = mag;
generate();
}

protected void generate() {
glBindTexture(GL_TEXTURE_2D, id);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
}
}

Code: Select all

package net.bunsoft.bunworks.render;

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

import java.nio.IntBuffer;

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

public class Window {
private int x;
private int y;
private int w;
private int h;
private String caption;

private long handle;

public Window(int x, int y, int w, int h, String caption) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.caption = caption;
}

public void init() {
GLFWErrorCallback.createPrint(System.err).set();

if (!glfwInit())
throw new IllegalStateException("Windowing system init failed!");

glfwDefaultWindowHints();
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);

handle = glfwCreateWindow(w, h, caption, NULL, NULL);
if (handle == NULL)
throw new RuntimeException("Window creation failed!");

try (MemoryStack stack = MemoryStack.stackPush()) {
IntBuffer pWidth = stack.mallocInt(1); // int*
IntBuffer pHeight = stack.mallocInt(1);  // int*

glfwGetWindowSize(handle, pWidth, pHeight);

GLFWVidMode vidMode = glfwGetVideoMode(glfwGetPrimaryMonitor());
assert vidMode != null;

glfwSetWindowPos(
handle,
(vidMode.width() - pWidth.get(0)) / 2,
(vidMode.height() - pHeight.get(0)) / 2
);
}

glfwSetFramebufferSizeCallback(handle, this::onResize);

glfwMakeContextCurrent(handle);
glfwSwapInterval(1);

glfwShowWindow(handle);
}

public void handleEvents() {
glfwSwapBuffers(handle);
glfwPollEvents();
}

public void close() {
glfwFreeCallbacks(handle);
glfwDestroyWindow(handle);

glfwTerminate();
glfwSetErrorCallback(null).free();
}

public void makeContentCurrent() {
glfwMakeContextCurrent(handle);
GL.createCapabilities();
}

public boolean shouldClose() {
return glfwWindowShouldClose(handle);
}

protected void onResize(long l, int i, int i1) {
w = i;
h = i1;
//surface.resize(w, h);
}
}

Code: Select all

package net.bunsoft.bunworks.core;

import net.bunsoft.bunworks.render.GraphicsDevice;
import net.bunsoft.bunworks.render.Window;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class Game {
public static final double FRAMERATE = 300.0;
public static final double STEPRATE = 240.0;

//protected GraphicsDevice gfx;
protected Window window;

private boolean isRunning;
private int exitCode;

private long frameCounter;
private long stepCounter;
private double timer;

public Game() {
isRunning = false;
exitCode = 0;

window = new Window(100, 100, 640, 480, "Bunworks Game");
//gfx = new GraphicsDevice();
}

public void run() {
isRunning = true;
start();

ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
executor.scheduleAtFixedRate(this::step, 0, (long) (1000000 / STEPRATE), TimeUnit.MICROSECONDS);
executor.scheduleAtFixedRate(this::doDraw, 0, (long) (1000000 / FRAMERATE), TimeUnit.MICROSECONDS);

while (isRunning) {
window.handleEvents();
if (window.shouldClose())
exit(0);
}

executor.shutdown();
end();
}

public void exit(int exitCode) {
this.exitCode = exitCode;
isRunning = false;
}

public int getExitCode() {
return exitCode;
}

public long getFrameCounter() {
return frameCounter;
}

public long getStepCounter() {
return stepCounter;
}

public double getTimer() {
return timer;
}

protected void start() {
window.init();
window.makeContentCurrent();

//gfx.init();
}

protected void step() {
stepCounter++;
timer += 1 / STEPRATE;
}

private void doDraw() {
window.makeContentCurrent();

//gfx.drawStart();
draw();
//gfx.drawEnd();

frameCounter++;
}

protected void draw() {

}

protected void end() {
window.close();
}

}

Code: Select all

package net.bunsoft.bunworks.render;

import static org.lwjgl.opengl.GL15C.*;
import static org.lwjgl.opengl.GL20C.*;
import static org.lwjgl.opengl.GL30C.*;

public class Mesh {
private int vbo;
private int vao;
private int ebo;

private Vertex[] vertices;
private float[] vertexData;
private int[] indices;

public Mesh() {
vbo = glGenBuffers();
vao = glGenVertexArrays();
ebo = glGenBuffers();

vertexData = new float[0];
indices = new int[0];
}

public Mesh(Vertex[] vertices,  int[] indices) {
this();

setVertices(vertices);
setIndices(indices);
}

public void setVertices(Vertex[] vertices) {
this.vertices = vertices;
this.vertexData = new float[vertices.length * Vertex.SIZE];

for (int i = 0; i < vertexData.length; i += Vertex.SIZE) {
Vertex vert = vertices[i / Vertex.SIZE];

vertexData[i] = (float) vert.x;
vertexData[i + 1] = (float) vert.y;
vertexData[i + 2] = (float) vert.z;
vertexData[i + 3] = 1.0f;
vertexData[i + 4] = (float) vert.r;
vertexData[i + 5] = (float) vert.g;
vertexData[i + 6] = (float) vert.b;
vertexData[i + 7] = (float) vert.a;
vertexData[i + 8] = (float) vert.u;
vertexData[i + 9] = (float) vert.v;
}

glBindVertexArray(vao);

glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, vertexData, GL_STATIC_DRAW);

int stride = Vertex.SIZE * Float.BYTES;
glVertexAttribPointer(0, 4, GL_FLOAT, false, stride, 0L);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 4, GL_FLOAT, false, stride, 4L * Float.BYTES);
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, false, stride, 8L * Float.BYTES);
glEnableVertexAttribArray(2);

glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}

public void setIndices(int[] indices) {
this.indices = indices;

glBindVertexArray(vao);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, this.indices, GL_STATIC_DRAW);

glBindVertexArray(0);
}

public void draw() {
glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, indices.length, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}
}

Code: Select all

package net.bunsoft.bunworks.render;

import net.bunsoft.bunworks.core.Property;
import net.bunsoft.bunworks.core.Vec3;

import java.util.HashMap;
import java.util.List;

public class Material {
private ShaderProgram shader;
private HashMap

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post