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 */
33static int SDLCALL
34SDL_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
107static SDL_bool
108SDL_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
121static SDL_bool
122SDL_UseAltivecPrefetch()
123{
124 /* Just guess G4 */
125 return SDL_TRUE;
126}
127#endif /* __MACOSX__ */
128
129static SDL_BlitFunc
130SDL_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 */
195int
196SDL_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