src/video/SDL_blit.c
author Ryan C. Gordon <icculus@icculus.org>
Thu, 09 Apr 2015 22:28:37 -0400
changeset 9541 cf8fab52e33b
parent 8149 681eb46b8ac4
child 9619 b94b6d0bff0f
permissions -rw-r--r--
Merged Alex Szpakowski's iOS-improvement branch to default.

Fixes Bugzilla #2798.
Fixes Bugzilla #2212.
Fixes Bugzilla #2826.
Fixes Bugzilla #2661.
Fixes Bugzilla #1885.
Fixes Bugzilla #1578.
Fixes Bugzilla #2751.

(whew!)

Notable changes, from Alex's notes:

- The SDL_WINDOW_ALLOW_HIGHDPI flag is now needed (along with SDL_GL_GetDrawableSize or SDL_GetRendererOutputSize) to use Retina / high DPI resolutions, bringing SDL’s Retina-related behavior on iOS in line with Mac OS X. Window dimensions and display modes are now in the “points” (non-high DPI) coordinate system rather than pixels, whereas SDL_GL_GetDrawableSize is in pixels.

- Reworked the custom extended launch screen code:
- It now hides after the first SDL_PumpEvents call rather than SDL_CreateWindow, and it fades out in a similar manner to the system launch screen behavior.
- It now mirrors the system launch screen behavior when deciding which image to display: it falls back to using the Launch Images dictionary in Info.plist if the iOS 8+ launch screen nib isn’t available, and if the Launch Images dictionary doesn’t exist it uses the old standard launch image names.
- The extended launch screen can now be disabled via the SDL_IPHONE_LAUNCHSCREEN define in SDL_config_iphoneos.h.

- Added support for SDL_HINT_ACCELEROMETER_AS_JOYSTICK.

- Added access to a window view's renderbuffer and framebuffer to syswm.

- Added OpenGL ES debug labels for the Renderbuffer and Framebuffer Objects created with SDL_GL_CreateContext.

- Added support for sRGB OpenGL ES contexts on iOS 7+.

- Updated OpenGL ES contexts to support native-resolution rendering (when SDL_WINDOW_ALLOW_HIGHDPI is enabled) on the iPhone 6 Plus, i.e. 1080x1920 rather than 1242x2208.

- Updated SDL_GL_CreateContext, SDL_GL_SwapWindow, SDL_GL_MakeCurrent, and SDL_GL_DeleteContext to be more robust.

- Updated SDL windows to display a UIView at all times, even when an OpenGL context is not active. This allows rotation, touch events, and other windowing-related events to work properly without an active OpenGL context. It also makes it easier to use SDL_GetWindowWMInfo after creating a SDL window.

- Updated the iOS-specific Objective-C code to use cleaner and more modern language features and APIs, including ARC instead of manual reference counting.

- Updated SDL_HINT_ORIENTATIONS to allow disabling custom orientations if the hint is set with no valid orientation names.

- Fixed several rotation and orientation bugs with windows and display modes, especially in iOS 8+.

- Fixed SDL_SetWindowFullscreen failing to update the status bar visibility on iOS 7+.

- Fixed the orientation of the offset applied to the window’s view when the onscreen keyboard is shown in iOS 8+.

- Fixed SDL_IsScreenKeyboardShown (patch by Phil Hassey.)

- Fixed several major memory leaks caused by missing autorelease pool blocks in the iOS-specific Objective-C code.

- Removed several dead code paths.

- The iOS 7 SDK (Xcode 5) or newer is now required to build SDL for iOS.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2014 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
    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 #ifdef __MACOSX__
   103 #include <sys/sysctl.h>
   104 
   105 static SDL_bool
   106 SDL_UseAltivecPrefetch()
   107 {
   108     const char key[] = "hw.l3cachesize";
   109     u_int64_t result = 0;
   110     size_t typeSize = sizeof(result);
   111 
   112     if (sysctlbyname(key, &result, &typeSize, NULL, 0) == 0 && result > 0) {
   113         return SDL_TRUE;
   114     } else {
   115         return SDL_FALSE;
   116     }
   117 }
   118 #else
   119 static SDL_bool
   120 SDL_UseAltivecPrefetch()
   121 {
   122     /* Just guess G4 */
   123     return SDL_TRUE;
   124 }
   125 #endif /* __MACOSX__ */
   126 
   127 static SDL_BlitFunc
   128 SDL_ChooseBlitFunc(Uint32 src_format, Uint32 dst_format, int flags,
   129                    SDL_BlitFuncEntry * entries)
   130 {
   131     int i, flagcheck;
   132     static Uint32 features = 0xffffffff;
   133 
   134     /* Get the available CPU features */
   135     if (features == 0xffffffff) {
   136         const char *override = SDL_getenv("SDL_BLIT_CPU_FEATURES");
   137 
   138         features = SDL_CPU_ANY;
   139 
   140         /* Allow an override for testing .. */
   141         if (override) {
   142             SDL_sscanf(override, "%u", &features);
   143         } else {
   144             if (SDL_HasMMX()) {
   145                 features |= SDL_CPU_MMX;
   146             }
   147             if (SDL_Has3DNow()) {
   148                 features |= SDL_CPU_3DNOW;
   149             }
   150             if (SDL_HasSSE()) {
   151                 features |= SDL_CPU_SSE;
   152             }
   153             if (SDL_HasSSE2()) {
   154                 features |= SDL_CPU_SSE2;
   155             }
   156             if (SDL_HasAltiVec()) {
   157                 if (SDL_UseAltivecPrefetch()) {
   158                     features |= SDL_CPU_ALTIVEC_PREFETCH;
   159                 } else {
   160                     features |= SDL_CPU_ALTIVEC_NOPREFETCH;
   161                 }
   162             }
   163         }
   164     }
   165 
   166     for (i = 0; entries[i].func; ++i) {
   167         /* Check for matching pixel formats */
   168         if (src_format != entries[i].src_format) {
   169             continue;
   170         }
   171         if (dst_format != entries[i].dst_format) {
   172             continue;
   173         }
   174 
   175         /* Check modulation flags */
   176         flagcheck =
   177             (flags & (SDL_COPY_MODULATE_COLOR | SDL_COPY_MODULATE_ALPHA));
   178         if ((flagcheck & entries[i].flags) != flagcheck) {
   179             continue;
   180         }
   181 
   182         /* Check blend flags */
   183         flagcheck =
   184             (flags &
   185              (SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD));
   186         if ((flagcheck & entries[i].flags) != flagcheck) {
   187             continue;
   188         }
   189 
   190         /* Check colorkey flag */
   191         flagcheck = (flags & SDL_COPY_COLORKEY);
   192         if ((flagcheck & entries[i].flags) != flagcheck) {
   193             continue;
   194         }
   195 
   196         /* Check scaling flags */
   197         flagcheck = (flags & SDL_COPY_NEAREST);
   198         if ((flagcheck & entries[i].flags) != flagcheck) {
   199             continue;
   200         }
   201 
   202         /* Check CPU features */
   203         flagcheck = entries[i].cpu;
   204         if ((flagcheck & features) != flagcheck) {
   205             continue;
   206         }
   207 
   208         /* We found the best one! */
   209         return entries[i].func;
   210     }
   211     return NULL;
   212 }
   213 
   214 /* Figure out which of many blit routines to set up on a surface */
   215 int
   216 SDL_CalculateBlit(SDL_Surface * surface)
   217 {
   218     SDL_BlitFunc blit = NULL;
   219     SDL_BlitMap *map = surface->map;
   220     SDL_Surface *dst = map->dst;
   221 
   222     /* Clean everything out to start */
   223     if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
   224         SDL_UnRLESurface(surface, 1);
   225     }
   226     map->blit = SDL_SoftBlit;
   227     map->info.src_fmt = surface->format;
   228     map->info.src_pitch = surface->pitch;
   229     map->info.dst_fmt = dst->format;
   230     map->info.dst_pitch = dst->pitch;
   231 
   232     /* See if we can do RLE acceleration */
   233     if (map->info.flags & SDL_COPY_RLE_DESIRED) {
   234         if (SDL_RLESurface(surface) == 0) {
   235             return 0;
   236         }
   237     }
   238 
   239     /* Choose a standard blit function */
   240     if (map->identity && !(map->info.flags & ~SDL_COPY_RLE_DESIRED)) {
   241         blit = SDL_BlitCopy;
   242     } else if (surface->format->BitsPerPixel < 8 &&
   243                SDL_ISPIXELFORMAT_INDEXED(surface->format->format)) {
   244         blit = SDL_CalculateBlit0(surface);
   245     } else if (surface->format->BytesPerPixel == 1 &&
   246                SDL_ISPIXELFORMAT_INDEXED(surface->format->format)) {
   247         blit = SDL_CalculateBlit1(surface);
   248     } else if (map->info.flags & SDL_COPY_BLEND) {
   249         blit = SDL_CalculateBlitA(surface);
   250     } else {
   251         blit = SDL_CalculateBlitN(surface);
   252     }
   253     if (blit == NULL) {
   254         Uint32 src_format = surface->format->format;
   255         Uint32 dst_format = dst->format->format;
   256 
   257         blit =
   258             SDL_ChooseBlitFunc(src_format, dst_format, map->info.flags,
   259                                SDL_GeneratedBlitFuncTable);
   260     }
   261 #ifndef TEST_SLOW_BLIT
   262     if (blit == NULL)
   263 #endif
   264     {
   265         Uint32 src_format = surface->format->format;
   266         Uint32 dst_format = dst->format->format;
   267 
   268         if (!SDL_ISPIXELFORMAT_INDEXED(src_format) &&
   269             !SDL_ISPIXELFORMAT_FOURCC(src_format) &&
   270             !SDL_ISPIXELFORMAT_INDEXED(dst_format) &&
   271             !SDL_ISPIXELFORMAT_FOURCC(dst_format)) {
   272             blit = SDL_Blit_Slow;
   273         }
   274     }
   275     map->data = blit;
   276 
   277     /* Make sure we have a blit function */
   278     if (blit == NULL) {
   279         SDL_InvalidateMap(map);
   280         return SDL_SetError("Blit combination not supported");
   281     }
   282 
   283     return 0;
   284 }
   285 
   286 /* vi: set ts=4 sw=4 expandtab: */