News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Drawing lines

Started by RuiLoureiro, December 05, 2007, 07:55:01 PM

Previous topic - Next topic

hutch--

There are times when I feel like a voice crying in the wilderness when it comes to writing reliable code and this among oher things means understanding the limitations of having 8 general purpose registers and understanding why the operating system comforms to the Intel convention of what registers to preserve and what registers you can trash within a procedure.


Volatile = EAX ECX & EDX.
System = EBX ESP EBP ESI EDI


There IS a reason for which registers are volatile, they are the first three registers in processor order. They were historically the Accumulator, Counter and Data registers. The rest are in their order, Base address register, Stack pointer, Base pointer, Source index, Destination index.

From the Intel manual this is the operation of PUSHAD / POPAD in the above mentioned order.


PUSHAD
Temp (ESP);
Push(EAX);
Push(ECX);
Push(EDX);
Push(EBX);
Push(Temp);
Push(EBP);
Push(ESI);
Push(EDI);

POPAD
EDI Pop();
ESI Pop();
EBP Pop();
increment ESP by 4 (* skip next 4 bytes of stack *)
EBX Pop();
EDX Pop();
ECX Pop();
EAX Pop();


These two old instructions are useful in temporary code for debugging, mainly to find mistakes that someone else has made in not preserving the correct registers in the first place but also for tasks like checking the value of a register in the middle of an algo while its running but they have no place in production code as they are far slower than preserving on the basis of need.

The simple rule is to do what you need to do to write safe code but don't do more so you write slow code.

Often we have had questions like "Why does my assembler code run slower than C code" and the answer is you have written SLOW assembler code. Then you get the perennial question "Why does my app run on win9(whatever) but crashes on XP" and the answer is the same as it always was, learn your register preservation rules and the problem will magically go away.

For Rui the situation is a simple one, learn your register preservation rules and write fast reliable code including if you wish later, code with no stack frame, keep listening to bad advice and you will write slow unreliable code.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

donkey

Well said Steve, I can hear your voice from behind the tree in that same wilderness  :bg
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

RuiLoureiro

donkey,
           thank you. I am going to study your code.

Hi Hutch,
           i didnt see your post before. Ok, when i need fast code i preserve only the registers that need to be preserved. Another thing is the rule (more or less) i said it is to myself. It is to myself.

           There is a problem with DrawVLine: it doesnt change the color. It draws the first set of lines in blue but when i change to red it draws in blue. I am sure the parameter is for red 000000FFh. So «invoke    SetDCPenColor, _hdc, Cor» doesnt work.

           Now, i am using the following code and it works correctly. At the end of drawing each set i use DestroiPen.


; ------------------------------------------------------------------------------
; Input:
;           _hdc    - Device context handle
;
DrawVerLine     proc    XIni:DWORD, YIni:DWORD, YEnd:DWORD, Cor:DWORD
                 ;
                cmp     _hPen, 0   
                jne     @F
                ;
                ; color: Cor, width: $PENWIDTH pixels
                ; --------------------------------------------------
                invoke    CreatePen, PS_SOLID, $PENWIDTH, Cor     
                mov       _hPen, eax
                invoke    SelectObject, _hdc, eax
                mov       _hPenOld, eax               
                ;
  @@:           invoke  MoveToEx, _hdc, XIni, YIni, NULL
                ;
                invoke  LineTo, _hdc, XIni, YEnd                   
                ;
                ret
DrawVerLine     endp
; ------------------------------------------------------------------------------
DestroiPen        proc
                  ;pushad
                  ;
                  cmp       _hPen, 0
                  je        _eDestroiPen
                  ;
                  invoke    SelectObject, _hdc, _hPenOld                                 
                  invoke    DeleteObject, eax                      ;_hPen
                  ;
                  mov       _hPen, 0                 
                  ;
_eDestroiPen:     ;popad
                  ret
DestroiPen        endp


Rui

ChrisLeslie

Hi Rui

Isn't this code a little bit dangerous if you leak away too much memory by a possible loop with millions of undestroyed Pens?

Chris

RuiLoureiro

Quote from: ChrisLeslie on December 09, 2007, 09:06:46 PM
Isn't this code a little bit dangerous if you leak away too much memory by a possible loop with millions of undestroyed Pens?

Hi Chris,
            Why ? I am not seeing.

1. _hPen =0  -> Create -> Draw  1ª line
2.                                    Draw  2ª line
3.                                    Draw  3ª line
4.                    Destroy -> _hPen=0

Where is the error ?   
Rui
           

ChrisLeslie

Hi Rui

I think that if your program draws millions of lines with a procedure that does not clean up after each call, and you forget to invoke your DestroiPen procedure then your computer might start to argue with you.

Chris

donkey

Quote from: ChrisLeslie on December 09, 2007, 11:14:54 PM
Hi Rui

I think that if your program draws millions of lines with a procedure that does not clean up after each call, and you forget to invoke your DestroiPen procedure then your computer might start to argue with you.

Chris

Actually, he can only create the pen once regardless of how many lines he draws, if _hPen contains a value the procedure will not create another until it is set to zero by the DestroiPen function. It seems like he has taken precautions though I would tend to create a pen at the start of the proggy and modify it when needed, destroying it on exit but that is my personal style, actually I think one app I did created 8 pens and only destroyed them just before ExitProcess.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

ChrisLeslie

You're right. I didn't see the anonymous jump. :U