1 | /* |
2 | Simple DirectMedia Layer |
3 | Copyright (C) 1997-2021 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: */ |
297 | |