Old school (?) drawing philosophy
|
|
Thread rating:  |
micjuneau@gmail.com - 11 Dec 2004 09:13 GMT I finally have a serviceable 2d image drawing engine working under System 1.0 through OS 9.2. I can draw arbitrary sized multi-frames sprites, with (pre-generated) white masks, if needed, and with auto-cleaning (saves background in temp bitmap and draws it back when moving) during the blit process. (All in C)
However, even with smallish 16x16 pixels^2 bitmaps, I notice a faint flicker, even if I'm looking at it. My strategy is to impose a delay in the drawing with an IF condition on the value of TickCount() (do drawing at every 4 ticks, for example), to blit the sprite, and deal with movement and boundary/collisions conditions afterwards.
I've read in the THINK C reference that while I could install a VBL task in the queue, the tasks that have to be done there must not move memory - my sprite blitting functions use several calls of CopyBits at their core, and that moves memory. The reference also mentions that Ticks can be tracked and followed by a "quick" drawing to ensure smooth animation. I'm wondering - is this done inside a VBL task, or is a simple tracking of TickCount's return value enough? I'm doing the latter, to little success.
My main question would be: how do you test the speed of a blitting function in a more systematic way than to fiddle with it until you cease to see flickering?
Right now, I reckon that my blit function does several things and may take more than a tick to resolve (in my target machines - 68k macs): 1) IF to check if the sprite cleans after itself. If yes, A) CopyBits the old buffer into the old location. B) Change the buffer location to the new one. C) CopyBits the new location into the buffer. No actual sprite is drawn yet. 2) IF to check if the sprite uses a mask - if yes, draws the white mask (a straightforward copybits with srcBic as its transfer mode). 3) CopyBits the sprite proper into its position (srcOr = transfer mode). 4) If there's no mask (2nd IF failed), copybits the sprite with srcCopy.
At the worst (mask + cleaning), there are 2 IFs statement to evaluate, 3 copybits going on, one Rect assigning and 2 pairs of HLock HUnlock that are needed around the new buffer CopyBits call.
I'm trying to figure out if this can be solved with VBL tasks, or if I plain and simple need to optimize my BlitSprite function.
David Phillip Oster - 12 Dec 2004 05:36 GMT > I've read in the THINK C reference that while I could install a VBL > task in the queue, the tasks that have to be done there must not move [quoted text clipped - 4 lines] > simple tracking of TickCount's return value enough? I'm doing the > latter, to little success. You can't just wait for TickCount to change: what if the use has multiple video cards, all set to different refresh rates? TickCount is in no way synchronized to anything. That is what SlotVBLs are for: You register for an interrupt that occurs when the card that controls a specific monitor sends its vertical blanking signal.
But: not all video cards send a VBL. Some LCD displays don't need one.
Also: you can't do any drawing with Quickdraw (including CopyBits) at VBL time, since all Quickdraw drawing calls look at the visRgn and clipRgn of the current GrafPort, and since these are RgnHandles, which are Handles, they are not guaranteed to be valid at interrupt time, depending on whatever heap shuffling the memory manager happens otbe doing.
I asked Apple: what if you create your windows in a private heap, then switch back to the main heap for everything else, so you know the memory manager isn't going to touch your RgnHandles. I was told that even then quickdraw at interrupt time wasn't guaranteed to be safe. (Besides, someone might have installed unsafe trap patches.)
> My main question would be: how do you test the speed of a blitting > function in a more systematic way than to fiddle with it until you > cease to see flickering? See how long it takes to execute it 10000 times in a tight loop, compared to executing an empty 10000 times loop?
> Right now, I reckon that my blit function does several things and may > take more than a tick to resolve (in my target machines - 68k macs): [quoted text clipped - 15 lines] > I'm trying to figure out if this can be solved with VBL tasks, or if I > plain and simple need to optimize my BlitSprite function. Use a SlotVBL to set a bit on entry to VBL time, and have your main thread poll for that bit and do the drawing.
None of the above applies to OS X. Under OS X, you'd just use OpenGL, which is hardware double buffered: while the user is looking at one frame, you are drawing the next frame to an offscreen buffer. Call SwapBuffers() and OpenGL busy-waits until that monitor's VBL time, when it swaps the back and fore buffers by writing to single register on the video card, and now you have an entire frame time to draw. See:
<http://www.ati.com/developer/demos/macss2/> the animusic demo, in particular, is simply eye-popping incredible.
 Signature David Phillip Oster
micjuneau@gmail.com - 17 Dec 2004 20:24 GMT --- See how long it takes to execute it 10000 times in a tight loop, compared to executing an empty 10000 times loop? ---
Empty 5000 times loops yields a 0 tick difference between the a tickcount made before the loop, and one after it. I guess the compiler knows better. However, I've tried my Blit routine (with all the mask+cleaning features) vs a raw one (which is essentially only a direct CopyBits use, with the transfer mode of my choice) and the difference is staggering. First loop strategy: BlitSprite use, and a pointer is incremented to point to the correct frame. Ticks = 745 Second loop strategy: DrawSprite use only (equivalent to CopyBits, using srcCopy, the fastest mode). Ticks = 25.
I've just stumbled (an hour ago) unto a sprite graphics library that hopefully, will be easily adaptable for b&w macs (it claims it is). It's called SAT (sprite animation toolkit) and I just downloaded version 2.6.0. There are many similar features, judging from its header file. However, I can't compare it to my stuff because it's compiled as a library and the source code isn't available. I'll take what I can from it. Thanks for your help on VBL tasks, you've been helpful, as always.
Reinder Verlinde - 17 Dec 2004 22:42 GMT > Empty 5000 times loops yields a 0 tick difference between the a > tickcount made before the loop, and one after it. I guess the compiler > knows better. That may be the case, but I guess that you do not realize how fast modern processors are.
An idle loop of say four instructions times 5000 loops takes 20000 instructions. At 1 GHz, that's 2 * 10^4 / 10^9 = 2 * 10^-5 seconds.
At 10 Mhz, it would take 2 ms. A Tick is about 16 ms.
=> The compiler does not have to optimize your loop away for it to take 'zero ticks'
You should use a faster counter, such as 'MicroSeconds' for your timing, or use many more loops.
Reinder
micjuneau@gmail.com - 18 Dec 2004 05:52 GMT --- That may be the case, but I guess that you do not realize how fast modern processors are.
An idle loop of say four instructions times 5000 loops takes 20000 instructions. At 1 GHz, that's 2 * 10^4 / 10^9 = 2 * 10^-5 seconds.
At 10 Mhz, it would take 2 ms. A Tick is about 16 ms. ---
Thanks for the approximative educated guesses. I just had a complete lack of knowledge in that area before.
--- You should use a faster counter, such as 'MicroSeconds' for your timing, or use many more loops. ---
Here's the thing. I'm using Symantec C++ 6.0 (THINK C) and intend to program for 68000 macs. There is no MicroSeconds in that generation of C compiler. If you know of any other way to using timing for that period, please tell me.
Reinder Verlinde - 18 Dec 2004 09:08 GMT > --- > That may be the case, but I guess that you do not realize how fast [quoted text clipped - 18 lines] > program for 68000 macs. There is no MicroSeconds in that generation of > C compiler. I think that you can get MicroSeconds there by installing QuickTime version <whatever> or higher. So, this might be a problem with your header files.
> If you know of any other way to using timing for that > period, please tell me. Use the extended Time Manager
Reinder
micjuneau@gmail.com - 29 Dec 2004 19:34 GMT ----- I think that you can get MicroSeconds there by installing QuickTime version <whatever> or higher. So, this might be a problem with your header files.
> If you know of any other way to using timing for that > period, please tell me. Use the extended Time Manager -----
I've gathered some notes from IM and from websites about the Time Manager:
original - below System 6.0.3 - gives control of milliseconds (about 1 millisecond is the best), can drift over time revised - between System 6.0.3 and 6.0.8L - gives control of microseconds (20 ms is the best), can drift over time Extended - From System 7.0 and up - gives control of nanoseconds, drifting is corrected
The differences are well explained in the graphs in this IM page: http://developer.apple.com/documentation/mac/Processes/Processes-57.html#HEADING57-0
As for the time delays I need - as I've told earlier, 500 Blits for a small image required 745 ticks, which comes to about 1,49 ticks per Blit (which, I remind you, uses the full gamut I've given it - background cleaning + mask + sprite itself).
Note again that yes, I intend to write code for Classic Macs first, and not to mess with SlotVBL interrupts. So my screen refresh frequency is 60.15 Hz. Checking the first edition of IM, here are the time delays at hand: Each of the 342 horizontal scan lines take 32.68 microsecs to draw. Each horizontal blanking (going from right edge to left edge between each line) take 12.25 microsecs. So the drawing process takes a total of 15367.65 microsecs = 15.37 ms. The vertical retrace takes 1.26 ms, and the grand cycle takes 16.63 ms.
This means that when I'm waiting for a VBL interrupt before I start drawing, I only have 1.26 ms at my disposal before there's a risk that there'll be blinking (especially near the top of the screen). Barring optimizing my blit routines in assembly (which I don't want to touch with a ten foot pole) to lower that estimate -count of 1,5 ms or so, I'll have to use the revised Time Manager (to get System 6 compatibility, but not prior to that) in order to draw my sprites with a strategy. I could roughly separate it into 2 drawing passes per screen refresh, one for the top half of the screen, and one for the bottom half, seeing as how 2 drawings of 1.5 ms each can fit fine into this 15.37 ms total time.
I'd use the VBL interrupt ONCE to turn on a flag, which would be a cue to start implementing 2 revised Time Manager interrupts that would control the start of both drawing passes.
Any comments, suggestions or error pointing you see with this strategy? I'd rather keep the original Time Manager to ensure compatibility for earlier-than-6.0.3 Systems. I'll give it a try first, I think. Then on to revised if it's not satisfactory.
micjuneau@gmail.com - 29 Dec 2004 19:40 GMT Sorry about the errors with the milliseconds (ms), and microseconds (us - mu seconds). original - milli revised - micro extended - nano screen refresh delays - total in milli, individual lines in micro
micjuneau@gmail.com - 29 Dec 2004 19:59 GMT Just a note on the program I had on hand at the start of this thread - I clearly see that the flickering starts to vanish partially between the middle of the screen and about 2/3rds of the screen down. There is no flicker between 2/3rds and the bottom of the screen. Flickering being an optical remanance effect, it's of course lessened if the VBL delay is set to numbers higher than 1 (ie, drawing cued at every x screen refresh).
However, I was deliberately not helping things by forcing a 17-pixel wide sprite unto my code. I'll repeat other tests with widths that are multiples of 4, if not 8.
micjuneau@gmail.com - 29 Dec 2004 21:30 GMT Sorry for the barrage of replies, but I just made some more tests and the results are widely different. Somehow, my last results are thrice as long as what I get now.
Blit, 16pixel wide, 10 000 times 293 ticks = 1/60.15 * 293 = 4871.16 ms per blit: 0.4871 ms
Blit + frame reeling, 16pixel wide, 10 000 times 297 ticks = 1/60.15 * 297 = 5087.28 ms per frame blit: 0.5087 ms
Blit, 16pixel wide, 10 000 times 301 ticks = 1/60.15 * 301 = 5004.16 ms per blit: 0.5004 ms
Blit + frame reeling, 17pixel wide, 10 000 times 306 ticks = 1/60.15 * 306 = 4937.66 ms per frame blit: 0.4938 ms
This means that in the best case scenario, with careful planning in the drawing of different regions on the screen, I can get about 28 smallish 16 pixel wide sprites on screen at any given time. Of course, the number will end up being lower since I need to perform other tasks (collision detection, AI, etc) and I'll probably need to use larger sprite (but the blit time is not directly proportional to width, thank god), but at least I'm relieved that it's not as stark as I thought.
C.R. Osterwald - 20 Dec 2004 14:53 GMT > I've just stumbled (an hour ago) unto a sprite graphics library that > hopefully, will be easily adaptable for b&w macs (it claims it is). [quoted text clipped - 3 lines] > a library and the source code isn't available. I'll take what I can > from it. You might want to check out SpriteWorld:
<http://www.spriteworld.org/>
The older version 2.3.1 should work fine on toaster Macs, and includes all source code. Pascal is also available.
--
micjuneau@gmail.com - 20 Dec 2004 16:57 GMT I found it too, shortly after my last message. It claims it requires 68020 macs and up, but I don't know if it's a requirement to compile it (meaning, it'd be usable only on compilers which run on these machines), or if the target environment for the compiled applications needs to be on 68020 macs.
I'd rather continue my work and develop all my functions myself, perfectly tailored to my needs, but looking at the header file for the SAT engine, I have a lot of wheels to reinvent.
Right now, I'm working on trying to use InsTime and PrimeTime to install tasks into a queue, that will give me control over milliseconds. I'm still trying to understand how I can avoid the flicker that comes when the background is restored under a sprite. I might have to devise a function that looks at which pixels must be changed and acts only upon those.
Gregory Weston - 21 Dec 2004 01:15 GMT > I've just stumbled (an hour ago) unto a sprite graphics library that > hopefully, will be easily adaptable for b&w macs (it claims it is). It is.
> It's called SAT (sprite animation toolkit) and I just downloaded > version 2.6.0. There are many similar features, judging from its header > file. However, I can't compare it to my stuff because it's compiled as > a library and the source code isn't available. I'll take what I can > from it. > Thanks for your help on VBL tasks, you've been helpful, as always. Mr. Ragnemalm made some fairly interesting architectural choices in that library that aren't obvious but give some useful side-effects, as I recall. It's been a long time since I did anything with it and that was mostly puttering. I ended up creating my own based on SpriteWorld 1.0b4 at the time and took it in my own direction after that.
G
 Signature Change account to gw when responding by mail.
|
|
|