我会自己发布一个答案。它在 Linux 桌面和嵌入式系统上都运行良好,据我所知性能良好。
这个想法是采用 EGL 上下文和 GLES,并将 AWT 画布表面设置为上下文的直接目标。您无需读取缓冲区然后将其绘制在画布上。
下面是我的 Window 类初始化。
private Canvas canvas;
private JAWTDrawingSurface ds;
public long display;
private long eglDisplay;
public long drawable;
private long surface;
public static final JAWT awt;
static {
awt = JAWT.calloc();
awt.version(JAWT_VERSION_1_4);
if (!JAWT_GetAWT(awt))
throw new AssertionError("GetAWT failed");
}
public void lock() throws AWTException {
int lock = JAWT_DrawingSurface_Lock(ds, ds.Lock());
if ((lock & JAWT_LOCK_ERROR) != 0)
throw new AWTException("JAWT_DrawingSurface_Lock() failed");
}
public void unlock() throws AWTException {
JAWT_DrawingSurface_Unlock(ds, ds.Unlock());
}
public void Init2()
{
frame = new JFrame("AWT test");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.setPreferredSize(new Dimension(width, height));
canvas = new Canvas();
frame.add(canvas);
frame.pack();
frame.setVisible(true);
frame.transferFocus();
int error;
System.out.println("Window init2() started");
this.ds = JAWT_GetDrawingSurface(canvas, awt.GetDrawingSurface());
//JAWTDrawingSurface ds = JAWT_GetDrawingSurface(canvas, awt.GetDrawingSurface());
try
{
lock();
try
{
JAWTDrawingSurfaceInfo dsi = JAWT_DrawingSurface_GetDrawingSurfaceInfo(ds, ds.GetDrawingSurfaceInfo());
JAWTX11DrawingSurfaceInfo dsiWin = JAWTX11DrawingSurfaceInfo.create(dsi.platformInfo());
int depth = dsiWin.depth();
this.display = dsiWin.display();
this.drawable = dsiWin.drawable();
System.out.printf("EGL Display %d, drawable: \n", display, drawable);
eglDisplay = eglGetDisplay(display);
EGLCapabilities egl;
try (MemoryStack stack = stackPush()) {
IntBuffer major = stack.mallocInt(1);
IntBuffer minor = stack.mallocInt(1);
if (!eglInitialize(eglDisplay, major, minor)) {
throw new IllegalStateException(String.format("Failed to initialize EGL [0x%X]", eglGetError()));
}
egl = EGL.createDisplayCapabilities(eglDisplay, major.get(0), minor.get(0));
}
System.out.println("EGL caps created");
IntBuffer attrib_list = BufferUtils.createIntBuffer(18);
attrib_list.put(EGL_CONFORMANT).put(EGL_OPENGL_ES2_BIT);
//attrib_list.put(EGL_ALPHA_MASK_SIZE).put(4);
//attrib_list.put(EGL_ALPHA_SIZE).put(4);
//attrib_list.put(EGL_RED_SIZE).put(5);
//attrib_list.put(EGL_GREEN_SIZE).put(6);
//attrib_list.put(EGL_BLUE_SIZE).put(5);
//attrib_list.put(EGL_DEPTH_SIZE).put(4);
//attrib_list.put(EGL_SURFACE_TYPE).put(EGL_WINDOW_BIT);
attrib_list.put(EGL_NONE);
attrib_list.flip();
PointerBuffer fbConfigs = BufferUtils.createPointerBuffer(1);
IntBuffer numConfigs = BufferUtils.createIntBuffer(1);
boolean test2 = eglChooseConfig(eglDisplay, attrib_list, fbConfigs,numConfigs);
if (fbConfigs == null || fbConfigs.capacity() == 0) {
// No framebuffer configurations supported!
System.out.println("No supported framebuffer configurations found");
}
long test = numConfigs.get(0);
IntBuffer context_attrib_list = BufferUtils.createIntBuffer(18);
context_attrib_list.put(EGL_CONTEXT_MAJOR_VERSION).put(3);
context_attrib_list.put(EGL_CONTEXT_MINOR_VERSION).put(0);
context_attrib_list.put(EGL_NONE);
context_attrib_list.flip();
long context = eglCreateContext(eglDisplay,fbConfigs.get(0),EGL_NO_CONTEXT,context_attrib_list);
error = eglGetError();
surface = eglCreateWindowSurface(eglDisplay,fbConfigs.get(0),drawable,(int[])null);
error = eglGetError();
eglMakeCurrent(eglDisplay,surface,surface,context);
error = eglGetError();
GLESCapabilities gles = GLES.createCapabilities();
System.out.println("CLES caps created");
}
finally
{
unlock();
}
}
catch (Exception e)
{
System.out.println("JAWT Failed");
}
// Render with OpenGL ES
glClearColor(0f,0f,0f,1f);
glfwSwapInterval(vSync);
glEnable(GL_DEPTH_TEST);
int[] range = new int[2];
int[] precision = new int[2];
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_HIGH_FLOAT, range, precision);
System.out.println("Window context Initialized");
}
请注意,属性列表可以是您想要的任何东西,也可以什么都不是。尽管我没有将 3.0 指定为上下文的版本兼容性,但实际上我遇到了 GLES 问题 - 它出于某种原因尝试使用 OpenGl ES-CL 1.1 并失败了。无论如何,只需指定次要和主要上下文版本即可修复它。
另请注意,这只是初始化。 JFrame 和 Canvas 在其他地方创建,然后将 Canvas 传递给 Window 类构造函数。
另一个重要的事情是 lock() / unlock() 功能。如果没有它们,您会遇到很多 XCB 错误和崩溃 - 因为其他线程会在您绘制时尝试更新显示,从而导致冲突并且 XCB 会崩溃。
此外,您需要在交换缓冲区时(即实际绘制帧缓冲区时)进行锁定和解锁。
public void update()
{
try
{
lock();
eglSwapBuffers(eglDisplay, surface);
unlock();
}
catch (Exception e)
{
System.out.println("Swap buffers failed");
}
}
不要介意我当前的异常处理能力不足 - 一旦我找到解决方案,我将立即编辑我的答案,以免我以前的版本让人们感到困惑。
我还要感谢 lwjgl-awt 项目,因为它给了我一些想法。它不支持 EGL,所以我不得不对其进行一些修改,但我从那里获取了部分内容,因此应归功于应得的信用。
https://github.com/LWJGLX/lwjgl3-awt
为了比较,这里是 GLFW 版本。它基本上是同一个类的初始化,但它只是做其他事情。然而,这里的窗口是直接在方法内部创建的。
public void Init()
{
System.out.println("Window init() started");
GLFWErrorCallback.createPrint().set();
if (!glfwInit()) {
throw new IllegalStateException("Unable to initialize glfw");
}
glfwDefaultWindowHints();
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
// GLFW setup for EGL & OpenGL ES
glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
windowHandle = glfwCreateWindow(width, height, title, NULL, NULL);
if (windowHandle == NULL) {
throw new RuntimeException("Failed to create the GLFW window");
}
System.out.printf("Window handle created %d\n", windowHandle);
SetCallbacks();
// EGL capabilities
displayHandle = glfwGetEGLDisplay();
System.out.printf("EGL DisplayHandle %d\n", displayHandle);
try (MemoryStack stack = stackPush()) {
IntBuffer major = stack.mallocInt(1);
IntBuffer minor = stack.mallocInt(1);
if (!eglInitialize(displayHandle, major, minor)) {
throw new IllegalStateException(String.format("Failed to initialize EGL [0x%X]", eglGetError()));
}
EGLCapabilities egl = EGL.createDisplayCapabilities(displayHandle, major.get(0), minor.get(0));
}
System.out.println("EGL caps created");
// OpenGL ES capabilities
glfwMakeContextCurrent(windowHandle);
System.out.printf("Current context: %d.%d rev %d, Client_Context: %d\n",glfwGetWindowAttrib(windowHandle,GLFW_CONTEXT_VERSION_MAJOR),
glfwGetWindowAttrib(windowHandle,GLFW_CONTEXT_VERSION_MINOR), glfwGetWindowAttrib(windowHandle,GLFW_CONTEXT_REVISION),
glfwGetWindowAttrib(windowHandle,GLFW_CLIENT_API));
GLESCapabilities gles = GLES.createCapabilities();
System.out.println("CLES caps created");
// Render with OpenGL ES
//glfwShowWindow(windowHandle);
glClearColor(0f,0f,0f,1f);
glfwSwapInterval(vSync);
glEnable(GL_DEPTH_TEST);
int[] range = new int[2];
int[] precision = new int[2];
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_HIGH_FLOAT, range, precision);
System.out.printf("Current context: %d.%d\n",glfwGetWindowAttrib(windowHandle,GLFW_CONTEXT_VERSION_MAJOR),
glfwGetWindowAttrib(windowHandle,GLFW_CONTEXT_VERSION_MINOR));
}