About software rendering

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
User avatar
Shaun
Member
Member
Posts: 43
Joined: Mon Sep 17, 2012 3:14 am
Contact:

About software rendering

Post by Shaun »

Hi,guys!

I have a problem about software rendering, and i found that it is a tough work about gui stuff. I have try a lot to find a way to solve my problem,and i failed because of the lack of wiki, toturials or codes. so, i would be very appreciate if some can post me some details.

Ok, let's check out my current status and problem, i have a well functional vesa driver, and i can draw anything i want on screen. I tend to using double buffering for performence consideration. let's say the the vedio memory address is A, and i reserved the same size memory in system memory address space which is B, when i draw something on screen, i just draw it in B,and then do a fast memcpy from B to A.By the way, i have made a bitblt() function based on the description of MSDN(http://msdn.microsoft.com/en-us/library ... s.85).aspx), and it also work fine.

now, my desktop have some pictures, and i want to move one from position PA to position PB, if there is nothing but a background picture underneath it, i just restore the old place pixels using bitblt() with raster operation code = SRCCOPY,
but, when there are two or more pictures underneath it, how could i figure out which picture i should redraw.

for example, the orignal desktop looks like this:
12.jpg
when i do a moving of the mail picture, the desktop looks like this:
13.jpg
there are three places i should redraw, Message, Pictures,and the old place of Mail picture. I would be very appreciate that someone can share some good solutions. thanks a lot.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: About software rendering

Post by Combuster »

when there are two or more pictures underneath it, how could i figure out which picture i should redraw.
There wouldn't be one. It would be all of them. In back-to-front order.

There are a number of geometry tricks you can try, but the basics involve the following:
1: Get all the area that needs changing as a rectangle.
2: Get all objects that have an overlapping bounding rectangle.
3: Sort these objects back-to-front
4: Draw each of them, but only draw the area that needs changing.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
Shaun
Member
Member
Posts: 43
Joined: Mon Sep 17, 2012 3:14 am
Contact:

Re: About software rendering

Post by Shaun »

@Combuster

great thanks for your reply and tricks.
There wouldn't be one. It would be all of them. In back-to-front order.
Yep,
1: Get all the area that needs changing as a rectangle.
this is easy to get.
2: Get all objects that have an overlapping bounding rectangle.
I got stuck here actually. I maintain all object's coordinate and height, width in a linked list struct. take a look at my draft picture below.
33.jpg
i move rectangle C1 to C2, after that, the A1, D1, and B1 rectangle should be redraw.On my opinion, The C1's coordinate is (x1, y1),
according to C1's x1 and its width, look up the linked list to get all objects which x1 is little than C1's. and then do the same for y1,
it's my current idea, i have not implemented it. i hope i clarified my points.Anyway, i will take a try.

thanks again.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: About software rendering

Post by Brendan »

Hi,
Shaun wrote:I got stuck here actually. I maintain all object's coordinate and height, width in a linked list struct. take a look at my draft picture below.
When something is moved:
  • everything in the area it was in needs to be redrawn
  • everything in the area it has moved to needs to be redrawn
For moving a rectangle, this gives you 2 "damaged areas of the screen" that need to be redrawn.

It should be easy (given all object's coordinates and height, width) to determine which objects are partially or completely effected by either "damaged area of the screen" and then redraw all effected objects. This is easier but slower.

It should also be possible to only redraw the pieces of each object that are effected, rather than redrawing the entire object that's effected. In this case, for each object you construct a list of "damaged areas of the object" (by determining which areas of the object overlap with the "damaged areas of the screen"). This is a bit harder, but faster.

Further, because there are 2 different "damaged areas of the screen" a single object can have 2 "damaged areas of the object". These "damaged areas of the object" can overlap; which can cause the same damaged area of the object to be redrawn twice (once for each damaged area of the screen). To solve that; you can split the initial 2 "damaged areas of the screen that may overlap" into multiple smaller "damaged area of the screen that do not overlap". In this case, the list of "damaged areas of the object" may have many more damaged areas, but none of the areas will overlap and therefore nothing will be redrawn unnecessarily. This is even harder, but even faster.

In any case, once you've got lists of "damaged areas of the objects", you can either redraw them in back-to-front order; or do further processing to avoid redrawing anything that's behind something else.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
User avatar
Shaun
Member
Member
Posts: 43
Joined: Mon Sep 17, 2012 3:14 am
Contact:

Re: About software rendering

Post by Shaun »

Hi,Brendan

First, thanks a lot for your advice and solutions. it's really do me a big favor!

After a week days hardworking, i made it finally. i maaaaaaaaade it! =D>

Now i can move it to anywhere i want. it's awwwwwwwesome.
Screenshot-1.jpg
Second, let's talk about it further more about gui theory.

In my current implementation, i create a gui kernel thread when kernel starts finished. This Gui thread mainly poll for mouse and keyboard for getting user input informations, when user doing a mouse move action or typing a key , the mouse driver or keyboard driver will wake up the gui thread, then the gui thread do the window redrawing stuff, in next step, this gui thread will also send mouse action(move, drag, button down. etc) to specified window. Is this way sounds reasonable?
I am not professional on Windows GUI, only know that windows send WM_PAINT message to window when mouse move, in fact, who take in charge the redrawing work?(kernel, framework, or user app?)

thanks again.
alexfru
Member
Member
Posts: 1112
Joined: Tue Mar 04, 2014 5:27 am

Re: About software rendering

Post by alexfru »

In Windows, the user application must redraw itself on WM_PAINT. The message contains the region coordinates.

It isn't often visible nowadays, but when the application is busy and can't redraw, you'd see its window become garbled when you move something across it, it simply fails to cover up someone else's tracks fast enough.
User avatar
Shaun
Member
Member
Posts: 43
Joined: Mon Sep 17, 2012 3:14 am
Contact:

Re: About software rendering

Post by Shaun »

alexfru wrote:In Windows, the user application must redraw itself on WM_PAINT. The message contains the region coordinates.
As far as i can remember, i haven't written any redrawing codes when i create a MFC application.I can find WM_PAINT message handler in source code that was generated by IDE(visual stdio), but just ignore it. Maybe the redrawing code locates in some MFC framework dlls? :-k

anyway, is it better for puting redrawing work in user apps?
klange
Member
Member
Posts: 679
Joined: Wed Mar 30, 2011 12:31 am
Libera.chat IRC: klange
Discord: klange

Re: About software rendering

Post by klange »

Shaun wrote:anyway, is it better for puting redrawing work in user apps?
This depends not on what's "better" but what method you use for drawing windows.

The traditional method for drawing windows is that each application gets its turn to draw directly to the screen, usually through some sort of "pen". This means the only source of truth for what a window looks like is the pixels on screen, and the applications themselves. So if we move a window, all of the applications underneath it need to redraw (the window we moved doesn't necessarily need to redraw though, as we can bitblit it from its old position to its new position if it was the top window). The primary advantage of this system is that it is very inexpensive for memory - you only have the display memory to worry about, and you're probably not even double buffering it. The primary disadvantage of this approach is it is time expensive to redraw things, which you're going to be doing a lot of, and a misbehaving application will cause graphical issues for the whole system.

Modern OSes have moved away from this approach to what's called compositing window managers or compositors. Compositors work by giving each individual window its own buffer (or canvas), which the application is free to draw into in some way: sometimes by pens (old Windows apps, X11 before the SHM extension), but more often through direct access - perhaps through a 3d graphics interface (Direct3D, OpenGL). When a window moves or changes, the screen is redrawn (with appropriate optimizations) from the various window buffers by the compositor (often employing effects like alpha blending). Through this approach, an application will never have to service a redraw request - it doesn't even need to know about changes to other applications' windows. We can also perform additional effects like rotating windows or even mapping windows to surfaces in a 3d environment.

Windows has used a compositor (DWM) since Vista. OS X has used a compositor (WindowServer / Quartz Compositor) since its first release (originally purely in software, then later hardware accelerated). X11 has had a number of compositors, notably Compiz (which I worked on), and all of the modern DE window managers (KWin, Gnome's Metacity and Mutter, etc.; Ubuntu' Unity is just a plugin for Compiz). Wayland is seeking to replace X11 and is effectively a compositor protocol, with no room for the traditional approach.

While compositing window managers have quite a bit of history (the Amiga had a compositor), they were not popularly used until OS X, primarily because holding a buffer for each individual window takes a lot of memory. With modern graphics cards, and even just modern RAM, this isn't an issue any more, so modern systems are overwhelming using compositing.
alexfru
Member
Member
Posts: 1112
Joined: Tue Mar 04, 2014 5:27 am

Re: About software rendering

Post by alexfru »

Shaun wrote:anyway, is it better for puting redrawing work in user apps?
Consider this. If the OS (re)draws stuff for you, it must know how to (re)draw it. Which, in turn, means that your OS must offer not only routines for drawing various graphical primitives (shapes, bitmaps, text), but also high-level objects like buttons, list boxes, edit boxes, scrollers and so on and it would need to traverse some data structure (created and possibly updated by the app and the updates can create race conditions) and examine them. While that's not a problem in itself and it probably has some advantages (like all apps would use the same common controls and generally have the same look and feel and the same code wouldn't need to be duplicated across many apps (you could put it into a DLL, though)), what are you going to do about custom thingies that only the application knows how to draw and and that aren't provided by the OS, like some specialized edit boxes for passwords (not the best example since these days that's a must have, but still) and non-standard menus? You'd need to either force all those non-standard things to be a bitmap accessible to the OS (and possibly cached in the OS, in case it's not accessible at the time of redraw) or to make an exception and still deliver some kind of WM_PAINT for these special things. If the app draws itself, the OS is smaller and simpler, but, conversely, the app is bigger and more complex. The raw Win32 API is too primitive and inconvenient to program against, which is what MFC tried to address, but never really succeeded (Borland Delphi's VCL was far more programmer-friendly, AFAIR).
User avatar
Owen
Member
Member
Posts: 1700
Joined: Fri Jun 13, 2008 3:21 pm
Location: Cambridge, United Kingdom
Contact:

Re: About software rendering

Post by Owen »

Shaun wrote:
alexfru wrote:In Windows, the user application must redraw itself on WM_PAINT. The message contains the region coordinates.
As far as i can remember, i haven't written any redrawing codes when i create a MFC application.I can find WM_PAINT message handler in source code that was generated by IDE(visual stdio), but just ignore it. Maybe the redrawing code locates in some MFC framework dlls? :-k

anyway, is it better for puting redrawing work in user apps?
Of course not. You ask for a button from MFC... why would MFC make you draw the button?

Heck, MFC probably doesn't draw the button, instead delegating to the button implementation provided by user32.dll.
alexfru
Member
Member
Posts: 1112
Joined: Tue Mar 04, 2014 5:27 am

Re: About software rendering

Post by alexfru »

Owen wrote:
Shaun wrote:
alexfru wrote:In Windows, the user application must redraw itself on WM_PAINT. The message contains the region coordinates.
As far as i can remember, i haven't written any redrawing codes when i create a MFC application.I can find WM_PAINT message handler in source code that was generated by IDE(visual stdio), but just ignore it. Maybe the redrawing code locates in some MFC framework dlls? :-k

anyway, is it better for puting redrawing work in user apps?
Of course not. You ask for a button from MFC... why would MFC make you draw the button?

Heck, MFC probably doesn't draw the button, instead delegating to the button implementation provided by user32.dll.
MFC lives in a library (e.g. a DLL), which, while is a part of the OS, isn't a part of the kernel, but rather a user-mode part of the application. I think, we need to make a clear distinction here. Actual drawing starts in win32k.sys, which is a kernel driver, in functions like NtGdiRectangle and NtGdiExtTextOutW.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: About software rendering

Post by Brendan »

Hi,
alexfru wrote:Consider this. If the OS (re)draws stuff for you, it must know how to (re)draw it. Which, in turn, means that your OS must offer not only routines for drawing various graphical primitives (shapes, bitmaps, text), but also high-level objects like buttons, list boxes, edit boxes, scrollers and so on and it would need to traverse some data structure (created and possibly updated by the app and the updates can create race conditions) and examine them. While that's not a problem in itself and it probably has some advantages (like all apps would use the same common controls and generally have the same look and feel and the same code wouldn't need to be duplicated across many apps (you could put it into a DLL, though)), what are you going to do about custom thingies that only the application knows how to draw and and that aren't provided by the OS, like some specialized edit boxes for passwords (not the best example since these days that's a must have, but still) and non-standard menus?
Let's define 2 things:
  • Primitives = things the OS knows how to draw (textures, shapes, simple text strings, etc)
    Higher level things = things an application (or something acting on behalf of an application) has to break down into primitives
To redraw a higher level thing (e.g. something like an application's entire window, a widget, etc) the OS only needs the list of primitives. The application doesn't have to break the higher level thing down into primitives a second time.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Post Reply