xref: /aosp_15_r20/external/libpng/mips/mips_init.c (revision a67afe4df73cf47866eedc69947994b8ff839aba)
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