Re: [Mono-winforms-list] Scrolling performance isues
El dom, 10-08-2008 a las 18:55 -0700, Chris Toshok escribió: Nice. That look pretty good, with the only issue being performance over an X connection with high latency - it'll block all UI until the redraws complete. I thought that was exactly we wanted to do ;-) That said, it's definitely better than what we have now :) Ok to commit for now? Specially for 2.0 :-) Carlos. ___ Mono-winforms-list maillist - Mono-winforms-list@lists.ximian.com http://lists.ximian.com/mailman/listinfo/mono-winforms-list
Re: [Mono-winforms-list] Scrolling performance isues
Nice. That look pretty good, with the only issue being performance over an X connection with high latency - it'll block all UI until the redraws complete. That said, it's definitely better than what we have now :) toshok On Aug 7, 2008, at 12:17 PM, Carlos Alberto Cortez [EMAIL PROTECTED] wrote: Hey Chris Comments below. I'm also not sure flushing the paint queue before doing the XCopyArea (suggestion 1 above) will be enough either. It's very easy to imagine a scenario where you're scrolling and we do another ScrollWindow before all the GraphicsExpose events have been received. We really do need to block things somehow. And it'll be more than just blocking the message queue - we'll need to actually stop the thread if there's a call to ScrollWindow (or anything else that ends up copying) until the GraphicsExposes have been handled. I went and began to review our code and wondering how to do it the proper way - then went to Gtk+ scrolling code once more, and then could see that the gtk textbox was handling the scroll itself (it seems the algorithm is what's called 'smooth scrolling', not sure). The idea is that after each request to scroll, they call XIfEvent to wait for GraphicsExpose/NoExpose events on the scrolled window, blocking the thread until they get one of them (so you can invalidate or exit the loop), and adding a expose operation on the window. I implemented this today for our implementation and it seems to work just fine, and it seems it follows your idea ;-) Take a look and tell what you think. Carlos. PD - The patch is a test, so needs to be beautified still ;-) But should work. xplatx11-changes.patch ___ Mono-winforms-list maillist - Mono-winforms-list@lists.ximian.com http://lists.ximian.com/mailman/listinfo/mono-winforms-list
Re: [Mono-winforms-list] Scrolling performance isues
Hey Chris Comments below. I'm also not sure flushing the paint queue before doing the XCopyArea (suggestion 1 above) will be enough either. It's very easy to imagine a scenario where you're scrolling and we do another ScrollWindow before all the GraphicsExpose events have been received. We really do need to block things somehow. And it'll be more than just blocking the message queue - we'll need to actually stop the thread if there's a call to ScrollWindow (or anything else that ends up copying) until the GraphicsExposes have been handled. I went and began to review our code and wondering how to do it the proper way - then went to Gtk+ scrolling code once more, and then could see that the gtk textbox was handling the scroll itself (it seems the algorithm is what's called 'smooth scrolling', not sure). The idea is that after each request to scroll, they call XIfEvent to wait for GraphicsExpose/NoExpose events on the scrolled window, blocking the thread until they get one of them (so you can invalidate or exit the loop), and adding a expose operation on the window. I implemented this today for our implementation and it seems to work just fine, and it seems it follows your idea ;-) Take a look and tell what you think. Carlos. PD - The patch is a test, so needs to be beautified still ;-) But should work. Index: XplatUIX11.cs === --- XplatUIX11.cs (revisión: 109846) +++ XplatUIX11.cs (copia de trabajo) @@ -4860,6 +4860,33 @@ y = dest_y_return; } + bool GraphicsExposePredicate (IntPtr display, ref XEvent xevent, IntPtr arg) + { + return (xevent.type == XEventName.GraphicsExpose || xevent.type == XEventName.NoExpose) +arg == xevent.GraphicsExposeEvent.drawable; + } + + delegate bool EventPredicate (IntPtr display, ref XEvent xevent, IntPtr arg); + + void ProcessGraphicsExpose (Hwnd hwnd) + { + XEvent xevent = new XEvent (); + IntPtr handle = Hwnd.HandleFromObject (hwnd); + EventPredicate predicate = GraphicsExposePredicate; + + for (;;) { +XIfEvent (Display, ref xevent, predicate, handle); +if (xevent.type != XEventName.GraphicsExpose) + break; + +AddExpose (hwnd, xevent.ExposeEvent.window == hwnd.ClientWindow, xevent.GraphicsExposeEvent.x, xevent.GraphicsExposeEvent.y, + xevent.GraphicsExposeEvent.width, xevent.GraphicsExposeEvent.height); + +if (xevent.GraphicsExposeEvent.count == 0) + break; + } + } + internal override void ScrollWindow(IntPtr handle, Rectangle area, int XAmount, int YAmount, bool with_children) { Hwnd hwnd; IntPtr gc; @@ -4913,6 +4940,8 @@ Rectangle dirty_area = GetDirtyArea (area, dest_rect, XAmount, YAmount); AddExpose (hwnd, true, dirty_area.X, dirty_area.Y, dirty_area.Width, dirty_area.Height); + ProcessGraphicsExpose (hwnd); + XFreeGC(DisplayHandle, gc); } @@ -4966,94 +4995,10 @@ visible_area.Intersect (r); } - // If region is null, the entire area is visible. - // Get the area not obscured otherwise. - Region visible_region = GetVisibleRegion (c, visible_area); - if (visible_region != null) { -RectangleF rectf = visible_region.GetBounds (Hwnd.GraphicsContext); -visible_area = new Rectangle ((int) rectf.X, (int) rectf.Y, - (int) rectf.Width, (int) rectf.Height); - -visible_region.Dispose (); - } - visible_area.Location = c.PointToClient (visible_area.Location); return visible_area; } - // Obscured area by other toplevel windows - Region GetVisibleRegion (Control c, Rectangle visible_area) - { - Region visible_region = null; - IntPtr Root; - IntPtr Parent; - IntPtr Children; - int ChildCount; - - Control form = c.FindForm (); - if (form == null || !form.IsHandleCreated) -return null; - - Hwnd hwnd = Hwnd.GetObjectFromWindow (form.Handle); - IntPtr form_handle = hwnd.whole_window; - - lock (XlibLock) { -XQueryTree (DisplayHandle, RootWindow, out Root, out Parent, out Children, out ChildCount); - } - - int intptr_size = IntPtr.Size; - bool above = false; - - for (int i = 0; i ChildCount; i++) { -IntPtr window = Marshal.ReadIntPtr (Children, i * intptr_size); - -XWindowAttributes win_attrs = new XWindowAttributes (); -lock (XlibLock) { - XGetWindowAttributes (DisplayHandle, window, ref win_attrs); -} - -Rectangle win_area = new Rectangle (win_attrs.x, win_attrs.y, - win_attrs.width, win_attrs.height); - -if (win_attrs.map_state != MapState.IsViewable || !win_area.IntersectsWith (visible_area)) - continue; - -IntPtr SubChildren; -int SubChildCount; - -if (above) { - if (visible_region == null) - visible_region = new Region (visible_area); - - visible_region.Exclude (win_area); - continue; -} - -lock (XlibLock) { - XQueryTree (DisplayHandle, window, out Root, out Parent, out SubChildren, out SubChildCount); -} - -if (SubChildren !=
Re: [Mono-winforms-list] Scrolling performance isues
On Fri, Jul 25, 2008 at 11:34 AM, Ivan N. Zlatev [EMAIL PROTECTED] wrote: Carlos Alberto Cortez wrote: Hey, The new code that detects not visibles areas of the window to scroll (obscured by other mwf windows or x11 top level ones), although working fine, is somewhat slow, as some people have noticed. After some research, I found that getting all the child windows for the root window (using XQueryTree on RootWindow, this is, top level windows) is the hot spot, and was causing the slow down. And after some more research in other graphics tool kits, found that: * Most of them make use of GraphicsExpose event, handling it by directly generating expose events or invalidating the area pointed by GraphicsExpose (Gtk+ as far as I know, and also Ivan told me other frameworks do that). Yes, this is because GraphicsExpose is designed exactly for that purpose. It is fired when a destination area can't be copied (XCopyArea) to because the source area is obscured. I still fail to see why we need special obscured-areas-checking logic when we can just handle that message. You answer your question below - the reason why we couldn't use GraphicsExpose is precisely because of the timing issue. Calculating the exact region to expose is just one possible solution (which turns out to likely be the wrong one). I do understand that if we do indeed handle the GraphicsExpose message we stand the problem that it might get delayed (X11 message roundtrip time) until after we perform the next ScrollWindow/XCopyArea, so because the destination area (for the previous ScrollWindow call) won't be repainted yet we will copy that garbage from it to the next offset. However we currently have an explicit AddExpose just after the XCopyArea, so we are working around this problem by forcing a repaint on the queue, so that we are guaranteed to be repainted prior to the next ScrollWindow. And this just-works (tm) :-) If we want to handle it properly we can either 1) Flush the paint queue prior to XCopyArea somehow ... or ... 2) Block the message queue until we get the last GraphicsExpose for the window, invalidate and then unblock the message queue. ... or ... 3) Something better And also, regarding our code: * When using composite (Xgl or similar) it's not necessary to do this detection, since the window manager (*it seems*) is doing something that somehow already knows which areas need to get an expose event (in other words: only mwf overlapping detection is needed, not for x top level windows). * The new code, at least in my laptop, without using composite, seems to work fine (no performance lost), and don't know if it's because XQueryTree on RootTree returns a minor number of windows (61 with no composite, instead of 89 with composite, using 5 terminals and a gtk+ application, for example). This I think is very implementation/environment/window manager/toolkit specific. E.g some toolkits/window managers might keep menu windows as hidden, but still mapped toplevels. I think this was referred to as one of the reason for the huge number of toplevels in some email I saw on a mailing list long time ago. Because of the variety of setups out there (window managers, toolkits, etc, etc) we can't really know with how many toplevels we are going to deal. To give you an example of the problem - on my GNOME + Metacity desktop with a standard set of programs running (Firefox, terminal, pidgin, nautilus, thunderbird, etc) XQueryTree returns 228 toplevels. So, it seems that we should actually handle GraphicsExpose (which all it involves) *or maybe* try to detect if we are using composite - if we are, simply don't use this new code, but just do simple calculations, and if we are not using it, do the detection, since it won't harm the performance. My personal position on the matter is that short-term (as in for Mono 2.0) we just handle GraphicsExpose instead of the new code and keep the AddExpose after XCopyArea to workaround the timing issue. Long-term we can look into adding a proper handling for the delays of GraphicsExpose if it's feasible. This has me a little confused - adding handling for GraphicsExpose isn't going to help anything if it's not done properly. What I mean is, adding the handling for GraphicsExpose (essentially adding the case statement and doing an AddExpose) won't give us anything more than what we currently have, since we can't guarantee that any of those events will have been received. It's a trivial change, and might lessen the problem somewhat, but it won't fix it. I'm also not sure flushing the paint queue before doing the XCopyArea (suggestion 1 above) will be enough either. It's very easy to imagine a scenario where you're scrolling and we do another ScrollWindow before all the GraphicsExpose events have been received. We really do need to block things somehow. And it'll be more than just blocking the
[Mono-winforms-list] Scrolling performance isues
Hey, The new code that detects not visibles areas of the window to scroll (obscured by other mwf windows or x11 top level ones), although working fine, is somewhat slow, as some people have noticed. After some research, I found that getting all the child windows for the root window (using XQueryTree on RootWindow, this is, top level windows) is the hot spot, and was causing the slow down. And after some more research in other graphics tool kits, found that: * Most of them make use of GraphicsExpose event, handling it by directly generating expose events or invalidating the area pointed by GraphicsExpose (Gtk+ as far as I know, and also Ivan told me other frameworks do that). And also, regarding our code: * When using composite (Xgl or similar) it's not necessary to do this detection, since the window manager (*it seems*) is doing something that somehow already knows which areas need to get an expose event (in other words: only mwf overlapping detection is needed, not for x top level windows). * The new code, at least in my laptop, without using composite, seems to work fine (no performance lost), and don't know if it's because XQueryTree on RootTree returns a minor number of windows (61 with no composite, instead of 89 with composite, using 5 terminals and a gtk+ application, for example). So, it seems that we should actually handle GraphicsExpose (which all it involves) *or maybe* try to detect if we are using composite - if we are, simply don't use this new code, but just do simple calculations, and if we are not using it, do the detection, since it won't harm the performance. But I woould like people to tell me how this code (2.0 branch or trunk) behaves for them, in both cases (since I remember that Ivan was having performance problems with the new code even without using composite). Hope it's clear ;-) Carlos. ___ Mono-winforms-list maillist - Mono-winforms-list@lists.ximian.com http://lists.ximian.com/mailman/listinfo/mono-winforms-list
Re: [Mono-winforms-list] Scrolling performance isues
Carlos Alberto Cortez wrote: Hey, The new code that detects not visibles areas of the window to scroll (obscured by other mwf windows or x11 top level ones), although working fine, is somewhat slow, as some people have noticed. After some research, I found that getting all the child windows for the root window (using XQueryTree on RootWindow, this is, top level windows) is the hot spot, and was causing the slow down. And after some more research in other graphics tool kits, found that: * Most of them make use of GraphicsExpose event, handling it by directly generating expose events or invalidating the area pointed by GraphicsExpose (Gtk+ as far as I know, and also Ivan told me other frameworks do that). Yes, this is because GraphicsExpose is designed exactly for that purpose. It is fired when a destination area can't be copied (XCopyArea) to because the source area is obscured. I still fail to see why we need special obscured-areas-checking logic when we can just handle that message. I do understand that if we do indeed handle the GraphicsExpose message we stand the problem that it might get delayed (X11 message roundtrip time) until after we perform the next ScrollWindow/XCopyArea, so because the destination area (for the previous ScrollWindow call) won't be repainted yet we will copy that garbage from it to the next offset. However we currently have an explicit AddExpose just after the XCopyArea, so we are working around this problem by forcing a repaint on the queue, so that we are guaranteed to be repainted prior to the next ScrollWindow. And this just-works (tm) :-) If we want to handle it properly we can either 1) Flush the paint queue prior to XCopyArea somehow ... or ... 2) Block the message queue until we get the last GraphicsExpose for the window, invalidate and then unblock the message queue. ... or ... 3) Something better And also, regarding our code: * When using composite (Xgl or similar) it's not necessary to do this detection, since the window manager (*it seems*) is doing something that somehow already knows which areas need to get an expose event (in other words: only mwf overlapping detection is needed, not for x top level windows). * The new code, at least in my laptop, without using composite, seems to work fine (no performance lost), and don't know if it's because XQueryTree on RootTree returns a minor number of windows (61 with no composite, instead of 89 with composite, using 5 terminals and a gtk+ application, for example). This I think is very implementation/environment/window manager/toolkit specific. E.g some toolkits/window managers might keep menu windows as hidden, but still mapped toplevels. I think this was referred to as one of the reason for the huge number of toplevels in some email I saw on a mailing list long time ago. Because of the variety of setups out there (window managers, toolkits, etc, etc) we can't really know with how many toplevels we are going to deal. To give you an example of the problem - on my GNOME + Metacity desktop with a standard set of programs running (Firefox, terminal, pidgin, nautilus, thunderbird, etc) XQueryTree returns 228 toplevels. So, it seems that we should actually handle GraphicsExpose (which all it involves) *or maybe* try to detect if we are using composite - if we are, simply don't use this new code, but just do simple calculations, and if we are not using it, do the detection, since it won't harm the performance. My personal position on the matter is that short-term (as in for Mono 2.0) we just handle GraphicsExpose instead of the new code and keep the AddExpose after XCopyArea to workaround the timing issue. Long-term we can look into adding a proper handling for the delays of GraphicsExpose if it's feasible. But I woould like people to tell me how this code (2.0 branch or trunk) behaves for them, in both cases (since I remember that Ivan was having performance problems with the new code even without using composite). As I mentioned above with my setup I have 228 toplevels and I get garbage everywhere when scrolling on a Core Duo 2 machine. Tell me what do you think, Cheers, -- Ivan N. Zlatev Web: http://www.i-nZ.net It's all some kind of whacked out conspiracy. ___ Mono-winforms-list maillist - Mono-winforms-list@lists.ximian.com http://lists.ximian.com/mailman/listinfo/mono-winforms-list