The pure PowerBASIC version using AND and SHIFT RIGHT originally is named Text_BlackOrWhiteOrig here. The second is Text_BlackOrWhiteASM having only the colors isolated to separate LONGs in assembly. Then the TYPE in UNION isolation is Text_BlackOrWhiteType. Finally, the selected, 100% assembly version is Text_BlackOrWhiteASM2. They are below PBMAIN which has timing loops and result printing.
#compile exe #dim all #if %def(%pb_cc32) 'ignore in PBWin #console off 'no unneeded console in PBCC #endif %UNICODE = 1 function pbmain () as long local hTWin as dword local Cntr, ForMax, BG_Color, Dummy as long local Run_Cnt, OrigTIX, TYPETIX, ASMTIX, ASMTIX2 as quad ' txt.window(""$$, 200, 150, 30, 50) to hTWin ForMax = 200000000 BG_Color = &h00F0F0F0& txt.print "any key to start"$$ txt.waitkey$ txt.cls '============================================================================= txt.print "Pass 1."$$ '-------------------------------------------------- 1 -- txt.print " Original"$$ '············································ 1O ···· tix Run_Cnt for Cntr = 1 to ForMax Dummy = Text_BlackOrWhiteOrig(BG_Color) next tix end Run_Cnt OrigTIX = Run_Cnt txt.print " Type"$$ '················································ 1T ···· tix Run_Cnt for Cntr = 1 to ForMax Dummy = Text_BlackOrWhiteType(BG_Color) next tix end Run_Cnt TypeTIX = Run_Cnt txt.print " Assembly V1"$$ '········································· 1A ···· tix Run_Cnt for Cntr = 1 to ForMax Dummy = Text_BlackOrWhiteASM(BG_Color) next tix end Run_Cnt ASMTIX = Run_Cnt txt.print " Assembly V2"$$ '········································ 1A2 ···· tix Run_Cnt for Cntr = 1 to ForMax Dummy = Text_BlackOrWhiteASM2(BG_Color) next tix end Run_Cnt ASMTIX2 = Run_Cnt txt.print "Pass 2."$$ '-------------------------------------------------- 2 -- txt.print " Type"$$ '················································ 2T ···· tix Run_Cnt for Cntr = 1 to ForMax Dummy = Text_BlackOrWhiteType(BG_Color) next tix end Run_Cnt TypeTIX += Run_Cnt txt.print " Assembly V1"$$ '········································· 2A ···· tix Run_Cnt for Cntr = 1 to ForMax Dummy = Text_BlackOrWhiteASM(BG_Color) next tix end Run_Cnt ASMTIX += Run_Cnt txt.print " Assembly V2"$$ '········································ 2A2 ···· tix Run_Cnt for Cntr = 1 to ForMax Dummy = Text_BlackOrWhiteASM2(BG_Color) next tix end Run_Cnt ASMTIX2 += Run_Cnt txt.print " Original"$$ '············································ 2O ···· tix Run_Cnt for Cntr = 1 to ForMax Dummy = Text_BlackOrWhiteOrig(BG_Color) next tix end Run_Cnt OrigTIX += Run_Cnt txt.print "Pass 3."$$ '-------------------------------------------------- 3 -- txt.print " Assembly V1"$$ '········································· 3A ···· tix Run_Cnt for Cntr = 1 to ForMax Dummy = Text_BlackOrWhiteASM(BG_Color) next tix end Run_Cnt ASMTIX += Run_Cnt txt.print " Assembly V2"$$ '········································ 3A2 ···· tix Run_Cnt for Cntr = 1 to ForMax Dummy = Text_BlackOrWhiteASM2(BG_Color) next tix end Run_Cnt ASMTIX2 += Run_Cnt txt.print " Original"$$ '············································ 3O ···· tix Run_Cnt for Cntr = 1 to ForMax Dummy = Text_BlackOrWhiteOrig(BG_Color) next tix end Run_Cnt OrigTIX += Run_Cnt txt.print " Type"$$ '················································ 3T ···· tix Run_Cnt for Cntr = 1 to ForMax Dummy = Text_BlackOrWhiteType(BG_Color) next tix end Run_Cnt TypeTIX += Run_Cnt txt.print "Pass 4"$$ '--------------------------------------------------- 4 -- txt.print " Assembly V2"$$ '········································ 4A2 ···· tix Run_Cnt for Cntr = 1 to ForMax Dummy = Text_BlackOrWhiteASM2(BG_Color) next tix end Run_Cnt ASMTIX2 += Run_Cnt txt.print " Original"$$ '············································ 4O ···· tix Run_Cnt for Cntr = 1 to ForMax Dummy = Text_BlackOrWhiteOrig(BG_Color) next tix end Run_Cnt OrigTIX += Run_Cnt txt.print " Type"$$ '················································ 4T ···· tix Run_Cnt for Cntr = 1 to ForMax Dummy = Text_BlackOrWhiteType(BG_Color) next tix end Run_Cnt TypeTIX += Run_Cnt txt.print " Assembly V1"$$ '········································· 4A ···· tix Run_Cnt for Cntr = 1 to ForMax Dummy = Text_BlackOrWhiteASM(BG_Color) next tix end Run_Cnt ASMTIX += Run_Cnt txt.print 'Calculate average and display -------------------------- results -- txt.print dec$(OrigTIX \ 4, 11); " Original, 4 run mean TIX count."$$ txt.print dec$(TypeTIX \ 4, 11); " Type, 4 run mean TIX count."$$ txt.print dec$(AsmTIX \ 4, 11); " Assembly V1, 4 run mean TIX count."$$ txt.print dec$(AsmTIX2 \ 4, 11); " Assembly V2, 4 run mean TIX count."$$ txt.print txt.print "Any key to end."$$ '---------------------------------------- end -- txt.waitkey$ end function '=============================================================================== function Text_BlackOrWhiteOrig(byval BG_Color as long) as long local Tmp as long local Lum as single ' 'Red Tmp = BG_Color and &h000000FF& Lum = 0.76245! * Tmp ' 'Green Tmp = BG_Color and &h0000FF00& shift right Tmp, 8 Lum += 1.49685! * Tmp ' 'Blue Tmp = BG_Color and &h00FF0000& 'blue shift right Tmp, 16 Lum += 0.2907! * Tmp ' 'Compare sum of red, green and blue luminance with transition for return. if Lum > 408! then function = -1 'Windows default (black) foreground for light background color. else function = &h00FFFFFF& 'White foreground for dark background colors. end if end function '=============================================================================== function Text_BlackOrWhiteASM(byval BG_Color as long) as long local RLg, GLg, BLg as long 'Red Long, Green Long and Blue Long local Lum as single ' ! push eax ! push ebx ! xor ebx, ebx ! mov eax, BG_Color ! mov bl, al 'red in b ! mov RLg, ebx 'red to mem ! mov bl, ah 'green in b ! mov GLg, ebx 'green to mem ! shl eax, 16 'blue in a ! and eax, &h000000FF??? 'in case BG_Color had something in MSB ! mov BLg, eax ! pop ebx ! pop eax 'Red Lum = 0.76245! * RLg 'Green Lum += 1.49685! * GLg 'Blue Lum += 0.2907! * BLg ' 'Compare sum of red, green and blue luminance with transition for return. if Lum > 408! then function = -1 'Windows default (black) foreground for light background color. else function = &h00FFFFFF& 'White foreground for dark background colors. end if end function '=============================================================================== type RGB_Bytes Rd as byte Gr as byte Bl as byte nu as byte end type union RGB_U Byt as RGB_Bytes Lg as long end union '------------------------------------------------------------------------------- function Text_BlackOrWhiteType(byval BG_Color as long) as long local BG as RGB_U local Lum as single ' BG.Lg = BG_Color 'Red Lum = 0.76245! * BG.Byt.Rd ' 'Green Lum += 1.49685! * BG.Byt.Gr ' 'Blue Lum += 0.2907! * BG.Byt.Bl ' 'Compare sum of red, green and blue luminance with transition for return. if Lum > 408! then function = -1 'Windows default (black) foreground for light background color. else function = &h00FFFFFF& 'White foreground for dark background colors. end if end function '=============================================================================== function Text_BlackOrWhiteASM2(byval BG_Color as long) as long 'Everything done in ASseMmbly and no LOCAL variables (all in registers), so 'PUSH/POP and #REGISTER NONE are not needed. ' 'Register purpose: ' eax for product low dword ' ebx for green value, then green luminance factor weighted. ' ecx full color, then blue only, then blue luminance factor weighted. ' edx product high dword (not actually used, cleared by MUL in this app). ' edi red color, then red luminance factor weighted, then sum of weighteds. ' ! xor ebx, ebx 'clear (upper 3 bytes not over-written, possible garbage) ' ! mov ecx, BG_Color 'passed value to register ! mov edi, ecx 'copy BG_Color (register-register better than memory) ! and edi, &h000000FF??? 'now is red only (no byte access of edi) ! mov bl, ch 'green only in ebx ! and ecx, &h00FF0000??? 'leave blue only in ecx ! shr ecx, 16 'shift to cl 'red multiply ! mov eax, 3197947??? '0.76245 * &h400000 (red weight pre-multiplied) ! mul edi 'weight by red, edi now available for sum ! mov edi, eax 'mov clears red for first product to sum 'green multipy ! mov eax, 6278243??? '1.49685 * &h400000 (green weight pre-multiplied) ! mul ebx ! add edi, eax 'add green product to sum 'blue multiply ! mov eax, 1219284??? '0.2907 * &h400000 (blue weight pre-multiplied) ! mul ecx ! add edi, eax 'add blue product to sum ' 'compare sum with transition and return result ! cmp edi, 1989358387??? '474.3 * &h400000 (transition point pre-multiplied) ! ja FG_Default 'default assumed black ! mov function, &h00FFFFFF& 'white ! jmp Done FG_Default: ! mov function, -1& Done: end function '=============================================================================== '
Full copyleft (ɔ), 2024 by Dale Yarker in source or compiled form. Complete license in new tab or window.
Created on 27 May 2024.
Done with this window?