Imported Upstream version 2.0.14
[platform/upstream/SDL.git] / src / video / SDL_blit.c
1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
4
5   This software is provided 'as-is', without any express or implied
6   warranty.  In no event will the authors be held liable for any damages
7   arising from the use of this software.
8
9   Permission is granted to anyone to use this software for any purpose,
10   including commercial applications, and to alter it and redistribute it
11   freely, subject to the following restrictions:
12
13   1. The origin of this software must not be misrepresented; you must not
14      claim that you wrote the original software. If you use this software
15      in a product, an acknowledgment in the product documentation would be
16      appreciated but is not required.
17   2. Altered source versions must be plainly marked as such, and must not be
18      misrepresented as being the original software.
19   3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "../SDL_internal.h"
22
23 #include "SDL_video.h"
24 #include "SDL_sysvideo.h"
25 #include "SDL_blit.h"
26 #include "SDL_blit_auto.h"
27 #include "SDL_blit_copy.h"
28 #include "SDL_blit_slow.h"
29 #include "SDL_RLEaccel_c.h"
30 #include "SDL_pixels_c.h"
31
32 /* The general purpose software blit routine */
33 static int SDLCALL
34 SDL_SoftBlit(SDL_Surface * src, SDL_Rect * srcrect,
35              SDL_Surface * dst, SDL_Rect * dstrect)
36 {
37     int okay;
38     int src_locked;
39     int dst_locked;
40
41     /* Everything is okay at the beginning...  */
42     okay = 1;
43
44     /* Lock the destination if it's in hardware */
45     dst_locked = 0;
46     if (SDL_MUSTLOCK(dst)) {
47         if (SDL_LockSurface(dst) < 0) {
48             okay = 0;
49         } else {
50             dst_locked = 1;
51         }
52     }
53     /* Lock the source if it's in hardware */
54     src_locked = 0;
55     if (SDL_MUSTLOCK(src)) {
56         if (SDL_LockSurface(src) < 0) {
57             okay = 0;
58         } else {
59             src_locked = 1;
60         }
61     }
62
63     /* Set up source and destination buffer pointers, and BLIT! */
64     if (okay && !SDL_RectEmpty(srcrect)) {
65         SDL_BlitFunc RunBlit;
66         SDL_BlitInfo *info = &src->map->info;
67
68         /* Set up the blit information */
69         info->src = (Uint8 *) src->pixels +
70             (Uint16) srcrect->y * src->pitch +
71             (Uint16) srcrect->x * info->src_fmt->BytesPerPixel;
72         info->src_w = srcrect->w;
73         info->src_h = srcrect->h;
74         info->src_pitch = src->pitch;
75         info->src_skip =
76             info->src_pitch - info->src_w * info->src_fmt->BytesPerPixel;
77         info->dst =
78             (Uint8 *) dst->pixels + (Uint16) dstrect->y * dst->pitch +
79             (Uint16) dstrect->x * info->dst_fmt->BytesPerPixel;
80         info->dst_w = dstrect->w;
81         info->dst_h = dstrect->h;
82         info->dst_pitch = dst->pitch;
83         info->dst_skip =
84             info->dst_pitch - info->dst_w * info->dst_fmt->BytesPerPixel;
85         RunBlit = (SDL_BlitFunc) src->map->data;
86
87         /* Run the actual software blit */
88         RunBlit(info);
89     }
90
91     /* We need to unlock the surfaces if they're locked */
92     if (dst_locked) {
93         SDL_UnlockSurface(dst);
94     }
95     if (src_locked) {
96         SDL_UnlockSurface(src);
97     }
98     /* Blit is done! */
99     return (okay ? 0 : -1);
100 }
101
102 #if SDL_HAVE_BLIT_AUTO
103
104 #ifdef __MACOSX__
105 #include <sys/sysctl.h>
106
107 static SDL_bool
108 SDL_UseAltivecPrefetch()
109 {
110     const char key[] = "hw.l3cachesize";
111     u_int64_t result = 0;
112     size_t typeSize = sizeof(result);
113
114     if (sysctlbyname(key, &result, &typeSize, NULL, 0) == 0 && result > 0) {
115         return SDL_TRUE;
116     } else {
117         return SDL_FALSE;
118     }
119 }
120 #else
121 static SDL_bool
122 SDL_UseAltivecPrefetch()
123 {
124     /* Just guess G4 */
125     return SDL_TRUE;
126 }
127 #endif /* __MACOSX__ */
128
129 static SDL_BlitFunc
130 SDL_ChooseBlitFunc(Uint32 src_format, Uint32 dst_format, int flags,
131                    SDL_BlitFuncEntry * entries)
132 {
133     int i, flagcheck = (flags & (SDL_COPY_MODULATE_COLOR | SDL_COPY_MODULATE_ALPHA | SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD | SDL_COPY_MUL | SDL_COPY_COLORKEY | SDL_COPY_NEAREST));
134     static int features = 0x7fffffff;
135
136     /* Get the available CPU features */
137     if (features == 0x7fffffff) {
138         const char *override = SDL_getenv("SDL_BLIT_CPU_FEATURES");
139
140         features = SDL_CPU_ANY;
141
142         /* Allow an override for testing .. */
143         if (override) {
144             SDL_sscanf(override, "%u", &features);
145         } else {
146             if (SDL_HasMMX()) {
147                 features |= SDL_CPU_MMX;
148             }
149             if (SDL_Has3DNow()) {
150                 features |= SDL_CPU_3DNOW;
151             }
152             if (SDL_HasSSE()) {
153                 features |= SDL_CPU_SSE;
154             }
155             if (SDL_HasSSE2()) {
156                 features |= SDL_CPU_SSE2;
157             }
158             if (SDL_HasAltiVec()) {
159                 if (SDL_UseAltivecPrefetch()) {
160                     features |= SDL_CPU_ALTIVEC_PREFETCH;
161                 } else {
162                     features |= SDL_CPU_ALTIVEC_NOPREFETCH;
163                 }
164             }
165         }
166     }
167
168     for (i = 0; entries[i].func; ++i) {
169         /* Check for matching pixel formats */
170         if (src_format != entries[i].src_format) {
171             continue;
172         }
173         if (dst_format != entries[i].dst_format) {
174             continue;
175         }
176
177         /* Check flags */
178         if ((flagcheck & entries[i].flags) != flagcheck) {
179             continue;
180         }
181
182         /* Check CPU features */
183         if ((entries[i].cpu & features) != entries[i].cpu) {
184             continue;
185         }
186
187         /* We found the best one! */
188         return entries[i].func;
189     }
190     return NULL;
191 }
192 #endif /* SDL_HAVE_BLIT_AUTO */
193
194 /* Figure out which of many blit routines to set up on a surface */
195 int
196 SDL_CalculateBlit(SDL_Surface * surface)
197 {
198     SDL_BlitFunc blit = NULL;
199     SDL_BlitMap *map = surface->map;
200     SDL_Surface *dst = map->dst;
201
202     /* We don't currently support blitting to < 8 bpp surfaces */
203     if (dst->format->BitsPerPixel < 8) {
204         SDL_InvalidateMap(map);
205         return SDL_SetError("Blit combination not supported");
206     }
207
208 #if SDL_HAVE_RLE
209     /* Clean everything out to start */
210     if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
211         SDL_UnRLESurface(surface, 1);
212     }
213 #endif
214
215     map->blit = SDL_SoftBlit;
216     map->info.src_fmt = surface->format;
217     map->info.src_pitch = surface->pitch;
218     map->info.dst_fmt = dst->format;
219     map->info.dst_pitch = dst->pitch;
220
221 #if SDL_HAVE_RLE
222     /* See if we can do RLE acceleration */
223     if (map->info.flags & SDL_COPY_RLE_DESIRED) {
224         if (SDL_RLESurface(surface) == 0) {
225             return 0;
226         }
227     }
228 #endif
229
230     /* Choose a standard blit function */
231     if (map->identity && !(map->info.flags & ~SDL_COPY_RLE_DESIRED)) {
232         blit = SDL_BlitCopy;
233     } else if (surface->format->Rloss > 8 || dst->format->Rloss > 8) {
234         /* Greater than 8 bits per channel not supported yet */
235         SDL_InvalidateMap(map);
236         return SDL_SetError("Blit combination not supported");
237     }
238 #if SDL_HAVE_BLIT_0
239     else if (surface->format->BitsPerPixel < 8 &&
240                SDL_ISPIXELFORMAT_INDEXED(surface->format->format)) {
241         blit = SDL_CalculateBlit0(surface);
242     }
243 #endif
244 #if SDL_HAVE_BLIT_1
245     else if (surface->format->BytesPerPixel == 1 &&
246                SDL_ISPIXELFORMAT_INDEXED(surface->format->format)) {
247         blit = SDL_CalculateBlit1(surface);
248     }
249 #endif
250 #if SDL_HAVE_BLIT_A
251     else if (map->info.flags & SDL_COPY_BLEND) {
252         blit = SDL_CalculateBlitA(surface);
253     }
254 #endif
255 #if SDL_HAVE_BLIT_N
256     else {
257         blit = SDL_CalculateBlitN(surface);
258     }
259 #endif
260 #if SDL_HAVE_BLIT_AUTO
261     if (blit == NULL) {
262         Uint32 src_format = surface->format->format;
263         Uint32 dst_format = dst->format->format;
264
265         blit =
266             SDL_ChooseBlitFunc(src_format, dst_format, map->info.flags,
267                                SDL_GeneratedBlitFuncTable);
268     }
269 #endif
270
271 #ifndef TEST_SLOW_BLIT
272     if (blit == NULL)
273 #endif
274     {
275         Uint32 src_format = surface->format->format;
276         Uint32 dst_format = dst->format->format;
277
278         if (!SDL_ISPIXELFORMAT_INDEXED(src_format) &&
279             !SDL_ISPIXELFORMAT_FOURCC(src_format) &&
280             !SDL_ISPIXELFORMAT_INDEXED(dst_format) &&
281             !SDL_ISPIXELFORMAT_FOURCC(dst_format)) {
282             blit = SDL_Blit_Slow;
283         }
284     }
285     map->data = blit;
286
287     /* Make sure we have a blit function */
288     if (blit == NULL) {
289         SDL_InvalidateMap(map);
290         return SDL_SetError("Blit combination not supported");
291     }
292
293     return 0;
294 }
295
296 /* vi: set ts=4 sw=4 expandtab: */