Buffered Graphics

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.
HOS

Buffered Graphics

Post by HOS »

well, i have been using VESA modes to set up a Linear Frame Buffer for my GUI. this worked great until i decided to create a second video memory buffer in main memory which could be copied to VESA's Linear Frame Buffer. so i made the small changes to write to the new buffer memory, and then copy the RAM video buffer to the VESA LFB every so often. well, needless to say, it is veeeeerrry sloooooow to copy the whole buffer. so, should i just have my graphics routines write directly to the VESA LFB and not use a second buffer? or is a second buffer needed to do some GUI things effectively? as of right now i am going to have to go back to writing directly to the Linear Frame Buffer memory and not worrying about ever copying it manually unless i figure out somethiing better. any suggestions? or am i just totally off track in the way that a GUI should even work?
Curufir

Re:Buffered Graphics

Post by Curufir »

any suggestions?
Don't redraw the whole screen. You are never going to get the speed of writing the entire screen into the LFB to be the same as the speed of manipulating a single pixel. One of the arts of computer graphics is deciding what needs to be drawn and when. If you want more speed then do things more efficiently.

Here endeth the lesson ;D.
HOS

Re:Buffered Graphics

Post by HOS »

alright, thank you for that suggestion, i can live with only updating part of the screen -- so is it necessary or advantageous at all to have a second buffer as opposed to just using VESA's LFB?
Curufir

Re:Buffered Graphics

Post by Curufir »

Well there are a couple of advantages afaik.

You can avoid flickering by synching with the monitors vertical refresh.

Manipulating VRAM is much slower than manipulating main RAM so working on a copy in RAM and dumping to VRAM when required is far more efficient than constantly manipulating VRAM.

You can update lazily if you want to, ie on the next convenient refresh as opposed to polling for a refresh.

There are probably some funky graphical effects that rely on double buffering too (Overlaying bitmaps springs to mind for some reason), maybe one of the GUI gurus knows...I don't :).
BI lazy

Re:Buffered Graphics

Post by BI lazy »

In BlueIllusion, rough as it is, several buffers exist. even the windows themselves are drawn into seperate buffers (on creation - then only when changed) which are finally drawn into a buffer belonging to the gui service (yes, it's a micro kernel, so there is a split between policy/management and executuion).

and after all that is done, a messege is sent to the video driver along with a pointer to the buffer and the coordinates of the region to be redrawn. The video driver fetches the image and only redraws the indicated region on the screen.

How I do the window moving stuff?

Ha, that one is tricky. I have the video driver move the active window. It is moved on the buffered background. AFter movement, I have the driver do some calculation of a thing I call "Displacement Rectangle" - which spans the affected region (former location of the window, new location). The displacement rectangle is redrawn finally. Oh, and the window boxes move smoothly.

So, HOS, I suggest the same as Curufir: use double buffering whereever you can, and write only to vga memory when needed and where needed. I have yet to figure out how to add clipping-rectangle lists to my window structures, but for now, I think I'll better flesh out my memory management to lazy paging at least for the heap regions for I am handing out too much memory despite present checking mechanisms.

stay safe...
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Buffered Graphics

Post by Pype.Clicker »

in general, it is unnecessary to have double-buffered video when you're working on a GUI. BI's scheme of having an off-vram buffer for 'popular' windows is more useful (and more used ;) ...

Double buffering only comes useful when dealing with fast changing graphics like video rendering, videogames, etc. which is one reason why they're often preferred full-screen ...

If you have some 'smart' video card which is able to handle high-level operations, you can afford double buffering for the fast changing windows and edit the 'display list' of those windows (i.e. switching which is onscreen and which is offscreen). However, finding programming info for such cards is hard.
Tux

Re:Buffered Graphics

Post by Tux »

Kwap, I think I have to myuch lead in my brain to go on with the coding. But here is the method I use:
I have 3 buffers. Let's call em buffer A,B, and C.

A stores the active window.
B stores the desktop windows. (EXCLUDING THE FOCUSED WINDOW!!)
C stores the background image.

When I move a window, the region of the screen where the window was is filled with the data of Buffer B.
Then, buffer A is drawn on the screen.

When a window is clicked to be focused, the GUI finds the window in the region. Then the background window is drawn in buffer A from buffer B. (temporary ram is allocated to transfer the now unfocused window to buffer B) and the GUI looks up what portions it has to redraw.

I am using a small text driver hack to test all this. I already have 3 versions of the GUI with moving, full resizing and etc. Problem is, I keep restarting the code because school is taking all my time, and I mostly code at 2 AM where my brain blanks out. And because of school, I don't code for long and forget what I was doing the last time I coded. Sigh....
Brian_Provinciano

Re:Buffered Graphics

Post by Brian_Provinciano »

I've written a couple GUIs. Here are some tips:

1. draw directly to the video memory on vblank. Have an interrupt to execute on each vblank, then draw it then.
2. if you want to double buffer, use the extra video ram for your seconary buffer, then toggle which page is shown with the vid regs.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Buffered Graphics

Post by Pype.Clicker »

Tux wrote: And because of school, I don't code for long and forget what I was doing the last time I coded. Sigh....
Documenting what you do will be the key ;)
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Buffered Graphics

Post by Pype.Clicker »

Brian Provinciano wrote: I've written a couple GUIs. Here are some tips:

1. draw directly to the video memory on vblank. Have an interrupt to execute on each vblank, then draw it then.
yup. Do you know how this can actually be implemented, i mean just using VESA or something, but not relying on an existing highly mysterious "windowing system" ?? any link or code sample would be welcome ...
2. if you want to double buffer, use the extra video ram for your seconary buffer, then toggle which page is shown with the vid regs.
Yes, that's the idea, and it work pretty fine when you're in a situation where you have to repaint most of the image at each frame, but when you're just updating a small region (ymms' volume level, or the clock display, or small animations, etc), it becomes very inefficient to repaint everything at each update (other tasks may need that processing power).
Brian_Provinciano

Re:Buffered Graphics

Post by Brian_Provinciano »

I myself have found that writing directly to the screen (preferebly during vblank) gives the absolute best results. I've written my GUIs from complete scratch, and have never even looked at source code from other windowing systems. Once you know all the fundimentals of how to code and how the computers work under it all, it's easy to do virtually anything.

I haven't written a GUI for VESA video modes yet, but the concepts hold true. Virtually all, even not so modern video cards have double buffering capabilities, and every thing has V/HBLANK stuff whether you know about it or not.

I never get flickering or anything, it's highly efficient. A couple points:

- when moving the window, simply XOR the rectangle of the window as it's new position, then on movement, XOR the original region, XOR the new region, and so forth. BLISTERING fast, no need to waste redrawing. Sure, Windows can redraw the whole window on each drag, but have you tried running it on a 386? How about using good 'ol Win31 on a trusty 286? Win31's windowing system was faster on a 286 than XP with it's visual enhancements turned on on a PIII :)

- never ever ever draw stuff that you don't need to, such as the parent window of a control being redrawn, etc. and only update windows that MUST be updated

- I have a WndCalcRect() function which calculates the window's regions, screen, client, etc. from the X,Y,width,height. The window stores a couple RECT structs and a width/height. This function is only called on window creation and window move. EXACTLY! everything is then done by reading the RECT structs and width/height (btw, unions for x,left/y,top :)). The less calculation the better.

- if you need to draw a complex control, like a fancy button, allocate a temp buffer of (width*height), draw all the stuff to that, then blit it. Otherwise, for a simple button, you can just draw the rect/outline/text/icon, and it will be fine.

- on a VERY rare occasion, you'll be drawing pixel by pixel, in which case you'd need to check if it's coordinate is visible in the current port and should be drawn. Generally though, you should only check once per draw. Each line, rect, outline, bitmap, etc. that is drawn to the screen should simply have it's bounds checked and adjusted accordigly, then go from there. You can then blit lines of pixels and such, without any per-pixel checking. I even do this on font characters, because even if they are only 8x8 pixels or less, it will still save time (8x8 adds up! compare operations eat up your CPU!)

- do the keyboard (ie. tab-switching between controls, arrow keys for listboxes, menus and such, etc.) code first. Complete it all first, before implementing the mouse. Many people don't bother with standard keyboard support in their GUIS--that's bad. Do all the keyboard stuff, then add the mouse support. I added the mouse support with all the port clicking, window dragging, etc. in a matter of hours the first time. They keyboard stuff on the other hand take a little longer, so get it out of the way first :)
BI lazy

Re:Buffered Graphics

Post by BI lazy »

hmmm...

could you be so kind to give a rough sketch of how to XOR a wondow onto the screen? Not that I don't understand the *meaning* but I have not really an imagination of how such an algorithm could look like. (maybe some quick and short asm-algorithm this is?)

My Method draws relatively quick on a pIII 500 mhz without any funky extra functions, but I'd like it to be really quick and economic.

thank's very much

ps: In my system, the window isn't *redrawn* on each drag. It is just *moved* and the gui service gets the new location for book keeping.
Brian_Provinciano

Re:Buffered Graphics

Post by Brian_Provinciano »

I was simply referring to drawing an XOR outline rectangle of the windows, not actually XORing an image of the window.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Buffered Graphics

Post by Pype.Clicker »

Brian Provinciano wrote: I was simply referring to drawing an XOR outline rectangle of the windows, not actually XORing an image of the window.
true. the advantage of that technique (which was also used for block selection in old painting programs like Deluxe Paint) is that you need no memory in order to remember what was previously there:

when you draw a stuff, you do
newcolor := oldcolor XOR anything

and when you want to erase, you do
newcolor := oldcolor XOR thesamething.

As (oldcolor XOR anything) XOR thesamething == oldcolor, you get back your old color :)

It's a bit (really a bit) slower than the buffer:=getpixel(); putpixel(anything); putpixel(buffer) approach as it requires 4 access to VRAM instead of 3VRAM and 2 MAINRAM (usually cached if you're just drawing an outline ;)

@brian: do you have anything special to enable to get the VRT interrupt ? or do you just poll for it ?
BI lazy

Re:Buffered Graphics

Post by BI lazy »

and what, if one does the entire drawing in a buffer and at the end of the operation updates the VRAM in one flush with a memcpy?
Post Reply