flat assembler
Message board for the users of flat assembler.
![]() |
Author |
|
Madis731 30 Jan 2006, 18:40
The general rule is to set an offline buffer and blit it to screen when you are ready. There is no point to draw a picture pixel-by-pixel.
When GetDC takes ~5000 clocks, SetPixel 4500 and Releasing the DC 6000 clocks you take and multiply it by 800x600 pixels and you got yourself a CPU hogger. I've posted a bunch of programs in the http://board.flatassembler.net/topic.php?t=4619 take a look. Its a bit different angle, I'm using only circles and rectangles because they are a lot faster "macrocalls" ![]() Try this also: Code: ; mov ebx,[window_x] ; dec ebx ; mov [window_x],ebx dec [window_x] ;decrement can work on an address also Last edited by Madis731 on 31 Jan 2006, 08:31; edited 1 time in total |
|||
![]() |
|
madmatt 31 Jan 2006, 07:09
Hi Kuemmel,
Looks like one of my old examples from the "Window's game programming for dumies book". If you want speed then you will have to use DirectDraw. I have a library that contains many functions for drawing directly to the video buffer for a huge speed increase over the windows plotting functions. I'll post some examples, my DirectX library, and some (minimal) documentation describing how to use all the functions. Hopefully, soon I'll be able to make better documentation and tutorials. I should have them posted before the day is done. ![]() MadMatt |
|||
![]() |
|
Kuemmel 31 Jan 2006, 09:43
Thanks guys !
I'll have a look at your code Madis and stay tuned for yours Madmatt. Do you also got a clue about the timer thing ? Just some code that stores the system time in 1/100 of seconds before the time critical routine and calculates the difference to it after and puts it on a message window to benchmark the whole thing ? Kuemmel |
|||
![]() |
|
Madis731 31 Jan 2006, 10:00
Oh, sorry about that - I forgot to answer. There are two possibilities.
When the time differences can be measured with a calendar ![]() The other trick you can use is the CPUs own tick counter. This doesn't read time, but rather the smallest increments the CPU can do. So on a 1000MHz CPU you would expect every tick to be about a pikosecond (that is 0.001nanoseconds). This comes handy if you are measuring up to 5million clock range where GetTickCount() would be imprecise. If you look at my previous post - it talks about clocks - these I read in with RDTSC which takes about 30-45 clocks itself and posts the results in a 64-bit "register" EDX:EAX (You usually need only EAX on CPUs lower than 3GHz). |
|||
![]() |
|
Kuemmel 31 Jan 2006, 13:08
Okay, I see. The exact clocks isn't may be too important for me, I think GetTickCount() would do it at first. So when I try to inplement it in some of the examples (the Dialog-Box one) of FlatASM it looks like this:
Code: section '.data' data readable writeable timer dd 0 section '.code' code readable executable start: invoke GetTickCount mov [timer],eax .....other code.... invoke GetTickCount mov ebx,[timer] sub eax,ebx mov [timer],eax ...conversion of 'timer' to string !?... invoke MessageBox,HWND_DESKTOP,timer$,caption,[flags] ... section '.idata' import data readable writeable library kernel,'KERNEL32.DLL',\ user,'USER32.DLL' import kernel,\ GetModuleHandle,'GetModuleHandleA',\ ExitProcess,'ExitProcess',\ GetTickCount,'GetTickCount' I didn't find any routine for transforming the timer integer value in a string in the Win32Help, is there one ? |
|||
![]() |
|
Madis731 31 Jan 2006, 13:28
Well some use C-functions, but I as a hardcore guy, prefer to use some converting algorithm. The first that comes to mind is divide the hex value by 10 in a loop and collect the modulae in a buffer and then print the buffer. You'll have to do it backwards because:
0A6h%0Ah=6 then you are left with 10h 010h%0Ah=6 only 1 remaining 1 %0Ah=1 The answer is "166" I came to the other thought recently, I think it will be faster, but because I haven't tried, I can't be sure ![]() here goes: Code: fild [integer] ;The only thing I'm afraid about is losing precision!!! fbstp [tword bcdstring] xor ecx,ecx @@: mov al,[tword bcdstring+counter] ;convert BCD-byte into two-byte string ;There are infinite possibilities here... mov [buffer+counter*2],ax inc ecx j<ifend> @b |
|||
![]() |
|
madmatt 31 Jan 2006, 18:03
Here's are the examples I promised
Quote: At the moment I see that the program plots really slow, I think this must got something to do with the GetDC/ReleaseDC thing and the whole possible allowed user interaction. How can I get rid of this ? The examples I provide here setup a directdraw video buffer and provides a much more direct (and MUCH faster) way to draw on the video screen. Also, there is an example in "Windows game programming for dummies" called 'Chapter 6 - wintimers.asm" that gives an example of how to setup a windows timer event. Not the most accurate, but fine for most purposes. If you have any questions just post it. MadMatt |
|||
![]() |
|
Kuemmel 01 Feb 2006, 10:51
madmatt wrote: Here's are the examples I promised @MadMatt: I got problems recompiling your examples (as stated, I downloaded the INCLUDE from the webpage)...first there was a memory problem, so I set the compiler to 65536, then it says 'illegal instruction' or 'invalid macro argument' at line 7 (probably the .inc file...) starting with 'IID_DirectDraw7'. The exe of the plasmas work... @Madis731: Thanks for the hint with the division by 10. I don't like to go the C-functions-way either, so I implemented your idea and it works fine ! |
|||
![]() |
|
Kuemmel 01 Feb 2006, 15:02
Hi guys,
just to let you know my 'advances' on the timer thing, here's my code for the timer and the number conversion...at the moment it just times some loop, takes about 5.6 seconds on my A64 3000+. The code may be really shitty, but it works. If any optimisations come into your mind, even for single instructions, just give me a hint. For example I remember on my Acorn computer (ARM-CPU) it was possible to do conditioned execution for all commands...think this is rare for x86, isn't it !? (still busy walking through all the endless x86 instructions of my book...) Another thing about the timing...is there a way to tell windows that my code gets 100% of the processor power, like in a single task application in DOS ? Code: format PE GUI 4.0 entry start include '%fasminc%/win32a.inc' section '.data' data readable writeable flags dd ? ;seems to be something for the message window... timer dd 0 ;to store the timer at start divisor dd 1000000000 ;maximum divisor must be < 2^31...as far as I can know... counter dd 10 ;this makes 10 loops for conversion... address_text dd 0 ;saves the pointer to text_result flag_number_start dd 0 ;flag for the start of the number to get rid of leading zeros text_result db 'Computation time: ',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;reserve some 13 characters for the result string including end zero caption db 'Benchmark Result',0 section '.code' code readable executable start: ;Get the timer of the System invoke GetTickCount mov [timer],eax ;do just something that consumes time...takes about 5.6 seconds on my Athlon64 3000+ mov eax,50000 consume_time_loop1: mov ebx,100000 consume_time_loop2: dec ebx jnz consume_time_loop2 dec eax jnz consume_time_loop1 ;Get the timer again and calculate difference... invoke GetTickCount mov ebx,[timer] sub eax,ebx mov [timer],eax ;Preparation for number to string conversion for the timer result mov eax,text_result add eax,18 ;offset for the leading text mov [address_text],eax ;Conversion of number to string conversion for the timer result NumberToString_loop: mov eax,[timer] ;get number xor edx,edx ;init edx !? or what is this...got it from other source mov ecx,[divisor] ;divide by divisor div ecx ;result into eax, reminder is in edx mov [timer],edx ;store edx in number cmp eax,0 ;test if there's a zero jnz go_on1 ;if not, put it into the string cmp [flag_number_start],0 ;if there is a zero then test if it is a starting zero or not jz go_on2 ;if starting zero then don't plot go_on1: mov [flag_number_start],1 ;set the flag for true that there's no more leading zeros add eax,$30 ;offset for the numbers in ASCII code mov ebx,[address_text] ;get storage address mov [ebx],al ;store ascii code in text string inc [address_text] ;increment storage address in string go_on2: mov eax,[divisor] ;get divisor xor edx,edx ;init edx !? or what is this...got it from other source mov ecx,10 ;divide divisor by 10 div ecx ;result into eax, reminder is in edx mov [divisor],eax cmp [counter],4 ;if counter = 3 then put a digit -> output string in seconds jne go_on3 mov word [ebx+1],$2e ;store a ASCII code for the '.' inc [address_text] ;increment storage address in string go_on3: dec [counter] ;decrement digit counter jnz NumberToString_loop ;if not zero loop again mov word [ebx+1],$20 ;store a ASCII code for the >space< mov word [ebx+2],$73 ;store a ASCII code for the 's' invoke MessageBox,HWND_DESKTOP,text_result,caption,[flags] exit: invoke ExitProcess,0 section '.idata' import data readable writeable library kernel,'KERNEL32.DLL',\ user,'USER32.DLL' import kernel,\ ExitProcess,'ExitProcess',\ GetTickCount,'GetTickCount' import user,\ MessageBox,'MessageBoxA' |
|||
![]() |
|
madmatt 01 Feb 2006, 19:10
Kuemmel,
You have to be using fasmw 1.65 compiler, you also have to use the win32a.inc supplied with the includes. Also, make sure your 'fasminc=' variable is set correctly, this would be in the 'fasmw.ini' file: [Environment] fasminc = C:\fasmw165\include |
|||
![]() |
|
Madis731 02 Feb 2006, 19:43
Try this code, see my comments marked with @Madis@:
Code: format PE GUI 4.0 entry start include 'win32a.inc' section '.code' code readable executable start: ;Get the timer of the System invoke GetTickCount mov [timer],eax ;do just something that consumes time...takes about 5.6 seconds on my Athlon64 3000+ mov eax,5000 consume_time_loop1: mov ecx,100000 consume_time_loop2: dec ecx jnz consume_time_loop2 dec eax jnz consume_time_loop1 ;Get the timer again and calculate difference... invoke GetTickCount sub eax,[timer] ;You can subtract the memory address directly @Madis@ mov [timer],eax ;Preparation for number to string conversion for the timer result ; mov eax,text_result ; add eax,18 ;offset for the leading text mov [address_text],text_result+18 ;You can add constants together here @Madis@ ;Conversion of number to string conversion for the timer result NumberToString_loop: ;Totally rewritten @Madis@ mov eax,[timer] ;Our timer is in eax and it remains there test eax,eax jne .overzeromilliseconds mov esi,[address_text] mov dword[esi],'0 s' jmp .underonesecond .overzeromilliseconds: mov edi,buffer ;I reserved another buffer where we put our intermediate result in xor ecx,ecx ;XOR (eXclusive OR) has the property of zeroing itself ;You can also use: ; sub ecx,ecx ; and ecx,0 ; mov ecx,0 <= The most logical ; imul ecx,0 |
|||
![]() |
|
Kuemmel 06 Feb 2006, 10:38
@Madis731: Thanks a lot ! This gave me a lot ideas how different x86 coding is compared to the ARM coding, where you got 16 registers but only limited instruction set...
@madmatt: With FA 165, now I could compile all your examples perfectly, but only the plasma-examples work correctly, the others go to black screen and don't show anything, only a slight flicker, when I press ESC at the end...(I'm running Athlon 3000+ and some simple ATI Radeon Graphics Card with Direct-X 9 installed) |
|||
![]() |
|
madmatt 06 Feb 2006, 19:24
Kuemmel,
Don't know what the problem could be. Have you updated your drivers yet? Tell me which ones worked for you and which ones didn't. Also know that these examples use the old directdraw interface, so may not work so well with newer cards. I will be using Direct3D 9 for future development so my blitting/drawing library will be more compatible with current and newer graphics cards. |
|||
![]() |
|
< Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2023, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.