On Sat, 8 Feb 2020 15:46:36 +0100 Egil Möller <e...@innovationgarage.no> said:
> Hi! > > I have for a time now been working on a new composing window manager to try > out a few UX ideas (https://redhog.github.io/InfiniteGlass videos: > https://www.youtube.com/watch?v=vbt7qtwiLiM > https://www.youtube.com/watch?v=E8f2KwgvxK4). > > However, I'm having a performance problem in my redraw loop: When a lot is > going on, e.g. during continuous stream of mouse events and/or PropertyNotify > events + property gets, DamageNotify events for windows are often queued up > and e.g. animations or video appear choppy. > > To solve that, I start a redraw loop with a certain framerate when the first > damage event comes in, to run for a set time. During this redraw loop, any > window that has had DamageNotify events also on every frame reloads their > contents to their textures, using () / glXBindTexImageEXT(). > This works fairly well, but when windows are large, this does mean that my > renderer process starts eating a lot of CPU. Worse, it does this for a short > amount of time _after_ all window changes have ceased. hint: don't glXCreatePixmap() every time you render. do it only when you first start compositing a window (i.e. on map) and if the window resizes. it'sa slow path to keep doing this every time. the bind is needed for changing gl state to tell it that that pixmap is the texture source. also don't re-get the pixmap every frame/damage. get it once as well at the same times you do glXCreatePixmap(). the pixmap id may change as the xserver may allocate a new pixmap for the newly sized window, but no need to keep doing round trips to the server to get it every damage. also... don't handle every damage event as a draw. accumulate them for some time (until the next frame tick/draw) and then draw it all in one go. also consider using the buffer age extension to limit redraws only to updated regions where you can assume the gl back buffer has content from N frames ago (the buffer age tells you). use a scissor clip and just update the regions you need (do the usual of merge nearby regions into single larger super-regions to do a trade-off of number of render passes vs a bit more overdraw). also just avoid doing any xlib calls that require round trips unless you have to. e.g. only get properties when you have been notified by events that they changed, then store the properties locally and use your local versions until you're told that they have changed ... etc. follow the model of "i shadow copy/store all the server state locally whenever i can and use what i have stored locally on my side until i am told it has changed or circumstances are that what i have is invalid and needs to be thrown out or updated". > Is there a way around this? Is the real solution to not use the X protocol > (or properties) for e.g. controlling animations? get the fd for the xlib server connection and use select() to listen on it for input available to read. when there is then fetch events until no more events exist (while xpending() { xnextevent()....}). and use select timeouts as your animation trigger. if you get your timeouts right you can set it to wake up fairly smoothly e.g. at 60hz. ... if you don't want to animate any frames, don't have a timeout and select "forever" until something comes in from the server. adjust the timeout based on how much time you spent processing events since the last time you went into select. even better - if the /dev/dri/card0 device exists, dlopen libdrm and get some symbols from it and ... use it to request the drm device sent you vsync events so you can use the vsync interrupt as your frame event. this will be another fd to listen on in select() and of course you can turn this vblank event stream on and off. this way your single select loop can multiplex all your i/o with timeouts for animation or vsync events for screen refresh rate bound animation etc. > Would it help to have multiple connections to the X server, and subscribe > only to damage events on one of them? > > I know that damages are not for the whole window but for a certain region, > but I don't think there's a way to update parts of a texture in OpenGL? you don't have to. if you stop creating a pixmap every time... it's zero-copy. or should be. you want to follow my above advice to minimize redraw regions. > Thanks in advance, > Egil just an aside. you want to make a "minimal compositing wm" and also want it fast and efficient and also want to do smooth animation and so on. this is why toolkits exist that have already solved these problems for you. :) they have gone and implemented these select based main loops and have glued in xlib for you and have implemented all the pixmap compositing glue to do it efficiently and have handled "only redraw the regions that update" and glued in vsync if available (or otherwise use the clock-based select timeouts) for animation. as you do more and more you will re-implement more and more of this. you might want to look at how toolkits do this or just use one. :) -- ------------- Codito, ergo sum - "I code, therefore I am" -------------- Carsten Haitzler - ras...@rasterman.com _______________________________________________ xorg-devel@lists.x.org: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: https://lists.x.org/mailman/listinfo/xorg-devel