1
2 /* mips_init.c - MSA optimised filter functions
3 *
4 * Copyright (c) 2018-2024 Cosmin Truta
5 * Copyright (c) 2016 Glenn Randers-Pehrson
6 * Written by Mandar Sahastrabuddhe, 2016
7 * Updated by guxiwei, 2023
8 *
9 * This code is released under the libpng license.
10 * For conditions of distribution and use, see the disclaimer
11 * and license in png.h
12 */
13
14 /* Below, after checking __linux__, various non-C90 POSIX 1003.1 functions are
15 * called.
16 */
17 #define _POSIX_SOURCE 1
18
19 #include <stdio.h>
20 #include "../pngpriv.h"
21
22 #ifdef PNG_READ_SUPPORTED
23
24 #if PNG_MIPS_MSA_IMPLEMENTATION == 1 || PNG_MIPS_MMI_IMPLEMENTATION > 0
25
26 #ifdef PNG_MIPS_MSA_CHECK_SUPPORTED /* Do MIPS MSA run-time checks */
27 /* WARNING: it is strongly recommended that you do not build libpng with
28 * run-time checks for CPU features if at all possible. In the case of the MIPS
29 * MSA instructions there is no processor-specific way of detecting the
30 * presence of the required support, therefore run-time detection is extremely
31 * OS specific.
32 *
33 * You may set the macro PNG_MIPS_MSA_FILE to the file name of file containing
34 * a fragment of C source code which defines the png_have_msa function. There
35 * are a number of implementations in contrib/mips-msa, but the only one that
36 * has partial support is contrib/mips-msa/linux.c - a generic Linux
37 * implementation which reads /proc/cpufino.
38 */
39 #ifndef PNG_MIPS_MSA_FILE
40 # ifdef __linux__
41 # define PNG_MIPS_MSA_FILE "contrib/mips-msa/linux.c"
42 # endif
43 #endif
44
45 #ifdef PNG_MIPS_MSA_FILE
46
47 #include <signal.h> /* for sig_atomic_t */
48 static int png_have_msa(png_structp png_ptr);
49 #include PNG_MIPS_MSA_FILE
50
51 #else /* PNG_MIPS_MSA_FILE */
52 # error "PNG_MIPS_MSA_FILE undefined: no support for run-time MIPS MSA checks"
53 #endif /* PNG_MIPS_MSA_FILE */
54 #endif /* PNG_MIPS_MSA_CHECK_SUPPORTED */
55
56 #ifdef PNG_MIPS_MMI_CHECK_SUPPORTED /* Do MIPS MMI run-times checks */
57 #ifndef PNG_MIPS_MMI_FILE
58 # ifdef __linux__
59 # define PNG_MIPS_MMI_FILE "contrib/mips-mmi/linux.c"
60 # endif
61 #endif
62
63 #ifdef PNG_MIPS_MMI_FILE
64
65 #include <signal.h> /* for sig_atomic_t */
66 static int png_have_mmi();
67 #include PNG_MIPS_MMI_FILE
68
69 #else /* PNG_MIPS_MMI_FILE */
70 # error "PNG_MIPS_MMI_FILE undefined: no support for run-time MIPS MMI checks"
71 #endif /* PNG_MIPS_MMI_FILE */
72 #endif /* PNG_MIPS_MMI_CHECK_SUPPORTED*/
73
74 #ifndef PNG_ALIGNED_MEMORY_SUPPORTED
75 # error "ALIGNED_MEMORY is required; set: -DPNG_ALIGNED_MEMORY_SUPPORTED"
76 #endif
77
78 /* MIPS supports two optimizations: MMI and MSA. The appropriate
79 * optimization is chosen at runtime
80 */
81 void
png_init_filter_functions_mips(png_structp pp,unsigned int bpp)82 png_init_filter_functions_mips(png_structp pp, unsigned int bpp)
83 {
84 #if PNG_MIPS_MMI_IMPLEMENTATION > 0
85 #ifdef PNG_MIPS_MMI_API_SUPPORTED
86 switch ((pp->options >> PNG_MIPS_MMI) & 3)
87 {
88 case PNG_OPTION_UNSET:
89 #endif /* PNG_MIPS_MMI_API_SUPPORTED */
90 #ifdef PNG_MIPS_MMI_CHECK_SUPPORTED
91 {
92 static volatile sig_atomic_t no_mmi = -1; /* not checked */
93
94 if (no_mmi < 0)
95 no_mmi = !png_have_mmi();
96
97 if (no_mmi)
98 goto MIPS_MSA_INIT;
99 }
100 #ifdef PNG_MIPS_MMI_API_SUPPORTED
101 break;
102 #endif
103 #endif /* PNG_MIPS_MMI_CHECK_SUPPORTED */
104
105 #ifdef PNG_MIPS_MMI_API_SUPPORTED
106 default: /* OFF or INVALID */
107 goto MIPS_MSA_INIT;
108
109 case PNG_OPTION_ON:
110 /* Option turned on */
111 break;
112 }
113 #endif
114 pp->read_filter[PNG_FILTER_VALUE_UP-1] = png_read_filter_row_up_mmi;
115 if (bpp == 3)
116 {
117 pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub3_mmi;
118 pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg3_mmi;
119 pp->read_filter[PNG_FILTER_VALUE_PAETH-1] =
120 png_read_filter_row_paeth3_mmi;
121 }
122 else if (bpp == 4)
123 {
124 pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub4_mmi;
125 pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg4_mmi;
126 pp->read_filter[PNG_FILTER_VALUE_PAETH-1] =
127 png_read_filter_row_paeth4_mmi;
128 }
129 #endif /* PNG_MIPS_MMI_IMPLEMENTATION > 0 */
130
131 MIPS_MSA_INIT:
132 #if PNG_MIPS_MSA_IMPLEMENTATION == 1
133 /* The switch statement is compiled in for MIPS_MSA_API, the call to
134 * png_have_msa is compiled in for MIPS_MSA_CHECK. If both are defined
135 * the check is only performed if the API has not set the MSA option on
136 * or off explicitly. In this case the check controls what happens.
137 */
138
139 #ifdef PNG_MIPS_MSA_API_SUPPORTED
140 switch ((pp->options >> PNG_MIPS_MSA) & 3)
141 {
142 case PNG_OPTION_UNSET:
143 /* Allow the run-time check to execute if it has been enabled -
144 * thus both API and CHECK can be turned on. If it isn't supported
145 * this case will fall through to the 'default' below, which just
146 * returns.
147 */
148 #endif /* PNG_MIPS_MSA_API_SUPPORTED */
149 #ifdef PNG_MIPS_MSA_CHECK_SUPPORTED
150 {
151 static volatile sig_atomic_t no_msa = -1; /* not checked */
152
153 if (no_msa < 0)
154 no_msa = !png_have_msa(pp);
155
156 if (no_msa)
157 return;
158 }
159 #ifdef PNG_MIPS_MSA_API_SUPPORTED
160 break;
161 #endif
162 #endif /* PNG_MIPS_MSA_CHECK_SUPPORTED */
163
164 #ifdef PNG_MIPS_MSA_API_SUPPORTED
165 default: /* OFF or INVALID */
166 return;
167
168 case PNG_OPTION_ON:
169 /* Option turned on */
170 break;
171 }
172 #endif
173
174 /* IMPORTANT: any new external functions used here must be declared using
175 * PNG_INTERNAL_FUNCTION in ../pngpriv.h. This is required so that the
176 * 'prefix' option to configure works:
177 *
178 * ./configure --with-libpng-prefix=foobar_
179 *
180 * Verify you have got this right by running the above command, doing a build
181 * and examining pngprefix.h; it must contain a #define for every external
182 * function you add. (Notice that this happens automatically for the
183 * initialization function.)
184 */
185 pp->read_filter[PNG_FILTER_VALUE_UP-1] = png_read_filter_row_up_msa;
186
187 if (bpp == 3)
188 {
189 pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub3_msa;
190 pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg3_msa;
191 pp->read_filter[PNG_FILTER_VALUE_PAETH-1] = png_read_filter_row_paeth3_msa;
192 }
193
194 else if (bpp == 4)
195 {
196 pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub4_msa;
197 pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg4_msa;
198 pp->read_filter[PNG_FILTER_VALUE_PAETH-1] = png_read_filter_row_paeth4_msa;
199 }
200 #endif /* PNG_MIPS_MSA_IMPLEMENTATION == 1 */
201 return;
202 }
203 #endif /* PNG_MIPS_MSA_IMPLEMENTATION == 1 || PNG_MIPS_MMI_IMPLEMENTATION > 0 */
204 #endif /* READ */
205