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?