Commit | Line | Data |
---|---|---|
3719602c PC |
1 | /* Copyright (C) 2010-2020 The RetroArch team |
2 | * | |
3 | * --------------------------------------------------------------------------------------- | |
4 | * The following license statement only applies to this file (scaler.c). | |
5 | * --------------------------------------------------------------------------------------- | |
6 | * | |
7 | * Permission is hereby granted, free of charge, | |
8 | * to any person obtaining a copy of this software and associated documentation files (the "Software"), | |
9 | * to deal in the Software without restriction, including without limitation the rights to | |
10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, | |
11 | * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | |
12 | * | |
13 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. | |
14 | * | |
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, | |
16 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | |
19 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
21 | */ | |
22 | ||
23 | #include <stdio.h> | |
24 | #include <stdlib.h> | |
25 | #include <string.h> | |
26 | #include <math.h> | |
27 | ||
28 | #include <gfx/scaler/scaler.h> | |
29 | #include <gfx/scaler/scaler_int.h> | |
30 | #include <gfx/scaler/filter.h> | |
31 | #include <gfx/scaler/pixconv.h> | |
32 | ||
33 | static bool allocate_frames(struct scaler_ctx *ctx) | |
34 | { | |
35 | uint64_t *scaled_frame = NULL; | |
36 | ctx->scaled.stride = ((ctx->out_width + 7) & ~7) * sizeof(uint64_t); | |
37 | ctx->scaled.width = ctx->out_width; | |
38 | ctx->scaled.height = ctx->in_height; | |
39 | scaled_frame = (uint64_t*)calloc(sizeof(uint64_t), | |
40 | (ctx->scaled.stride * ctx->scaled.height) >> 3); | |
41 | ||
42 | if (!scaled_frame) | |
43 | return false; | |
44 | ||
45 | ctx->scaled.frame = scaled_frame; | |
46 | ||
47 | if (ctx->in_fmt != SCALER_FMT_ARGB8888) | |
48 | { | |
49 | uint32_t *input_frame = NULL; | |
50 | ctx->input.stride = ((ctx->in_width + 7) & ~7) * sizeof(uint32_t); | |
51 | input_frame = (uint32_t*)calloc(sizeof(uint32_t), | |
52 | (ctx->input.stride * ctx->in_height) >> 2); | |
53 | ||
54 | if (!input_frame) | |
55 | return false; | |
56 | ||
57 | ctx->input.frame = input_frame; | |
58 | } | |
59 | ||
60 | if (ctx->out_fmt != SCALER_FMT_ARGB8888) | |
61 | { | |
62 | uint32_t *output_frame = NULL; | |
63 | ctx->output.stride = ((ctx->out_width + 7) & ~7) * sizeof(uint32_t); | |
64 | ||
65 | output_frame = (uint32_t*)calloc(sizeof(uint32_t), | |
66 | (ctx->output.stride * ctx->out_height) >> 2); | |
67 | ||
68 | if (!output_frame) | |
69 | return false; | |
70 | ||
71 | ctx->output.frame = output_frame; | |
72 | } | |
73 | ||
74 | return true; | |
75 | } | |
76 | ||
77 | bool scaler_ctx_gen_filter(struct scaler_ctx *ctx) | |
78 | { | |
79 | scaler_ctx_gen_reset(ctx); | |
80 | ||
81 | ctx->scaler_special = NULL; | |
82 | ctx->unscaled = false; | |
83 | ||
84 | if (!allocate_frames(ctx)) | |
85 | return false; | |
86 | ||
87 | if ( ctx->in_width == ctx->out_width | |
88 | && ctx->in_height == ctx->out_height) | |
89 | { | |
90 | ctx->unscaled = true; /* Only pixel format conversion ... */ | |
91 | ||
92 | if (ctx->in_fmt == ctx->out_fmt) | |
93 | ctx->direct_pixconv = conv_copy; | |
94 | else | |
95 | { | |
96 | /* Bind a pixel converter callback function to the | |
97 | * 'direct_pixconv' function pointer of the scaler context object. */ | |
98 | switch (ctx->in_fmt) | |
99 | { | |
100 | case SCALER_FMT_0RGB1555: | |
101 | switch (ctx->out_fmt) | |
102 | { | |
103 | case SCALER_FMT_ARGB8888: | |
104 | ctx->direct_pixconv = conv_0rgb1555_argb8888; | |
105 | break; | |
106 | case SCALER_FMT_RGB565: | |
107 | ctx->direct_pixconv = conv_0rgb1555_rgb565; | |
108 | break; | |
109 | case SCALER_FMT_BGR24: | |
110 | ctx->direct_pixconv = conv_0rgb1555_bgr24; | |
111 | break; | |
112 | default: | |
113 | break; | |
114 | } | |
115 | break; | |
116 | case SCALER_FMT_RGB565: | |
117 | switch (ctx->out_fmt) | |
118 | { | |
119 | case SCALER_FMT_ARGB8888: | |
120 | ctx->direct_pixconv = conv_rgb565_argb8888; | |
121 | break; | |
122 | case SCALER_FMT_ABGR8888: | |
123 | ctx->direct_pixconv = conv_rgb565_abgr8888; | |
124 | break; | |
125 | case SCALER_FMT_BGR24: | |
126 | ctx->direct_pixconv = conv_rgb565_bgr24; | |
127 | break; | |
128 | case SCALER_FMT_0RGB1555: | |
129 | ctx->direct_pixconv = conv_rgb565_0rgb1555; | |
130 | break; | |
131 | default: | |
132 | break; | |
133 | } | |
134 | break; | |
135 | case SCALER_FMT_BGR24: | |
136 | switch (ctx->out_fmt) | |
137 | { | |
138 | case SCALER_FMT_ARGB8888: | |
139 | ctx->direct_pixconv = conv_bgr24_argb8888; | |
140 | break; | |
141 | case SCALER_FMT_RGB565: | |
142 | ctx->direct_pixconv = conv_bgr24_rgb565; | |
143 | default: | |
144 | break; | |
145 | } | |
146 | break; | |
147 | case SCALER_FMT_ARGB8888: | |
148 | switch (ctx->out_fmt) | |
149 | { | |
150 | case SCALER_FMT_0RGB1555: | |
151 | ctx->direct_pixconv = conv_argb8888_0rgb1555; | |
152 | break; | |
153 | case SCALER_FMT_BGR24: | |
154 | ctx->direct_pixconv = conv_argb8888_bgr24; | |
155 | break; | |
156 | case SCALER_FMT_ABGR8888: | |
157 | ctx->direct_pixconv = conv_argb8888_abgr8888; | |
158 | break; | |
159 | case SCALER_FMT_RGBA4444: | |
160 | ctx->direct_pixconv = conv_argb8888_rgba4444; | |
161 | break; | |
162 | default: | |
163 | break; | |
164 | } | |
165 | break; | |
166 | case SCALER_FMT_YUYV: | |
167 | switch (ctx->out_fmt) | |
168 | { | |
169 | case SCALER_FMT_ARGB8888: | |
170 | ctx->direct_pixconv = conv_yuyv_argb8888; | |
171 | break; | |
172 | default: | |
173 | break; | |
174 | } | |
175 | break; | |
176 | case SCALER_FMT_RGBA4444: | |
177 | switch (ctx->out_fmt) | |
178 | { | |
179 | case SCALER_FMT_ARGB8888: | |
180 | ctx->direct_pixconv = conv_rgba4444_argb8888; | |
181 | break; | |
182 | case SCALER_FMT_RGB565: | |
183 | ctx->direct_pixconv = conv_rgba4444_rgb565; | |
184 | break; | |
185 | default: | |
186 | break; | |
187 | } | |
188 | break; | |
189 | case SCALER_FMT_ABGR8888: | |
190 | switch (ctx->out_fmt) | |
191 | { | |
192 | case SCALER_FMT_BGR24: | |
193 | ctx->direct_pixconv = conv_abgr8888_bgr24; | |
194 | break; | |
195 | default: | |
196 | break; | |
197 | } | |
198 | break; | |
199 | } | |
200 | ||
201 | if (!ctx->direct_pixconv) | |
202 | return false; | |
203 | } | |
204 | } | |
205 | else | |
206 | { | |
207 | ctx->scaler_horiz = scaler_argb8888_horiz; | |
208 | ctx->scaler_vert = scaler_argb8888_vert; | |
209 | ||
210 | switch (ctx->in_fmt) | |
211 | { | |
212 | case SCALER_FMT_ARGB8888: | |
213 | /* No need to convert :D */ | |
214 | break; | |
215 | ||
216 | case SCALER_FMT_0RGB1555: | |
217 | ctx->in_pixconv = conv_0rgb1555_argb8888; | |
218 | break; | |
219 | ||
220 | case SCALER_FMT_RGB565: | |
221 | ctx->in_pixconv = conv_rgb565_argb8888; | |
222 | break; | |
223 | ||
224 | case SCALER_FMT_BGR24: | |
225 | ctx->in_pixconv = conv_bgr24_argb8888; | |
226 | break; | |
227 | ||
228 | case SCALER_FMT_RGBA4444: | |
229 | ctx->in_pixconv = conv_rgba4444_argb8888; | |
230 | break; | |
231 | ||
232 | default: | |
233 | return false; | |
234 | } | |
235 | ||
236 | switch (ctx->out_fmt) | |
237 | { | |
238 | case SCALER_FMT_ARGB8888: | |
239 | /* No need to convert :D */ | |
240 | break; | |
241 | ||
242 | case SCALER_FMT_RGBA4444: | |
243 | ctx->out_pixconv = conv_argb8888_rgba4444; | |
244 | break; | |
245 | ||
246 | case SCALER_FMT_0RGB1555: | |
247 | ctx->out_pixconv = conv_argb8888_0rgb1555; | |
248 | break; | |
249 | ||
250 | case SCALER_FMT_BGR24: | |
251 | ctx->out_pixconv = conv_argb8888_bgr24; | |
252 | break; | |
253 | ||
254 | case SCALER_FMT_ABGR8888: | |
255 | ctx->out_pixconv = conv_argb8888_abgr8888; | |
256 | break; | |
257 | ||
258 | default: | |
259 | return false; | |
260 | } | |
261 | ||
262 | if (!scaler_gen_filter(ctx)) | |
263 | return false; | |
264 | } | |
265 | ||
266 | return true; | |
267 | } | |
268 | ||
269 | void scaler_ctx_gen_reset(struct scaler_ctx *ctx) | |
270 | { | |
271 | if (ctx->horiz.filter) | |
272 | free(ctx->horiz.filter); | |
273 | if (ctx->horiz.filter_pos) | |
274 | free(ctx->horiz.filter_pos); | |
275 | if (ctx->vert.filter) | |
276 | free(ctx->vert.filter); | |
277 | if (ctx->vert.filter_pos) | |
278 | free(ctx->vert.filter_pos); | |
279 | if (ctx->scaled.frame) | |
280 | free(ctx->scaled.frame); | |
281 | if (ctx->input.frame) | |
282 | free(ctx->input.frame); | |
283 | if (ctx->output.frame) | |
284 | free(ctx->output.frame); | |
285 | ||
286 | ctx->horiz.filter = NULL; | |
287 | ctx->horiz.filter_len = 0; | |
288 | ctx->horiz.filter_stride = 0; | |
289 | ctx->horiz.filter_pos = NULL; | |
290 | ||
291 | ctx->vert.filter = NULL; | |
292 | ctx->vert.filter_len = 0; | |
293 | ctx->vert.filter_stride = 0; | |
294 | ctx->vert.filter_pos = NULL; | |
295 | ||
296 | ctx->scaled.frame = NULL; | |
297 | ctx->scaled.width = 0; | |
298 | ctx->scaled.height = 0; | |
299 | ctx->scaled.stride = 0; | |
300 | ||
301 | ctx->input.frame = NULL; | |
302 | ctx->input.stride = 0; | |
303 | ||
304 | ctx->output.frame = NULL; | |
305 | ctx->output.stride = 0; | |
306 | } | |
307 | ||
308 | /** | |
309 | * scaler_ctx_scale: | |
310 | * @ctx : pointer to scaler context object. | |
311 | * @output : pointer to output image. | |
312 | * @input : pointer to input image. | |
313 | * | |
314 | * Scales an input image to an output image. | |
315 | **/ | |
316 | void scaler_ctx_scale(struct scaler_ctx *ctx, | |
317 | void *output, const void *input) | |
318 | { | |
319 | const void *input_frame = input; | |
320 | void *output_frame = output; | |
321 | int input_stride = ctx->in_stride; | |
322 | int output_stride = ctx->out_stride; | |
323 | ||
324 | if (ctx->in_fmt != SCALER_FMT_ARGB8888) | |
325 | { | |
326 | ctx->in_pixconv(ctx->input.frame, input, | |
327 | ctx->in_width, ctx->in_height, | |
328 | ctx->input.stride, ctx->in_stride); | |
329 | ||
330 | input_frame = ctx->input.frame; | |
331 | input_stride = ctx->input.stride; | |
332 | } | |
333 | ||
334 | if (ctx->out_fmt != SCALER_FMT_ARGB8888) | |
335 | { | |
336 | output_frame = ctx->output.frame; | |
337 | output_stride = ctx->output.stride; | |
338 | } | |
339 | ||
340 | /* Take some special, and (hopefully) more optimized path. */ | |
341 | if (ctx->scaler_special) | |
342 | ctx->scaler_special(ctx, output_frame, input_frame, | |
343 | ctx->out_width, ctx->out_height, | |
344 | ctx->in_width, ctx->in_height, | |
345 | output_stride, input_stride); | |
346 | else | |
347 | { | |
348 | /* Take generic filter path. */ | |
349 | if (ctx->scaler_horiz) | |
350 | ctx->scaler_horiz(ctx, input_frame, input_stride); | |
351 | if (ctx->scaler_vert) | |
352 | ctx->scaler_vert (ctx, output, output_stride); | |
353 | } | |
354 | ||
355 | if (ctx->out_fmt != SCALER_FMT_ARGB8888) | |
356 | ctx->out_pixconv(output, ctx->output.frame, | |
357 | ctx->out_width, ctx->out_height, | |
358 | ctx->out_stride, ctx->output.stride); | |
359 | } |