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

Linux|X11 example glitches and high CPU load #2

Closed
pythoneer opened this issue Jul 11, 2021 · 16 comments
Closed

Linux|X11 example glitches and high CPU load #2

pythoneer opened this issue Jul 11, 2021 · 16 comments
Labels
help wanted Extra attention is needed

Comments

@pythoneer
Copy link

pythoneer commented Jul 11, 2021

I am running the webview example and have noticed quite some problems.

I am running:

[naikon@archdesk webview]$ screenfetch 
                   -`                 
                  .o+`                 naikon@archdesk
                 `ooo/                 OS: Arch Linux 
                `+oooo:                Kernel: x86_64 Linux 5.12.15-arch1-1
               `+oooooo:               Uptime: 28m
               -+oooooo+:              Packages: 1621
             `/:-:++oooo+:             Shell: bash 5.1.8
            `/++++/+++++++:            Resolution: 7680x2160
           `/++++++++++++++:           DE: GNOME 40.0
          `/+++ooooooooooooo/`         WM: Mutter
         ./ooosssso++osssssso+`        WM Theme: 
        .oossssso-````/ossssss+`       GTK Theme: Mcata-dark [GTK2/3]
       -osssssso.      :ssssssso.      Icon Theme: Flat-Remix-Blue-Dark
      :osssssss/        osssso+++.     Font: Noto Sans 11
     /ossssssss/        +ssssooo/-     Disk: 672G / 901G (79%)
   `/ossssso+/:-        -:/+osssso+-   CPU: AMD Ryzen 7 3700X 8-Core @ 16x 3.6GHz
  `+sso+:-`                 `.-/+oso:  GPU: Radeon RX 580 Series (POLARIS10, DRM 3.40.0, 5.12.15-arch1-1, LLVM 12.0.0)
 `++:.                           `-/+/ RAM: 4394MiB / 32118MiB
 .`                                 `/

on X11 right now (i'll check wayland later) i have some glitches while running it. First there is a very high CPU load that seems to be a symptom of what looks like that the webview is recreated multiple times. In the attached video you can see that in the application window itself the rendered website "jumps" around. I have tested this with multiple websites and i don't think it has anything to do with rendering glitches of the website with the rendering engine. I made a dual monitor capture because one thing i notices was that my "Dock" on left monitor was hiding and showing rapidly while the example was running. To give a little context here – i have a System-Monitor running in "Fullscreen" on the left monitor and in that case the "Dock" is hiding (it does while every time the focused widow would overlap it). While running the example i noticed "flashing" "mirrors" of the website that gets rendered for brief millisecons (unfortunatly it does not show on the screen capture) but the "Dock" hiding and showing indicates that for a brief moment another window is obscuring the System-Monitor and had focus. After running the example i have occasionally a "dead" window open on the exact place the "flashing" was happening after the example gets closed and i can't close that.

For me it looks like as if the webview is created rapidly multiple times and gets attached to the "main" view (resulting in the jumping of website content) and sometimes that does not work and the webview gets its "own" window poping up on the left monitor and gets closed immediately and sometimes the example application gets closed in between resulting in the "dead" window.

smaller_webview.mp4

better version of the video github only allows mp4 and i don't want the files to get overly large.

The "jumping" and "Dock" hiding etc is much more quickly without the video capturing.

screenshot of the leftover "dead" window on the left screen on the position the short lived copy of the second window
Screenshot from 2021-07-11 10-21-06

@MoAlyousef
Copy link
Collaborator

Hi
Your analysis is right, the webview is created once but the display is flushed repeatedly in the parent's window draw call. Strangely on my kubuntu it works correctly.
I changed the code to only reparent and flush the display once on creation of the webview. Can you try that by cloning the repo and running cargo run --example example?
I also added an app::sleep in src/lib.rs line 261 (but commented out), can you check if the cpu usage is still high, can you try uncommenting that line?
Thank you

@pythoneer
Copy link
Author

The changes did stop the high CPU load. Unfortunately the website does not get rendered properly. I see a black rectangle inside the fltk window that is supposedly the webview. It looks like it responds to mouse events. I can tell by the changing mouse courser in that black rectangle ... i also can "drag and drop" things from inside it – like highlighting text (without visual confirmation/indication) and drag it outside of the window where it gets rendered.

first start
Screenshot from 2021-07-11 16-40-53

highlighting and dragging text out of the rectangle
webview_drag

I also uncommented the app::sleep in src/lib.rs line 261 (even though there was no CPU load problem to begin with) but after that the rendered black rectangle gets stretched to the full size of its supposed position in the parent window but still no correctly rendered content. I tried to make the window resizable (win.make_resizable(true);) to force some kind of redrawing that might got lost due to the last changes but it had no effect.

Screenshot from 2021-07-11 16-43-38

@pythoneer
Copy link
Author

pythoneer commented Jul 11, 2021

To better reproduce this i installed Fedora 34 (https://download.fedoraproject.org/pub/fedora/linux/releases/34/Workstation/x86_64/iso/Fedora-Workstation-Live-x86_64-34-1.2.iso) in VirtualBox and it pretty much looks the same (if a switch to the dark adwaita theme because if the rectangle is dark or not depends on the gnome theme).

Screenshot from 2021-07-11 17-37-34

On top of my head i think i just needed to install this

sudo dnf groupinstall "Development Tools" "Development Libraries"
sudo dnf install clang
sudo dnf install webkit2gtk3-devel
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

cloned the webview repo and cargo runed the example

(and logged in with a gnome x11 session of course)
Screenshot from 2021-07-11 17-42-54

@MoAlyousef
Copy link
Collaborator

Thanks. I’ll try to repro with this setup.

@MoAlyousef
Copy link
Collaborator

MoAlyousef commented Jul 11, 2021

I see the glitches on the fedora vm. The issue seems to be with XReparentWindow which appears to fail for some reason. I've tried several things but unfortunately I can't get it fixed. I've tried comparing my kubuntu machine against the fedora vm, and the differences I see:

  • kubuntu has DRI3 support, fedora on xorg doesn't, even with latest mesa-dri-drivers and a more recent x11 server.
    xdpyinfo | grep DRI
  • kubuntu uses AMD gpu, the vm uses svga3d (offered by vbox).
    glxinfo | grep "renderer string"

@MoAlyousef MoAlyousef added the help wanted Extra attention is needed label Jul 11, 2021
@pythoneer
Copy link
Author

on my machine both commands yield

[naikon@archdesk ~]$ xdpyinfo | grep DRI
    DRI2
    DRI3
[naikon@archdesk ~]$ glxinfo | grep "renderer string"
OpenGL renderer string: Radeon RX 580 Series (POLARIS10, DRM 3.40.0, 5.12.15-arch1-1, LLVM 12.0.0)

So i don't think that is the particular reason but i do think it has something to do with the reparenting. Testing the GDK_BACKEND=x11 from the wayland issue i noticed that as soon as the window was reparented under wayland the black rectangle was visible as we see in this issue here. Without the x11 flag, and thus separated windows, the website rendered just fine in its own window.

@MoAlyousef
Copy link
Collaborator

Looking for similar issues, I found this. It seems on gnome the window manager tries to reparent the window, which is why repeated calls to XReparentWindow show the tearing effect. I'll try looking into this issue closely during the weekend.

@pythoneer
Copy link
Author

pythoneer commented Jul 13, 2021

just out of curiosity what exactly is the reason not to use "just"

inner = wv::webview_create(
    debug as i32,
    &mut win.raw_handle() as *mut *mut raw::c_void as *mut raw::c_void,
);

like on the windows branch? I thought that webview_create would solve this, like i mentioned in the boscop webview issue here where i thought that this webview would track closely the development of the original webview (like the "new" webview/webview(-sys) does today).

Because the current version still says

// Creates a new webview instance. If debug is non-zero - developer tools will
// be enabled (if the platform supports them). Window parameter can be a
// pointer to the native window handle. If it's non-null - then child WebView
// is embedded into the given parent window. Otherwise a new window is created.
// Depending on the platform, a GtkWindow, NSWindow or HWND pointer can be
// passed here.
WEBVIEW_API webview_t webview_create(int debug, void *window);

I would assume the same is true for webview-official-sys is it not? I tried to do it myself but couldn't get the types right for the window handle it obviously is not just a copy paste from the windows branch, maybe its impossible and that is the reason – idk? Is *.raw_handle() just giving the wrong thing on Linux/macOS?

EDIT: I think i get it *.raw_handle() delivers an x11 XID and webview_create accepts GtkWindow

EDIT2:
I know this is unhelpful for KDE (or anything other than Gnome/GTK based Platforms) but maybe there needs to be a code branch for Gnome anyways. I found gdk_x11_window_lookup_for_display that might be helpful. Looks like chromium has a function to convert an XID into a GdkWindow and then a GtkWindow that might be an inspiration

GtkWindow* GetGtkWindowFromX11Window(XID xid) {
  GdkWindow* gdk_window =
      gdk_x11_window_lookup_for_display(gdk_display_get_default(), xid);
  if (!gdk_window)
    return NULL;
  GtkWindow* gtk_window = NULL;
  gdk_window_get_user_data(gdk_window,
                           reinterpret_cast<gpointer*>(&gtk_window));
  if (!gtk_window)
    return NULL;
  return gtk_window;
}

@pythoneer
Copy link
Author

pythoneer commented Jul 13, 2021

Did a little testing but i am just not familiar with GTK/X11 and probably mixed some things up. I added x11 to the cflags in the build.rs

let cflags = std::process::Command::new("pkg-config")
    .args(&["--cflags", "gtk+-3.0", "x11"])
    .output()
    .expect("Needs pkg-config and gtk installed");

and added GetGtkWindowFromX11Window to the gtkwid.c (with some debug prints)

#include <gdk/gdk.h>
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include <X11/X.h>
#include <stdio.h>

long my_get_xid(GdkWindow *win) { return GDK_WINDOW_XID(win); }

GdkWindow *my_get_win(GtkWindow *win) {
  GdkWindow *w = gtk_widget_get_window(GTK_WIDGET(win));
  return w;
}

GtkWindow* GetGtkWindowFromX11Window(XID xid) {

  printf("C xid is %lu\n", xid);
  printf("C default display is %lu\n", gdk_display_get_default());

  GdkWindow* gdk_window =
      gdk_x11_window_lookup_for_display(gdk_display_get_default(), xid);

  printf("C gdk_window is %lu\n", gdk_window);

  if (!gdk_window)
    return NULL;
  GtkWindow* gtk_window = NULL;
  gdk_window_get_user_data(gdk_window,(gpointer*)(&gtk_window));

  printf("C gtk_window is %lu\n", gtk_window);

  if (!gtk_window)
    return NULL;
  return gtk_window;
}

and altered the linux branch of lib.rs a little bit

#[cfg(target_os = "linux")]
{
    use std::os::raw::*;
    // pub enum GdkWindow {}
    pub enum GtkWindow {}
    // pub enum Display {}
    pub enum XID {}
    extern "C" {
        pub fn gtk_init(argc: *mut i32, argv: *mut *mut c_char);
        // pub fn my_get_win(wid: *mut GtkWindow) -> *mut GdkWindow;
        // pub fn my_get_xid(w: *mut GdkWindow) -> u64;
        // pub fn XReparentWindow(
        //     display: *mut Display,
        //     w: u64,
        //     parent: u64,
        //     x: i32,
        //     y: i32,
        // );
        // pub fn XMapWindow(display: *mut Display, w: u64);
        // pub fn XFlush(disp: *mut Display);

        pub fn GetGtkWindowFromX11Window(xid: *mut XID) -> *mut GtkWindow;
    }

    // this is necessary or `gdk_display_get_default` from gtkwid.c::GetGtkWindowFromX11Window
    // always returns `NULL`
    gtk_init(&mut 0, std::ptr::null_mut());

    let xid_handle = win.raw_handle();
    println!("r xid handle: {:?}", xid_handle);
    let gtk_handle = GetGtkWindowFromX11Window(xid_handle as _);
    println!("r gtk handle: {:?}", gtk_handle);

    inner = wv::webview_create(
        debug as i32,
        gtk_handle as *mut *mut raw::c_void as *mut raw::c_void,
    );

    // gtk_init(&mut 0, std::ptr::null_mut());
    // inner = wv::webview_create(debug as i32, std::ptr::null_mut() as _);
    // assert!(!inner.is_null());
    // let temp_win = wv::webview_get_window(inner);
    // let temp = my_get_win(temp_win as _);
    // assert!(!temp.is_null());
    // let xid = my_get_xid(temp as _);
    // let flxid = win.raw_handle();
    // XReparentWindow(app::display() as _, xid, flxid, win.x(), win.y());
    // XMapWindow(app::display() as _, xid);
    // XFlush(app::display() as _);
    // win.draw(move |w| {
    //     wv::webview_set_size(inner, w.w(), w.h(), 0);
    // });
}

without much success. The console output is

r xid handle: 56623108
C xid is 56623108
C default display is 94705467986144
C gdk_window is 0
r gtk handle: 0x0

so for some reason the line

GdkWindow* gdk_window =
      gdk_x11_window_lookup_for_display(gdk_display_get_default(), xid);

is failing and i don't really know why. Interestingly enough xdotool yields those x ids

xdotool search --name "Webview"
60817459
58727212
56623107
71303244

and one of them 56623107 is somehow one off 56623108. i tried the other ones as well (looks like if no other windows are created in the meantime the ids stay the same for consecutive runs) by hand but all the time gdk_window is returned as null unfortunately. I am pretty much stuck here and don't know really what went wrong here – but as i said i am not really sure what i am doing 😄

@MoAlyousef
Copy link
Collaborator

Yeah Gtk methods to derive an XID are specifically made for Gtk widgets/windows that already have a GdkWindow member. Unfortunately things aren't documented as such. I had previously asked on the gnome discourse:
https://discourse.gnome.org/t/gdks-window-foreign-new-for-display-returns-null-for-external-xwindow-xid/6448
but unfortunately got no response.
And as you've noticed, webview only takes a gtk widget/window, so the only other solution is to embed a Gtk window inside an fltk app on linux/bsd. In the latest changes, I've added a different code path for distros with "gnome-shell", not sure if there's a better way to do it, which basically consists of repeated reparenting if the parent changes, this will show as the artifact you described in the beginning (but should be better since the code checks whether the parent was changed before reparenting).

@pythoneer
Copy link
Author

In the latest changes, I've added a different code path for distros with "gnome-shell", not sure if there's a better way to do it, which basically consists of repeated reparenting if the parent changes, this will show as the artifact you described in the beginning (but should be better since the code checks whether the parent was changed before reparenting).

Yes its definitely better – lesser CPU load and the website is more usable (being able to click links, scroll and typing etc. occasionally in between the "flicker" events ) – but still not really usable because of the constant shift of the website. I am unsure where to go from here and how to reach out ... maybe create a pure C fltk demo and post on stackoverflow?

@MoAlyousef
Copy link
Collaborator

Yeah I’ll probably do that eventually if all else fails. I have a few things to try first, like handling the reparent notify event.

@MoAlyousef
Copy link
Collaborator

Can you try the latest changes on your machine, it appears to be working on the fedora vm.

@pythoneer
Copy link
Author

Are you sure its working on the Fedora vm and you have pushed all the changes? I pulled the latest changes (ddbcf94) both on my Arch machine and the Fedora vm and both behave the same by just showing a white window and it looks like i am not able to interact with the "invisible" content (like i could with the black rectangle by highlighting and dragging text etc.)

Screenshot from 2021-07-15 07-08-18

Screenshot from 2021-07-15 07-09-06

I also noticed that while the example was running i was unable to copy and paste the screenshots here in this text input field on github. I also noticed, while on gnome overview (don't know how this is called but when you press the meta/windows key) i rapidly appearing, disappearing application icon but no visible window like that cogwheel/gear icon the example application has and it looks like its stealing the "focus" from the drop target or something

Screenshot from 2021-07-15 07-13-39

@MoAlyousef
Copy link
Collaborator

I’ve posted a question on the fltk mailing list with a repro in C++, the similar questions on stackoverflow have no satisfactory answers.

I’ve tried handling the X11 ReparentNotify event but it doesn’t always register for some reason. Using a simple gtk3 window I don’t get the repeated movements in the window, it does require though repeated reparenting, it seems the webkit2gtk window does some things on its own, which will require further investigation.

@MoAlyousef
Copy link
Collaborator

MoAlyousef commented Aug 19, 2021

Hi
Sorry for the delay. This should be fixed in version 0.2.2. If you have the time to try it out, that would be great.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

2 participants