22// Use of this source code is governed by GNU General Public License (GPL-2.0) that can be found in the COPYING file.
33
44using System ;
5- using System . Runtime . CompilerServices ;
5+ using System . Runtime . Intrinsics ;
6+ using System . Runtime . Intrinsics . X86 ;
67using PaintDotNet ;
78
89namespace SvgFileTypePlugin . Extensions ;
@@ -28,20 +29,116 @@ public static Document CreateSingleLayerDocument(this Surface surface, bool take
2829 return document ;
2930 }
3031
31- public static bool IsEmpty ( this Surface surface )
32+ public static unsafe bool IsEmpty ( this Surface surface )
3233 {
3334 ArgumentNullException . ThrowIfNull ( surface ) ;
3435
35- for ( int y = 0 ; y < surface . Height ; y ++ )
36+ const int unrollFactor = 4 ;
37+ int pixcnt = surface . Width * surface . Height ;
38+ sbyte * ptr = ( sbyte * ) surface . Scan0 . VoidStar ;
39+
40+ if ( Avx2 . IsSupported && pixcnt >= Vector256 < uint > . Count )
3641 {
37- ref ColorBgra pix = ref surface . GetRowReferenceUnchecked ( y ) ;
38- for ( int x = surface . Width ; x > 0 ; x -- )
42+ Vector256 < sbyte > valphamask = Vector256 . Create (
43+ 3 , 7 , 11 , 15 , 19 , 23 , 27 , 31 ,
44+ 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff ,
45+ 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff ,
46+ 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff ) . AsSByte ( ) ;
47+ Vector256 < sbyte > zero = Vector256 < sbyte > . Zero ;
48+ while ( pixcnt >= Vector256 < uint > . Count * unrollFactor )
49+ {
50+ Vector256 < sbyte > v0 = Avx . LoadVector256 ( ptr ) ;
51+ Vector256 < sbyte > v1 = Avx . LoadVector256 ( ptr + Vector256 < sbyte > . Count ) ;
52+ Vector256 < sbyte > v2 = Avx . LoadVector256 ( ptr + 2 * Vector256 < sbyte > . Count ) ;
53+ Vector256 < sbyte > v3 = Avx . LoadVector256 ( ptr + 3 * Vector256 < sbyte > . Count ) ;
54+
55+ v0 = Avx2 . Shuffle ( v0 , valphamask ) ;
56+ v1 = Avx2 . Shuffle ( v1 , valphamask ) ;
57+ v2 = Avx2 . Shuffle ( v2 , valphamask ) ;
58+ v3 = Avx2 . Shuffle ( v3 , valphamask ) ;
59+
60+ v0 = Avx2 . CompareGreaterThan ( v0 , zero ) ;
61+ v1 = Avx2 . CompareGreaterThan ( v1 , zero ) ;
62+ v2 = Avx2 . CompareGreaterThan ( v2 , zero ) ;
63+ v3 = Avx2 . CompareGreaterThan ( v3 , zero ) ;
64+
65+ if ( Avx2 . MoveMask ( v0 ) != 0 || Avx2 . MoveMask ( v1 ) != 0
66+ || Avx2 . MoveMask ( v2 ) != 0 || Avx2 . MoveMask ( v3 ) != 0 )
67+ {
68+ return false ;
69+ }
70+
71+ ptr += Vector256 < sbyte > . Count * unrollFactor ;
72+ pixcnt -= Vector256 < uint > . Count * unrollFactor ;
73+ }
74+
75+ while ( pixcnt >= Vector256 < sbyte > . Count )
3976 {
40- if ( pix . A > 0 )
77+ Vector256 < sbyte > v = Avx . LoadVector256 ( ptr ) ;
78+ v = Avx2 . Shuffle ( v , valphamask ) ;
79+ v = Avx2 . CompareGreaterThan ( v , zero ) ;
80+ if ( Avx2 . MoveMask ( v ) != 0 )
4181 return false ;
42- pix = ref Unsafe . Add ( ref pix , 1 ) ;
82+ ptr += Vector256 < sbyte > . Count ;
83+ pixcnt -= Vector256 < uint > . Count ;
4384 }
4485 }
86+
87+ if ( Ssse3 . IsSupported && pixcnt >= Vector128 < uint > . Count )
88+ {
89+ Vector128 < sbyte > valphamask = Vector128 . Create (
90+ 3 , 7 , 11 , 15 ,
91+ 0xff , 0xff , 0xff , 0xff ,
92+ 0xff , 0xff , 0xff , 0xff ,
93+ 0xff , 0xff , 0xff , 0xff ) . AsSByte ( ) ;
94+ Vector128 < sbyte > zero = Vector128 < sbyte > . Zero ;
95+ while ( pixcnt >= Vector128 < uint > . Count * unrollFactor )
96+ {
97+ Vector128 < sbyte > v0 = Sse2 . LoadVector128 ( ptr ) ;
98+ Vector128 < sbyte > v1 = Sse2 . LoadVector128 ( ptr + Vector128 < sbyte > . Count ) ;
99+ Vector128 < sbyte > v2 = Sse2 . LoadVector128 ( ptr + 2 * Vector128 < sbyte > . Count ) ;
100+ Vector128 < sbyte > v3 = Sse2 . LoadVector128 ( ptr + 3 * Vector128 < sbyte > . Count ) ;
101+
102+ v0 = Ssse3 . Shuffle ( v0 , valphamask ) ;
103+ v1 = Ssse3 . Shuffle ( v1 , valphamask ) ;
104+ v2 = Ssse3 . Shuffle ( v2 , valphamask ) ;
105+ v3 = Ssse3 . Shuffle ( v3 , valphamask ) ;
106+
107+ v0 = Sse2 . CompareGreaterThan ( v0 , zero ) ;
108+ v1 = Sse2 . CompareGreaterThan ( v1 , zero ) ;
109+ v2 = Sse2 . CompareGreaterThan ( v2 , zero ) ;
110+ v3 = Sse2 . CompareGreaterThan ( v3 , zero ) ;
111+
112+ if ( Sse2 . MoveMask ( v0 ) != 0 || Sse2 . MoveMask ( v1 ) != 0
113+ || Sse2 . MoveMask ( v2 ) != 0 || Sse2 . MoveMask ( v3 ) != 0 )
114+ {
115+ return false ;
116+ }
117+
118+ ptr += Vector128 < sbyte > . Count * unrollFactor ;
119+ pixcnt -= Vector128 < uint > . Count * unrollFactor ;
120+ }
121+
122+ while ( pixcnt >= Vector128 < sbyte > . Count )
123+ {
124+ Vector128 < sbyte > v = Sse2 . LoadVector128 ( ptr ) ;
125+ v = Ssse3 . Shuffle ( v , valphamask ) ;
126+ v = Sse2 . CompareGreaterThan ( v , zero ) ;
127+ if ( Sse2 . MoveMask ( v ) != 0 )
128+ return false ;
129+ ptr += Vector128 < sbyte > . Count ;
130+ pixcnt -= Vector128 < uint > . Count ;
131+ }
132+ }
133+
134+ while ( pixcnt > 0 )
135+ {
136+ if ( ptr [ 3 ] > 0 )
137+ return false ;
138+ ptr += sizeof ( uint ) ;
139+ pixcnt -- ;
140+ }
141+
45142 return true ;
46143 }
47144
0 commit comments