Skip to content

Commit ab08b3f

Browse files
committed
Add x86_64 asm versions of blendpixel and filldata
1 parent b1ca368 commit ab08b3f

11 files changed

Lines changed: 149 additions & 343 deletions

Source/asm/blendpixel_x86_64.inc

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// x86-64 SSE alpha blend of one pixel: dst = (dst*(255-a) + src*a) / 255 per channel, with
2+
// the /255 as the exact (t*32897) shr 23 (pmulhuw + psrlw). Where dst.A = 0 the source is
3+
// copied, matching the scalar path. `const Color` is passed by reference. Bit-identical to
4+
// the scalar blend for opaque or fully-transparent destinations.
5+
assembler; nostackframe;
6+
asm
7+
{$IFDEF UNIX}
8+
mov rcx, rdi // Pixel
9+
mov rdx, rsi // @Color
10+
{$ENDIF}
11+
movzx eax, byte ptr [rcx+3] // dst.A
12+
test eax, eax
13+
jz @copy
14+
movd xmm0, [rcx] // dst pixel
15+
movd xmm1, [rdx] // src color
16+
pxor xmm2, xmm2
17+
punpcklbw xmm0, xmm2 // dst -> 4 words
18+
punpcklbw xmm1, xmm2 // src -> 4 words
19+
pshuflw xmm3, xmm1, $FF // a = src.A, broadcast to 4 words
20+
mov eax, 255
21+
pinsrw xmm1, eax, 3 // src.A lane -> 255, so the A addend is 255*a
22+
pcmpeqw xmm4, xmm4
23+
psrlw xmm4, 8 // 255 in each word
24+
psubw xmm4, xmm3 // ia = 255 - a
25+
pmullw xmm0, xmm4 // dst * ia
26+
pmullw xmm1, xmm3 // addend: src*a (A lane = 255*a)
27+
paddw xmm0, xmm1
28+
mov eax, 32897
29+
movd xmm5, eax
30+
pshuflw xmm5, xmm5, 0 // div-255 magic, broadcast
31+
pmulhuw xmm0, xmm5 // (t * 32897) >> 16
32+
psrlw xmm0, 7 // >> 7 => t / 255
33+
packuswb xmm0, xmm0
34+
movd [rcx], xmm0
35+
jmp @done
36+
@copy:
37+
mov eax, [rdx]
38+
mov [rcx], eax
39+
@done:
40+
end;

Source/asm/filldata_x86_64.inc

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// x86-64 fill for a row of pixels (pure asm). Small/medium fills use cached movdqu stores
2+
// (fast, and keeps the pixels in cache for the draw that usually follows); fills of 4 MB or
3+
// more use aligned non-temporal (movntdq) stores - ~3x faster for the large image-clear case.
4+
// `const Value` is passed by reference. All registers touched are volatile, hence nostackframe.
5+
assembler; nostackframe;
6+
asm
7+
{$IFDEF UNIX}
8+
mov rcx, rdi // Data
9+
mov r8, rdx // @Value
10+
mov rdx, rsi // Count
11+
{$ENDIF}
12+
mov r9d, [r8] // Value (const record, passed by reference)
13+
test rdx, rdx
14+
jle @done // Count <= 0
15+
movd xmm0, r9d
16+
pshufd xmm0, xmm0, 0 // broadcast the pixel to all 4 lanes
17+
mov rax, rcx // rax = running destination
18+
mov rcx, rdx // rcx = pixel count
19+
cmp rcx, 1048576 // >= 4 MB (1M pixels) -> non-temporal
20+
jae @large
21+
22+
// small / medium: cached stores, 8 px (32 bytes) per iteration - two store ports keep up
23+
mov edx, ecx
24+
and rcx, -8 // whole blocks of 8 pixels
25+
jz @stail
26+
@sloop:
27+
movdqu [rax], xmm0
28+
movdqu [rax+16], xmm0
29+
add rax, 32
30+
sub rcx, 8
31+
jnz @sloop
32+
@stail:
33+
and edx, 7 // 0..7 leftover pixels
34+
jz @done
35+
cmp edx, 4
36+
jb @stloop // fewer than 4 -> scalar tail
37+
movdqu [rax], xmm0 // one 4-pixel block
38+
add rax, 16
39+
sub edx, 4
40+
jz @done
41+
@stloop:
42+
mov [rax], r9d
43+
add rax, 4
44+
dec edx
45+
jnz @stloop
46+
jmp @done
47+
48+
// large: align to 16 bytes, then non-temporal
49+
@large:
50+
@align:
51+
test rax, 15
52+
jz @lbulk
53+
mov [rax], r9d
54+
add rax, 4
55+
dec rcx
56+
jmp @align
57+
@lbulk:
58+
mov edx, ecx
59+
and rcx, -4
60+
jz @ltail
61+
@lloop:
62+
movntdq [rax], xmm0
63+
add rax, 16
64+
sub rcx, 4
65+
jnz @lloop
66+
@ltail:
67+
and edx, 3
68+
jz @lfence
69+
@ltloop:
70+
mov [rax], r9d
71+
add rax, 4
72+
dec edx
73+
jnz @ltloop
74+
@lfence:
75+
sfence
76+
@done:
77+
end;

Source/compress/simba.compress_synlz.pas

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ function SynLZDecompressedSize(Src: PByte): Int32;
7272
end;
7373

7474
{$IF DEFINED(SYNLZ_ASM)}
75-
{$I ../asm/synlzcompress_x64.inc}
76-
{$I ../asm/synlzdecompress_x64.inc}
75+
{$I ../asm/synlzcompress_x86_64.inc}
76+
{$I ../asm/synlzdecompress_x86_64.inc}
7777
{$ENDIF}
7878

7979
function SynLZCompressPas(Src: PByte; Size: Int32; Dst: PByte): Int32;

Source/simba.colormath_distance_unrolled.pas

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,17 @@ function DistanceDeltaE_UnRolled(const C1: PColorLAB; const C2: PColorBGRA; cons
3131
implementation
3232

3333
function DistanceRGB_UnRolled(const C1: PColorRGB; const C2: PColorBGRA; const mul: TChannelMultipliers): Single;
34-
{$IF DEFINED(COLORDIST_ASM) and DEFINED(CPUX86_64)}
35-
{$I asm/distancergb_x64_86.inc}
34+
{$IF DEFINED(COLORDIST_ASM)}
35+
{$I asm/distancergb_x86_64.inc}
3636
{$ELSE}
3737
begin
3838
Result := Sqrt(Sqr((C1^.R - C2^.R) * mul[0]) + Sqr((C1^.G - C2^.G) * mul[1]) + Sqr((C1^.B - C2^.B) * mul[2]));
3939
end;
4040
{$ENDIF}
4141

4242
function DistanceHSL_UnRolled(const C1: PColorHSL; const C2: PColorBGRA; const mul: TChannelMultipliers): Single;
43-
{$IF DEFINED(COLORDIST_ASM) and DEFINED(CPUX86_64)}
44-
{$I asm/distancehsl_x64_86.inc}
43+
{$IF DEFINED(COLORDIST_ASM)}
44+
{$I asm/distancehsl_x86_64.inc}
4545
{$ELSE}
4646
var
4747
R,G,B,deltaC,deltaH,cMax,cMin, H,S,L: Single;
@@ -88,8 +88,8 @@ function DistanceHSL_UnRolled(const C1: PColorHSL; const C2: PColorBGRA; const m
8888
{$ENDIF}
8989

9090
function DistanceHSV_UnRolled(const C1: PColorHSV; const C2: PColorBGRA; const mul: TChannelMultipliers): Single;
91-
{$IF DEFINED(COLORDIST_ASM) and DEFINED(CPUX86_64)}
92-
{$I asm/distancehsv_x64_86.inc}
91+
{$IF DEFINED(COLORDIST_ASM)}
92+
{$I asm/distancehsv_x86_64.inc}
9393
{$ELSE}
9494
var
9595
R, G, B: Single;

0 commit comments

Comments
 (0)