gpu_neon: fix some missing ebuf updates
[pcsx_rearmed.git] / deps / libretro-common / formats / image_texture.c
CommitLineData
3719602c
PC
1/* Copyright (C) 2010-2020 The RetroArch team
2 *
3 * ---------------------------------------------------------------------------------------
4 * The following license statement only applies to this file (image_texture.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 <stdint.h>
24#include <stdlib.h>
25#include <string.h>
26#include <stddef.h>
27
28#include <boolean.h>
29#include <formats/image.h>
30#include <file/nbio.h>
31#include <string/stdstring.h>
32
33enum image_type_enum image_texture_get_type(const char *path)
34{
35 /* We are comparing against a fixed list of file
36 * extensions, the longest (jpeg) being 4 characters
37 * in length. We therefore only need to extract the first
38 * 5 characters from the extension of the input path
39 * to correctly validate a match */
40 const char *ext = NULL;
41 char ext_lower[6];
42
43 ext_lower[0] = '\0';
44
45 if (string_is_empty(path))
46 return IMAGE_TYPE_NONE;
47
48 /* Get file extension */
49 ext = strrchr(path, '.');
50
51 if (!ext || (*(++ext) == '\0'))
52 return IMAGE_TYPE_NONE;
53
54 /* Copy and convert to lower case */
55 strlcpy(ext_lower, ext, sizeof(ext_lower));
56 string_to_lower(ext_lower);
57
58#ifdef HAVE_RPNG
59 if (string_is_equal(ext_lower, "png"))
60 return IMAGE_TYPE_PNG;
61#endif
62#ifdef HAVE_RJPEG
63 if (string_is_equal(ext_lower, "jpg") ||
64 string_is_equal(ext_lower, "jpeg"))
65 return IMAGE_TYPE_JPEG;
66#endif
67#ifdef HAVE_RBMP
68 if (string_is_equal(ext_lower, "bmp"))
69 return IMAGE_TYPE_BMP;
70#endif
71#ifdef HAVE_RTGA
72 if (string_is_equal(ext_lower, "tga"))
73 return IMAGE_TYPE_TGA;
74#endif
75
76 return IMAGE_TYPE_NONE;
77}
78
79bool image_texture_set_color_shifts(
80 unsigned *r_shift, unsigned *g_shift, unsigned *b_shift,
81 unsigned *a_shift,
82 struct texture_image *out_img
83 )
84{
85 *a_shift = 24;
86 *r_shift = 16;
87 *g_shift = 8;
88 *b_shift = 0;
89
90 if (out_img->supports_rgba)
91 {
92 *r_shift = 0;
93 *b_shift = 16;
94 return true;
95 }
96
97 return false;
98}
99
100bool image_texture_color_convert(unsigned r_shift,
101 unsigned g_shift, unsigned b_shift, unsigned a_shift,
102 struct texture_image *out_img)
103{
104 /* This is quite uncommon. */
105 if (a_shift != 24 || r_shift != 16 || g_shift != 8 || b_shift != 0)
106 {
107 uint32_t i;
108 uint32_t num_pixels = out_img->width * out_img->height;
109 uint32_t *pixels = (uint32_t*)out_img->pixels;
110
111 for (i = 0; i < num_pixels; i++)
112 {
113 uint32_t col = pixels[i];
114 uint8_t a = (uint8_t)(col >> 24);
115 uint8_t r = (uint8_t)(col >> 16);
116 uint8_t g = (uint8_t)(col >> 8);
117 uint8_t b = (uint8_t)(col >> 0);
118 /* Explicitly cast these to uint32_t to prevent
119 * ASAN runtime error: left shift of 255 by 24 places
120 * cannot be represented in type 'int' */
121 pixels[i] = ((uint32_t)a << a_shift) |
122 ((uint32_t)r << r_shift) |
123 ((uint32_t)g << g_shift) |
124 ((uint32_t)b << b_shift);
125 }
126
127 return true;
128 }
129
130 return false;
131}
132
133#ifdef GEKKO
134
135#define GX_BLIT_LINE_32(off) \
136{ \
137 unsigned x; \
138 const uint16_t *tmp_src = src; \
139 uint16_t *tmp_dst = dst; \
140 for (x = 0; x < width2 >> 3; x++, tmp_src += 8, tmp_dst += 32) \
141 { \
142 tmp_dst[ 0 + off] = tmp_src[0]; \
143 tmp_dst[ 16 + off] = tmp_src[1]; \
144 tmp_dst[ 1 + off] = tmp_src[2]; \
145 tmp_dst[ 17 + off] = tmp_src[3]; \
146 tmp_dst[ 2 + off] = tmp_src[4]; \
147 tmp_dst[ 18 + off] = tmp_src[5]; \
148 tmp_dst[ 3 + off] = tmp_src[6]; \
149 tmp_dst[ 19 + off] = tmp_src[7]; \
150 } \
151 src += tmp_pitch; \
152}
153
154static bool image_texture_internal_gx_convert_texture32(
155 struct texture_image *image)
156{
157 unsigned tmp_pitch, width2, i;
158 const uint16_t *src = NULL;
159 uint16_t *dst = NULL;
160 /* Memory allocation in libogc is extremely primitive so try
161 * to avoid gaps in memory when converting by copying over to
162 * a temporary buffer first, then converting over into
163 * main buffer again. */
164 void *tmp = malloc(image->width
165 * image->height * sizeof(uint32_t));
166
167 if (!tmp)
168 return false;
169
170 memcpy(tmp, image->pixels, image->width
171 * image->height * sizeof(uint32_t));
172 tmp_pitch = (image->width * sizeof(uint32_t)) >> 1;
173
174 image->width &= ~3;
175 image->height &= ~3;
176 width2 = image->width << 1;
177 src = (uint16_t*)tmp;
178 dst = (uint16_t*)image->pixels;
179
180 for (i = 0; i < image->height; i += 4, dst += 4 * width2)
181 {
182 GX_BLIT_LINE_32(0)
183 GX_BLIT_LINE_32(4)
184 GX_BLIT_LINE_32(8)
185 GX_BLIT_LINE_32(12)
186 }
187
188 free(tmp);
189 return true;
190}
191#endif
192
193static bool image_texture_load_internal(
194 enum image_type_enum type,
195 void *ptr,
196 size_t len,
197 struct texture_image *out_img,
198 unsigned a_shift, unsigned r_shift,
199 unsigned g_shift, unsigned b_shift)
200{
201 int ret;
202 bool success = false;
203 void *img = image_transfer_new(type);
204
205 if (!img)
206 goto end;
207
208 image_transfer_set_buffer_ptr(img, type, (uint8_t*)ptr, len);
209
210 if (!image_transfer_start(img, type))
211 goto end;
212
213 while (image_transfer_iterate(img, type));
214
215 if (!image_transfer_is_valid(img, type))
216 goto end;
217
218 do
219 {
220 ret = image_transfer_process(img, type,
221 (uint32_t**)&out_img->pixels, len, &out_img->width,
222 &out_img->height);
223 } while (ret == IMAGE_PROCESS_NEXT);
224
225 if (ret == IMAGE_PROCESS_ERROR || ret == IMAGE_PROCESS_ERROR_END)
226 goto end;
227
228 image_texture_color_convert(r_shift, g_shift, b_shift,
229 a_shift, out_img);
230
231#ifdef GEKKO
232 if (!image_texture_internal_gx_convert_texture32(out_img))
233 {
234 image_texture_free(out_img);
235 goto end;
236 }
237#endif
238
239 success = true;
240
241end:
242 if (img)
243 image_transfer_free(img, type);
244
245 return success;
246}
247
248void image_texture_free(struct texture_image *img)
249{
250 if (!img)
251 return;
252
253 if (img->pixels)
254 free(img->pixels);
255 img->width = 0;
256 img->height = 0;
257 img->pixels = NULL;
258}
259
260bool image_texture_load_buffer(struct texture_image *out_img,
261 enum image_type_enum type, void *buffer, size_t buffer_len)
262{
263 unsigned r_shift, g_shift, b_shift, a_shift;
264 image_texture_set_color_shifts(&r_shift, &g_shift, &b_shift,
265 &a_shift, out_img);
266
267 if (type != IMAGE_TYPE_NONE)
268 {
269 if (image_texture_load_internal(
270 type, buffer, buffer_len, out_img,
271 a_shift, r_shift, g_shift, b_shift))
272 {
273 return true;
274 }
275 }
276
277 out_img->supports_rgba = false;
278 out_img->pixels = NULL;
279 out_img->width = 0;
280 out_img->height = 0;
281
282 return false;
283}
284
285bool image_texture_load(struct texture_image *out_img,
286 const char *path)
287{
288 unsigned r_shift, g_shift, b_shift, a_shift;
289 size_t file_len = 0;
290 struct nbio_t *handle = NULL;
291 void *ptr = NULL;
292 enum image_type_enum type = image_texture_get_type(path);
293
294 image_texture_set_color_shifts(&r_shift, &g_shift, &b_shift,
295 &a_shift, out_img);
296
297 if (type != IMAGE_TYPE_NONE)
298 {
299 handle = (struct nbio_t*)nbio_open(path, NBIO_READ);
300 if (!handle)
301 goto error;
302 nbio_begin_read(handle);
303
304 while (!nbio_iterate(handle));
305
306 ptr = nbio_get_ptr(handle, &file_len);
307
308 if (!ptr)
309 goto error;
310
311 if (image_texture_load_internal(
312 type,
313 ptr, file_len, out_img,
314 a_shift, r_shift, g_shift, b_shift))
315 goto success;
316 }
317
318error:
319 out_img->supports_rgba = false;
320 out_img->pixels = NULL;
321 out_img->width = 0;
322 out_img->height = 0;
323 if (handle)
324 nbio_free(handle);
325
326 return false;
327
328success:
329 if (handle)
330 nbio_free(handle);
331
332 return true;
333}