2
2
// Use of this source code is governed by GNU General Public License (GPL-2.0) that can be found in the COPYING file.
3
3
4
4
using System ;
5
- using System . Runtime . CompilerServices ;
5
+ using System . Runtime . Intrinsics ;
6
+ using System . Runtime . Intrinsics . X86 ;
6
7
using PaintDotNet ;
7
8
8
9
namespace SvgFileTypePlugin . Extensions ;
@@ -28,20 +29,116 @@ public static Document CreateSingleLayerDocument(this Surface surface, bool take
28
29
return document ;
29
30
}
30
31
31
- public static bool IsEmpty ( this Surface surface )
32
+ public static unsafe bool IsEmpty ( this Surface surface )
32
33
{
33
34
ArgumentNullException . ThrowIfNull ( surface ) ;
34
35
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 )
36
41
{
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 )
39
76
{
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 )
41
81
return false ;
42
- pix = ref Unsafe . Add ( ref pix , 1 ) ;
82
+ ptr += Vector256 < sbyte > . Count ;
83
+ pixcnt -= Vector256 < uint > . Count ;
43
84
}
44
85
}
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
+
45
142
return true ;
46
143
}
47
144
0 commit comments