Thread: RE: [ocemp-devel] Rendering models for OcempGUI
Status: Beta
Brought to you by:
marcusva
From: Benjamin O. <bo...@ve...> - 2005-12-14 21:46:05
|
Marcus, I need a little better understanding of how OcempGUI draws things. As I understand it, under the current model, and with *both* proposed models, any widget is still a Sprite at heart. Thus it can be imported on its own (say, from ocempgui.widgets import button) and used without any other pieces of OcempGUI. A Button could simply be added to a custom sprite group and it would function like any other sprite, even without all the rest of the ocempgui pieces. If either proposed models changes that, then I strongly vote against it. However I don't think they do, as everything will still inherit from Sprite. Second, I'm not sure exactly where the inefficiency of the current model is. Maybe some examples would help me understand: If I have a HFrame with 20 Label children, and I update 5 of them, does the HFrame get redrawn for *each* dirty child widget? So effectively, I want to update the surfaces of 5 widgets, and instead I do 10 updates? So if that HFrame is in a Table, and I update 5 children, then I have to do 15 updates? If that's what the current model is, then I can see how that is very inefficient. I have a solution that might work, but I'm honestly not sure if it fits in the sprite-based model or the partial updates model (or neither). Every container class can keep two surfaces: its active surface, and its "pure" background surface. The background surface only needs to be drawn when the container is created and when its attributes change, and is simply the surface as if it had no children. The container also keeps a Sprite Group (RenderLayer or RenderUpdates, whatever) of its children. Then when a child widget is marked dirty, it clears and draws with only the parent surface, instead of passing the info up the chain: MyGroup.clear(parent.surface, parent.background) MyGroup.draw(parent.surface) Because "clear" and "draw" *only* affect the areas where the sprite rect is, it's more efficient than redrawing the whole surface of the container. Then instead of passing rect info up the chain to the Renderer, the child simply marks the parent as dirty. If 5 children of a container change at the same time, the parent container is just marked dirty 5 times. This continues up the chain until it reaches the top-level container attached to the Renderer. Then the Renderer picks up the top-level container, and blits its surface to the screen. Thus, every update to a child only affects the layer above it. The problem I see to this is that you might make the child surface larger than the parent surface, and the parent won't know it (and expand to fit) until it is time to draw. This is the same problem I had with the ScrolledList in the chat program, so maybe this isn't such a good solution after all. Perhaps you could only force the parent to redraw itself if it detects a child blitting out of its own surface range. I'm not sure how complicated that would be. I'll stop now because this is already longer than I expected and I still want to respond to David Keeney. Ben |
From: Benjamin O. <bo...@ve...> - 2005-12-16 00:07:37
|
It's been a busy day today. I have a few quick thoughts: > No, such a problem can occur in nearly any model, which does not apply > changes instantly. Thus a Container has to maintain size information in > a different way as it is currently done (you mentioned that in another > mail, too). If a child is about to change its size, which also would > affect the container size, this one has to keep track of it, which would > mean some additional parent calls in the set_size() methods and any > other method, that changes the child size. Yeah, personally my opinion is that for whatever the new model is, changes are applied instantly to a widgets surface. Programmatically it just makes more sense. One of the things I don't like with the current model is that a widget doesn't actually have a surface or rect until it's been drawn. This makes it difficult to do something as simple as position a Frame in the middle of the display screen when the Frame is created. > I like the idea you described above, but am concerned about the overhead > in any Container (even a Button would then have a RenderUpdates group). > The model however is nice as it would not mean too many changes to the > current approach, but could speed up several parts by the simple > avoidance of blitting any child, if not necessary. This goes back to the old rule of "you can have low memory or fast performance, but not both." Personally I would rather use more memory and get faster performance. I think in computers today, memory is much easier to get than processor speed. Also, a Sprite Group is still basically just a fancy list. I think the overhead for something like that is probably small. But that's an assumption on my part. The overhead I'm worried about is making every widget have two surfaces: its display surface and its background surface. Also, what if a container has a child widget that moves on top of another child widget? When the first child moves, it can't clear that area with its background, because there's another child in that spot. Maybe the solution is to use spritecollide for any children with dirty set. Any colliding children must also be set to dirty. Ben |
From: Marcus v. A. <ma...@sy...> - 2005-12-16 07:53:32
|
On, Fri Dec 16, 2005, Benjamin Olsen wrote: > It's been a busy day today. I have a few quick thoughts: >=20 > > No, such a problem can occur in nearly any model, which does not apply > > changes instantly. Thus a Container has to maintain size information > in > > a different way as it is currently done (you mentioned that in another > > mail, too). If a child is about to change its size, which also would > > affect the container size, this one has to keep track of it, which > would > > mean some additional parent calls in the set_size() methods and any > > other method, that changes the child size. >=20 > Yeah, personally my opinion is that for whatever the new model is, > changes are applied instantly to a widgets surface. Programmatically it > just makes more sense. One of the things I don't like with the current > model is that a widget doesn't actually have a surface or rect until > it's been drawn. This makes it difficult to do something as simple as > position a Frame in the middle of the display screen when the Frame is > created. Early versions tried to avoid this, but because of a scaring and inflexible rendering model I dropped that some time ago. Reintegration should not be too hard with the new model.=20 >=20 > > I like the idea you described above, but am concerned about the > overhead > > in any Container (even a Button would then have a RenderUpdates > group). > > The model however is nice as it would not mean too many changes to the > > current approach, but could speed up several parts by the simple > > avoidance of blitting any child, if not necessary. >=20 > This goes back to the old rule of "you can have low memory or fast > performance, but not both." Personally I would rather use more memory > and get faster performance. I think in computers today, memory is much > easier to get than processor speed. >=20 > Also, a Sprite Group is still basically just a fancy list. I think the > overhead for something like that is probably small. But that's an > assumption on my part. You might be right. I'll investigate in that and maybe set up an minimalistic ContainerRenderer implementation, that fits the needs here as such a thing (loop approach with blitting and clearing functionality) is needed anyways to accomplish the task. Both cases can be evaluated then and run through a profiling script to get an impression of which of both might be outperform the other one. > The overhead I'm worried about is making every widget have two surfaces: > its display surface and its background surface. Also, what if a The background surface is only of interest for Bins and Containers as any other widget usually occupies its whole display surface and does not need to blit any children on its background. Thus only those containers will become critical parts when it comes to memory overhead and performance. If users need a fully GUI driven environment with all those pieces it is better for them to live with that overhead as it provides a high flexibility while doing things "right", not? > container has a child widget that moves on top of another child widget? > When the first child moves, it can't clear that area with its > background, because there's another child in that spot. > > Maybe the solution is to use spritecollide for any children with dirty > set. Any colliding children must also be set to dirty. This depends on the Container. At the moment all Containers shipped with OcempGUI do not allow that as it makes no sense for them. Frames and Tables are layout containers, that move their children to correct positions and readjust their sizes on demand. Each Button implementation would mess up its own look, if it would allow it and the scrollable widget types like the ScrolledWindow and its inherited class ScrolledList are Bin classes, that can hold only a single child. If users define own implementations, which should allow that (such as a Pane contaienr widget in Gtk+), they have to spend it the necessary code to avoid collisions, so this is not any show stopper at the moment. Regards Marcus |
From: Marcus v. A. <ma...@sy...> - 2005-12-29 20:08:59
|
On, Fri Dec 16, 2005, Marcus von Appen wrote: [...] > > Also, a Sprite Group is still basically just a fancy list. I think the > > overhead for something like that is probably small. But that's an > > assumption on my part. >=20 > You might be right. I'll investigate in that and maybe set up an > minimalistic ContainerRenderer implementation, that fits the needs here > as such a thing (loop approach with blitting and clearing functionality) > is needed anyways to accomplish the task. > Both cases can be evaluated then and run through a profiling script to > get an impression of which of both might be outperform the other one. Unfortunately I am low on time at the moment, which causes me to move the evaluation and creation of a new renderering model over to the next year (haha... :-), so there won't be any news on this the next few days (and possibly the next two or three weeks, too). Questions, concerns and co. are processed as usual however :). I hope you had some nice christmas holidays and will have prosperous new year. Regards Marcus |
From: Ben O. <bo...@ve...> - 2006-01-03 17:14:10
|
Merry Christmas and Happy New Year! Honestly, I took the whole week off last week, and instead of doing productive things like programming, I played around and had fun. It's hard to come back to work today. :) While you're working on testing rendering methods, I'm just going to finish the little project that led me to OcempGUI in the first place. So having a few weeks before testing a new rendering model will work just fine for me. Is there anything you want me to help on in the mean time? Ben > -----Original Message----- > From: oce...@li... [mailto:ocemp-devel- > ad...@li...] On Behalf Of Marcus von Appen > Sent: Thursday, December 29, 2005 1:08 PM > To: Ocemp-devel > Subject: Re: [ocemp-devel] Rendering models for OcempGUI >=20 > On, Fri Dec 16, 2005, Marcus von Appen wrote: >=20 > [...] > > > Also, a Sprite Group is still basically just a fancy list. I think the > > > overhead for something like that is probably small. But that's an > > > assumption on my part. > > > > You might be right. I'll investigate in that and maybe set up an > > minimalistic ContainerRenderer implementation, that fits the needs here > > as such a thing (loop approach with blitting and clearing functionality) > > is needed anyways to accomplish the task. > > Both cases can be evaluated then and run through a profiling script to > > get an impression of which of both might be outperform the other one. >=20 > Unfortunately I am low on time at the moment, which causes me to move > the evaluation and creation of a new renderering model over to the next > year > (haha... :-), so there won't be any news on this the next few days (and > possibly the next two or three weeks, too). > Questions, concerns and co. are processed as usual however :). >=20 > I hope you had some nice christmas holidays and will have prosperous new > year. >=20 > Regards > Marcus |
From: Marcus v. A. <ma...@sy...> - 2006-01-03 19:25:32
|
On, Tue Jan 03, 2006, Benjamin Olsen wrote: [...]=20 > While you're working on testing rendering methods, I'm just going to > finish the little project that led me to OcempGUI in the first place. So > having a few weeks before testing a new rendering model will work just > fine for me. Is there anything you want me to help on in the mean time? No, nothing as several new widgets I have in mind (table grid and a multiline textview) would not make much sense before realizing the new model. Regards Marcus |
From: Marcus v. A. <ma...@sy...> - 2005-12-15 10:49:10
|
On, Wed Dec 14, 2005, Benjamin Olsen wrote: > Marcus, >=20 > I need a little better understanding of how OcempGUI draws things. As I > understand it, under the current model, and with *both* proposed models, > any widget is still a Sprite at heart. Thus it can be imported on its Right. > own (say, from ocempgui.widgets import button) and used without any > other pieces of OcempGUI. A Button could simply be added to a custom > sprite group and it would function like any other sprite, even without > all the rest of the ocempgui pieces. Exactly. This is what I had in mind, when I started with the first implementations. =20 > If either proposed models changes that, then I strongly vote against it. > However I don't think they do, as everything will still inherit from > Sprite. They won't change as this would limit users too much :-). > Second, I'm not sure exactly where the inefficiency of the current model > is. Maybe some examples would help me understand: >=20 > If I have a HFrame with 20 Label children, and I update 5 of them, does > the HFrame get redrawn for *each* dirty child widget? So effectively, I > want to update the surfaces of 5 widgets, and instead I do 10 updates? > So if that HFrame is in a Table, and I update 5 children, then I have to > do 15 updates? No, that's not the way it currently works. Redrawing widgets is done using the "dirty" attribute in the widget's update() method. The theory is something like that: 1) widget needs to be redrawn/updated -> dirty attribute is set to True. 2) If the widget has a parent, its dirty attribute is set to True, too. 3) RenderLayer/Renderer cycle over the sprites and call update() on them. 4) The update() method of the widget(s) cause its surface to be redrawn using draw() _only_, if the dirty attribute is True. 5) Container/Bin will update their children (as they are usually not attached to the RenderLayer directly) and then update themselves 6) Blitting, etc. Your example thus would update only once, both the HFrame and Labels. This however is the theory. As the RenderLayer/Renderer periodically cycle over the sprites it can happen, that the HFrame is updated more than once as a Label possibly will be set to dirty right after updating the HFrame. This approach has low drawing overhead, but another serious problem: It is slow as every widget will be redrawn _fully_. Thus a HFrame will blit _any_ of its associated children to its newly created surface, no matter, if only one or all updated. One will not notice a slowdown on fast machines (I actually noticed it only, when I sat in front of a 800Mhz Athlon). And this is why I want to rewrite the rendering stuff to allow Containers, Bins and possibly other more complex widgets partial updates. > If that's what the current model is, then I can see how that is very > inefficient. I have a solution that might work, but I'm honestly not > sure if it fits in the sprite-based model or the partial updates model > (or neither). > > Every container class can keep two surfaces: its active surface, and its > "pure" background surface. The background surface only needs to be drawn > when the container is created and when its attributes change, and is > simply the surface as if it had no children. The container also keeps a > Sprite Group (RenderLayer or RenderUpdates, whatever) of its children. > Then when a child widget is marked dirty, it clears and draws with only > the parent surface, instead of passing the info up the chain: > MyGroup.clear(parent.surface, parent.background) > MyGroup.draw(parent.surface) > > Because "clear" and "draw" *only* affect the areas where the sprite rect > is, it's more efficient than redrawing the whole surface of the > container. Then instead of passing rect info up the chain to the > Renderer, the child simply marks the parent as dirty. If 5 children of a > container change at the same time, the parent container is just marked > dirty 5 times. This continues up the chain until it reaches the > top-level container attached to the Renderer. Then the Renderer picks up > the top-level container, and blits its surface to the screen. >=20 > Thus, every update to a child only affects the layer above it. The idea sounds interesting as it fits the partial updates quite well. The only problem I see, is the timing. As this model causes the sprite groups of the Containers to be synchronized with the general Renderer timer, you probably will have the same issues with delays in the size information updates. =20 > The problem I see to this is that you might make the child surface > larger than the parent surface, and the parent won't know it (and expand > to fit) until it is time to draw. This is the same problem I had with > the ScrolledList in the chat program, so maybe this isn't such a good > solution after all. No, such a problem can occur in nearly any model, which does not apply changes instantly. Thus a Container has to maintain size information in a different way as it is currently done (you mentioned that in another mail, too). If a child is about to change its size, which also would affect the container size, this one has to keep track of it, which would mean some additional parent calls in the set_size() methods and any other method, that changes the child size. > Perhaps you could only force the parent to redraw itself if it detects a > child blitting out of its own surface range. I'm not sure how > complicated that would be. The parent also needs to be redrawn, whenever its states and possible other attributes change. This however is not the bottleneck. To keep track of size information a parent widget needs to know about its children sizes right after they change. Thus a child should update itself as soon as it changes and inform the parent about that change. The parent then can change its own size, fit the other children accordingly or whatever else and blit the child on its surface. Now it informs its parent and so on the whole chain up. The topmost parent will do the same but be updated and blitted again by the RenderLayer. Several things of this are already accomplished in the current state. The bottlenecks however are in the redrawing approach. As I said, currently every child is blitted again and again on its parent surface, whenever one of the children changes (independant of if it is the affected widget or not) or the parent itself changes. This is one of the main problems to get rid of. I think, I did not make that issue clear enough, when I talked about partial updates and co. Sorry, if my previous descriptions were misleading. I like the idea you described above, but am concerned about the overhead in any Container (even a Button would then have a RenderUpdates group). The model however is nice as it would not mean too many changes to the current approach, but could speed up several parts by the simple avoidance of blitting any child, if not necessary. I'll sort my thoughts and write a bit more about it later. Regards Marcus |