Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Library doesn't work with Gtk under Wayland #1416

Open
Nokse22 opened this issue Apr 30, 2024 · 12 comments
Open

Library doesn't work with Gtk under Wayland #1416

Nokse22 opened this issue Apr 30, 2024 · 12 comments

Comments

@Nokse22
Copy link
Contributor

Nokse22 commented Apr 30, 2024

Describe the bug
I tried to use libf3d with python and Gtk, but it doesn't render and it crashes

To Reproduce
Steps to reproduce the behavior:

  1. Run the provided python code
  2. Open a 3d file
  3. It won't render and it will crash after resizing the window.

Expected behavior
It should render correctly inside the Gtk.GLArea, if I render it outside it works.

System Information:

  • OS: Fedora 40
  • GPU and GPU driver: AMD Radeon™ Graphics

F3D Information
The version of f3d library is 2.4.0 installed with pip

Additional context

import gi
import f3d

gi.require_version('Gtk', '4.0')
gi.require_version('Adw', '1')

from gi.repository import Gtk, Adw

class F3Dwindow(Adw.ApplicationWindow):
    __gtype_name__ = 'F3Dwindow'

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        
        self.set_default_size(300, 300)
        self.set_title("F3D")
        
        self.gl_area = Gtk.GLArea(vexpand=True)
        self.gl_area.connect("realize", self.on_realize)
        self.gl_area.connect("render", self.on_render)
        
        box = Gtk.Box(orientation=1)
        
        button = Gtk.Button(label="open")
        button.connect("clicked", self.open_file_chooser)
        
        hb = Adw.HeaderBar()
        hb.pack_start(button)
        
        box.append(hb)
        box.append(self.gl_area)
        
        self.set_content(box)
        
        f3d.Engine.autoload_plugins()
        self.engine = f3d.Engine(f3d.Window.EXTERNAL)
    
    def on_realize(self, area):
        ctx = area.get_context()

    def on_render(self, area, ctx):
        ctx.make_current()
        self.engine.window.render()
        
        print(area.get_error())
        
        return True

    def open_file_chooser(self, *args):
        dialog = Gtk.FileDialog(
            title="Open File",
        )
        dialog.open(self, None, self.on_open_file_response)

    def on_open_file_response(self, dialog, response):
        file = dialog.open_finish(response)
        print(f"Selected File: {file.get_path()}")

        if file:
            filepath = file.get_path()
            self.engine.loader.load_geometry(filepath)
    
        
class F3Dapp(Adw.Application):
    def __init__(self):
        super().__init__()

    def do_activate(self):
        win = self.props.active_window
        if not win:
            win = F3Dwindow(application=self)
        win.present()

def main():
    app = F3Dapp()
    return app.run()

main()

This code should show an application window with a button to open a 3d model file and a Gtk.GLArea where to render the 3d model.

Every time it renders it prints this:

Current framebuffer is bind to framebuffer object 85
color attachment 0:
 this attachment is a texture with name: 166
 its mipmap level is: 0
 this is not a cube map texture.
 this is not 3D texture.
color attachment 1:
 this attachment is empty
color attachment 2:
 this attachment is empty
color attachment 3:
 this attachment is empty
color attachment 4:
 this attachment is empty
color attachment 5:
 this attachment is empty
color attachment 6:
 this attachment is empty
color attachment 7:
 this attachment is empty
depth attachment :
 this attachment is a texture with name: 167
 its mipmap level is: 0
 this is not a cube map texture.
 this is not 3D texture.
stencil attachment :
 this attachment is empty
there are 8 draw buffers. 
draw buffer[0]=GL_COLOR_ATTACHMENT0
draw buffer[1]=GL_NONE
draw buffer[2]=GL_NONE
draw buffer[3]=GL_NONE
draw buffer[4]=GL_NONE
draw buffer[5]=GL_NONE
draw buffer[6]=GL_NONE
draw buffer[7]=GL_NONE
read buffer=GL_COLOR_ATTACHMENT0

And the result of print(area.get_error()) at line 45 before crashing is:

Segmentation fault (core dumped)

Otherwise is None


I can correctly draw using OpenGL like this and it won't crash:

import gi
import f3d

from OpenGL.GL import *
from OpenGL.GLU import *

[...]

    def on_render(self, area, ctx):
        # self.engine.window.render()
        
        glClearColor(1,0,0,1)
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
        
        print(area.get_error())
        
        return True

[...]

If I do this:

[...]

    def on_render(self, area, ctx):
        img = self.engine.window.render_to_image()

        img.save("/home/user/image.png")
        
        print(area.get_error())
        
        return True

[...]

It will save an image of the same size of the Gtk.GLArea, but all black if no model is loaded or an image like the following one if a geometry is loaded.

image


With Gtk.GLArea I can set the allowed APIs with:

self.gl_area.set_allowed_apis(Gdk.GLAPI.GL)
self.gl_area.set_allowed_apis(Gdk.GLAPI.GLES)

With only GL it will not crash and it will not print anything, with GLES it will.

@Meakk
Copy link
Contributor

Meakk commented Apr 30, 2024

Interesting! Thank you for sharing. I see nothing wrong in your code. I'll try to reproduce locally to take a closer look and let you know.

@Nokse22
Copy link
Contributor Author

Nokse22 commented Apr 30, 2024

Thank you very much!

@Meakk
Copy link
Contributor

Meakk commented Apr 30, 2024

By default it seems like it's using GLES and I have a blank window. When adding self.gl_area.set_allowed_apis(Gdk.GLAPI.GL), GTK seems to complain it cannot create a GL context, any idea?

2024-04-30-111250_window

@Nokse22
Copy link
Contributor Author

Nokse22 commented Apr 30, 2024

I got that error only when setting the GLES api and required version above 3.3 with:

self.gl_area.set_allowed_apis(Gdk.GLAPI.GLES)
self.gl_area.set_required_version(4,0)

When setting only GL it never happened

I can confirm it is using GLES, adding print(area.get_api()) in on_render prints that is using GLES

@snoyer
Copy link
Contributor

snoyer commented Apr 30, 2024

It's interesting that, as @Nokse22 already pointed out, the image from render_to_image() is the right size; we can also add print(self.engine.window.size) to on_render() to see that the engine does indeed resize with the window.
So the the engine and the context/area/surface do get connected to some extent but then the actual rendering fails?

@Nokse22
Copy link
Contributor Author

Nokse22 commented Apr 30, 2024

I got it working but only on X11, the code is the same, I haven't set any preferred API or version for OpenGL and it doesn't crash. I thought it was only the app that didn't support Wayland.

Screenshot from 2024-05-01 00-23-21

@Nokse22 Nokse22 changed the title Library doesn't work with Gtk Library doesn't work with Gtk under Wayland Apr 30, 2024
@Meakk
Copy link
Contributor

Meakk commented May 1, 2024

When using an external window type, libf3d does not handle the OpenGL surface so that's definitely a GTK issue.
However I'm under X11 and it's not working on my side, but my issue looks unrelated to yours.
Anyway, that looks good! Can I borrow your code to add it in the examples?

@snoyer
Copy link
Contributor

snoyer commented May 1, 2024

Also not working on X11 here :(
Maybe #1417 will help narrowing it down?

@Nokse22
Copy link
Contributor Author

Nokse22 commented May 1, 2024

Maybe #1417 will help narrowing it down?

Hopefully so I can also report it properly to GTK

When using an external window type, libf3d does not handle the OpenGL surface so that's definitely a GTK issue.

I will create an issue on GTK

However I'm under X11 and it's not working on my side, but my issue looks unrelated to yours.

That's too bad, I am working on a flatpak, when it's done I'll send it

Anyway, that looks good! Can I borrow your code to add it in the examples?

Of course! While testing I also made one with python and Qt f you want, it also only works in x11:

from PySide6.QtGui import QGuiApplication
from PySide6.QtOpenGL import QOpenGLWindow
import f3d

class F3DWindow(QOpenGLWindow):
    def __init__(self):
        super().__init__()
        self.mEngine = f3d.Engine(f3d.Window.Type.EXTERNAL)
        
        self.mEngine.loader.load_geometry("/path/to/geometry.obj")
        
    def paintGL(self):
        self.mEngine.window.render()
        print("rendering")

def main():
    a = QGuiApplication()
    w = F3DWindow()
    w.setTitle("F3D QT External Window")
    w.resize(300, 300)
    w.show()
    
    return a.exec_()

main()

@Meakk
Copy link
Contributor

Meakk commented May 2, 2024

This example with Qt is working perfectly fine on my side (with X11). Thanks again for sharing, I'll also add it to the examples!

@Nokse22
Copy link
Contributor Author

Nokse22 commented May 3, 2024

More debugging

I have understood that the library uses GL and not GLES and the errors I got were because it was using GLES, forcing GL api on wayland fixes the errors, but it still doesn't render.

Wayland uses EGL as a backend while x11 uses GXL and this seems to be the issue, in fact using EGL on x11 causes the same issue. Unfortunately you can't use GXL in Wayland.

I still don't know if there is an issue in Gtk or something needs to be updated in the library to be able to use it in Wayland.

Using Gtk debug I was able to get the errors that points to some specific API calls

Errors
(exhibit:2): Gdk-CRITICAL **: 19:19:10.270: OPENGL:
    Source: API
    Type: Error
    Severity: High
    Message: GL_INVALID_ENUM in glTexImage2DMultisample(internalformat=GL_NONE)

(exhibit:2): Gdk-WARNING **: 19:19:10.270: OPENGL:
    Source: API
    Type: Other
    Severity: Medium
    Message: FBO incomplete: color attachment incomplete [0]


(exhibit:2): Gdk-CRITICAL **: 19:19:10.270: OPENGL:
    Source: API
    Type: Error
    Severity: High
    Message: GL_INVALID_VALUE in glTexImage2D(internalFormat=GL_NONE)

(exhibit:2): Gdk-CRITICAL **: 19:19:10.270: OPENGL:
    Source: API
    Type: Error
    Severity: High
    Message: GL_INVALID_VALUE in glTexImage2D(internalFormat=GL_NONE)

(exhibit:2): Gdk-WARNING **: 19:19:10.271: OPENGL:
    Source: API
    Type: Other
    Severity: Medium
    Message: FBO incomplete: color attachment incomplete [0]


(exhibit:2): Gdk-CRITICAL **: 19:19:10.271: OPENGL:
    Source: API
    Type: Error
    Severity: High
    Message: GL_INVALID_VALUE in glTexImage2D(internalFormat=GL_NONE)

(exhibit:2): Gdk-WARNING **: 19:19:10.271: OPENGL:
    Source: API
    Type: Other
    Severity: Medium
    Message: FBO incomplete: color attachment incomplete [0]


(exhibit:2): Gdk-CRITICAL **: 19:19:10.271: OPENGL:
    Source: API
    Type: Error
    Severity: High
    Message: GL_INVALID_VALUE in glTexImage2D(internalFormat=GL_NONE)

(exhibit:2): Gdk-WARNING **: 19:19:10.271: OPENGL:
    Source: API
    Type: Other
    Severity: Medium
    Message: FBO incomplete: color attachment incomplete [0]


(exhibit:2): Gdk-WARNING **: 19:19:10.271: OPENGL:
    Source: API
    Type: Other
    Severity: Medium
    Message: FBO incomplete: color attachment incomplete [0]


(exhibit:2): Gdk-CRITICAL **: 19:19:10.271: OPENGL:
    Source: API
    Type: Error
    Severity: High
    Message: GL_INVALID_FRAMEBUFFER_OPERATION in glBlitFramebuffer(incomplete draw/read buffers)

(exhibit:2): Gdk-WARNING **: 19:19:10.271: OPENGL:
    Source: API
    Type: Other
    Severity: Medium
    Message: FBO incomplete: color attachment incomplete [0]


(exhibit:2): Gdk-WARNING **: 19:19:10.271: OPENGL:
    Source: API
    Type: Other
    Severity: Medium
    Message: FBO incomplete: color attachment incomplete [0]


(exhibit:2): Gdk-CRITICAL **: 19:19:10.271: OPENGL:
    Source: API
    Type: Error
    Severity: High
    Message: GL_INVALID_FRAMEBUFFER_OPERATION in glBlitFramebuffer(incomplete draw/read buffers)

(exhibit:2): Gdk-WARNING **: 19:19:10.271: OPENGL:
    Source: API
    Type: Other
    Severity: Medium
    Message: FBO incomplete: color attachment incomplete [0]


(exhibit:2): Gdk-CRITICAL **: 19:19:10.271: OPENGL:
    Source: API
    Type: Error
    Severity: High
    Message: GL_INVALID_FRAMEBUFFER_OPERATION in glBlitFramebuffer(incomplete draw/read buffers)

(exhibit:2): Gdk-WARNING **: 19:19:10.271: OPENGL:
    Source: API
    Type: Other
    Severity: Medium
    Message: FBO incomplete: color attachment incomplete [0]


(exhibit:2): Gdk-CRITICAL **: 19:19:10.271: OPENGL:
    Source: API
    Type: Error
    Severity: High
    Message: GL_INVALID_FRAMEBUFFER_OPERATION in glBlitFramebuffer(incomplete draw/read buffers)

(exhibit:2): Gdk-WARNING **: 19:19:10.275: OPENGL:
    Source: API
    Type: Other
    Severity: Medium
    Message: FBO incomplete: color attachment incomplete [0]


(exhibit:2): Gdk-CRITICAL **: 19:19:10.275: OPENGL:
    Source: API
    Type: Error
    Severity: High
    Message: GL_INVALID_FRAMEBUFFER_OPERATION in glBlitFramebuffer(incomplete draw/read buffers)

(exhibit:2): Gdk-WARNING **: 19:19:10.275: OPENGL:
    Source: API
    Type: Other
    Severity: Medium
    Message: FBO incomplete: color attachment incomplete [0]


(exhibit:2): Gdk-CRITICAL **: 19:19:10.275: OPENGL:
    Source: API
    Type: Error
    Severity: High
    Message: GL_INVALID_FRAMEBUFFER_OPERATION in glClear(incomplete framebuffer)

(exhibit:2): Gdk-CRITICAL **: 19:19:10.275: OPENGL:
    Source: API
    Type: Error
    Severity: High
    Message: GL_INVALID_VALUE in glUniform1i(invalid sampler/tex unit index for uniform 0)

(exhibit:2): Gdk-CRITICAL **: 19:19:10.275: OPENGL:
    Source: API
    Type: Error
    Severity: High
    Message: GL_INVALID_VALUE in glUniform1i(invalid sampler/tex unit index for uniform 1)

(exhibit:2): Gdk-CRITICAL **: 19:19:10.275: OPENGL:
    Source: API
    Type: Error
    Severity: High
    Message: GL_INVALID_VALUE in glUniform1i(invalid sampler/tex unit index for uniform 2)

(exhibit:2): Gdk-CRITICAL **: 19:19:10.275: OPENGL:
    Source: API
    Type: Error
    Severity: High
    Message: GL_INVALID_FRAMEBUFFER_OPERATION in glDrawArrays

(exhibit:2): Gdk-CRITICAL **: 19:19:10.275: OPENGL:
    Source: API
    Type: Error
    Severity: High
    Message: GL_INVALID_VALUE in glUniform1i(invalid sampler/tex unit index for uniform 0)

(exhibit:2): Gdk-WARNING **: 19:19:10.275: OPENGL:
    Source: API
    Type: Other
    Severity: Medium
    Message: FBO incomplete: color attachment incomplete [0]


(exhibit:2): Gdk-CRITICAL **: 19:19:10.285: OPENGL:
    Source: API
    Type: Error
    Severity: High
    Message: GL_INVALID_FRAMEBUFFER_OPERATION in glDrawArrays

(exhibit:2): Gdk-WARNING **: 19:19:10.285: OPENGL:
    Source: API
    Type: Other
    Severity: Medium
    Message: FBO incomplete: color attachment incomplete [0]


(exhibit:2): Gdk-WARNING **: 19:19:10.285: OPENGL:
    Source: API
    Type: Other
    Severity: Medium
    Message: FBO incomplete: color attachment incomplete [0]


(exhibit:2): Gdk-CRITICAL **: 19:19:10.285: OPENGL:
    Source: API
    Type: Error
    Severity: High
    Message: GL_INVALID_FRAMEBUFFER_OPERATION in glBlitFramebuffer(incomplete draw/read buffers)

(exhibit:2): Gdk-WARNING **: 19:19:10.285: OPENGL:
    Source: API
    Type: Other
    Severity: Medium
    Message: FBO incomplete: color attachment incomplete [0]


(exhibit:2): Gdk-CRITICAL **: 19:19:10.285: OPENGL:
    Source: API
    Type: Error
    Severity: High
    Message: GL_INVALID_FRAMEBUFFER_OPERATION in glBlitFramebuffer(incomplete draw/read buffers)

Here is a summary of all the different error messages:

GL_INVALID_ENUM in glTexImage2DMultisample(internalformat=GL_NONE)
GL_INVALID_VALUE in glTexImage2D(internalFormat=GL_NONE)
FBO incomplete: color attachment incomplete [0]
GL_INVALID_FRAMEBUFFER_OPERATION in glBlitFramebuffer(incomplete draw/read buffers)
GL_INVALID_FRAMEBUFFER_OPERATION in glClear(incomplete framebuffer)
GL_INVALID_VALUE in glUniform1i(invalid sampler/tex unit index for uniform 0)
GL_INVALID_VALUE in glUniform1i(invalid sampler/tex unit index for uniform 1)
GL_INVALID_VALUE in glUniform1i(invalid sampler/tex unit index for uniform 2)
GL_INVALID_FRAMEBUFFER_OPERATION in glDrawArrays
FBO incomplete: color attachment incomplete [0]
GL_INVALID_FRAMEBUFFER_OPERATION in glBlitFramebuffer(incomplete draw/read buffers)

@Nokse22
Copy link
Contributor Author

Nokse22 commented Jun 4, 2024

I fixed it compiling all from source and adding VTK_OPENGL_HAS_EGL=ON that is enabled by default only on android, but Wayland uses EGL, so it was missing.

Compiling it this way, though will cause it to not work with X11 with GXL so I had to force EGL on X11 too. Maybe there is a way to make it work both with EGL and GXL.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants