Compare speed of four versions of function Text_BlackOrWhite

  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.


Source Code
#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?