【问题标题】:OpenGL and AWT/Swing User InterfaceOpenGL 和 AWT/Swing 用户界面
【发布时间】:2019-12-06 13:38:25
【问题描述】:

我目前正在为嵌入式系统开发带有 OpenGL (LWJGL) 的 3d 查看器。 无需赘述,有一个使用 Java/Swing 编写的应用程序,目前已在 Java+Swing 上完全实现了 UI 和逻辑。但后来决定,除了 2d 自上而下的图片,还有 3d 视图会很酷,这就是我进来的地方。

我会说我必须使用 GLES 3.0 或 Opengl 2.1,我更喜欢 GLES,因为它与 2.1 相比具有更多功能 我还有一个使用 GLFW 窗口系统(LWJGL 的默认设置)实现的独立应用程序,它在设备上运行良好 - 它不会滞后并提供不错的 FPS。同样,在 GLFW 窗口中运行时。

但现在我需要最好将它附加到 JFrame,这就是我的问题开始的地方。基本上,我需要将我的 3D 视图渲染为背景,然后在其顶部显示 Swing 按钮/面板和其他窗口(例如带有选项菜单)。

我已经实现了一个简单的读取 FrameBuffer 并将其作为光栅图像绘制在画布上的基本算法。但这很慢。我得到了大约 10 FPS。

private void render()
{
    logic.Render(window);      //GLFW window
    window.update();

    ByteBuffer nativeBuffer = BufferUtils.createByteBuffer(GlobalSettings.WINDOW_WIDTH*GlobalSettings.WINDOW_HEIGHT*4);
    BufferedImage image = new BufferedImage(GlobalSettings.WINDOW_WIDTH,GlobalSettings.WINDOW_HEIGHT, BufferedImage.TYPE_4BYTE_ABGR);
    GLES30.glReadPixels(0, 0, GlobalSettings.WINDOW_WIDTH,GlobalSettings.WINDOW_HEIGHT, GLES20.GL_RGBA, GLES30.GL_UNSIGNED_BYTE, nativeBuffer);
    byte[] imgData = ((DataBufferByte)image.getRaster().getDataBuffer()).getData();
    nativeBuffer.get(imgData);

    Graphics g = canvas.getGraphics();
    g.drawImage(image, 0,0, GlobalSettings.WINDOW_WIDTH,GlobalSettings.WINDOW_HEIGHT, null);

}

我尝试过的另一件事是使用这个库https://github.com/LWJGLX/lwjgl3-awt,它似乎被推荐了很多。问题是,它使用了一些 OpenGL 3.1 功能,并且让它在 2.1 环境下完全工作是一项巨大的苦差事。但至于 GLES - 我根本无法让它工作,而且我显然不能让它为 2.1 创建上下文,然后进一步使用 GLES 功能,所以它基本上破坏了我的整个渲染代码。 也许我只是做得不对,但无论如何 - 我无法让它为我工作。

这几乎就是我的立场。我想我会在这里寻求帮助。对我来说,在这一点上,我可能不得不完全为 OpenGL/GLFW 编写整个接口,并完全放弃 Swing。这根本不理想 - 我什至想知道我们是否有这样的时间。

如果有办法让我的东西与 AWT 一起工作,请指出正确的方向。

【问题讨论】:

  • 首先避免使用BufferUtils.createByteBuffer 为每帧分配一个新缓冲区。使用malloc 分配一次,然后一遍又一遍地重复使用。
  • 这是一个正确的建议,但是我发现问题似乎出在 JFrame 本身。即使我在上面做了一些简单的事情,例如画一个点 - 它似乎每秒只更新几次......
  • 我目前正在探索将 AWT 表面设置为 EGL 上下文渲染的直接目标的选项。

标签: java swing embedded awt opengl-es-3.0


【解决方案1】:

我会自己发布一个答案。它在 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));
}

【讨论】:

  • 呃,我不确定我是否有时间。如果我这样做,我会制作一个版本。否则,您可以自己添加修改。它实际上基本上归结为使用 GLES 而不是 OpenGL - 在大多数情况下是 1:1 转换,并使用 EGL 上下文/显示/表面而不是原生表面,因为 GLES 需要 EGL 上下文。
猜你喜欢
  • 2016-08-09
  • 2016-06-18
  • 1970-01-01
  • 1970-01-01
  • 2014-06-14
  • 1970-01-01
  • 1970-01-01
  • 2011-08-15
  • 2013-09-24
相关资源
最近更新 更多