1 /* Copyright (C) 2010-2020 The RetroArch team
3 * ---------------------------------------------------------------------------------------
4 * The following license statement only applies to this file (scaler.c).
5 * ---------------------------------------------------------------------------------------
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:
13 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
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.
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>
33 static bool allocate_frames(struct scaler_ctx *ctx)
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);
45 ctx->scaled.frame = scaled_frame;
47 if (ctx->in_fmt != SCALER_FMT_ARGB8888)
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);
57 ctx->input.frame = input_frame;
60 if (ctx->out_fmt != SCALER_FMT_ARGB8888)
62 uint32_t *output_frame = NULL;
63 ctx->output.stride = ((ctx->out_width + 7) & ~7) * sizeof(uint32_t);
65 output_frame = (uint32_t*)calloc(sizeof(uint32_t),
66 (ctx->output.stride * ctx->out_height) >> 2);
71 ctx->output.frame = output_frame;
77 bool scaler_ctx_gen_filter(struct scaler_ctx *ctx)
79 scaler_ctx_gen_reset(ctx);
81 ctx->scaler_special = NULL;
82 ctx->unscaled = false;
84 if (!allocate_frames(ctx))
87 if ( ctx->in_width == ctx->out_width
88 && ctx->in_height == ctx->out_height)
90 ctx->unscaled = true; /* Only pixel format conversion ... */
92 if (ctx->in_fmt == ctx->out_fmt)
93 ctx->direct_pixconv = conv_copy;
96 /* Bind a pixel converter callback function to the
97 * 'direct_pixconv' function pointer of the scaler context object. */
100 case SCALER_FMT_0RGB1555:
101 switch (ctx->out_fmt)
103 case SCALER_FMT_ARGB8888:
104 ctx->direct_pixconv = conv_0rgb1555_argb8888;
106 case SCALER_FMT_RGB565:
107 ctx->direct_pixconv = conv_0rgb1555_rgb565;
109 case SCALER_FMT_BGR24:
110 ctx->direct_pixconv = conv_0rgb1555_bgr24;
116 case SCALER_FMT_RGB565:
117 switch (ctx->out_fmt)
119 case SCALER_FMT_ARGB8888:
120 ctx->direct_pixconv = conv_rgb565_argb8888;
122 case SCALER_FMT_ABGR8888:
123 ctx->direct_pixconv = conv_rgb565_abgr8888;
125 case SCALER_FMT_BGR24:
126 ctx->direct_pixconv = conv_rgb565_bgr24;
128 case SCALER_FMT_0RGB1555:
129 ctx->direct_pixconv = conv_rgb565_0rgb1555;
135 case SCALER_FMT_BGR24:
136 switch (ctx->out_fmt)
138 case SCALER_FMT_ARGB8888:
139 ctx->direct_pixconv = conv_bgr24_argb8888;
141 case SCALER_FMT_RGB565:
142 ctx->direct_pixconv = conv_bgr24_rgb565;
147 case SCALER_FMT_ARGB8888:
148 switch (ctx->out_fmt)
150 case SCALER_FMT_0RGB1555:
151 ctx->direct_pixconv = conv_argb8888_0rgb1555;
153 case SCALER_FMT_BGR24:
154 ctx->direct_pixconv = conv_argb8888_bgr24;
156 case SCALER_FMT_ABGR8888:
157 ctx->direct_pixconv = conv_argb8888_abgr8888;
159 case SCALER_FMT_RGBA4444:
160 ctx->direct_pixconv = conv_argb8888_rgba4444;
166 case SCALER_FMT_YUYV:
167 switch (ctx->out_fmt)
169 case SCALER_FMT_ARGB8888:
170 ctx->direct_pixconv = conv_yuyv_argb8888;
176 case SCALER_FMT_RGBA4444:
177 switch (ctx->out_fmt)
179 case SCALER_FMT_ARGB8888:
180 ctx->direct_pixconv = conv_rgba4444_argb8888;
182 case SCALER_FMT_RGB565:
183 ctx->direct_pixconv = conv_rgba4444_rgb565;
189 case SCALER_FMT_ABGR8888:
190 switch (ctx->out_fmt)
192 case SCALER_FMT_BGR24:
193 ctx->direct_pixconv = conv_abgr8888_bgr24;
201 if (!ctx->direct_pixconv)
207 ctx->scaler_horiz = scaler_argb8888_horiz;
208 ctx->scaler_vert = scaler_argb8888_vert;
212 case SCALER_FMT_ARGB8888:
213 /* No need to convert :D */
216 case SCALER_FMT_0RGB1555:
217 ctx->in_pixconv = conv_0rgb1555_argb8888;
220 case SCALER_FMT_RGB565:
221 ctx->in_pixconv = conv_rgb565_argb8888;
224 case SCALER_FMT_BGR24:
225 ctx->in_pixconv = conv_bgr24_argb8888;
228 case SCALER_FMT_RGBA4444:
229 ctx->in_pixconv = conv_rgba4444_argb8888;
236 switch (ctx->out_fmt)
238 case SCALER_FMT_ARGB8888:
239 /* No need to convert :D */
242 case SCALER_FMT_RGBA4444:
243 ctx->out_pixconv = conv_argb8888_rgba4444;
246 case SCALER_FMT_0RGB1555:
247 ctx->out_pixconv = conv_argb8888_0rgb1555;
250 case SCALER_FMT_BGR24:
251 ctx->out_pixconv = conv_argb8888_bgr24;
254 case SCALER_FMT_ABGR8888:
255 ctx->out_pixconv = conv_argb8888_abgr8888;
262 if (!scaler_gen_filter(ctx))
269 void scaler_ctx_gen_reset(struct scaler_ctx *ctx)
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);
286 ctx->horiz.filter = NULL;
287 ctx->horiz.filter_len = 0;
288 ctx->horiz.filter_stride = 0;
289 ctx->horiz.filter_pos = NULL;
291 ctx->vert.filter = NULL;
292 ctx->vert.filter_len = 0;
293 ctx->vert.filter_stride = 0;
294 ctx->vert.filter_pos = NULL;
296 ctx->scaled.frame = NULL;
297 ctx->scaled.width = 0;
298 ctx->scaled.height = 0;
299 ctx->scaled.stride = 0;
301 ctx->input.frame = NULL;
302 ctx->input.stride = 0;
304 ctx->output.frame = NULL;
305 ctx->output.stride = 0;
310 * @ctx : pointer to scaler context object.
311 * @output : pointer to output image.
312 * @input : pointer to input image.
314 * Scales an input image to an output image.
316 void scaler_ctx_scale(struct scaler_ctx *ctx,
317 void *output, const void *input)
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;
324 if (ctx->in_fmt != SCALER_FMT_ARGB8888)
326 ctx->in_pixconv(ctx->input.frame, input,
327 ctx->in_width, ctx->in_height,
328 ctx->input.stride, ctx->in_stride);
330 input_frame = ctx->input.frame;
331 input_stride = ctx->input.stride;
334 if (ctx->out_fmt != SCALER_FMT_ARGB8888)
336 output_frame = ctx->output.frame;
337 output_stride = ctx->output.stride;
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);
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);
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);