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?