Is there any optimization can be made ?


GetCaptionRect proc hWnd:DWORD, rc:DWORD, scrco:DWORD

invoke GetWindowRect, hWnd, rc
push edi
mov edi, rc
assume edi:ptr RECT

invoke GetWindowLong, hWnd, GWL_STYLE ; get size of frame
xor ebx, ebx
.if eax & WS_THICKFRAME
mov bl, SM_CXSIZEFRAME
mov bh, SM_CYSIZEFRAME
.else
mov bl, SM_CXFIXEDFRAME
mov bh, SM_CYFIXEDFRAME
.endif
push ebx
xor bh, bh
sub [edi].right, $invoke(GetSystemMetrics, ebx)

.if scrco
add [edi].left, eax
.else
push eax
mov eax, [edi].left
sub [edi].right, eax
pop eax
mov [edi].left, eax
.endif
pop ebx
mov bl,bh
xor bh,bh
invoke GetSystemMetrics, ebx
.if scrco
add [edi].top, eax
.else
mov [edi].top, eax
.endif
mov ebx, $invoke(GetSystemMetrics, SM_CYBORDER)
sub $invoke(GetSystemMetrics, SM_CYCAPTION), ebx ; height of caption minus gray shadow border
.if scrco
add eax, [edi].top
.endif
mov [edi].bottom, eax
assume edi:nothing
pop edi
ret
GetCaptionRect endp
Posted on 2002-05-08 15:04:10 by yoursguideline
Yes, you can optimize it for size, i.e. make the font even smaller than it is. ;)
Posted on 2002-05-08 17:54:41 by Maverick
lol, good one Maverick!:grin:

hi yoursguideline,

you might not want to make the font so small in your code tags i can barely see it.
Posted on 2002-05-08 18:53:21 by smurf
yoursguideline, I could optimize it, but you wouldn't be able to read it. Maybe you should do it?
    [*]No INVOKE
    [*]Jcc instead of HLL-syntax[*]No Stack Frame[*]No MacrosThen repost...
Posted on 2002-05-08 19:09:34 by bitRAKE
My best suggestion:

-use GetWindowRect to get the window rectangle
-use GetSystemMetrics to get the height of the caption
-use GetClientRect to get the client rectangle

the thickness of the border should be the difference between the client rectangle width and the window rectangle width (divided by 2). Not sure.. but scroll bars may mess this up. I don't think so though.

using the frame thickness, the top left corner of the caption rectangle should be (framethickness, framethickness). The height of course, is returned by GetSystemMetrics and the width is Window Width - Client Width

You can save repeated calls to GetSystemMetrics by saving the height of the caption bar, as I doubt it'll change while the program is running :)

Also, I'll assume you'll be calling this from WM_SIZE for the most part (I can't see why you would call this any other time...). Conveniently, WM_SIZE returns the width and height of the client area which you can get by doing this

WM_SIZE_HANDLER:
movzx eax,WORD PTR
mov ClientWidth,eax
movzx eax,WORD PTR
mov ClientHeight,eax
ret

(Thanks to Ernie ;) )

--Chorus
Posted on 2002-05-08 20:14:21 by chorus
actually.. a scroll bar will affect the value of the Client Width... so you'll want to account for this ... my bad

--Chorus
Posted on 2002-05-08 20:19:58 by chorus
yoursguideline,

A quick glance through the code you posted indicates that a lot of it is straight API code and there are no high speed ASM sections in it that would optimise to any advantage for speed so if it works properly and does what you want, i would be inclined to use it and just make sure you comment it so you understand it next time you read it.

Regards,

hutch@movsd.com

PS : You should preserve EBX as well as it is used in your procedure.
Posted on 2002-05-08 20:22:54 by hutch--
GetCaptionRect proc uses edi,hWnd:DWORD, rc:DWORD, scrco:DWORD

push $invoke(GetSystemMetrics, SM_CYCAPTION)
; height of caption minus gray shadow border
sub [esp], $invoke(GetSystemMetrics, SM_CYBORDER)

mov edi, rc
assume edi:ptr RECT
invoke GetWindowRect, hWnd, edi
invoke GetWindowLong, hWnd, GWL_STYLE ; get size of frame

.if eax & WS_THICKFRAME
push SM_CYSIZEFRAME
push SM_CXSIZEFRAME
.else
push SM_CYFIXEDFRAME
push SM_CXFIXEDFRAME
.endif

call GetSystemMetrics
sub [edi].right, eax

.if scrco
add [edi].left, eax
call GetSystemMetrics
add [edi].top, eax
pop eax
add eax, [edi].top
mov [edi].bottom, eax
.else
xchg eax, [edi].left
sub [edi].right, eax
call GetSystemMetrics
mov [edi].top, eax
pop [edi].bottom
.endif
assume edi:nothing
ret
GetCaptionRect endp
Does this work? If it doesn't still use the data flow.
Posted on 2002-05-08 21:18:05 by bitRAKE
I tend to agree with hutch, if it ain't broke, don't fix it. Even if your program spends 90% of it's time here, the amount of overhead required by every API call is so huge, that the few clocks you may save here and there should make little difference in end performance. There are times when optimization can have a big impact. This just doesn't look much like one of them.

Then again, this is an assembly forum. :)
Posted on 2002-05-08 22:09:52 by S/390
Thanks for kindly help. and sorry for the small font.

BitRake, your optimized code is very neat. It's work for me. How could you do that? by experience?
I see that you use uses edi, is this a trick to remove the lines push edi and pop edi?

hutch,
PS : You should preserve EBX as well as it is used in your procedure.
How about ecx and edx?

By the way. how could i change the following C code into asm? It involves divide operation. Does it need to use fpu? I am rather a newbie on fpu.


static int GetLuminosity(COLORREF color)
{
#define HLSMAX 240 // This is what Display Properties uses
#define RGBMAX 255 // max r/g/b value is 255
int r = GetRValue(color);
int g = GetGValue(color);
int b = GetBValue(color);
int rgbMax = max( max(r,g), b);
int rgbMin = min( min(r,g), b);
return (((rgbMax+rgbMin) * HLSMAX) + RGBMAX ) / (2*RGBMAX);
}
Posted on 2002-05-09 00:44:06 by yoursguideline
yoursguideline,

The normal rule in Windows coding is to preserve EBX ESI & EDI. You can freely modify EAX ECX & EDX. ESP and EBP are normally used for procedure entry and exit and if you start manually coding procedures, you will need to preserve them as well.

Your code should preserve EBX as it uses it and there will be places where this can crash you program depending on what value was in EBX before your proc.

Regards,

hutch@movsd.com
Posted on 2002-05-09 05:38:02 by hutch--

BitRake, your optimized code is very neat. It's work for me. How could you do that? by experience? I see that you use uses edi, is this a trick to remove the lines push edi and pop edi?
After the algorithm works it's good to look at the code just as data flow: input, manipulation, and output. Sometimes, I draw graphs of dependancies - with practice it becomes very easy for small algo. And of course, I know x86 architecture very well - I can create operations and transformations in code with equal output. Yeah, uses is nice because you don't have to edit in two places if you change the algo.

Another version:
GetCaptionRect proc uses ebx edi,hWnd:DWORD, rc:DWORD, scrco:DWORD

mov edi, rc
assume edi:ptr RECT

push SM_CYFIXEDFRAME ; assume not WS_THICKFRAME
push SM_CXFIXEDFRAME
push GWL_STYLE
push hWnd
push edi
push hWnd
push SM_CYBORDER
push SM_CYCAPTION

call GetSystemMetrics
mov ebx, eax
call GetSystemMetrics
sub ebx, eax ; height of caption minus gray shadow border

call GetWindowRect
; get size of frame
call GetWindowLong

test eax, WS_THICKFRAME
je _a
mov DWORD PTR [esp], SM_CXSIZEFRAME
mov DWORD PTR [esp + 4], SM_CYSIZEFRAME
_a:

call GetSystemMetrics
sub [edi].right, eax

test scrco,-1
je _0
add [edi].left, eax
call GetSystemMetrics
add [edi].top, eax
add ebx, [edi].top
jmp _1
_0:
xchg eax, [edi].left
sub [edi].right, eax
call GetSystemMetrics
mov [edi].top, eax
_1:
mov [edi].bottom, ebx

assume edi:nothing
ret
GetCaptionRect endp
Next would be to remove the stack frame.
Posted on 2002-05-09 08:03:22 by bitRAKE
I can make loads of improvments :P *IF* you dont mind a wee bit of 95 incompatability :/

When I was doing my custom title bar routine about two or so months back I used about the same method. Until I ran across the API GetTitleBarInfo which is very nice (at least for me it was). And it comes with a bonus. It also shows the current states for all the buttons.

I think you will be most interested in the rcTitleBar field in the TITLEBARINFO structure.

Enjoy!
Posted on 2002-05-09 09:12:31 by Graebel
Graebel, it looks good. Thanks for the API. You are smart and know what i am doing. :cool:

bitRAKE, what is stack frame?

Do anyone know how to determine the maximum/minimum button is in disable state?
Posted on 2002-05-09 10:37:51 by yoursguideline

bitRAKE, what is stack frame?
When you have a PROC:
GetCaptionRect proc uses ebx edi,hWnd:DWORD, rc:DWORD, scrco:DWORD

...
...
...
ret
GetCaptionRect endp
MASM will assemble:
GetCaptionRect:

push ebp
mov ebp,esp
push ebx
push edi
...
...
...
pop edi
pop ebx
leave ; mov esp, ebp / pop ebp
ret 12
This is the stack frame.
The code can be reduced to:
GetCaptionRect:

push ebx
push edi
...
...
...
pop edi
pop ebx
ret 12
Register EBP isn't used and further optimization is possible. Note that we use the stack in the PROC as well as access parameters - we will have to acces this info from ESP and calculate the offset manually! :) Fun stuff :)

This is quite extreme for such a simple PROC, but if I were writing a compiler (or coding for a contest) then these things should be considered. :)
Posted on 2002-05-09 11:01:04 by bitRAKE
Actually yes. Check the return values in the rgstate field of the TITLEBARINFO struct.

indexed as:

0 The title bar itself.
1 Reserved.
2 Minimize button.
3 Maximize button.
4 Help button.
5 Close button

Value:
STATE_SYSTEM_FOCUSABLE The element can accept the focus.
STATE_SYSTEM_INVISIBLE The element is invisible.
STATE_SYSTEM_OFFSCREEN The element has no visible representation.
STATE_SYSTEM_UNAVAILABLE The element is unavailable.
STATE_SYSTEM_PRESSED The element is in the pressed state.

If I remember right, if the button is not visible you will get STATE_SYSTEM_INVISIBLE and disabled is STATE_SYSTEM_UNAVAILABLE.
Posted on 2002-05-09 12:13:58 by Graebel
There is another challenge about optimizing the code.

The arg is 0x00bbggrr
[size=12]

GetRValue MACRO arg:REQ
mov eax, arg
and eax, 0ffh
endm <eax>

GetGValue MACRO arg:REQ
mov eax, arg
mov al, ah
and eax, 0ffh
endm <eax>

GetBValue MACRO arg:REQ
mov eax, arg
bswap eax
mov al, ah
and eax, 0ffh
endm <eax>
[/size]
Posted on 2002-05-09 15:13:08 by yoursguideline
GetRValue MACRO arg:REQ

mov eax, arg
and eax, 0ffh
endm <eax>

GetGValue MACRO arg:REQ
mov eax, arg
shr eax, 8
and eax, 0ffh
endm <eax>

GetBValue MACRO arg:REQ
mov eax, arg
shr eax, 16 ; thx, Scronty ;)
;and eax, 0ffh ; uncomment if your not sure top byte zero
endm <eax>
These are too general for further optimization.
Posted on 2002-05-09 15:24:03 by bitRAKE
In the future, the eax may be 8 bytes so that the al/ah will be 2 bytes. Doing the bit shifting is not safe (I think)

:)
Posted on 2002-05-09 15:38:17 by yoursguideline
I use your words: "The arg is 0x00bbggrr" :)

shr eax,12

...would give 0x000000bb :)
Yes, it is only safe if most significant byte is zero.
Posted on 2002-05-09 17:01:36 by bitRAKE