Merge SDL-ryan-batching-renderer branch to default.
authorRyan C. Gordon <icculus@icculus.org>
Wed, 31 Oct 2018 15:03:41 -0400
changeset 12381dc9108cd4340
parent 12379 5dc13016cf34
parent 12380 f8db1cd5494e
child 12382 03d0bddca61b
Merge SDL-ryan-batching-renderer branch to default.
include/SDL_hints.h
src/core/android/SDL_android.c
src/dynapi/SDL_dynapi_overrides.h
src/dynapi/SDL_dynapi_procs.h
src/joystick/SDL_gamecontroller.c
src/joystick/SDL_joystick.c
src/render/SDL_render.c
src/render/direct3d11/SDL_render_d3d11.c
src/render/metal/SDL_render_metal.m
src/render/opengl/SDL_render_gl.c
src/render/opengl/SDL_shaders_gl.h
src/render/opengles2/SDL_render_gles2.c
src/render/software/SDL_render_sw.c
src/video/wayland/SDL_waylandvideo.c
src/video/wayland/SDL_waylandwindow.c
src/video/windows/SDL_windowsevents.c
src/video/windows/SDL_windowsmouse.c
src/video/windows/SDL_windowswindow.c
     1.1 --- a/include/SDL_hints.h	Mon Oct 22 10:55:18 2018 -0400
     1.2 +++ b/include/SDL_hints.h	Wed Oct 31 15:03:41 2018 -0400
     1.3 @@ -1044,6 +1044,31 @@
     1.4  #define SDL_HINT_AUDIO_CATEGORY   "SDL_AUDIO_CATEGORY"
     1.5  
     1.6  /**
     1.7 + *  \brief  A variable controlling whether the 2D render API is compatible or efficient.
     1.8 + *
     1.9 + *  This variable can be set to the following values:
    1.10 + *
    1.11 + *    "0"     - Don't use batching to make rendering more efficient.
    1.12 + *    "1"     - Use batching, but might cause problems if app makes its own direct OpenGL calls.
    1.13 + *
    1.14 + *  Up to SDL 2.0.9, the render API would draw immediately when requested. Now
    1.15 + *  it batches up draw requests and sends them all to the GPU only when forced
    1.16 + *  to (during SDL_RenderPresent, when changing render targets, by updating a
    1.17 + *  texture that the batch needs, etc). This is significantly more efficient,
    1.18 + *  but it can cause problems for apps that expect to render on top of the
    1.19 + *  render API's output. As such, SDL will disable batching if a specific
    1.20 + *  render backend is requested (since this might indicate that the app is
    1.21 + *  planning to use the underlying graphics API directly). This hint can
    1.22 + *  be used to explicitly request batching in this instance. It is a contract
    1.23 + *  that you will either never use the underlying graphics API directly, or
    1.24 + *  if you do, you will call SDL_RenderFlush() before you do so any current
    1.25 + *  batch goes to the GPU before your work begins. Not following this contract
    1.26 + *  will result in undefined behavior.
    1.27 + */
    1.28 +#define SDL_HINT_RENDER_BATCHING  "SDL_RENDER_BATCHING"
    1.29 +
    1.30 +
    1.31 +/**
    1.32   *  \brief  An enumeration of hint priorities
    1.33   */
    1.34  typedef enum
     2.1 --- a/include/SDL_rect.h	Mon Oct 22 10:55:18 2018 -0400
     2.2 +++ b/include/SDL_rect.h	Wed Oct 31 15:03:41 2018 -0400
     2.3 @@ -40,7 +40,7 @@
     2.4  #endif
     2.5  
     2.6  /**
     2.7 - *  \brief  The structure that defines a point
     2.8 + *  \brief  The structure that defines a point (integer)
     2.9   *
    2.10   *  \sa SDL_EnclosePoints
    2.11   *  \sa SDL_PointInRect
    2.12 @@ -52,7 +52,20 @@
    2.13  } SDL_Point;
    2.14  
    2.15  /**
    2.16 - *  \brief A rectangle, with the origin at the upper left.
    2.17 + *  \brief  The structure that defines a point (floating point)
    2.18 + *
    2.19 + *  \sa SDL_EnclosePoints
    2.20 + *  \sa SDL_PointInRect
    2.21 + */
    2.22 +typedef struct SDL_FPoint
    2.23 +{
    2.24 +    float x;
    2.25 +    float y;
    2.26 +} SDL_FPoint;
    2.27 +
    2.28 +
    2.29 +/**
    2.30 + *  \brief A rectangle, with the origin at the upper left (integer).
    2.31   *
    2.32   *  \sa SDL_RectEmpty
    2.33   *  \sa SDL_RectEquals
    2.34 @@ -67,6 +80,19 @@
    2.35      int w, h;
    2.36  } SDL_Rect;
    2.37  
    2.38 +
    2.39 +/**
    2.40 + *  \brief A rectangle, with the origin at the upper left (floating point).
    2.41 + */
    2.42 +typedef struct SDL_FRect
    2.43 +{
    2.44 +    float x;
    2.45 +    float y;
    2.46 +    float w;
    2.47 +    float h;
    2.48 +} SDL_FRect;
    2.49 +
    2.50 +
    2.51  /**
    2.52   *  \brief Returns true if point resides inside a rectangle.
    2.53   */
     3.1 --- a/include/SDL_render.h	Mon Oct 22 10:55:18 2018 -0400
     3.2 +++ b/include/SDL_render.h	Wed Oct 31 15:03:41 2018 -0400
     3.3 @@ -835,6 +835,148 @@
     3.4                                             const SDL_Point *center,
     3.5                                             const SDL_RendererFlip flip);
     3.6  
     3.7 +
     3.8 +/**
     3.9 + *  \brief Draw a point on the current rendering target.
    3.10 + *
    3.11 + *  \param renderer The renderer which should draw a point.
    3.12 + *  \param x The x coordinate of the point.
    3.13 + *  \param y The y coordinate of the point.
    3.14 + *
    3.15 + *  \return 0 on success, or -1 on error
    3.16 + */
    3.17 +extern DECLSPEC int SDLCALL SDL_RenderDrawPointF(SDL_Renderer * renderer,
    3.18 +                                                 float x, float y);
    3.19 +
    3.20 +/**
    3.21 + *  \brief Draw multiple points on the current rendering target.
    3.22 + *
    3.23 + *  \param renderer The renderer which should draw multiple points.
    3.24 + *  \param points The points to draw
    3.25 + *  \param count The number of points to draw
    3.26 + *
    3.27 + *  \return 0 on success, or -1 on error
    3.28 + */
    3.29 +extern DECLSPEC int SDLCALL SDL_RenderDrawPointsF(SDL_Renderer * renderer,
    3.30 +                                                  const SDL_FPoint * points,
    3.31 +                                                  int count);
    3.32 +
    3.33 +/**
    3.34 + *  \brief Draw a line on the current rendering target.
    3.35 + *
    3.36 + *  \param renderer The renderer which should draw a line.
    3.37 + *  \param x1 The x coordinate of the start point.
    3.38 + *  \param y1 The y coordinate of the start point.
    3.39 + *  \param x2 The x coordinate of the end point.
    3.40 + *  \param y2 The y coordinate of the end point.
    3.41 + *
    3.42 + *  \return 0 on success, or -1 on error
    3.43 + */
    3.44 +extern DECLSPEC int SDLCALL SDL_RenderDrawLineF(SDL_Renderer * renderer,
    3.45 +                                                float x1, float y1, float x2, float y2);
    3.46 +
    3.47 +/**
    3.48 + *  \brief Draw a series of connected lines on the current rendering target.
    3.49 + *
    3.50 + *  \param renderer The renderer which should draw multiple lines.
    3.51 + *  \param points The points along the lines
    3.52 + *  \param count The number of points, drawing count-1 lines
    3.53 + *
    3.54 + *  \return 0 on success, or -1 on error
    3.55 + */
    3.56 +extern DECLSPEC int SDLCALL SDL_RenderDrawLinesF(SDL_Renderer * renderer,
    3.57 +                                                const SDL_FPoint * points,
    3.58 +                                                int count);
    3.59 +
    3.60 +/**
    3.61 + *  \brief Draw a rectangle on the current rendering target.
    3.62 + *
    3.63 + *  \param renderer The renderer which should draw a rectangle.
    3.64 + *  \param rect A pointer to the destination rectangle, or NULL to outline the entire rendering target.
    3.65 + *
    3.66 + *  \return 0 on success, or -1 on error
    3.67 + */
    3.68 +extern DECLSPEC int SDLCALL SDL_RenderDrawRectF(SDL_Renderer * renderer,
    3.69 +                                               const SDL_FRect * rect);
    3.70 +
    3.71 +/**
    3.72 + *  \brief Draw some number of rectangles on the current rendering target.
    3.73 + *
    3.74 + *  \param renderer The renderer which should draw multiple rectangles.
    3.75 + *  \param rects A pointer to an array of destination rectangles.
    3.76 + *  \param count The number of rectangles.
    3.77 + *
    3.78 + *  \return 0 on success, or -1 on error
    3.79 + */
    3.80 +extern DECLSPEC int SDLCALL SDL_RenderDrawRectsF(SDL_Renderer * renderer,
    3.81 +                                                 const SDL_FRect * rects,
    3.82 +                                                 int count);
    3.83 +
    3.84 +/**
    3.85 + *  \brief Fill a rectangle on the current rendering target with the drawing color.
    3.86 + *
    3.87 + *  \param renderer The renderer which should fill a rectangle.
    3.88 + *  \param rect A pointer to the destination rectangle, or NULL for the entire
    3.89 + *              rendering target.
    3.90 + *
    3.91 + *  \return 0 on success, or -1 on error
    3.92 + */
    3.93 +extern DECLSPEC int SDLCALL SDL_RenderFillRectF(SDL_Renderer * renderer,
    3.94 +                                                const SDL_FRect * rect);
    3.95 +
    3.96 +/**
    3.97 + *  \brief Fill some number of rectangles on the current rendering target with the drawing color.
    3.98 + *
    3.99 + *  \param renderer The renderer which should fill multiple rectangles.
   3.100 + *  \param rects A pointer to an array of destination rectangles.
   3.101 + *  \param count The number of rectangles.
   3.102 + *
   3.103 + *  \return 0 on success, or -1 on error
   3.104 + */
   3.105 +extern DECLSPEC int SDLCALL SDL_RenderFillRectsF(SDL_Renderer * renderer,
   3.106 +                                                 const SDL_FRect * rects,
   3.107 +                                                 int count);
   3.108 +
   3.109 +/**
   3.110 + *  \brief Copy a portion of the texture to the current rendering target.
   3.111 + *
   3.112 + *  \param renderer The renderer which should copy parts of a texture.
   3.113 + *  \param texture The source texture.
   3.114 + *  \param srcrect   A pointer to the source rectangle, or NULL for the entire
   3.115 + *                   texture.
   3.116 + *  \param dstrect   A pointer to the destination rectangle, or NULL for the
   3.117 + *                   entire rendering target.
   3.118 + *
   3.119 + *  \return 0 on success, or -1 on error
   3.120 + */
   3.121 +extern DECLSPEC int SDLCALL SDL_RenderCopyF(SDL_Renderer * renderer,
   3.122 +                                            SDL_Texture * texture,
   3.123 +                                            const SDL_Rect * srcrect,
   3.124 +                                            const SDL_FRect * dstrect);
   3.125 +
   3.126 +/**
   3.127 + *  \brief Copy a portion of the source texture to the current rendering target, rotating it by angle around the given center
   3.128 + *
   3.129 + *  \param renderer The renderer which should copy parts of a texture.
   3.130 + *  \param texture The source texture.
   3.131 + *  \param srcrect   A pointer to the source rectangle, or NULL for the entire
   3.132 + *                   texture.
   3.133 + *  \param dstrect   A pointer to the destination rectangle, or NULL for the
   3.134 + *                   entire rendering target.
   3.135 + *  \param angle    An angle in degrees that indicates the rotation that will be applied to dstrect, rotating it in a clockwise direction
   3.136 + *  \param center   A pointer to a point indicating the point around which dstrect will be rotated (if NULL, rotation will be done around dstrect.w/2, dstrect.h/2).
   3.137 + *  \param flip     An SDL_RendererFlip value stating which flipping actions should be performed on the texture
   3.138 + *
   3.139 + *  \return 0 on success, or -1 on error
   3.140 + */
   3.141 +extern DECLSPEC int SDLCALL SDL_RenderCopyExF(SDL_Renderer * renderer,
   3.142 +                                            SDL_Texture * texture,
   3.143 +                                            const SDL_Rect * srcrect,
   3.144 +                                            const SDL_FRect * dstrect,
   3.145 +                                            const double angle,
   3.146 +                                            const SDL_FPoint *center,
   3.147 +                                            const SDL_RendererFlip flip);
   3.148 +
   3.149  /**
   3.150   *  \brief Read pixels from the current rendering target.
   3.151   *
   3.152 @@ -876,6 +1018,31 @@
   3.153   */
   3.154  extern DECLSPEC void SDLCALL SDL_DestroyRenderer(SDL_Renderer * renderer);
   3.155  
   3.156 +/**
   3.157 + *  \brief Force the rendering context to flush any pending commands to the
   3.158 + *         underlying rendering API.
   3.159 + *
   3.160 + *  You do not need to (and in fact, shouldn't) call this function unless
   3.161 + *  you are planning to call into OpenGL/Direct3D/Metal/whatever directly
   3.162 + *  in addition to using an SDL_Renderer.
   3.163 + *
   3.164 + *  This is for a very-specific case: if you are using SDL's render API,
   3.165 + *  you asked for a specific renderer backend (OpenGL, Direct3D, etc),
   3.166 + *  you set SDL_HINT_RENDER_BATCHING to "1", and you plan to make
   3.167 + *  OpenGL/D3D/whatever calls in addition to SDL render API calls. If all of
   3.168 + *  this applies, you should call SDL_RenderFlush() between calls to SDL's
   3.169 + *  render API and the low-level API you're using in cooperation.
   3.170 + *
   3.171 + *  In all other cases, you can ignore this function. This is only here to
   3.172 + *  get maximum performance out of a specific situation. In all other cases,
   3.173 + *  SDL will do the right thing, perhaps at a performance loss.
   3.174 + *
   3.175 + *  This function is first available in SDL 2.0.10, and is not needed in
   3.176 + *  2.0.9 and earlier, as earlier versions did not queue rendering commands
   3.177 + *  at all, instead flushing them to the OS immediately.
   3.178 + */
   3.179 +extern DECLSPEC int SDLCALL SDL_RenderFlush(SDL_Renderer * renderer);
   3.180 +
   3.181  
   3.182  /**
   3.183   *  \brief Bind the texture to the current OpenGL/ES/ES2 context for use with
     4.1 --- a/src/SDL_assert.c	Mon Oct 22 10:55:18 2018 -0400
     4.2 +++ b/src/SDL_assert.c	Wed Oct 31 15:03:41 2018 -0400
     4.3 @@ -178,6 +178,7 @@
     4.4  
     4.5      (void) userdata;  /* unused in default handler. */
     4.6  
     4.7 +    /* !!! FIXME: why is this using SDL_stack_alloc and not just "char message[SDL_MAX_LOG_MESSAGE];" ? */
     4.8      message = SDL_stack_alloc(char, SDL_MAX_LOG_MESSAGE);
     4.9      if (!message) {
    4.10          /* Uh oh, we're in real trouble now... */
     5.1 --- a/src/SDL_internal.h	Mon Oct 22 10:55:18 2018 -0400
     5.2 +++ b/src/SDL_internal.h	Wed Oct 31 15:03:41 2018 -0400
     5.3 @@ -35,6 +35,10 @@
     5.4  #define SDL_VARIABLE_LENGTH_ARRAY
     5.5  #endif
     5.6  
     5.7 +#define SDL_MAX_SMALL_ALLOC_STACKSIZE 128
     5.8 +#define SDL_small_alloc(type, count, pisstack) ( (*(pisstack) = ((sizeof(type)*(count)) < SDL_MAX_SMALL_ALLOC_STACKSIZE)), (*(pisstack) ? SDL_stack_alloc(type, count) : (type*)SDL_malloc(sizeof(type)*(count))) )
     5.9 +#define SDL_small_free(ptr, isstack) if ((isstack)) { SDL_stack_free(ptr); } else { SDL_free(ptr); }
    5.10 +
    5.11  #include "dynapi/SDL_dynapi.h"
    5.12  
    5.13  #if SDL_DYNAMIC_API
     6.1 --- a/src/SDL_log.c	Mon Oct 22 10:55:18 2018 -0400
     6.2 +++ b/src/SDL_log.c	Wed Oct 31 15:03:41 2018 -0400
     6.3 @@ -282,6 +282,7 @@
     6.4          return;
     6.5      }
     6.6  
     6.7 +    /* !!! FIXME: why not just "char message[SDL_MAX_LOG_MESSAGE];" ? */
     6.8      message = SDL_stack_alloc(char, SDL_MAX_LOG_MESSAGE);
     6.9      if (!message) {
    6.10          return;
    6.11 @@ -321,6 +322,7 @@
    6.12          char *output;
    6.13          size_t length;
    6.14          LPTSTR tstr;
    6.15 +        SDL_bool isstack;
    6.16  
    6.17  #if !defined(HAVE_STDIO_H) && !defined(__WINRT__)
    6.18          BOOL attachResult;
    6.19 @@ -364,7 +366,7 @@
    6.20  #endif /* !defined(HAVE_STDIO_H) && !defined(__WINRT__) */
    6.21  
    6.22          length = SDL_strlen(SDL_priority_prefixes[priority]) + 2 + SDL_strlen(message) + 1 + 1 + 1;
    6.23 -        output = SDL_stack_alloc(char, length);
    6.24 +        output = SDL_small_alloc(char, length, &isstack);
    6.25          SDL_snprintf(output, length, "%s: %s\r\n", SDL_priority_prefixes[priority], message);
    6.26          tstr = WIN_UTF8ToString(output);
    6.27          
    6.28 @@ -389,7 +391,7 @@
    6.29  #endif /* !defined(HAVE_STDIO_H) && !defined(__WINRT__) */
    6.30  
    6.31          SDL_free(tstr);
    6.32 -        SDL_stack_free(output);
    6.33 +        SDL_small_free(output, isstack);
    6.34      }
    6.35  #elif defined(__ANDROID__)
    6.36      {
    6.37 @@ -404,7 +406,7 @@
    6.38      extern void SDL_NSLog(const char *text);
    6.39      {
    6.40          char *text;
    6.41 -
    6.42 +        /* !!! FIXME: why not just "char text[SDL_MAX_LOG_MESSAGE];" ? */
    6.43          text = SDL_stack_alloc(char, SDL_MAX_LOG_MESSAGE);
    6.44          if (text) {
    6.45              SDL_snprintf(text, SDL_MAX_LOG_MESSAGE, "%s: %s", SDL_priority_prefixes[priority], message);
     7.1 --- a/src/core/android/SDL_android.c	Mon Oct 22 10:55:18 2018 -0400
     7.2 +++ b/src/core/android/SDL_android.c	Wed Oct 31 15:03:41 2018 -0400
     7.3 @@ -481,10 +481,11 @@
     7.4              int argc;
     7.5              int len;
     7.6              char **argv;
     7.7 +            SDL_bool isstack;
     7.8  
     7.9              /* Prepare the arguments. */
    7.10              len = (*env)->GetArrayLength(env, array);
    7.11 -            argv = SDL_stack_alloc(char*, 1 + len + 1);
    7.12 +            argv = SDL_small_alloc(char*, 1 + len + 1, &isstack);  /* !!! FIXME: check for NULL */
    7.13              argc = 0;
    7.14              /* Use the name "app_process" so PHYSFS_platformCalcBaseDir() works.
    7.15                 https://bitbucket.org/MartinFelis/love-android-sdl2/issue/23/release-build-crash-on-start
    7.16 @@ -517,7 +518,7 @@
    7.17              for (i = 0; i < argc; ++i) {
    7.18                  SDL_free(argv[i]);
    7.19              }
    7.20 -            SDL_stack_free(argv);
    7.21 +            SDL_small_free(argv, isstack);
    7.22  
    7.23          } else {
    7.24              __android_log_print(ANDROID_LOG_ERROR, "SDL", "nativeRunMain(): Couldn't find function %s in library %s", function_name, library_file);
     8.1 --- a/src/dynapi/SDL_dynapi_overrides.h	Mon Oct 22 10:55:18 2018 -0400
     8.2 +++ b/src/dynapi/SDL_dynapi_overrides.h	Wed Oct 31 15:03:41 2018 -0400
     8.3 @@ -701,3 +701,14 @@
     8.4  #define SDL_JoystickGetDevicePlayerIndex SDL_JoystickGetDevicePlayerIndex_REAL
     8.5  #define SDL_JoystickGetPlayerIndex SDL_JoystickGetPlayerIndex_REAL
     8.6  #define SDL_GameControllerGetPlayerIndex SDL_GameControllerGetPlayerIndex_REAL
     8.7 +#define SDL_RenderFlush SDL_RenderFlush_REAL
     8.8 +#define SDL_RenderDrawPointF SDL_RenderDrawPointF_REAL
     8.9 +#define SDL_RenderDrawPointsF SDL_RenderDrawPointsF_REAL
    8.10 +#define SDL_RenderDrawLineF SDL_RenderDrawLineF_REAL
    8.11 +#define SDL_RenderDrawLinesF SDL_RenderDrawLinesF_REAL
    8.12 +#define SDL_RenderDrawRectF SDL_RenderDrawRectF_REAL
    8.13 +#define SDL_RenderDrawRectsF SDL_RenderDrawRectsF_REAL
    8.14 +#define SDL_RenderFillRectF SDL_RenderFillRectF_REAL
    8.15 +#define SDL_RenderFillRectsF SDL_RenderFillRectsF_REAL
    8.16 +#define SDL_RenderCopyF SDL_RenderCopyF_REAL
    8.17 +#define SDL_RenderCopyExF SDL_RenderCopyExF_REAL
     9.1 --- a/src/dynapi/SDL_dynapi_procs.h	Mon Oct 22 10:55:18 2018 -0400
     9.2 +++ b/src/dynapi/SDL_dynapi_procs.h	Wed Oct 31 15:03:41 2018 -0400
     9.3 @@ -755,3 +755,14 @@
     9.4  SDL_DYNAPI_PROC(int,SDL_JoystickGetDevicePlayerIndex,(int a),(a),return)
     9.5  SDL_DYNAPI_PROC(int,SDL_JoystickGetPlayerIndex,(SDL_Joystick *a),(a),return)
     9.6  SDL_DYNAPI_PROC(int,SDL_GameControllerGetPlayerIndex,(SDL_GameController *a),(a),return)
     9.7 +SDL_DYNAPI_PROC(int,SDL_RenderFlush,(SDL_Renderer *a),(a),return)
     9.8 +SDL_DYNAPI_PROC(int,SDL_RenderDrawPointF,(SDL_Renderer *a, float b, float c),(a,b,c),return)
     9.9 +SDL_DYNAPI_PROC(int,SDL_RenderDrawPointsF,(SDL_Renderer *a, const SDL_FPoint *b, int c),(a,b,c),return)
    9.10 +SDL_DYNAPI_PROC(int,SDL_RenderDrawLineF,(SDL_Renderer *a, float b, float c, float d, float e),(a,b,c,d,e),return)
    9.11 +SDL_DYNAPI_PROC(int,SDL_RenderDrawLinesF,(SDL_Renderer *a, const SDL_FPoint *b, int c),(a,b,c),return)
    9.12 +SDL_DYNAPI_PROC(int,SDL_RenderDrawRectF,(SDL_Renderer *a, const SDL_FRect *b),(a,b),return)
    9.13 +SDL_DYNAPI_PROC(int,SDL_RenderDrawRectsF,(SDL_Renderer *a, const SDL_FRect *b, int c),(a,b,c),return)
    9.14 +SDL_DYNAPI_PROC(int,SDL_RenderFillRectF,(SDL_Renderer *a, const SDL_FRect *b),(a,b),return)
    9.15 +SDL_DYNAPI_PROC(int,SDL_RenderFillRectsF,(SDL_Renderer *a, const SDL_FRect *b, int c),(a,b,c),return)
    9.16 +SDL_DYNAPI_PROC(int,SDL_RenderCopyF,(SDL_Renderer *a, SDL_Texture *b, const SDL_Rect *c, const SDL_FRect *d),(a,b,c,d),return)
    9.17 +SDL_DYNAPI_PROC(int,SDL_RenderCopyExF,(SDL_Renderer *a, SDL_Texture *b, const SDL_Rect *c, const SDL_FRect *d, const double e, const SDL_FPoint *f, const SDL_RendererFlip g),(a,b,c,d,e,f,g),return)
    10.1 --- a/src/file/SDL_rwops.c	Mon Oct 22 10:55:18 2018 -0400
    10.2 +++ b/src/file/SDL_rwops.c	Wed Oct 31 15:03:41 2018 -0400
    10.3 @@ -528,6 +528,7 @@
    10.4          char *path;
    10.5          FILE *fp;
    10.6  
    10.7 +        /* !!! FIXME: why not just "char path[PATH_MAX];" ? */
    10.8          path = SDL_stack_alloc(char, PATH_MAX);
    10.9          if (path) {
   10.10              SDL_snprintf(path, PATH_MAX, "%s/%s",
    11.1 --- a/src/joystick/SDL_gamecontroller.c	Mon Oct 22 10:55:18 2018 -0400
    11.2 +++ b/src/joystick/SDL_gamecontroller.c	Wed Oct 31 15:03:41 2018 -0400
    11.3 @@ -202,13 +202,14 @@
    11.4  {
    11.5      int i, num_events;
    11.6      SDL_Event *events;
    11.7 +    SDL_bool isstack;
    11.8  
    11.9      num_events = SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEADDED);
   11.10      if (num_events <= 0) {
   11.11          return;
   11.12      }
   11.13  
   11.14 -    events = SDL_stack_alloc(SDL_Event, num_events);
   11.15 +    events = SDL_small_alloc(SDL_Event, num_events, &isstack);
   11.16      if (!events) {
   11.17          return;
   11.18      }
   11.19 @@ -219,7 +220,7 @@
   11.20      }
   11.21      SDL_PeepEvents(events, num_events, SDL_ADDEVENT, 0, 0);
   11.22  
   11.23 -    SDL_stack_free(events);
   11.24 +    SDL_small_free(events, isstack);
   11.25  }
   11.26  
   11.27  static SDL_bool HasSameOutput(SDL_ExtendedGameControllerBind *a, SDL_ExtendedGameControllerBind *b)
    12.1 --- a/src/joystick/SDL_joystick.c	Mon Oct 22 10:55:18 2018 -0400
    12.2 +++ b/src/joystick/SDL_joystick.c	Wed Oct 31 15:03:41 2018 -0400
    12.3 @@ -777,13 +777,14 @@
    12.4  {
    12.5      int i, num_events;
    12.6      SDL_Event *events;
    12.7 +    SDL_bool isstack;
    12.8  
    12.9      num_events = SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, SDL_JOYDEVICEADDED, SDL_JOYDEVICEADDED);
   12.10      if (num_events <= 0) {
   12.11          return;
   12.12      }
   12.13  
   12.14 -    events = SDL_stack_alloc(SDL_Event, num_events);
   12.15 +    events = SDL_small_alloc(SDL_Event, num_events, &isstack);
   12.16      if (!events) {
   12.17          return;
   12.18      }
   12.19 @@ -794,7 +795,7 @@
   12.20      }
   12.21      SDL_PeepEvents(events, num_events, SDL_ADDEVENT, 0, 0);
   12.22  
   12.23 -    SDL_stack_free(events);
   12.24 +    SDL_small_free(events, isstack);
   12.25  }
   12.26  
   12.27  void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance)
    13.1 --- a/src/loadso/dlopen/SDL_sysloadso.c	Mon Oct 22 10:55:18 2018 -0400
    13.2 +++ b/src/loadso/dlopen/SDL_sysloadso.c	Wed Oct 31 15:03:41 2018 -0400
    13.3 @@ -61,12 +61,13 @@
    13.4      void *symbol = dlsym(handle, name);
    13.5      if (symbol == NULL) {
    13.6          /* append an underscore for platforms that need that. */
    13.7 +        SDL_bool isstack;
    13.8          size_t len = 1 + SDL_strlen(name) + 1;
    13.9 -        char *_name = SDL_stack_alloc(char, len);
   13.10 +        char *_name = SDL_small_alloc(char, len, &isstack);
   13.11          _name[0] = '_';
   13.12          SDL_strlcpy(&_name[1], name, len);
   13.13          symbol = dlsym(handle, _name);
   13.14 -        SDL_stack_free(_name);
   13.15 +        SDL_small_free(_name, isstack);
   13.16          if (symbol == NULL) {
   13.17              SDL_SetError("Failed loading %s: %s", name,
   13.18                           (const char *) dlerror());
    14.1 --- a/src/render/SDL_render.c	Mon Oct 22 10:55:18 2018 -0400
    14.2 +++ b/src/render/SDL_render.c	Wed Oct 31 15:03:41 2018 -0400
    14.3 @@ -105,6 +105,519 @@
    14.4  static char renderer_magic;
    14.5  static char texture_magic;
    14.6  
    14.7 +static SDL_INLINE void
    14.8 +DebugLogRenderCommands(const SDL_RenderCommand *cmd)
    14.9 +{
   14.10 +#if 0
   14.11 +    unsigned int i = 1;
   14.12 +    SDL_Log("Render commands to flush:");
   14.13 +    while (cmd) {
   14.14 +        switch (cmd->command) {
   14.15 +            case SDL_RENDERCMD_NO_OP:
   14.16 +                SDL_Log(" %u. no-op", i++);
   14.17 +                break;
   14.18 +
   14.19 +            case SDL_RENDERCMD_SETVIEWPORT:
   14.20 +                SDL_Log(" %u. set viewport (first=%u, rect={(%d, %d), %dx%d})", i++,
   14.21 +                        (unsigned int) cmd->data.viewport.first,
   14.22 +                        cmd->data.viewport.rect.x, cmd->data.viewport.rect.y,
   14.23 +                        cmd->data.viewport.rect.w, cmd->data.viewport.rect.h);
   14.24 +                break;
   14.25 +
   14.26 +            case SDL_RENDERCMD_SETCLIPRECT:
   14.27 +                SDL_Log(" %u. set cliprect (enabled=%s, rect={(%d, %d), %dx%d})", i++,
   14.28 +                        cmd->data.cliprect.enabled ? "true" : "false",
   14.29 +                        cmd->data.cliprect.rect.x, cmd->data.cliprect.rect.y,
   14.30 +                        cmd->data.cliprect.rect.w, cmd->data.cliprect.rect.h);
   14.31 +                break;
   14.32 +
   14.33 +            case SDL_RENDERCMD_SETDRAWCOLOR:
   14.34 +                SDL_Log(" %u. set draw color (first=%u, r=%d, g=%d, b=%d, a=%d)", i++,
   14.35 +                        (unsigned int) cmd->data.color.first,
   14.36 +                        (int) cmd->data.color.r, (int) cmd->data.color.g,
   14.37 +                        (int) cmd->data.color.b, (int) cmd->data.color.a);
   14.38 +                break;
   14.39 +
   14.40 +            case SDL_RENDERCMD_CLEAR:
   14.41 +                SDL_Log(" %u. clear (first=%u, r=%d, g=%d, b=%d, a=%d)", i++,
   14.42 +                        (unsigned int) cmd->data.color.first,
   14.43 +                        (int) cmd->data.color.r, (int) cmd->data.color.g,
   14.44 +                        (int) cmd->data.color.b, (int) cmd->data.color.a);
   14.45 +                break;
   14.46 +
   14.47 +            case SDL_RENDERCMD_DRAW_POINTS:
   14.48 +                SDL_Log(" %u. draw points (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d)", i++,
   14.49 +                        (unsigned int) cmd->data.draw.first,
   14.50 +                        (unsigned int) cmd->data.draw.count,
   14.51 +                        (int) cmd->data.draw.r, (int) cmd->data.draw.g,
   14.52 +                        (int) cmd->data.draw.b, (int) cmd->data.draw.a,
   14.53 +                        (int) cmd->data.draw.blend);
   14.54 +                break;
   14.55 +
   14.56 +            case SDL_RENDERCMD_DRAW_LINES:
   14.57 +                SDL_Log(" %u. draw lines (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d)", i++,
   14.58 +                        (unsigned int) cmd->data.draw.first,
   14.59 +                        (unsigned int) cmd->data.draw.count,
   14.60 +                        (int) cmd->data.draw.r, (int) cmd->data.draw.g,
   14.61 +                        (int) cmd->data.draw.b, (int) cmd->data.draw.a,
   14.62 +                        (int) cmd->data.draw.blend);
   14.63 +                break;
   14.64 +
   14.65 +            case SDL_RENDERCMD_FILL_RECTS:
   14.66 +                SDL_Log(" %u. fill rects (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d)", i++,
   14.67 +                        (unsigned int) cmd->data.draw.first,
   14.68 +                        (unsigned int) cmd->data.draw.count,
   14.69 +                        (int) cmd->data.draw.r, (int) cmd->data.draw.g,
   14.70 +                        (int) cmd->data.draw.b, (int) cmd->data.draw.a,
   14.71 +                        (int) cmd->data.draw.blend);
   14.72 +                break;
   14.73 +
   14.74 +            case SDL_RENDERCMD_COPY:
   14.75 +                SDL_Log(" %u. copy (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d, tex=%p)", i++,
   14.76 +                        (unsigned int) cmd->data.draw.first,
   14.77 +                        (unsigned int) cmd->data.draw.count,
   14.78 +                        (int) cmd->data.draw.r, (int) cmd->data.draw.g,
   14.79 +                        (int) cmd->data.draw.b, (int) cmd->data.draw.a,
   14.80 +                        (int) cmd->data.draw.blend, cmd->data.draw.texture);
   14.81 +                break;
   14.82 +
   14.83 +
   14.84 +            case SDL_RENDERCMD_COPY_EX:
   14.85 +                SDL_Log(" %u. copyex (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d, tex=%p)", i++,
   14.86 +                        (unsigned int) cmd->data.draw.first,
   14.87 +                        (unsigned int) cmd->data.draw.count,
   14.88 +                        (int) cmd->data.draw.r, (int) cmd->data.draw.g,
   14.89 +                        (int) cmd->data.draw.b, (int) cmd->data.draw.a,
   14.90 +                        (int) cmd->data.draw.blend, cmd->data.draw.texture);
   14.91 +                break;
   14.92 +        }
   14.93 +        cmd = cmd->next;
   14.94 +    }
   14.95 +#endif
   14.96 +}
   14.97 +
   14.98 +static int
   14.99 +FlushRenderCommands(SDL_Renderer *renderer)
  14.100 +{
  14.101 +    SDL_AllocVertGap *prevgap = &renderer->vertex_data_gaps;
  14.102 +    SDL_AllocVertGap *gap = prevgap;
  14.103 +    int retval;
  14.104 +
  14.105 +    SDL_assert((renderer->render_commands == NULL) == (renderer->render_commands_tail == NULL));
  14.106 +
  14.107 +    if (renderer->render_commands == NULL) {  /* nothing to do! */
  14.108 +        SDL_assert(renderer->vertex_data_used == 0);
  14.109 +        return 0;
  14.110 +    }
  14.111 +
  14.112 +    DebugLogRenderCommands(renderer->render_commands);
  14.113 +
  14.114 +    retval = renderer->RunCommandQueue(renderer, renderer->render_commands, renderer->vertex_data, renderer->vertex_data_used);
  14.115 +
  14.116 +    while (gap) {
  14.117 +        prevgap = gap;
  14.118 +        gap = gap->next;
  14.119 +    }
  14.120 +    prevgap->next = renderer->vertex_data_gaps_pool;
  14.121 +    renderer->vertex_data_gaps_pool = renderer->vertex_data_gaps.next;
  14.122 +    renderer->vertex_data_gaps.next = NULL;
  14.123 +
  14.124 +    /* Move the whole render command queue to the unused pool so we can reuse them next time. */
  14.125 +    if (renderer->render_commands_tail != NULL) {
  14.126 +        renderer->render_commands_tail->next = renderer->render_commands_pool;
  14.127 +        renderer->render_commands_pool = renderer->render_commands;
  14.128 +        renderer->render_commands_tail = NULL;
  14.129 +        renderer->render_commands = NULL;
  14.130 +    }
  14.131 +    renderer->vertex_data_used = 0;
  14.132 +    renderer->render_command_generation++;
  14.133 +    renderer->color_queued = SDL_FALSE;
  14.134 +    renderer->viewport_queued = SDL_FALSE;
  14.135 +    renderer->cliprect_queued = SDL_FALSE;
  14.136 +    return retval;
  14.137 +}
  14.138 +
  14.139 +static int
  14.140 +FlushRenderCommandsIfTextureNeeded(SDL_Texture *texture)
  14.141 +{
  14.142 +    SDL_Renderer *renderer = texture->renderer;
  14.143 +    if (texture->last_command_generation == renderer->render_command_generation) {
  14.144 +        /* the current command queue depends on this texture, flush the queue now before it changes */
  14.145 +        return FlushRenderCommands(renderer);
  14.146 +    }
  14.147 +    return 0;
  14.148 +}
  14.149 +
  14.150 +static SDL_INLINE int
  14.151 +FlushRenderCommandsIfNotBatching(SDL_Renderer *renderer)
  14.152 +{
  14.153 +    return renderer->batching ? 0 : FlushRenderCommands(renderer);
  14.154 +}
  14.155 +
  14.156 +int
  14.157 +SDL_RenderFlush(SDL_Renderer * renderer)
  14.158 +{
  14.159 +    return FlushRenderCommands(renderer);
  14.160 +}
  14.161 +
  14.162 +static SDL_AllocVertGap *
  14.163 +AllocateVertexGap(SDL_Renderer *renderer)
  14.164 +{
  14.165 +    SDL_AllocVertGap *retval = renderer->vertex_data_gaps_pool;
  14.166 +    if (retval) {
  14.167 +        renderer->vertex_data_gaps_pool = retval->next;
  14.168 +        retval->next = NULL;
  14.169 +    } else {
  14.170 +        retval = (SDL_AllocVertGap *) SDL_malloc(sizeof (SDL_AllocVertGap));
  14.171 +        if (!retval) {
  14.172 +            SDL_OutOfMemory();
  14.173 +        }
  14.174 +    }
  14.175 +    return retval;
  14.176 +}
  14.177 +
  14.178 +
  14.179 +void *
  14.180 +SDL_AllocateRenderVertices(SDL_Renderer *renderer, const size_t numbytes, const size_t alignment, size_t *offset)
  14.181 +{
  14.182 +    const size_t needed = renderer->vertex_data_used + numbytes + alignment;
  14.183 +    size_t aligner, aligned;
  14.184 +    void *retval;
  14.185 +
  14.186 +    SDL_AllocVertGap *prevgap = &renderer->vertex_data_gaps;
  14.187 +    SDL_AllocVertGap *gap = prevgap->next;
  14.188 +    while (gap) {
  14.189 +        const size_t gapoffset = gap->offset;
  14.190 +        aligner = (alignment && ((gap->offset % alignment) != 0)) ? (alignment - (gap->offset % alignment)) : 0;
  14.191 +        aligned = gapoffset + aligner;
  14.192 +
  14.193 +        /* Can we use this gap? */
  14.194 +        if ((aligner < gap->len) && ((gap->len - aligner) >= numbytes)) {
  14.195 +            /* we either finished this gap off, trimmed the left, trimmed the right, or split it into two gaps. */
  14.196 +            if (gap->len == numbytes) {  /* finished it off, remove it */
  14.197 +                SDL_assert(aligned == gapoffset);
  14.198 +                prevgap->next = gap->next;
  14.199 +                gap->next = renderer->vertex_data_gaps_pool;
  14.200 +                renderer->vertex_data_gaps_pool = gap;
  14.201 +            } else if (aligned == gapoffset) {  /* trimmed the left */
  14.202 +                gap->offset += numbytes;
  14.203 +                gap->len -= numbytes;
  14.204 +            } else if (((aligned - gapoffset) + numbytes) == gap->len) {  /* trimmed the right */
  14.205 +                gap->len -= numbytes;
  14.206 +            } else {  /* split into two gaps */
  14.207 +                SDL_AllocVertGap *newgap = AllocateVertexGap(renderer);
  14.208 +                if (!newgap) {
  14.209 +                    return NULL;
  14.210 +                }
  14.211 +                newgap->offset = aligned + numbytes;
  14.212 +                newgap->len = gap->len - (aligner + numbytes);
  14.213 +                newgap->next = gap->next;
  14.214 +                // gap->offset doesn't change.
  14.215 +                gap->len = aligner;
  14.216 +                gap->next = newgap;
  14.217 +            }
  14.218 +
  14.219 +            if (offset) {
  14.220 +                *offset = aligned;
  14.221 +            }
  14.222 +            return ((Uint8 *) renderer->vertex_data) + aligned;
  14.223 +        }
  14.224 +
  14.225 +        /* Try the next gap */
  14.226 +        prevgap = gap;
  14.227 +        gap = gap->next;
  14.228 +    }
  14.229 +
  14.230 +    /* no gaps with enough space; get a new piece of the vertex buffer */
  14.231 +    while (needed > renderer->vertex_data_allocation) {
  14.232 +        const size_t current_allocation = renderer->vertex_data ? renderer->vertex_data_allocation : 1024;
  14.233 +        const size_t newsize = current_allocation * 2;
  14.234 +        void *ptr = SDL_realloc(renderer->vertex_data, newsize);
  14.235 +        if (ptr == NULL) {
  14.236 +            SDL_OutOfMemory();
  14.237 +            return NULL;
  14.238 +        }
  14.239 +        renderer->vertex_data = ptr;
  14.240 +        renderer->vertex_data_allocation = newsize;
  14.241 +    }
  14.242 +
  14.243 +    aligner = (alignment && ((renderer->vertex_data_used % alignment) != 0)) ? (alignment - (renderer->vertex_data_used % alignment)) : 0;
  14.244 +    aligned = renderer->vertex_data_used + aligner;
  14.245 +
  14.246 +    retval = ((Uint8 *) renderer->vertex_data) + aligned;
  14.247 +    if (offset) {
  14.248 +        *offset = aligned;
  14.249 +    }
  14.250 +
  14.251 +    if (aligner) {  /* made a new gap... */
  14.252 +        SDL_AllocVertGap *newgap = AllocateVertexGap(renderer);
  14.253 +        if (newgap) {  /* just let it slide as lost space if malloc fails. */
  14.254 +            newgap->offset = renderer->vertex_data_used;
  14.255 +            newgap->len = aligner;
  14.256 +            newgap->next = NULL;
  14.257 +            prevgap->next = newgap;
  14.258 +        }
  14.259 +    }
  14.260 +
  14.261 +    renderer->vertex_data_used += aligner + numbytes;
  14.262 +
  14.263 +    return retval;
  14.264 +}
  14.265 +
  14.266 +static SDL_RenderCommand *
  14.267 +AllocateRenderCommand(SDL_Renderer *renderer)
  14.268 +{
  14.269 +    SDL_RenderCommand *retval = NULL;
  14.270 +
  14.271 +    /* !!! FIXME: are there threading limitations in SDL's render API? If not, we need to mutex this. */
  14.272 +    retval = renderer->render_commands_pool;
  14.273 +    if (retval != NULL) {
  14.274 +        renderer->render_commands_pool = retval->next;
  14.275 +        retval->next = NULL;
  14.276 +    } else {
  14.277 +        retval = SDL_calloc(1, sizeof (*retval));
  14.278 +        if (!retval) {
  14.279 +            SDL_OutOfMemory();
  14.280 +            return NULL;
  14.281 +        }
  14.282 +    }
  14.283 +
  14.284 +    SDL_assert((renderer->render_commands == NULL) == (renderer->render_commands_tail == NULL));
  14.285 +    if (renderer->render_commands_tail != NULL) {
  14.286 +        renderer->render_commands_tail->next = retval;
  14.287 +    } else {
  14.288 +        renderer->render_commands = retval;
  14.289 +    }
  14.290 +    renderer->render_commands_tail = retval;
  14.291 +
  14.292 +    return retval;
  14.293 +}
  14.294 +
  14.295 +static int
  14.296 +QueueCmdSetViewport(SDL_Renderer *renderer)
  14.297 +{
  14.298 +    int retval = 0;
  14.299 +    if (!renderer->viewport_queued || (SDL_memcmp(&renderer->viewport, &renderer->last_queued_viewport, sizeof (SDL_Rect)) != 0)) {
  14.300 +        SDL_RenderCommand *cmd = AllocateRenderCommand(renderer);
  14.301 +        retval = -1;
  14.302 +        if (cmd != NULL) {
  14.303 +            cmd->command = SDL_RENDERCMD_SETVIEWPORT;
  14.304 +            cmd->data.viewport.first = 0;  /* render backend will fill this in. */
  14.305 +            SDL_memcpy(&cmd->data.viewport.rect, &renderer->viewport, sizeof (renderer->viewport));
  14.306 +            retval = renderer->QueueSetViewport(renderer, cmd);
  14.307 +            if (retval < 0) {
  14.308 +                cmd->command = SDL_RENDERCMD_NO_OP;
  14.309 +            } else {
  14.310 +                SDL_memcpy(&renderer->last_queued_viewport, &renderer->viewport, sizeof (SDL_Rect));
  14.311 +                renderer->viewport_queued = SDL_TRUE;
  14.312 +            }
  14.313 +        }
  14.314 +    }
  14.315 +    return retval;
  14.316 +}
  14.317 +
  14.318 +static int
  14.319 +QueueCmdSetClipRect(SDL_Renderer *renderer)
  14.320 +{
  14.321 +    int retval = 0;
  14.322 +    if ((!renderer->cliprect_queued) ||
  14.323 +         (renderer->clipping_enabled != renderer->last_queued_cliprect_enabled) ||
  14.324 +         (SDL_memcmp(&renderer->clip_rect, &renderer->last_queued_cliprect, sizeof (SDL_Rect)) != 0)) {
  14.325 +        SDL_RenderCommand *cmd = AllocateRenderCommand(renderer);
  14.326 +        if (cmd == NULL) {
  14.327 +            retval = -1;
  14.328 +        } else {
  14.329 +            cmd->command = SDL_RENDERCMD_SETCLIPRECT;
  14.330 +            cmd->data.cliprect.enabled = renderer->clipping_enabled;
  14.331 +            SDL_memcpy(&cmd->data.cliprect.rect, &renderer->clip_rect, sizeof (cmd->data.cliprect.rect));
  14.332 +            SDL_memcpy(&renderer->last_queued_cliprect, &renderer->clip_rect, sizeof (SDL_Rect));
  14.333 +            renderer->last_queued_cliprect_enabled = renderer->clipping_enabled;
  14.334 +            renderer->cliprect_queued = SDL_TRUE;
  14.335 +        }
  14.336 +    }
  14.337 +    return retval;
  14.338 +}
  14.339 +
  14.340 +static int
  14.341 +QueueCmdSetDrawColor(SDL_Renderer *renderer, const Uint8 r, const Uint8 g, const Uint8 b, const Uint8 a)
  14.342 +{
  14.343 +    const Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b);
  14.344 +    int retval = 0;
  14.345 +    
  14.346 +    if (!renderer->color_queued || (color != renderer->last_queued_color)) {
  14.347 +        SDL_RenderCommand *cmd = AllocateRenderCommand(renderer);
  14.348 +        retval = -1;
  14.349 +
  14.350 +        if (cmd != NULL) {
  14.351 +            cmd->command = SDL_RENDERCMD_SETDRAWCOLOR;
  14.352 +            cmd->data.color.first = 0;  /* render backend will fill this in. */
  14.353 +            cmd->data.color.r = r;
  14.354 +            cmd->data.color.g = g;
  14.355 +            cmd->data.color.b = b;
  14.356 +            cmd->data.color.a = a;
  14.357 +            retval = renderer->QueueSetDrawColor(renderer, cmd);
  14.358 +            if (retval < 0) {
  14.359 +                cmd->command = SDL_RENDERCMD_NO_OP;
  14.360 +            } else {
  14.361 +                renderer->last_queued_color = color;
  14.362 +                renderer->color_queued = SDL_TRUE;
  14.363 +            }
  14.364 +        }
  14.365 +    }
  14.366 +    return retval;
  14.367 +}
  14.368 +
  14.369 +static int
  14.370 +QueueCmdClear(SDL_Renderer *renderer)
  14.371 +{
  14.372 +    SDL_RenderCommand *cmd = AllocateRenderCommand(renderer);
  14.373 +    if (cmd == NULL) {
  14.374 +        return -1;
  14.375 +    }
  14.376 +
  14.377 +    cmd->command = SDL_RENDERCMD_CLEAR;
  14.378 +    cmd->data.color.first = 0;
  14.379 +    cmd->data.color.r = renderer->r;
  14.380 +    cmd->data.color.g = renderer->g;
  14.381 +    cmd->data.color.b = renderer->b;
  14.382 +    cmd->data.color.a = renderer->a;
  14.383 +    return 0;
  14.384 +}
  14.385 +
  14.386 +static int
  14.387 +PrepQueueCmdDraw(SDL_Renderer *renderer, const Uint8 r, const Uint8 g, const Uint8 b, const Uint8 a)
  14.388 +{
  14.389 +    int retval = 0;
  14.390 +    if (retval == 0) {
  14.391 +        retval = QueueCmdSetDrawColor(renderer, r, g, b, a);
  14.392 +    }
  14.393 +    if (retval == 0) {
  14.394 +        retval = QueueCmdSetViewport(renderer);
  14.395 +    }
  14.396 +    if (retval == 0) {
  14.397 +        retval = QueueCmdSetClipRect(renderer);
  14.398 +    }
  14.399 +    return retval;
  14.400 +}
  14.401 +
  14.402 +static SDL_RenderCommand *
  14.403 +PrepQueueCmdDrawSolid(SDL_Renderer *renderer, const SDL_RenderCommandType cmdtype)
  14.404 +{
  14.405 +    /* !!! FIXME: drop this draw if viewport w or h is zero. */
  14.406 +    SDL_RenderCommand *cmd = NULL;
  14.407 +    if (PrepQueueCmdDraw(renderer, renderer->r, renderer->g, renderer->b, renderer->a) == 0) {
  14.408 +        cmd = AllocateRenderCommand(renderer);
  14.409 +        if (cmd != NULL) {
  14.410 +            cmd->command = cmdtype;
  14.411 +            cmd->data.draw.first = 0;  /* render backend will fill this in. */
  14.412 +            cmd->data.draw.count = 0;  /* render backend will fill this in. */
  14.413 +            cmd->data.draw.r = renderer->r;
  14.414 +            cmd->data.draw.g = renderer->g;
  14.415 +            cmd->data.draw.b = renderer->b;
  14.416 +            cmd->data.draw.a = renderer->a;
  14.417 +            cmd->data.draw.blend = renderer->blendMode;
  14.418 +            cmd->data.draw.texture = NULL;  /* no texture. */
  14.419 +        }
  14.420 +    }
  14.421 +    return cmd;
  14.422 +}
  14.423 +
  14.424 +static int
  14.425 +QueueCmdDrawPoints(SDL_Renderer *renderer, const SDL_FPoint * points, const int count)
  14.426 +{
  14.427 +    SDL_RenderCommand *cmd = PrepQueueCmdDrawSolid(renderer, SDL_RENDERCMD_DRAW_POINTS);
  14.428 +    int retval = -1;
  14.429 +    if (cmd != NULL) {
  14.430 +        retval = renderer->QueueDrawPoints(renderer, cmd, points, count);
  14.431 +        if (retval < 0) {
  14.432 +            cmd->command = SDL_RENDERCMD_NO_OP;
  14.433 +        }
  14.434 +    }
  14.435 +    return retval;
  14.436 +}
  14.437 +
  14.438 +static int
  14.439 +QueueCmdDrawLines(SDL_Renderer *renderer, const SDL_FPoint * points, const int count)
  14.440 +{
  14.441 +    SDL_RenderCommand *cmd = PrepQueueCmdDrawSolid(renderer, SDL_RENDERCMD_DRAW_LINES);
  14.442 +    int retval = -1;
  14.443 +    if (cmd != NULL) {
  14.444 +        retval = renderer->QueueDrawLines(renderer, cmd, points, count);
  14.445 +        if (retval < 0) {
  14.446 +            cmd->command = SDL_RENDERCMD_NO_OP;
  14.447 +        }
  14.448 +    }
  14.449 +    return retval;
  14.450 +}
  14.451 +
  14.452 +static int
  14.453 +QueueCmdFillRects(SDL_Renderer *renderer, const SDL_FRect * rects, const int count)
  14.454 +{
  14.455 +    SDL_RenderCommand *cmd = PrepQueueCmdDrawSolid(renderer, SDL_RENDERCMD_FILL_RECTS);
  14.456 +    int retval = -1;
  14.457 +    if (cmd != NULL) {
  14.458 +        retval = renderer->QueueFillRects(renderer, cmd, rects, count);
  14.459 +        if (retval < 0) {
  14.460 +            cmd->command = SDL_RENDERCMD_NO_OP;
  14.461 +        }
  14.462 +    }
  14.463 +    return retval;
  14.464 +}
  14.465 +
  14.466 +static SDL_RenderCommand *
  14.467 +PrepQueueCmdDrawTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_RenderCommandType cmdtype)
  14.468 +{
  14.469 +    /* !!! FIXME: drop this draw if viewport w or h is zero. */
  14.470 +    SDL_RenderCommand *cmd = NULL;
  14.471 +    if (PrepQueueCmdDraw(renderer, texture->r, texture->g, texture->b, texture->a) == 0) {
  14.472 +        cmd = AllocateRenderCommand(renderer);
  14.473 +        if (cmd != NULL) {
  14.474 +            cmd->command = cmdtype;
  14.475 +            cmd->data.draw.first = 0;  /* render backend will fill this in. */
  14.476 +            cmd->data.draw.count = 0;  /* render backend will fill this in. */
  14.477 +            cmd->data.draw.r = texture->r;
  14.478 +            cmd->data.draw.g = texture->g;
  14.479 +            cmd->data.draw.b = texture->b;
  14.480 +            cmd->data.draw.a = texture->a;
  14.481 +            cmd->data.draw.blend = texture->blendMode;
  14.482 +            cmd->data.draw.texture = texture;
  14.483 +        }
  14.484 +    }
  14.485 +    return cmd;
  14.486 +}
  14.487 +
  14.488 +static int
  14.489 +QueueCmdCopy(SDL_Renderer *renderer, SDL_Texture * texture, const SDL_Rect * srcrect, const SDL_FRect * dstrect)
  14.490 +{
  14.491 +    SDL_RenderCommand *cmd = PrepQueueCmdDrawTexture(renderer, texture, SDL_RENDERCMD_COPY);
  14.492 +    int retval = -1;
  14.493 +    if (cmd != NULL) {
  14.494 +        retval = renderer->QueueCopy(renderer, cmd, texture, srcrect, dstrect);
  14.495 +        if (retval < 0) {
  14.496 +            cmd->command = SDL_RENDERCMD_NO_OP;
  14.497 +        }
  14.498 +    }
  14.499 +    return retval;
  14.500 +}
  14.501 +
  14.502 +static int
  14.503 +QueueCmdCopyEx(SDL_Renderer *renderer, SDL_Texture * texture,
  14.504 +               const SDL_Rect * srcquad, const SDL_FRect * dstrect,
  14.505 +               const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
  14.506 +{
  14.507 +    SDL_RenderCommand *cmd = PrepQueueCmdDrawTexture(renderer, texture, SDL_RENDERCMD_COPY_EX);
  14.508 +    int retval = -1;
  14.509 +    SDL_assert(renderer->QueueCopyEx != NULL);  /* should have caught at higher level. */
  14.510 +    if (cmd != NULL) {
  14.511 +        retval = renderer->QueueCopyEx(renderer, cmd, texture, srcquad, dstrect, angle, center, flip);
  14.512 +        if (retval < 0) {
  14.513 +            cmd->command = SDL_RENDERCMD_NO_OP;
  14.514 +        }
  14.515 +    }
  14.516 +    return retval;
  14.517 +}
  14.518 +
  14.519 +
  14.520  static int UpdateLogicalSize(SDL_Renderer *renderer);
  14.521  
  14.522  int
  14.523 @@ -183,7 +696,8 @@
  14.524                          renderer->viewport.y = 0;
  14.525                          renderer->viewport.w = w;
  14.526                          renderer->viewport.h = h;
  14.527 -                        renderer->UpdateViewport(renderer);
  14.528 +                        QueueCmdSetViewport(renderer);
  14.529 +                        FlushRenderCommandsIfNotBatching(renderer);
  14.530                      }
  14.531                  }
  14.532  
  14.533 @@ -300,12 +814,27 @@
  14.534      return 0;
  14.535  }
  14.536  
  14.537 +static SDL_INLINE
  14.538 +void VerifyDrawQueueFunctions(const SDL_Renderer *renderer)
  14.539 +{
  14.540 +    /* all of these functions are required to be implemented, even as no-ops, so we don't
  14.541 +        have to check that they aren't NULL over and over. */
  14.542 +    SDL_assert(renderer->QueueSetViewport != NULL);
  14.543 +    SDL_assert(renderer->QueueSetDrawColor != NULL);
  14.544 +    SDL_assert(renderer->QueueDrawPoints != NULL);
  14.545 +    SDL_assert(renderer->QueueDrawLines != NULL);
  14.546 +    SDL_assert(renderer->QueueFillRects != NULL);
  14.547 +    SDL_assert(renderer->QueueCopy != NULL);
  14.548 +    SDL_assert(renderer->RunCommandQueue != NULL);
  14.549 +}
  14.550 +
  14.551  SDL_Renderer *
  14.552  SDL_CreateRenderer(SDL_Window * window, int index, Uint32 flags)
  14.553  {
  14.554  #if !SDL_RENDER_DISABLED
  14.555      SDL_Renderer *renderer = NULL;
  14.556      int n = SDL_GetNumRenderDrivers();
  14.557 +    SDL_bool batching = SDL_TRUE;
  14.558      const char *hint;
  14.559  
  14.560      if (!window) {
  14.561 @@ -335,6 +864,9 @@
  14.562                  if (SDL_strcasecmp(hint, driver->info.name) == 0) {
  14.563                      /* Create a new renderer instance */
  14.564                      renderer = driver->CreateRenderer(window, flags);
  14.565 +                    if (renderer) {
  14.566 +                        batching = SDL_FALSE;
  14.567 +                    }
  14.568                      break;
  14.569                  }
  14.570              }
  14.571 @@ -366,9 +898,20 @@
  14.572          }
  14.573          /* Create a new renderer instance */
  14.574          renderer = render_drivers[index]->CreateRenderer(window, flags);
  14.575 +        batching = SDL_FALSE;
  14.576      }
  14.577  
  14.578      if (renderer) {
  14.579 +        VerifyDrawQueueFunctions(renderer);
  14.580 +
  14.581 +        /* let app/user override batching decisions. */
  14.582 +        if (renderer->always_batch) {
  14.583 +            batching = SDL_TRUE;
  14.584 +        } else if (SDL_GetHint(SDL_HINT_RENDER_BATCHING)) {
  14.585 +            batching = SDL_GetHintBoolean(SDL_HINT_RENDER_BATCHING, SDL_TRUE);
  14.586 +        }
  14.587 +
  14.588 +        renderer->batching = batching;
  14.589          renderer->magic = &renderer_magic;
  14.590          renderer->window = window;
  14.591          renderer->target_mutex = SDL_CreateMutex();
  14.592 @@ -377,6 +920,9 @@
  14.593          renderer->dpi_scale.x = 1.0f;
  14.594          renderer->dpi_scale.y = 1.0f;
  14.595  
  14.596 +        /* new textures start at zero, so we start at 1 so first render doesn't flush by accident. */
  14.597 +        renderer->render_command_generation = 1;
  14.598 +
  14.599          if (window && renderer->GetOutputSize) {
  14.600              int window_w, window_h;
  14.601              int output_w, output_h;
  14.602 @@ -418,11 +964,15 @@
  14.603      renderer = SW_CreateRendererForSurface(surface);
  14.604  
  14.605      if (renderer) {
  14.606 +        VerifyDrawQueueFunctions(renderer);
  14.607          renderer->magic = &renderer_magic;
  14.608          renderer->target_mutex = SDL_CreateMutex();
  14.609          renderer->scale.x = 1.0f;
  14.610          renderer->scale.y = 1.0f;
  14.611  
  14.612 +        /* new textures start at zero, so we start at 1 so first render doesn't flush by accident. */
  14.613 +        renderer->render_command_generation = 1;
  14.614 +
  14.615          SDL_RenderSetViewport(renderer, NULL);
  14.616      }
  14.617      return renderer;
  14.618 @@ -744,11 +1294,8 @@
  14.619  int
  14.620  SDL_SetTextureColorMod(SDL_Texture * texture, Uint8 r, Uint8 g, Uint8 b)
  14.621  {
  14.622 -    SDL_Renderer *renderer;
  14.623 -
  14.624      CHECK_TEXTURE_MAGIC(texture, -1);
  14.625  
  14.626 -    renderer = texture->renderer;
  14.627      if (r < 255 || g < 255 || b < 255) {
  14.628          texture->modMode |= SDL_TEXTUREMODULATE_COLOR;
  14.629      } else {
  14.630 @@ -759,11 +1306,8 @@
  14.631      texture->b = b;
  14.632      if (texture->native) {
  14.633          return SDL_SetTextureColorMod(texture->native, r, g, b);
  14.634 -    } else if (renderer->SetTextureColorMod) {
  14.635 -        return renderer->SetTextureColorMod(renderer, texture);
  14.636 -    } else {
  14.637 -        return 0;
  14.638      }
  14.639 +    return 0;
  14.640  }
  14.641  
  14.642  int
  14.643 @@ -787,11 +1331,8 @@
  14.644  int
  14.645  SDL_SetTextureAlphaMod(SDL_Texture * texture, Uint8 alpha)
  14.646  {
  14.647 -    SDL_Renderer *renderer;
  14.648 -
  14.649      CHECK_TEXTURE_MAGIC(texture, -1);
  14.650  
  14.651 -    renderer = texture->renderer;
  14.652      if (alpha < 255) {
  14.653          texture->modMode |= SDL_TEXTUREMODULATE_ALPHA;
  14.654      } else {
  14.655 @@ -800,11 +1341,8 @@
  14.656      texture->a = alpha;
  14.657      if (texture->native) {
  14.658          return SDL_SetTextureAlphaMod(texture->native, alpha);
  14.659 -    } else if (renderer->SetTextureAlphaMod) {
  14.660 -        return renderer->SetTextureAlphaMod(renderer, texture);
  14.661 -    } else {
  14.662 -        return 0;
  14.663      }
  14.664 +    return 0;
  14.665  }
  14.666  
  14.667  int
  14.668 @@ -832,11 +1370,8 @@
  14.669      texture->blendMode = blendMode;
  14.670      if (texture->native) {
  14.671          return SDL_SetTextureBlendMode(texture->native, blendMode);
  14.672 -    } else if (renderer->SetTextureBlendMode) {
  14.673 -        return renderer->SetTextureBlendMode(renderer, texture);
  14.674 -    } else {
  14.675 -        return 0;
  14.676      }
  14.677 +    return 0;
  14.678  }
  14.679  
  14.680  int
  14.681 @@ -941,7 +1476,6 @@
  14.682  SDL_UpdateTexture(SDL_Texture * texture, const SDL_Rect * rect,
  14.683                    const void *pixels, int pitch)
  14.684  {
  14.685 -    SDL_Renderer *renderer;
  14.686      SDL_Rect full_rect;
  14.687  
  14.688      CHECK_TEXTURE_MAGIC(texture, -1);
  14.689 @@ -968,7 +1502,10 @@
  14.690      } else if (texture->native) {
  14.691          return SDL_UpdateTextureNative(texture, rect, pixels, pitch);
  14.692      } else {
  14.693 -        renderer = texture->renderer;
  14.694 +        SDL_Renderer *renderer = texture->renderer;
  14.695 +        if (FlushRenderCommandsIfTextureNeeded(texture) < 0) {
  14.696 +            return -1;
  14.697 +        }
  14.698          return renderer->UpdateTexture(renderer, texture, rect, pixels, pitch);
  14.699      }
  14.700  }
  14.701 @@ -1078,6 +1615,9 @@
  14.702          renderer = texture->renderer;
  14.703          SDL_assert(renderer->UpdateTextureYUV);
  14.704          if (renderer->UpdateTextureYUV) {
  14.705 +            if (FlushRenderCommandsIfTextureNeeded(texture) < 0) {
  14.706 +                return -1;
  14.707 +            }
  14.708              return renderer->UpdateTextureYUV(renderer, texture, rect, Yplane, Ypitch, Uplane, Upitch, Vplane, Vpitch);
  14.709          } else {
  14.710              return SDL_Unsupported();
  14.711 @@ -1108,7 +1648,6 @@
  14.712  SDL_LockTexture(SDL_Texture * texture, const SDL_Rect * rect,
  14.713                  void **pixels, int *pitch)
  14.714  {
  14.715 -    SDL_Renderer *renderer;
  14.716      SDL_Rect full_rect;
  14.717  
  14.718      CHECK_TEXTURE_MAGIC(texture, -1);
  14.719 @@ -1126,11 +1665,18 @@
  14.720      }
  14.721  
  14.722      if (texture->yuv) {
  14.723 +        if (FlushRenderCommandsIfTextureNeeded(texture) < 0) {
  14.724 +            return -1;
  14.725 +        }
  14.726          return SDL_LockTextureYUV(texture, rect, pixels, pitch);
  14.727      } else if (texture->native) {
  14.728 +        /* Calls a real SDL_LockTexture/SDL_UnlockTexture on unlock, flushing then. */
  14.729          return SDL_LockTextureNative(texture, rect, pixels, pitch);
  14.730      } else {
  14.731 -        renderer = texture->renderer;
  14.732 +        SDL_Renderer *renderer = texture->renderer;
  14.733 +        if (FlushRenderCommandsIfTextureNeeded(texture) < 0) {
  14.734 +            return -1;
  14.735 +        }
  14.736          return renderer->LockTexture(renderer, texture, rect, pixels, pitch);
  14.737      }
  14.738  }
  14.739 @@ -1180,8 +1726,6 @@
  14.740  void
  14.741  SDL_UnlockTexture(SDL_Texture * texture)
  14.742  {
  14.743 -    SDL_Renderer *renderer;
  14.744 -
  14.745      CHECK_TEXTURE_MAGIC(texture, );
  14.746  
  14.747      if (texture->access != SDL_TEXTUREACCESS_STREAMING) {
  14.748 @@ -1192,7 +1736,7 @@
  14.749      } else if (texture->native) {
  14.750          SDL_UnlockTextureNative(texture);
  14.751      } else {
  14.752 -        renderer = texture->renderer;
  14.753 +        SDL_Renderer *renderer = texture->renderer;
  14.754          renderer->UnlockTexture(renderer, texture);
  14.755      }
  14.756  }
  14.757 @@ -1217,6 +1761,8 @@
  14.758          return 0;
  14.759      }
  14.760  
  14.761 +    FlushRenderCommands(renderer);  /* time to send everything to the GPU! */
  14.762 +
  14.763      /* texture == NULL is valid and means reset the target to the window */
  14.764      if (texture) {
  14.765          CHECK_TEXTURE_MAGIC(texture, -1);
  14.766 @@ -1272,15 +1818,15 @@
  14.767  
  14.768      SDL_UnlockMutex(renderer->target_mutex);
  14.769  
  14.770 -    if (renderer->UpdateViewport(renderer) < 0) {
  14.771 +    if (QueueCmdSetViewport(renderer) < 0) {
  14.772          return -1;
  14.773      }
  14.774 -    if (renderer->UpdateClipRect(renderer) < 0) {
  14.775 +    if (QueueCmdSetClipRect(renderer) < 0) {
  14.776          return -1;
  14.777      }
  14.778  
  14.779      /* All set! */
  14.780 -    return 0;
  14.781 +    return FlushRenderCommandsIfNotBatching(renderer);
  14.782  }
  14.783  
  14.784  SDL_Texture *
  14.785 @@ -1452,6 +1998,7 @@
  14.786  int
  14.787  SDL_RenderSetViewport(SDL_Renderer * renderer, const SDL_Rect * rect)
  14.788  {
  14.789 +    int retval;
  14.790      CHECK_RENDERER_MAGIC(renderer, -1);
  14.791  
  14.792      if (rect) {
  14.793 @@ -1466,7 +2013,8 @@
  14.794              return -1;
  14.795          }
  14.796      }
  14.797 -    return renderer->UpdateViewport(renderer);
  14.798 +    retval = QueueCmdSetViewport(renderer);
  14.799 +    return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
  14.800  }
  14.801  
  14.802  void
  14.803 @@ -1485,6 +2033,7 @@
  14.804  int
  14.805  SDL_RenderSetClipRect(SDL_Renderer * renderer, const SDL_Rect * rect)
  14.806  {
  14.807 +    int retval;
  14.808      CHECK_RENDERER_MAGIC(renderer, -1)
  14.809  
  14.810      if (rect) {
  14.811 @@ -1497,7 +2046,9 @@
  14.812          renderer->clipping_enabled = SDL_FALSE;
  14.813          SDL_zero(renderer->clip_rect);
  14.814      }
  14.815 -    return renderer->UpdateClipRect(renderer);
  14.816 +
  14.817 +    retval = QueueCmdSetClipRect(renderer);
  14.818 +    return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
  14.819  }
  14.820  
  14.821  void
  14.822 @@ -1601,37 +2152,43 @@
  14.823  int
  14.824  SDL_RenderClear(SDL_Renderer * renderer)
  14.825  {
  14.826 +    int retval;
  14.827      CHECK_RENDERER_MAGIC(renderer, -1);
  14.828 -
  14.829 -    /* Don't draw while we're hidden */
  14.830 -    if (renderer->hidden) {
  14.831 -        return 0;
  14.832 -    }
  14.833 -    return renderer->RenderClear(renderer);
  14.834 +    retval = QueueCmdClear(renderer);
  14.835 +    return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
  14.836  }
  14.837  
  14.838 +
  14.839 +/* !!! FIXME: delete all the duplicate code for the integer versions in 2.1,
  14.840 +   !!! FIXME:  making the floating point versions the only available APIs. */
  14.841 +
  14.842  int
  14.843  SDL_RenderDrawPoint(SDL_Renderer * renderer, int x, int y)
  14.844  {
  14.845 -    SDL_Point point;
  14.846 -
  14.847 -    point.x = x;
  14.848 -    point.y = y;
  14.849 -    return SDL_RenderDrawPoints(renderer, &point, 1);
  14.850 +    const SDL_FPoint fpoint = { (float) x, (float) y };
  14.851 +    return SDL_RenderDrawPointsF(renderer, &fpoint, 1);
  14.852 +}
  14.853 +
  14.854 +int
  14.855 +SDL_RenderDrawPointF(SDL_Renderer * renderer, float x, float y)
  14.856 +{
  14.857 +    const SDL_FPoint fpoint = { x, y };
  14.858 +    return SDL_RenderDrawPointsF(renderer, &fpoint, 1);
  14.859  }
  14.860  
  14.861  static int
  14.862  RenderDrawPointsWithRects(SDL_Renderer * renderer,
  14.863 -                     const SDL_Point * points, int count)
  14.864 +                          const SDL_Point * points, const int count)
  14.865  {
  14.866 -    SDL_FRect *frects;
  14.867 +    int retval = -1;
  14.868 +    SDL_bool isstack;
  14.869 +    SDL_FRect *frects = SDL_small_alloc(SDL_FRect, count, &isstack);
  14.870      int i;
  14.871 -    int status;
  14.872 -
  14.873 -    frects = SDL_stack_alloc(SDL_FRect, count);
  14.874 +
  14.875      if (!frects) {
  14.876          return SDL_OutOfMemory();
  14.877      }
  14.878 +
  14.879      for (i = 0; i < count; ++i) {
  14.880          frects[i].x = points[i].x * renderer->scale.x;
  14.881          frects[i].y = points[i].y * renderer->scale.y;
  14.882 @@ -1639,11 +2196,11 @@
  14.883          frects[i].h = renderer->scale.y;
  14.884      }
  14.885  
  14.886 -    status = renderer->RenderFillRects(renderer, frects, count);
  14.887 -
  14.888 -    SDL_stack_free(frects);
  14.889 -
  14.890 -    return status;
  14.891 +    retval = QueueCmdFillRects(renderer, frects, count);
  14.892 +
  14.893 +    SDL_small_free(frects, isstack);
  14.894 +
  14.895 +    return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
  14.896  }
  14.897  
  14.898  int
  14.899 @@ -1652,7 +2209,8 @@
  14.900  {
  14.901      SDL_FPoint *fpoints;
  14.902      int i;
  14.903 -    int status;
  14.904 +    int retval;
  14.905 +    SDL_bool isstack;
  14.906  
  14.907      CHECK_RENDERER_MAGIC(renderer, -1);
  14.908  
  14.909 @@ -1672,7 +2230,7 @@
  14.910          return RenderDrawPointsWithRects(renderer, points, count);
  14.911      }
  14.912  
  14.913 -    fpoints = SDL_stack_alloc(SDL_FPoint, count);
  14.914 +    fpoints = SDL_small_alloc(SDL_FPoint, count, &isstack);
  14.915      if (!fpoints) {
  14.916          return SDL_OutOfMemory();
  14.917      }
  14.918 @@ -1681,46 +2239,117 @@
  14.919          fpoints[i].y = points[i].y * renderer->scale.y;
  14.920      }
  14.921  
  14.922 -    status = renderer->RenderDrawPoints(renderer, fpoints, count);
  14.923 -
  14.924 -    SDL_stack_free(fpoints);
  14.925 -
  14.926 -    return status;
  14.927 +    retval = QueueCmdDrawPoints(renderer, fpoints, count);
  14.928 +
  14.929 +    SDL_small_free(fpoints, isstack);
  14.930 +
  14.931 +    return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
  14.932 +}
  14.933 +
  14.934 +static int
  14.935 +RenderDrawPointsWithRectsF(SDL_Renderer * renderer,
  14.936 +                           const SDL_FPoint * fpoints, const int count)
  14.937 +{
  14.938 +    int retval = -1;
  14.939 +    SDL_bool isstack;
  14.940 +    SDL_FRect *frects = SDL_small_alloc(SDL_FRect, count, &isstack);
  14.941 +    int i;
  14.942 +
  14.943 +    if (!frects) {
  14.944 +        return SDL_OutOfMemory();
  14.945 +    }
  14.946 +
  14.947 +    for (i = 0; i < count; ++i) {
  14.948 +        frects[i].x = fpoints[i].x * renderer->scale.x;
  14.949 +        frects[i].y = fpoints[i].y * renderer->scale.y;
  14.950 +        frects[i].w = renderer->scale.x;
  14.951 +        frects[i].h = renderer->scale.y;
  14.952 +    }
  14.953 +
  14.954 +    retval = QueueCmdFillRects(renderer, frects, count);
  14.955 +
  14.956 +    SDL_small_free(frects, isstack);
  14.957 +
  14.958 +    return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
  14.959 +}
  14.960 +
  14.961 +int
  14.962 +SDL_RenderDrawPointsF(SDL_Renderer * renderer,
  14.963 +                      const SDL_FPoint * points, int count)
  14.964 +{
  14.965 +    SDL_FPoint *fpoints;
  14.966 +    int i;
  14.967 +    int retval;
  14.968 +    SDL_bool isstack;
  14.969 +
  14.970 +    CHECK_RENDERER_MAGIC(renderer, -1);
  14.971 +
  14.972 +    if (!points) {
  14.973 +        return SDL_SetError("SDL_RenderDrawFPoints(): Passed NULL points");
  14.974 +    }
  14.975 +    if (count < 1) {
  14.976 +        return 0;
  14.977 +    }
  14.978 +
  14.979 +    /* Don't draw while we're hidden */
  14.980 +    if (renderer->hidden) {
  14.981 +        return 0;
  14.982 +    }
  14.983 +
  14.984 +    if (renderer->scale.x != 1.0f || renderer->scale.y != 1.0f) {
  14.985 +        return RenderDrawPointsWithRectsF(renderer, points, count);
  14.986 +    }
  14.987 +
  14.988 +    fpoints = SDL_small_alloc(SDL_FPoint, count, &isstack);
  14.989 +    if (!fpoints) {
  14.990 +        return SDL_OutOfMemory();
  14.991 +    }
  14.992 +    for (i = 0; i < count; ++i) {
  14.993 +        fpoints[i].x = points[i].x * renderer->scale.x;
  14.994 +        fpoints[i].y = points[i].y * renderer->scale.y;
  14.995 +    }
  14.996 +
  14.997 +    retval = QueueCmdDrawPoints(renderer, fpoints, count);
  14.998 +
  14.999 +    SDL_small_free(fpoints, isstack);
 14.1000 +
 14.1001 +    return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
 14.1002  }
 14.1003  
 14.1004  int
 14.1005  SDL_RenderDrawLine(SDL_Renderer * renderer, int x1, int y1, int x2, int y2)
 14.1006  {
 14.1007 -    SDL_Point points[2];
 14.1008 -
 14.1009 -    points[0].x = x1;
 14.1010 -    points[0].y = y1;
 14.1011 -    points[1].x = x2;
 14.1012 -    points[1].y = y2;
 14.1013 -    return SDL_RenderDrawLines(renderer, points, 2);
 14.1014 +    const SDL_FPoint points[2] = { { (float) x1, (float) y1 }, { (float) x2, (float) y2 } };
 14.1015 +    return SDL_RenderDrawLinesF(renderer, points, 2);
 14.1016 +}
 14.1017 +
 14.1018 +int
 14.1019 +SDL_RenderDrawLineF(SDL_Renderer * renderer, float x1, float y1, float x2, float y2)
 14.1020 +{
 14.1021 +    const SDL_FPoint points[2] = { { x1, y1 }, { x2, y2 } };
 14.1022 +    return SDL_RenderDrawLinesF(renderer, points, 2);
 14.1023  }
 14.1024  
 14.1025  static int
 14.1026  RenderDrawLinesWithRects(SDL_Renderer * renderer,
 14.1027 -                     const SDL_Point * points, int count)
 14.1028 +                     const SDL_Point * points, const int count)
 14.1029  {
 14.1030      SDL_FRect *frect;
 14.1031      SDL_FRect *frects;
 14.1032      SDL_FPoint fpoints[2];
 14.1033 -    int i, nrects;
 14.1034 -    int status;
 14.1035 -
 14.1036 -    frects = SDL_stack_alloc(SDL_FRect, count-1);
 14.1037 +    int i, nrects = 0;
 14.1038 +    int retval = 0;
 14.1039 +    SDL_bool isstack;
 14.1040 +
 14.1041 +    frects = SDL_small_alloc(SDL_FRect, count-1, &isstack);
 14.1042      if (!frects) {
 14.1043          return SDL_OutOfMemory();
 14.1044      }
 14.1045  
 14.1046 -    status = 0;
 14.1047 -    nrects = 0;
 14.1048      for (i = 0; i < count-1; ++i) {
 14.1049          if (points[i].x == points[i+1].x) {
 14.1050 -            int minY = SDL_min(points[i].y, points[i+1].y);
 14.1051 -            int maxY = SDL_max(points[i].y, points[i+1].y);
 14.1052 +            const int minY = SDL_min(points[i].y, points[i+1].y);
 14.1053 +            const int maxY = SDL_max(points[i].y, points[i+1].y);
 14.1054  
 14.1055              frect = &frects[nrects++];
 14.1056              frect->x = points[i].x * renderer->scale.x;
 14.1057 @@ -1728,8 +2357,8 @@
 14.1058              frect->w = renderer->scale.x;
 14.1059              frect->h = (maxY - minY + 1) * renderer->scale.y;
 14.1060          } else if (points[i].y == points[i+1].y) {
 14.1061 -            int minX = SDL_min(points[i].x, points[i+1].x);
 14.1062 -            int maxX = SDL_max(points[i].x, points[i+1].x);
 14.1063 +            const int minX = SDL_min(points[i].x, points[i+1].x);
 14.1064 +            const int maxX = SDL_max(points[i].x, points[i+1].x);
 14.1065  
 14.1066              frect = &frects[nrects++];
 14.1067              frect->x = minX * renderer->scale.x;
 14.1068 @@ -1742,18 +2371,73 @@
 14.1069              fpoints[0].y = points[i].y * renderer->scale.y;
 14.1070              fpoints[1].x = points[i+1].x * renderer->scale.x;
 14.1071              fpoints[1].y = points[i+1].y * renderer->scale.y;
 14.1072 -            status += renderer->RenderDrawLines(renderer, fpoints, 2);
 14.1073 +            retval += QueueCmdDrawLines(renderer, fpoints, 2);
 14.1074          }
 14.1075      }
 14.1076  
 14.1077 -    status += renderer->RenderFillRects(renderer, frects, nrects);
 14.1078 -
 14.1079 -    SDL_stack_free(frects);
 14.1080 -
 14.1081 -    if (status < 0) {
 14.1082 -        status = -1;
 14.1083 +    retval += QueueCmdFillRects(renderer, frects, nrects);
 14.1084 +
 14.1085 +    SDL_small_free(frects, isstack);
 14.1086 +
 14.1087 +    if (retval < 0) {
 14.1088 +        retval = -1;
 14.1089      }
 14.1090 -    return status;
 14.1091 +    return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
 14.1092 +}
 14.1093 +
 14.1094 +static int
 14.1095 +RenderDrawLinesWithRectsF(SDL_Renderer * renderer,
 14.1096 +                          const SDL_FPoint * points, const int count)
 14.1097 +{
 14.1098 +    SDL_FRect *frect;
 14.1099 +    SDL_FRect *frects;
 14.1100 +    SDL_FPoint fpoints[2];
 14.1101 +    int i, nrects = 0;
 14.1102 +    int retval = 0;
 14.1103 +    SDL_bool isstack;
 14.1104 +
 14.1105 +    frects = SDL_small_alloc(SDL_FRect, count-1, &isstack);
 14.1106 +    if (!frects) {
 14.1107 +        return SDL_OutOfMemory();
 14.1108 +    }
 14.1109 +
 14.1110 +    for (i = 0; i < count-1; ++i) {
 14.1111 +        if (points[i].x == points[i+1].x) {
 14.1112 +            const int minY = SDL_min(points[i].y, points[i+1].y);
 14.1113 +            const int maxY = SDL_max(points[i].y, points[i+1].y);
 14.1114 +
 14.1115 +            frect = &frects[nrects++];
 14.1116 +            frect->x = points[i].x * renderer->scale.x;
 14.1117 +            frect->y = minY * renderer->scale.y;
 14.1118 +            frect->w = renderer->scale.x;
 14.1119 +            frect->h = (maxY - minY + 1) * renderer->scale.y;
 14.1120 +        } else if (points[i].y == points[i+1].y) {
 14.1121 +            const int minX = SDL_min(points[i].x, points[i+1].x);
 14.1122 +            const int maxX = SDL_max(points[i].x, points[i+1].x);
 14.1123 +
 14.1124 +            frect = &frects[nrects++];
 14.1125 +            frect->x = minX * renderer->scale.x;
 14.1126 +            frect->y = points[i].y * renderer->scale.y;
 14.1127 +            frect->w = (maxX - minX + 1) * renderer->scale.x;
 14.1128 +            frect->h = renderer->scale.y;
 14.1129 +        } else {
 14.1130 +            /* FIXME: We can't use a rect for this line... */
 14.1131 +            fpoints[0].x = points[i].x * renderer->scale.x;
 14.1132 +            fpoints[0].y = points[i].y * renderer->scale.y;
 14.1133 +            fpoints[1].x = points[i+1].x * renderer->scale.x;
 14.1134 +            fpoints[1].y = points[i+1].y * renderer->scale.y;
 14.1135 +            retval += QueueCmdDrawLines(renderer, fpoints, 2);
 14.1136 +        }
 14.1137 +    }
 14.1138 +
 14.1139 +    retval += QueueCmdFillRects(renderer, frects, nrects);
 14.1140 +
 14.1141 +    SDL_small_free(frects, isstack);
 14.1142 +
 14.1143 +    if (retval < 0) {
 14.1144 +        retval = -1;
 14.1145 +    }
 14.1146 +    return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
 14.1147  }
 14.1148  
 14.1149  int
 14.1150 @@ -1762,7 +2446,8 @@
 14.1151  {
 14.1152      SDL_FPoint *fpoints;
 14.1153      int i;
 14.1154 -    int status;
 14.1155 +    int retval;
 14.1156 +    SDL_bool isstack;
 14.1157  
 14.1158      CHECK_RENDERER_MAGIC(renderer, -1);
 14.1159  
 14.1160 @@ -1782,7 +2467,7 @@
 14.1161          return RenderDrawLinesWithRects(renderer, points, count);
 14.1162      }
 14.1163  
 14.1164 -    fpoints = SDL_stack_alloc(SDL_FPoint, count);
 14.1165 +    fpoints = SDL_small_alloc(SDL_FPoint, count, &isstack);
 14.1166      if (!fpoints) {
 14.1167          return SDL_OutOfMemory();
 14.1168      }
 14.1169 @@ -1791,27 +2476,90 @@
 14.1170          fpoints[i].y = points[i].y * renderer->scale.y;
 14.1171      }
 14.1172  
 14.1173 -    status = renderer->RenderDrawLines(renderer, fpoints, count);
 14.1174 -
 14.1175 -    SDL_stack_free(fpoints);
 14.1176 -
 14.1177 -    return status;
 14.1178 +    retval = QueueCmdDrawLines(renderer, fpoints, count);
 14.1179 +
 14.1180 +    SDL_small_free(fpoints, isstack);
 14.1181 +
 14.1182 +    return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
 14.1183 +}
 14.1184 +
 14.1185 +int
 14.1186 +SDL_RenderDrawLinesF(SDL_Renderer * renderer,
 14.1187 +                     const SDL_FPoint * points, int count)
 14.1188 +{
 14.1189 +    SDL_FPoint *fpoints;
 14.1190 +    int i;
 14.1191 +    int retval;
 14.1192 +    SDL_bool isstack;
 14.1193 +
 14.1194 +    CHECK_RENDERER_MAGIC(renderer, -1);
 14.1195 +
 14.1196 +    if (!points) {
 14.1197 +        return SDL_SetError("SDL_RenderDrawLines(): Passed NULL points");
 14.1198 +    }
 14.1199 +    if (count < 2) {
 14.1200 +        return 0;
 14.1201 +    }
 14.1202 +
 14.1203 +    /* Don't draw while we're hidden */
 14.1204 +    if (renderer->hidden) {
 14.1205 +        return 0;
 14.1206 +    }
 14.1207 +
 14.1208 +    if (renderer->scale.x != 1.0f || renderer->scale.y != 1.0f) {
 14.1209 +        return RenderDrawLinesWithRectsF(renderer, points, count);
 14.1210 +    }
 14.1211 +
 14.1212 +    fpoints = SDL_small_alloc(SDL_FPoint, count, &isstack);
 14.1213 +    if (!fpoints) {
 14.1214 +        return SDL_OutOfMemory();
 14.1215 +    }
 14.1216 +    for (i = 0; i < count; ++i) {
 14.1217 +        fpoints[i].x = points[i].x * renderer->scale.x;
 14.1218 +        fpoints[i].y = points[i].y * renderer->scale.y;
 14.1219 +    }
 14.1220 +
 14.1221 +    retval = QueueCmdDrawLines(renderer, fpoints, count);
 14.1222 +
 14.1223 +    SDL_small_free(fpoints, isstack);
 14.1224 +
 14.1225 +    return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
 14.1226  }
 14.1227  
 14.1228  int
 14.1229  SDL_RenderDrawRect(SDL_Renderer * renderer, const SDL_Rect * rect)
 14.1230  {
 14.1231 -    SDL_Rect full_rect;
 14.1232 -    SDL_Point points[5];
 14.1233 +    SDL_FRect frect;
 14.1234 +    SDL_FRect *prect = NULL;
 14.1235 +
 14.1236 +    if (rect) {
 14.1237 +        frect.x = (float) rect->x;
 14.1238 +        frect.y = (float) rect->y;
 14.1239 +        frect.w = (float) rect->w;
 14.1240 +        frect.h = (float) rect->h;
 14.1241 +        prect = &frect;
 14.1242 +    }
 14.1243 +
 14.1244 +    return SDL_RenderDrawRectF(renderer, prect);
 14.1245 +}
 14.1246 +
 14.1247 +int
 14.1248 +SDL_RenderDrawRectF(SDL_Renderer * renderer, const SDL_FRect * rect)
 14.1249 +{
 14.1250 +    SDL_FRect frect;
 14.1251 +    SDL_FPoint points[5];
 14.1252  
 14.1253      CHECK_RENDERER_MAGIC(renderer, -1);
 14.1254  
 14.1255      /* If 'rect' == NULL, then outline the whole surface */
 14.1256      if (!rect) {
 14.1257 -        SDL_RenderGetViewport(renderer, &full_rect);
 14.1258 -        full_rect.x = 0;
 14.1259 -        full_rect.y = 0;
 14.1260 -        rect = &full_rect;
 14.1261 +        SDL_Rect r;
 14.1262 +        SDL_RenderGetViewport(renderer, &r);
 14.1263 +        frect.x = 0.0f;
 14.1264 +        frect.y = 0.0f;
 14.1265 +        frect.w = (float) r.w;
 14.1266 +        frect.h = (float) r.h;
 14.1267 +        rect = &frect;
 14.1268      }
 14.1269  
 14.1270      points[0].x = rect->x;
 14.1271 @@ -1824,7 +2572,7 @@
 14.1272      points[3].y = rect->y+rect->h-1;
 14.1273      points[4].x = rect->x;
 14.1274      points[4].y = rect->y;
 14.1275 -    return SDL_RenderDrawLines(renderer, points, 5);
 14.1276 +    return SDL_RenderDrawLinesF(renderer, points, 5);
 14.1277  }
 14.1278  
 14.1279  int
 14.1280 @@ -1856,20 +2604,75 @@
 14.1281  }
 14.1282  
 14.1283  int
 14.1284 +SDL_RenderDrawRectsF(SDL_Renderer * renderer,
 14.1285 +                     const SDL_FRect * rects, int count)
 14.1286 +{
 14.1287 +    int i;
 14.1288 +
 14.1289 +    CHECK_RENDERER_MAGIC(renderer, -1);
 14.1290 +
 14.1291 +    if (!rects) {
 14.1292 +        return SDL_SetError("SDL_RenderDrawRects(): Passed NULL rects");
 14.1293 +    }
 14.1294 +    if (count < 1) {
 14.1295 +        return 0;
 14.1296 +    }
 14.1297 +
 14.1298 +    /* Don't draw while we're hidden */
 14.1299 +    if (renderer->hidden) {
 14.1300 +        return 0;
 14.1301 +    }
 14.1302 +
 14.1303 +    for (i = 0; i < count; ++i) {
 14.1304 +        if (SDL_RenderDrawRectF(renderer, &rects[i]) < 0) {
 14.1305 +            return -1;
 14.1306 +        }
 14.1307 +    }
 14.1308 +    return 0;
 14.1309 +}
 14.1310 +
 14.1311 +int
 14.1312  SDL_RenderFillRect(SDL_Renderer * renderer, const SDL_Rect * rect)
 14.1313  {
 14.1314 -    SDL_Rect full_rect = { 0, 0, 0, 0 };
 14.1315 +    SDL_FRect frect;
 14.1316 +
 14.1317 +    CHECK_RENDERER_MAGIC(renderer, -1);
 14.1318 +
 14.1319 +    /* If 'rect' == NULL, then outline the whole surface */
 14.1320 +    if (rect) {
 14.1321 +        frect.x = (float) rect->x;
 14.1322 +        frect.y = (float) rect->y;
 14.1323 +        frect.w = (float) rect->w;
 14.1324 +        frect.h = (float) rect->h;
 14.1325 +    } else {
 14.1326 +        SDL_Rect r;
 14.1327 +        SDL_RenderGetViewport(renderer, &r);
 14.1328 +        frect.x = 0.0f;
 14.1329 +        frect.y = 0.0f;
 14.1330 +        frect.w = (float) r.w;
 14.1331 +        frect.h = (float) r.h;
 14.1332 +    }
 14.1333 +    return SDL_RenderFillRectsF(renderer, &frect, 1);
 14.1334 +}
 14.1335 +
 14.1336 +int
 14.1337 +SDL_RenderFillRectF(SDL_Renderer * renderer, const SDL_FRect * rect)
 14.1338 +{
 14.1339 +    SDL_FRect frect;
 14.1340  
 14.1341      CHECK_RENDERER_MAGIC(renderer, -1);
 14.1342  
 14.1343      /* If 'rect' == NULL, then outline the whole surface */
 14.1344      if (!rect) {
 14.1345 -        SDL_RenderGetViewport(renderer, &full_rect);
 14.1346 -        full_rect.x = 0;
 14.1347 -        full_rect.y = 0;
 14.1348 -        rect = &full_rect;
 14.1349 +        SDL_Rect r;
 14.1350 +        SDL_RenderGetViewport(renderer, &r);
 14.1351 +        frect.x = 0.0f;
 14.1352 +        frect.y = 0.0f;
 14.1353 +        frect.w = (float) r.w;
 14.1354 +        frect.h = (float) r.h;
 14.1355 +        rect = &frect;
 14.1356      }
 14.1357 -    return SDL_RenderFillRects(renderer, rect, 1);
 14.1358 +    return SDL_RenderFillRectsF(renderer, rect, 1);
 14.1359  }
 14.1360  
 14.1361  int
 14.1362 @@ -1878,7 +2681,8 @@
 14.1363  {
 14.1364      SDL_FRect *frects;
 14.1365      int i;
 14.1366 -    int status;
 14.1367 +    int retval;
 14.1368 +    SDL_bool isstack;
 14.1369  
 14.1370      CHECK_RENDERER_MAGIC(renderer, -1);
 14.1371  
 14.1372 @@ -1894,7 +2698,7 @@
 14.1373          return 0;
 14.1374      }
 14.1375  
 14.1376 -    frects = SDL_stack_alloc(SDL_FRect, count);
 14.1377 +    frects = SDL_small_alloc(SDL_FRect, count, &isstack);
 14.1378      if (!frects) {
 14.1379          return SDL_OutOfMemory();
 14.1380      }
 14.1381 @@ -1905,20 +2709,132 @@
 14.1382          frects[i].h = rects[i].h * renderer->scale.y;
 14.1383      }
 14.1384  
 14.1385 -    status = renderer->RenderFillRects(renderer, frects, count);
 14.1386 -
 14.1387 -    SDL_stack_free(frects);
 14.1388 -
 14.1389 -    return status;
 14.1390 +    retval = QueueCmdFillRects(renderer, frects, count);
 14.1391 +
 14.1392 +    SDL_small_free(frects, isstack);
 14.1393 +
 14.1394 +    return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
 14.1395 +}
 14.1396 +
 14.1397 +int
 14.1398 +SDL_RenderFillRectsF(SDL_Renderer * renderer,
 14.1399 +                     const SDL_FRect * rects, int count)
 14.1400 +{
 14.1401 +    SDL_FRect *frects;
 14.1402 +    int i;
 14.1403 +    int retval;
 14.1404 +    SDL_bool isstack;
 14.1405 +
 14.1406 +    CHECK_RENDERER_MAGIC(renderer, -1);
 14.1407 +
 14.1408 +    if (!rects) {
 14.1409 +        return SDL_SetError("SDL_RenderFillFRects(): Passed NULL rects");
 14.1410 +    }
 14.1411 +    if (count < 1) {
 14.1412 +        return 0;
 14.1413 +    }
 14.1414 +
 14.1415 +    /* Don't draw while we're hidden */
 14.1416 +    if (renderer->hidden) {
 14.1417 +        return 0;
 14.1418 +    }
 14.1419 +
 14.1420 +    frects = SDL_small_alloc(SDL_FRect, count, &isstack);
 14.1421 +    if (!frects) {
 14.1422 +        return SDL_OutOfMemory();
 14.1423 +    }
 14.1424 +    for (i = 0; i < count; ++i) {
 14.1425 +        frects[i].x = rects[i].x * renderer->scale.x;
 14.1426 +        frects[i].y = rects[i].y * renderer->scale.y;
 14.1427 +        frects[i].w = rects[i].w * renderer->scale.x;
 14.1428 +        frects[i].h = rects[i].h * renderer->scale.y;
 14.1429 +    }
 14.1430 +
 14.1431 +    retval = QueueCmdFillRects(renderer, frects, count);
 14.1432 +
 14.1433 +    SDL_small_free(frects, isstack);
 14.1434 +
 14.1435 +    return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
 14.1436 +}
 14.1437 +
 14.1438 +/* !!! FIXME: move this to a public API if we want to do float versions of all of these later */
 14.1439 +SDL_FORCE_INLINE SDL_bool SDL_FRectEmpty(const SDL_FRect *r)
 14.1440 +{
 14.1441 +    return ((!r) || (r->w <= 0.0f) || (r->h <= 0.0f)) ? SDL_TRUE : SDL_FALSE;
 14.1442 +}
 14.1443 +
 14.1444 +/* !!! FIXME: move this to a public API if we want to do float versions of all of these later */
 14.1445 +static SDL_bool
 14.1446 +SDL_HasIntersectionF(const SDL_FRect * A, const SDL_FRect * B)
 14.1447 +{
 14.1448 +    float Amin, Amax, Bmin, Bmax;
 14.1449 +
 14.1450 +    if (!A) {
 14.1451 +        SDL_InvalidParamError("A");
 14.1452 +        return SDL_FALSE;
 14.1453 +    }
 14.1454 +
 14.1455 +    if (!B) {
 14.1456 +        SDL_InvalidParamError("B");
 14.1457 +        return SDL_FALSE;
 14.1458 +    }
 14.1459 +
 14.1460 +    /* Special cases for empty rects */
 14.1461 +    if (SDL_FRectEmpty(A) || SDL_FRectEmpty(B)) {
 14.1462 +        return SDL_FALSE;
 14.1463 +    }
 14.1464 +
 14.1465 +    /* Horizontal intersection */
 14.1466 +    Amin = A->x;
 14.1467 +    Amax = Amin + A->w;
 14.1468 +    Bmin = B->x;
 14.1469 +    Bmax = Bmin + B->w;
 14.1470 +    if (Bmin > Amin)
 14.1471 +        Amin = Bmin;
 14.1472 +    if (Bmax < Amax)
 14.1473 +        Amax = Bmax;
 14.1474 +    if (Amax <= Amin)
 14.1475 +        return SDL_FALSE;
 14.1476 +
 14.1477 +    /* Vertical intersection */
 14.1478 +    Amin = A->y;
 14.1479 +    Amax = Amin + A->h;
 14.1480 +    Bmin = B->y;
 14.1481 +    Bmax = Bmin + B->h;
 14.1482 +    if (Bmin > Amin)
 14.1483 +        Amin = Bmin;
 14.1484 +    if (Bmax < Amax)
 14.1485 +        Amax = Bmax;
 14.1486 +    if (Amax <= Amin)
 14.1487 +        return SDL_FALSE;
 14.1488 +
 14.1489 +    return SDL_TRUE;
 14.1490  }
 14.1491  
 14.1492  int
 14.1493  SDL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
 14.1494                 const SDL_Rect * srcrect, const SDL_Rect * dstrect)
 14.1495  {
 14.1496 -    SDL_Rect real_srcrect = { 0, 0, 0, 0 };
 14.1497 -    SDL_Rect real_dstrect = { 0, 0, 0, 0 };
 14.1498 -    SDL_FRect frect;
 14.1499 +    SDL_FRect dstfrect;
 14.1500 +    SDL_FRect *pdstfrect = NULL;
 14.1501 +    if (dstrect) {
 14.1502 +        dstfrect.x = (float) dstrect->x;
 14.1503 +        dstfrect.y = (float) dstrect->y;
 14.1504 +        dstfrect.w = (float) dstrect->w;
 14.1505 +        dstfrect.h = (float) dstrect->h;
 14.1506 +        pdstfrect = &dstfrect;
 14.1507 +    }
 14.1508 +    return SDL_RenderCopyF(renderer, texture, srcrect, pdstfrect);
 14.1509 +}
 14.1510 +
 14.1511 +int
 14.1512 +SDL_RenderCopyF(SDL_Renderer * renderer, SDL_Texture * texture,
 14.1513 +                const SDL_Rect * srcrect, const SDL_FRect * dstrect)
 14.1514 +{
 14.1515 +    SDL_Rect real_srcrect;
 14.1516 +    SDL_FRect real_dstrect;
 14.1517 +    SDL_Rect r;
 14.1518 +    int retval;
 14.1519  
 14.1520      CHECK_RENDERER_MAGIC(renderer, -1);
 14.1521      CHECK_TEXTURE_MAGIC(texture, -1);
 14.1522 @@ -1942,11 +2858,13 @@
 14.1523          }
 14.1524      }
 14.1525  
 14.1526 -    SDL_RenderGetViewport(renderer, &real_dstrect);
 14.1527 -    real_dstrect.x = 0;
 14.1528 -    real_dstrect.y = 0;
 14.1529 +    SDL_RenderGetViewport(renderer, &r);
 14.1530 +    real_dstrect.x = 0.0f;
 14.1531 +    real_dstrect.y = 0.0f;
 14.1532 +    real_dstrect.w = (float) r.w;
 14.1533 +    real_dstrect.h = (float) r.h;
 14.1534      if (dstrect) {
 14.1535 -        if (!SDL_HasIntersection(dstrect, &real_dstrect)) {
 14.1536 +        if (!SDL_HasIntersectionF(dstrect, &real_dstrect)) {
 14.1537              return 0;
 14.1538          }
 14.1539          real_dstrect = *dstrect;
 14.1540 @@ -1956,28 +2874,56 @@
 14.1541          texture = texture->native;
 14.1542      }
 14.1543  
 14.1544 -    frect.x = real_dstrect.x * renderer->scale.x;
 14.1545 -    frect.y = real_dstrect.y * renderer->scale.y;
 14.1546 -    frect.w = real_dstrect.w * renderer->scale.x;
 14.1547 -    frect.h = real_dstrect.h * renderer->scale.y;
 14.1548 -
 14.1549 -    return renderer->RenderCopy(renderer, texture, &real_srcrect, &frect);
 14.1550 +    real_dstrect.x *= renderer->scale.x;
 14.1551 +    real_dstrect.y *= renderer->scale.y;
 14.1552 +    real_dstrect.w *= renderer->scale.x;
 14.1553 +    real_dstrect.h *= renderer->scale.y;
 14.1554 +
 14.1555 +    texture->last_command_generation = renderer->render_command_generation;
 14.1556 +
 14.1557 +    retval = QueueCmdCopy(renderer, texture, &real_srcrect, &real_dstrect);
 14.1558 +    return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
 14.1559  }
 14.1560  
 14.1561 -
 14.1562  int
 14.1563  SDL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
 14.1564                 const SDL_Rect * srcrect, const SDL_Rect * dstrect,
 14.1565                 const double angle, const SDL_Point *center, const SDL_RendererFlip flip)
 14.1566  {
 14.1567 -    SDL_Rect real_srcrect = { 0, 0, 0, 0 };
 14.1568 -    SDL_Rect real_dstrect = { 0, 0, 0, 0 };
 14.1569 -    SDL_Point real_center;
 14.1570 -    SDL_FRect frect;
 14.1571 +    SDL_FRect dstfrect;
 14.1572 +    SDL_FRect *pdstfrect = NULL;
 14.1573      SDL_FPoint fcenter;
 14.1574 +    SDL_FPoint *pfcenter = NULL;
 14.1575 +
 14.1576 +    if (dstrect) {
 14.1577 +        dstfrect.x = (float) dstrect->x;
 14.1578 +        dstfrect.y = (float) dstrect->y;
 14.1579 +        dstfrect.w = (float) dstrect->w;
 14.1580 +        dstfrect.h = (float) dstrect->h;
 14.1581 +        pdstfrect = &dstfrect;
 14.1582 +    }
 14.1583 +
 14.1584 +    if (center) {
 14.1585 +        fcenter.x = (float) center->x;
 14.1586 +        fcenter.y = (float) center->y;
 14.1587 +        pfcenter = &fcenter;
 14.1588 +    }
 14.1589 +
 14.1590 +    return SDL_RenderCopyExF(renderer, texture, srcrect, pdstfrect, angle, pfcenter, flip);
 14.1591 +}
 14.1592 +
 14.1593 +int
 14.1594 +SDL_RenderCopyExF(SDL_Renderer * renderer, SDL_Texture * texture,
 14.1595 +               const SDL_Rect * srcrect, const SDL_FRect * dstrect,
 14.1596 +               const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
 14.1597 +{
 14.1598 +    SDL_Rect real_srcrect;
 14.1599 +    SDL_FRect real_dstrect;
 14.1600 +    SDL_FPoint real_center;
 14.1601 +    int retval;
 14.1602  
 14.1603      if (flip == SDL_FLIP_NONE && (int)(angle/360) == angle/360) { /* fast path when we don't need rotation or flipping */
 14.1604 -        return SDL_RenderCopy(renderer, texture, srcrect, dstrect);
 14.1605 +        return SDL_RenderCopyF(renderer, texture, srcrect, dstrect);
 14.1606      }
 14.1607  
 14.1608      CHECK_RENDERER_MAGIC(renderer, -1);
 14.1609 @@ -1986,7 +2932,7 @@
 14.1610      if (renderer != texture->renderer) {
 14.1611          return SDL_SetError("Texture was not created with this renderer");
 14.1612      }
 14.1613 -    if (!renderer->RenderCopyEx) {
 14.1614 +    if (!renderer->QueueCopyEx) {
 14.1615          return SDL_SetError("Renderer does not support RenderCopyEx");
 14.1616      }
 14.1617  
 14.1618 @@ -2009,9 +2955,12 @@
 14.1619      if (dstrect) {
 14.1620          real_dstrect = *dstrect;
 14.1621      } else {
 14.1622 -        SDL_RenderGetViewport(renderer, &real_dstrect);
 14.1623 -        real_dstrect.x = 0;
 14.1624 -        real_dstrect.y = 0;
 14.1625 +        SDL_Rect r;
 14.1626 +        SDL_RenderGetViewport(renderer, &r);
 14.1627 +        real_dstrect.x = 0.0f;
 14.1628 +        real_dstrect.y = 0.0f;
 14.1629 +        real_dstrect.w = (float) r.w;
 14.1630 +        real_dstrect.h = (float) r.h;
 14.1631      }
 14.1632  
 14.1633      if (texture->native) {
 14.1634 @@ -2021,19 +2970,22 @@
 14.1635      if (center) {
 14.1636          real_center = *center;
 14.1637      } else {
 14.1638 -        real_center.x = real_dstrect.w/2;
 14.1639 -        real_center.y = real_dstrect.h/2;
 14.1640 +        real_center.x = real_dstrect.w / 2.0f;
 14.1641 +        real_center.y = real_dstrect.h / 2.0f;
 14.1642      }
 14.1643  
 14.1644 -    frect.x = real_dstrect.x * renderer->scale.x;
 14.1645 -    frect.y = real_dstrect.y * renderer->scale.y;
 14.1646 -    frect.w = real_dstrect.w * renderer->scale.x;
 14.1647 -    frect.h = real_dstrect.h * renderer->scale.y;
 14.1648 -
 14.1649 -    fcenter.x = real_center.x * renderer->scale.x;
 14.1650 -    fcenter.y = real_center.y * renderer->scale.y;
 14.1651 -
 14.1652 -    return renderer->RenderCopyEx(renderer, texture, &real_srcrect, &frect, angle, &fcenter, flip);
 14.1653 +    real_dstrect.x *= renderer->scale.x;
 14.1654 +    real_dstrect.y *= renderer->scale.y;
 14.1655 +    real_dstrect.w *= renderer->scale.x;
 14.1656 +    real_dstrect.h *= renderer->scale.y;
 14.1657 +
 14.1658 +    real_center.x *= renderer->scale.x;
 14.1659 +    real_center.y *= renderer->scale.y;
 14.1660 +
 14.1661 +    texture->last_command_generation = renderer->render_command_generation;
 14.1662 +
 14.1663 +    retval = QueueCmdCopyEx(renderer, texture, &real_srcrect, &real_dstrect, angle, &real_center, flip);
 14.1664 +    return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
 14.1665  }
 14.1666  
 14.1667  int
 14.1668 @@ -2048,6 +3000,8 @@
 14.1669          return SDL_Unsupported();
 14.1670      }
 14.1671  
 14.1672 +    FlushRenderCommands(renderer);  /* we need to render before we read the results. */
 14.1673 +
 14.1674      if (!format) {
 14.1675          format = SDL_GetWindowPixelFormat(renderer->window);
 14.1676      }
 14.1677 @@ -2078,7 +3032,9 @@
 14.1678  {
 14.1679      CHECK_RENDERER_MAGIC(renderer, );
 14.1680  
 14.1681 -    /* Don't draw while we're hidden */
 14.1682 +    FlushRenderCommands(renderer);  /* time to send everything to the GPU! */
 14.1683 +
 14.1684 +    /* Don't present while we're hidden */
 14.1685      if (renderer->hidden) {
 14.1686          return;
 14.1687      }
 14.1688 @@ -2094,7 +3050,9 @@
 14.1689  
 14.1690      renderer = texture->renderer;
 14.1691      if (texture == renderer->target) {
 14.1692 -        SDL_SetRenderTarget(renderer, NULL);
 14.1693 +        SDL_SetRenderTarget(renderer, NULL);  /* implies command queue flush */
 14.1694 +    } else {
 14.1695 +        FlushRenderCommandsIfTextureNeeded(texture);
 14.1696      }
 14.1697  
 14.1698      texture->magic = NULL;
 14.1699 @@ -2123,10 +3081,43 @@
 14.1700  void
 14.1701  SDL_DestroyRenderer(SDL_Renderer * renderer)
 14.1702  {
 14.1703 +    SDL_RenderCommand *cmd;
 14.1704 +    SDL_AllocVertGap *gap;
 14.1705 +    SDL_AllocVertGap *nextgap;
 14.1706 +
 14.1707      CHECK_RENDERER_MAGIC(renderer, );
 14.1708  
 14.1709      SDL_DelEventWatch(SDL_RendererEventWatch, renderer);
 14.1710  
 14.1711 +    if (renderer->render_commands_tail != NULL) {
 14.1712 +        renderer->render_commands_tail->next = renderer->render_commands_pool;
 14.1713 +        cmd = renderer->render_commands;
 14.1714 +    } else {
 14.1715 +        cmd = renderer->render_commands_pool;
 14.1716 +    }
 14.1717 +
 14.1718 +    renderer->render_commands_pool = NULL;
 14.1719 +    renderer->render_commands_tail = NULL;
 14.1720 +    renderer->render_commands = NULL;
 14.1721 +
 14.1722 +    while (cmd != NULL) {
 14.1723 +        SDL_RenderCommand *next = cmd->next;
 14.1724 +        SDL_free(cmd);
 14.1725 +        cmd = next;
 14.1726 +    }
 14.1727 +
 14.1728 +    SDL_free(renderer->vertex_data);
 14.1729 +
 14.1730 +    for (gap = renderer->vertex_data_gaps.next; gap; gap = nextgap) {
 14.1731 +        nextgap = gap->next;
 14.1732 +        SDL_free(gap);
 14.1733 +    }
 14.1734 +
 14.1735 +    for (gap = renderer->vertex_data_gaps_pool; gap; gap = nextgap) {
 14.1736 +        nextgap = gap->next;
 14.1737 +        SDL_free(gap);
 14.1738 +    }
 14.1739 +
 14.1740      /* Free existing textures for this renderer */
 14.1741      while (renderer->textures) {
 14.1742          SDL_Texture *tex = renderer->textures; (void) tex;
 14.1743 @@ -2158,6 +3149,7 @@
 14.1744      if (texture->native) {
 14.1745          return SDL_GL_BindTexture(texture->native, texw, texh);
 14.1746      } else if (renderer && renderer->GL_BindTexture) {
 14.1747 +        FlushRenderCommandsIfTextureNeeded(texture);  /* in case the app is going to mess with it. */
 14.1748          return renderer->GL_BindTexture(renderer, texture, texw, texh);
 14.1749      } else {
 14.1750          return SDL_Unsupported();
 14.1751 @@ -2173,6 +3165,7 @@
 14.1752      if (texture->native) {
 14.1753          return SDL_GL_UnbindTexture(texture->native);
 14.1754      } else if (renderer && renderer->GL_UnbindTexture) {
 14.1755 +        FlushRenderCommandsIfTextureNeeded(texture);  /* in case the app messed with it. */
 14.1756          return renderer->GL_UnbindTexture(renderer, texture);
 14.1757      }
 14.1758  
 14.1759 @@ -2185,6 +3178,7 @@
 14.1760      CHECK_RENDERER_MAGIC(renderer, NULL);
 14.1761  
 14.1762      if (renderer->GetMetalLayer) {
 14.1763 +        FlushRenderCommands(renderer);  /* in case the app is going to mess with it. */
 14.1764          return renderer->GetMetalLayer(renderer);
 14.1765      }
 14.1766      return NULL;
 14.1767 @@ -2196,6 +3190,7 @@
 14.1768      CHECK_RENDERER_MAGIC(renderer, NULL);
 14.1769  
 14.1770      if (renderer->GetMetalCommandEncoder) {
 14.1771 +        FlushRenderCommands(renderer);  /* in case the app is going to mess with it. */
 14.1772          return renderer->GetMetalCommandEncoder(renderer);
 14.1773      }
 14.1774      return NULL;
    15.1 --- a/src/render/SDL_sysrender.h	Mon Oct 22 10:55:18 2018 -0400
    15.2 +++ b/src/render/SDL_sysrender.h	Wed Oct 31 15:03:41 2018 -0400
    15.3 @@ -39,20 +39,6 @@
    15.4      SDL_ScaleModeBest
    15.5  } SDL_ScaleMode;
    15.6  
    15.7 -typedef struct
    15.8 -{
    15.9 -    float x;
   15.10 -    float y;
   15.11 -} SDL_FPoint;
   15.12 -
   15.13 -typedef struct
   15.14 -{
   15.15 -    float x;
   15.16 -    float y;
   15.17 -    float w;
   15.18 -    float h;
   15.19 -} SDL_FRect;
   15.20 -
   15.21  /* Define the SDL texture structure */
   15.22  struct SDL_Texture
   15.23  {
   15.24 @@ -75,12 +61,63 @@
   15.25      int pitch;
   15.26      SDL_Rect locked_rect;
   15.27  
   15.28 +    Uint32 last_command_generation; /* last command queue generation this texture was in. */
   15.29 +
   15.30      void *driverdata;           /**< Driver specific texture representation */
   15.31  
   15.32      SDL_Texture *prev;
   15.33      SDL_Texture *next;
   15.34  };
   15.35  
   15.36 +typedef enum
   15.37 +{
   15.38 +    SDL_RENDERCMD_NO_OP,
   15.39 +    SDL_RENDERCMD_SETVIEWPORT,
   15.40 +    SDL_RENDERCMD_SETCLIPRECT,
   15.41 +    SDL_RENDERCMD_SETDRAWCOLOR,
   15.42 +    SDL_RENDERCMD_CLEAR,
   15.43 +    SDL_RENDERCMD_DRAW_POINTS,
   15.44 +    SDL_RENDERCMD_DRAW_LINES,
   15.45 +    SDL_RENDERCMD_FILL_RECTS,
   15.46 +    SDL_RENDERCMD_COPY,
   15.47 +    SDL_RENDERCMD_COPY_EX
   15.48 +} SDL_RenderCommandType;
   15.49 +
   15.50 +typedef struct SDL_RenderCommand
   15.51 +{
   15.52 +    SDL_RenderCommandType command;
   15.53 +    union {
   15.54 +        struct {
   15.55 +            size_t first;
   15.56 +            SDL_Rect rect;
   15.57 +        } viewport;
   15.58 +        struct {
   15.59 +            SDL_bool enabled;
   15.60 +            SDL_Rect rect;
   15.61 +        } cliprect;
   15.62 +        struct {
   15.63 +            size_t first;
   15.64 +            size_t count;
   15.65 +            Uint8 r, g, b, a;
   15.66 +            SDL_BlendMode blend;
   15.67 +            SDL_Texture *texture;
   15.68 +        } draw;
   15.69 +        struct {
   15.70 +            size_t first;
   15.71 +            Uint8 r, g, b, a;
   15.72 +        } color;
   15.73 +    } data;
   15.74 +    struct SDL_RenderCommand *next;
   15.75 +} SDL_RenderCommand;
   15.76 +
   15.77 +typedef struct SDL_AllocVertGap
   15.78 +{
   15.79 +    size_t offset;
   15.80 +    size_t len;
   15.81 +    struct SDL_AllocVertGap *next;
   15.82 +} SDL_AllocVertGap;
   15.83 +
   15.84 +
   15.85  /* Define the SDL renderer structure */
   15.86  struct SDL_Renderer
   15.87  {
   15.88 @@ -90,12 +127,20 @@
   15.89      int (*GetOutputSize) (SDL_Renderer * renderer, int *w, int *h);
   15.90      SDL_bool (*SupportsBlendMode)(SDL_Renderer * renderer, SDL_BlendMode blendMode);
   15.91      int (*CreateTexture) (SDL_Renderer * renderer, SDL_Texture * texture);
   15.92 -    int (*SetTextureColorMod) (SDL_Renderer * renderer,
   15.93 -                               SDL_Texture * texture);
   15.94 -    int (*SetTextureAlphaMod) (SDL_Renderer * renderer,
   15.95 -                               SDL_Texture * texture);
   15.96 -    int (*SetTextureBlendMode) (SDL_Renderer * renderer,
   15.97 -                                SDL_Texture * texture);
   15.98 +    int (*QueueSetViewport) (SDL_Renderer * renderer, SDL_RenderCommand *cmd);
   15.99 +    int (*QueueSetDrawColor) (SDL_Renderer * renderer, SDL_RenderCommand *cmd);
  15.100 +    int (*QueueDrawPoints) (SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points,
  15.101 +                             int count);
  15.102 +    int (*QueueDrawLines) (SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points,
  15.103 +                            int count);
  15.104 +    int (*QueueFillRects) (SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects,
  15.105 +                            int count);
  15.106 +    int (*QueueCopy) (SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
  15.107 +                       const SDL_Rect * srcrect, const SDL_FRect * dstrect);
  15.108 +    int (*QueueCopyEx) (SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
  15.109 +                        const SDL_Rect * srcquad, const SDL_FRect * dstrect,
  15.110 +                        const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip);
  15.111 +    int (*RunCommandQueue) (SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize);
  15.112      int (*UpdateTexture) (SDL_Renderer * renderer, SDL_Texture * texture,
  15.113                            const SDL_Rect * rect, const void *pixels,
  15.114                            int pitch);
  15.115 @@ -108,20 +153,6 @@
  15.116                          const SDL_Rect * rect, void **pixels, int *pitch);
  15.117      void (*UnlockTexture) (SDL_Renderer * renderer, SDL_Texture * texture);
  15.118      int (*SetRenderTarget) (SDL_Renderer * renderer, SDL_Texture * texture);
  15.119 -    int (*UpdateViewport) (SDL_Renderer * renderer);
  15.120 -    int (*UpdateClipRect) (SDL_Renderer * renderer);
  15.121 -    int (*RenderClear) (SDL_Renderer * renderer);
  15.122 -    int (*RenderDrawPoints) (SDL_Renderer * renderer, const SDL_FPoint * points,
  15.123 -                             int count);
  15.124 -    int (*RenderDrawLines) (SDL_Renderer * renderer, const SDL_FPoint * points,
  15.125 -                            int count);
  15.126 -    int (*RenderFillRects) (SDL_Renderer * renderer, const SDL_FRect * rects,
  15.127 -                            int count);
  15.128 -    int (*RenderCopy) (SDL_Renderer * renderer, SDL_Texture * texture,
  15.129 -                       const SDL_Rect * srcrect, const SDL_FRect * dstrect);
  15.130 -    int (*RenderCopyEx) (SDL_Renderer * renderer, SDL_Texture * texture,
  15.131 -                       const SDL_Rect * srcquad, const SDL_FRect * dstrect,
  15.132 -                       const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip);
  15.133      int (*RenderReadPixels) (SDL_Renderer * renderer, const SDL_Rect * rect,
  15.134                               Uint32 format, void * pixels, int pitch);
  15.135      void (*RenderPresent) (SDL_Renderer * renderer);
  15.136 @@ -178,6 +209,26 @@
  15.137      Uint8 r, g, b, a;                   /**< Color for drawing operations values */
  15.138      SDL_BlendMode blendMode;            /**< The drawing blend mode */
  15.139  
  15.140 +    SDL_bool always_batch;
  15.141 +    SDL_bool batching;
  15.142 +    SDL_RenderCommand *render_commands;
  15.143 +    SDL_RenderCommand *render_commands_tail;
  15.144 +    SDL_RenderCommand *render_commands_pool;
  15.145 +    Uint32 render_command_generation;
  15.146 +    Uint32 last_queued_color;
  15.147 +    SDL_Rect last_queued_viewport;
  15.148 +    SDL_Rect last_queued_cliprect;
  15.149 +    SDL_bool last_queued_cliprect_enabled;
  15.150 +    SDL_bool color_queued;
  15.151 +    SDL_bool viewport_queued;
  15.152 +    SDL_bool cliprect_queued;
  15.153 +
  15.154 +    void *vertex_data;
  15.155 +    size_t vertex_data_used;
  15.156 +    size_t vertex_data_allocation;
  15.157 +    SDL_AllocVertGap vertex_data_gaps;
  15.158 +    SDL_AllocVertGap *vertex_data_gaps_pool;
  15.159 +
  15.160      void *driverdata;
  15.161  };
  15.162  
  15.163 @@ -209,6 +260,11 @@
  15.164  extern SDL_BlendFactor SDL_GetBlendModeDstAlphaFactor(SDL_BlendMode blendMode);
  15.165  extern SDL_BlendOperation SDL_GetBlendModeAlphaOperation(SDL_BlendMode blendMode);
  15.166  
  15.167 +/* drivers call this during their Queue*() methods to make space in a array that are used
  15.168 +   for a vertex buffer during RunCommandQueue(). Pointers returned here are only valid until
  15.169 +   the next call, because it might be in an array that gets realloc()'d. */
  15.170 +extern void *SDL_AllocateRenderVertices(SDL_Renderer *renderer, const size_t numbytes, const size_t alignment, size_t *offset);
  15.171 +
  15.172  #endif /* SDL_sysrender_h_ */
  15.173  
  15.174  /* vi: set ts=4 sw=4 expandtab: */
    16.1 --- a/src/render/direct3d/SDL_render_d3d.c	Mon Oct 22 10:55:18 2018 -0400
    16.2 +++ b/src/render/direct3d/SDL_render_d3d.c	Wed Oct 31 15:03:41 2018 -0400
    16.3 @@ -30,6 +30,8 @@
    16.4  #include "SDL_hints.h"
    16.5  #include "SDL_loadso.h"
    16.6  #include "SDL_syswm.h"
    16.7 +#include "SDL_log.h"
    16.8 +#include "SDL_assert.h"
    16.9  #include "../SDL_sysrender.h"
   16.10  #include "../SDL_d3dmath.h"
   16.11  #include "../../video/windows/SDL_windowsvideo.h"
   16.12 @@ -41,61 +43,23 @@
   16.13  
   16.14  #include "SDL_shaders_d3d.h"
   16.15  
   16.16 +typedef struct
   16.17 +{
   16.18 +    SDL_Rect viewport;
   16.19 +    SDL_bool viewport_dirty;
   16.20 +    SDL_Texture *texture;
   16.21 +    SDL_BlendMode blend;
   16.22 +    SDL_bool cliprect_enabled;
   16.23 +    SDL_bool cliprect_enabled_dirty;
   16.24 +    SDL_Rect cliprect;
   16.25 +    SDL_bool cliprect_dirty;
   16.26 +    SDL_bool is_copy_ex;
   16.27 +    LPDIRECT3DPIXELSHADER9 shader;
   16.28 +} D3D_DrawStateCache;
   16.29 +
   16.30  
   16.31  /* Direct3D renderer implementation */
   16.32  
   16.33 -static SDL_Renderer *D3D_CreateRenderer(SDL_Window * window, Uint32 flags);
   16.34 -static void D3D_WindowEvent(SDL_Renderer * renderer,
   16.35 -                            const SDL_WindowEvent *event);
   16.36 -static SDL_bool D3D_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode);
   16.37 -static int D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
   16.38 -static int D3D_RecreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
   16.39 -static int D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   16.40 -                             const SDL_Rect * rect, const void *pixels,
   16.41 -                             int pitch);
   16.42 -static int D3D_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
   16.43 -                                const SDL_Rect * rect,
   16.44 -                                const Uint8 *Yplane, int Ypitch,
   16.45 -                                const Uint8 *Uplane, int Upitch,
   16.46 -                                const Uint8 *Vplane, int Vpitch);
   16.47 -static int D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   16.48 -                           const SDL_Rect * rect, void **pixels, int *pitch);
   16.49 -static void D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
   16.50 -static int D3D_SetRenderTargetInternal(SDL_Renderer * renderer, SDL_Texture * texture);
   16.51 -static int D3D_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture);
   16.52 -static int D3D_UpdateViewport(SDL_Renderer * renderer);
   16.53 -static int D3D_UpdateClipRect(SDL_Renderer * renderer);
   16.54 -static int D3D_RenderClear(SDL_Renderer * renderer);
   16.55 -static int D3D_RenderDrawPoints(SDL_Renderer * renderer,
   16.56 -                                const SDL_FPoint * points, int count);
   16.57 -static int D3D_RenderDrawLines(SDL_Renderer * renderer,
   16.58 -                               const SDL_FPoint * points, int count);
   16.59 -static int D3D_RenderFillRects(SDL_Renderer * renderer,
   16.60 -                               const SDL_FRect * rects, int count);
   16.61 -static int D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   16.62 -                          const SDL_Rect * srcrect, const SDL_FRect * dstrect);
   16.63 -static int D3D_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
   16.64 -                          const SDL_Rect * srcrect, const SDL_FRect * dstrect,
   16.65 -                          const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip);
   16.66 -static int D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
   16.67 -                                Uint32 format, void * pixels, int pitch);
   16.68 -static void D3D_RenderPresent(SDL_Renderer * renderer);
   16.69 -static void D3D_DestroyTexture(SDL_Renderer * renderer,
   16.70 -                               SDL_Texture * texture);
   16.71 -static void D3D_DestroyRenderer(SDL_Renderer * renderer);
   16.72 -
   16.73 -
   16.74 -SDL_RenderDriver D3D_RenderDriver = {
   16.75 -    D3D_CreateRenderer,
   16.76 -    {
   16.77 -     "direct3d",
   16.78 -     (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
   16.79 -     1,
   16.80 -     {SDL_PIXELFORMAT_ARGB8888},
   16.81 -     0,
   16.82 -     0}
   16.83 -};
   16.84 -
   16.85  typedef struct
   16.86  {
   16.87      void* d3dDLL;
   16.88 @@ -111,6 +75,11 @@
   16.89      IDirect3DSurface9 *currentRenderTarget;
   16.90      void* d3dxDLL;
   16.91      LPDIRECT3DPIXELSHADER9 shaders[NUM_SHADERS];
   16.92 +    LPDIRECT3DVERTEXBUFFER9 vertexBuffers[8];
   16.93 +    size_t vertexBufferSize[8];
   16.94 +    int currentVertexBuffer;
   16.95 +    SDL_bool reportedVboProblem;
   16.96 +    D3D_DrawStateCache drawstate;
   16.97  } D3D_RenderData;
   16.98  
   16.99  typedef struct
  16.100 @@ -265,9 +234,8 @@
  16.101      D3DMATRIX matrix;
  16.102  
  16.103      IDirect3DDevice9 *device = data->device;
  16.104 -
  16.105 +    IDirect3DDevice9_SetFVF(device, D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);
  16.106      IDirect3DDevice9_SetVertexShader(device, NULL);
  16.107 -    IDirect3DDevice9_SetFVF(device, D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);
  16.108      IDirect3DDevice9_SetRenderState(device, D3DRS_ZENABLE, D3DZB_FALSE);
  16.109      IDirect3DDevice9_SetRenderState(device, D3DRS_CULLMODE, D3DCULL_NONE);
  16.110      IDirect3DDevice9_SetRenderState(device, D3DRS_LIGHTING, FALSE);
  16.111 @@ -300,21 +268,10 @@
  16.112                                            D3DTOP_DISABLE);
  16.113  
  16.114      /* Set an identity world and view matrix */
  16.115 +    SDL_zero(matrix);
  16.116      matrix.m[0][0] = 1.0f;
  16.117 -    matrix.m[0][1] = 0.0f;
  16.118 -    matrix.m[0][2] = 0.0f;
  16.119 -    matrix.m[0][3] = 0.0f;
  16.120 -    matrix.m[1][0] = 0.0f;
  16.121      matrix.m[1][1] = 1.0f;
  16.122 -    matrix.m[1][2] = 0.0f;
  16.123 -    matrix.m[1][3] = 0.0f;
  16.124 -    matrix.m[2][0] = 0.0f;
  16.125 -    matrix.m[2][1] = 0.0f;
  16.126      matrix.m[2][2] = 1.0f;
  16.127 -    matrix.m[2][3] = 0.0f;
  16.128 -    matrix.m[3][0] = 0.0f;
  16.129 -    matrix.m[3][1] = 0.0f;
  16.130 -    matrix.m[3][2] = 0.0f;
  16.131      matrix.m[3][3] = 1.0f;
  16.132      IDirect3DDevice9_SetTransform(device, D3DTS_WORLD, &matrix);
  16.133      IDirect3DDevice9_SetTransform(device, D3DTS_VIEW, &matrix);
  16.134 @@ -326,63 +283,7 @@
  16.135      data->beginScene = SDL_TRUE;
  16.136  }
  16.137  
  16.138 -static int
  16.139 -D3D_Reset(SDL_Renderer * renderer)
  16.140 -{
  16.141 -    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  16.142 -    HRESULT result;
  16.143 -    SDL_Texture *texture;
  16.144 -
  16.145 -    /* Release the default render target before reset */
  16.146 -    if (data->defaultRenderTarget) {
  16.147 -        IDirect3DSurface9_Release(data->defaultRenderTarget);
  16.148 -        data->defaultRenderTarget = NULL;
  16.149 -    }
  16.150 -    if (data->currentRenderTarget != NULL) {
  16.151 -        IDirect3DSurface9_Release(data->currentRenderTarget);
  16.152 -        data->currentRenderTarget = NULL;
  16.153 -    }
  16.154 -
  16.155 -    /* Release application render targets */
  16.156 -    for (texture = renderer->textures; texture; texture = texture->next) {
  16.157 -        if (texture->access == SDL_TEXTUREACCESS_TARGET) {
  16.158 -            D3D_DestroyTexture(renderer, texture);
  16.159 -        } else {
  16.160 -            D3D_RecreateTexture(renderer, texture);
  16.161 -        }
  16.162 -    }
  16.163 -
  16.164 -    result = IDirect3DDevice9_Reset(data->device, &data->pparams);
  16.165 -    if (FAILED(result)) {
  16.166 -        if (result == D3DERR_DEVICELOST) {
  16.167 -            /* Don't worry about it, we'll reset later... */
  16.168 -            return 0;
  16.169 -        } else {
  16.170 -            return D3D_SetError("Reset()", result);
  16.171 -        }
  16.172 -    }
  16.173 -
  16.174 -    /* Allocate application render targets */
  16.175 -    for (texture = renderer->textures; texture; texture = texture->next) {
  16.176 -        if (texture->access == SDL_TEXTUREACCESS_TARGET) {
  16.177 -            D3D_CreateTexture(renderer, texture);
  16.178 -        }
  16.179 -    }
  16.180 -
  16.181 -    IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget);
  16.182 -    D3D_InitRenderState(data);
  16.183 -    D3D_SetRenderTargetInternal(renderer, renderer->target);
  16.184 -    D3D_UpdateViewport(renderer);
  16.185 -
  16.186 -    /* Let the application know that render targets were reset */
  16.187 -    {
  16.188 -        SDL_Event event;
  16.189 -        event.type = SDL_RENDER_TARGETS_RESET;
  16.190 -        SDL_PushEvent(&event);
  16.191 -    }
  16.192 -
  16.193 -    return 0;
  16.194 -}
  16.195 +static int D3D_Reset(SDL_Renderer * renderer);
  16.196  
  16.197  static int
  16.198  D3D_ActivateRenderer(SDL_Renderer * renderer)
  16.199 @@ -431,177 +332,6 @@
  16.200      return 0;
  16.201  }
  16.202  
  16.203 -SDL_Renderer *
  16.204 -D3D_CreateRenderer(SDL_Window * window, Uint32 flags)
  16.205 -{
  16.206 -    SDL_Renderer *renderer;
  16.207 -    D3D_RenderData *data;
  16.208 -    SDL_SysWMinfo windowinfo;
  16.209 -    HRESULT result;
  16.210 -    D3DPRESENT_PARAMETERS pparams;
  16.211 -    IDirect3DSwapChain9 *chain;
  16.212 -    D3DCAPS9 caps;
  16.213 -    DWORD device_flags;
  16.214 -    Uint32 window_flags;
  16.215 -    int w, h;
  16.216 -    SDL_DisplayMode fullscreen_mode;
  16.217 -    int displayIndex;
  16.218 -
  16.219 -    renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
  16.220 -    if (!renderer) {
  16.221 -        SDL_OutOfMemory();
  16.222 -        return NULL;
  16.223 -    }
  16.224 -
  16.225 -    data = (D3D_RenderData *) SDL_calloc(1, sizeof(*data));
  16.226 -    if (!data) {
  16.227 -        SDL_free(renderer);
  16.228 -        SDL_OutOfMemory();
  16.229 -        return NULL;
  16.230 -    }
  16.231 -
  16.232 -    if (!D3D_LoadDLL(&data->d3dDLL, &data->d3d)) {
  16.233 -        SDL_free(renderer);
  16.234 -        SDL_free(data);
  16.235 -        SDL_SetError("Unable to create Direct3D interface");
  16.236 -        return NULL;
  16.237 -    }
  16.238 -
  16.239 -    renderer->WindowEvent = D3D_WindowEvent;
  16.240 -    renderer->SupportsBlendMode = D3D_SupportsBlendMode;
  16.241 -    renderer->CreateTexture = D3D_CreateTexture;
  16.242 -    renderer->UpdateTexture = D3D_UpdateTexture;
  16.243 -    renderer->UpdateTextureYUV = D3D_UpdateTextureYUV;
  16.244 -    renderer->LockTexture = D3D_LockTexture;
  16.245 -    renderer->UnlockTexture = D3D_UnlockTexture;
  16.246 -    renderer->SetRenderTarget = D3D_SetRenderTarget;
  16.247 -    renderer->UpdateViewport = D3D_UpdateViewport;
  16.248 -    renderer->UpdateClipRect = D3D_UpdateClipRect;
  16.249 -    renderer->RenderClear = D3D_RenderClear;
  16.250 -    renderer->RenderDrawPoints = D3D_RenderDrawPoints;
  16.251 -    renderer->RenderDrawLines = D3D_RenderDrawLines;
  16.252 -    renderer->RenderFillRects = D3D_RenderFillRects;
  16.253 -    renderer->RenderCopy = D3D_RenderCopy;
  16.254 -    renderer->RenderCopyEx = D3D_RenderCopyEx;
  16.255 -    renderer->RenderReadPixels = D3D_RenderReadPixels;
  16.256 -    renderer->RenderPresent = D3D_RenderPresent;
  16.257 -    renderer->DestroyTexture = D3D_DestroyTexture;
  16.258 -    renderer->DestroyRenderer = D3D_DestroyRenderer;
  16.259 -    renderer->info = D3D_RenderDriver.info;
  16.260 -    renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
  16.261 -    renderer->driverdata = data;
  16.262 -
  16.263 -    SDL_VERSION(&windowinfo.version);
  16.264 -    SDL_GetWindowWMInfo(window, &windowinfo);
  16.265 -
  16.266 -    window_flags = SDL_GetWindowFlags(window);
  16.267 -    SDL_GetWindowSize(window, &w, &h);
  16.268 -    SDL_GetWindowDisplayMode(window, &fullscreen_mode);
  16.269 -
  16.270 -    SDL_zero(pparams);
  16.271 -    pparams.hDeviceWindow = windowinfo.info.win.window;
  16.272 -    pparams.BackBufferWidth = w;
  16.273 -    pparams.BackBufferHeight = h;
  16.274 -    pparams.BackBufferCount = 1;
  16.275 -    pparams.SwapEffect = D3DSWAPEFFECT_DISCARD;
  16.276 -
  16.277 -    if (window_flags & SDL_WINDOW_FULLSCREEN && (window_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
  16.278 -        pparams.Windowed = FALSE;
  16.279 -        pparams.BackBufferFormat = PixelFormatToD3DFMT(fullscreen_mode.format);
  16.280 -        pparams.FullScreen_RefreshRateInHz = fullscreen_mode.refresh_rate;
  16.281 -    } else {
  16.282 -        pparams.Windowed = TRUE;
  16.283 -        pparams.BackBufferFormat = D3DFMT_UNKNOWN;
  16.284 -        pparams.FullScreen_RefreshRateInHz = 0;
  16.285 -    }
  16.286 -    if (flags & SDL_RENDERER_PRESENTVSYNC) {
  16.287 -        pparams.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
  16.288 -    } else {
  16.289 -        pparams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
  16.290 -    }
  16.291 -
  16.292 -    /* Get the adapter for the display that the window is on */
  16.293 -    displayIndex = SDL_GetWindowDisplayIndex(window);
  16.294 -    data->adapter = SDL_Direct3D9GetAdapterIndex(displayIndex);
  16.295 -
  16.296 -    IDirect3D9_GetDeviceCaps(data->d3d, data->adapter, D3DDEVTYPE_HAL, &caps);
  16.297 -
  16.298 -    device_flags = D3DCREATE_FPU_PRESERVE;
  16.299 -    if (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) {
  16.300 -        device_flags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
  16.301 -    } else {
  16.302 -        device_flags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  16.303 -    }
  16.304 -
  16.305 -    if (SDL_GetHintBoolean(SDL_HINT_RENDER_DIRECT3D_THREADSAFE, SDL_FALSE)) {
  16.306 -        device_flags |= D3DCREATE_MULTITHREADED;
  16.307 -    }
  16.308 -
  16.309 -    result = IDirect3D9_CreateDevice(data->d3d, data->adapter,
  16.310 -                                     D3DDEVTYPE_HAL,
  16.311 -                                     pparams.hDeviceWindow,
  16.312 -                                     device_flags,
  16.313 -                                     &pparams, &data->device);
  16.314 -    if (FAILED(result)) {
  16.315 -        D3D_DestroyRenderer(renderer);
  16.316 -        D3D_SetError("CreateDevice()", result);
  16.317 -        return NULL;
  16.318 -    }
  16.319 -
  16.320 -    /* Get presentation parameters to fill info */
  16.321 -    result = IDirect3DDevice9_GetSwapChain(data->device, 0, &chain);
  16.322 -    if (FAILED(result)) {
  16.323 -        D3D_DestroyRenderer(renderer);
  16.324 -        D3D_SetError("GetSwapChain()", result);
  16.325 -        return NULL;
  16.326 -    }
  16.327 -    result = IDirect3DSwapChain9_GetPresentParameters(chain, &pparams);
  16.328 -    if (FAILED(result)) {
  16.329 -        IDirect3DSwapChain9_Release(chain);
  16.330 -        D3D_DestroyRenderer(renderer);
  16.331 -        D3D_SetError("GetPresentParameters()", result);
  16.332 -        return NULL;
  16.333 -    }
  16.334 -    IDirect3DSwapChain9_Release(chain);
  16.335 -    if (pparams.PresentationInterval == D3DPRESENT_INTERVAL_ONE) {
  16.336 -        renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
  16.337 -    }
  16.338 -    data->pparams = pparams;
  16.339 -
  16.340 -    IDirect3DDevice9_GetDeviceCaps(data->device, &caps);
  16.341 -    renderer->info.max_texture_width = caps.MaxTextureWidth;
  16.342 -    renderer->info.max_texture_height = caps.MaxTextureHeight;
  16.343 -    if (caps.NumSimultaneousRTs >= 2) {
  16.344 -        renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE;
  16.345 -    }
  16.346 -
  16.347 -    if (caps.PrimitiveMiscCaps & D3DPMISCCAPS_SEPARATEALPHABLEND) {
  16.348 -        data->enableSeparateAlphaBlend = SDL_TRUE;
  16.349 -    }
  16.350 -
  16.351 -    /* Store the default render target */
  16.352 -    IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget);
  16.353 -    data->currentRenderTarget = NULL;
  16.354 -
  16.355 -    /* Set up parameters for rendering */
  16.356 -    D3D_InitRenderState(data);
  16.357 -
  16.358 -    if (caps.MaxSimultaneousTextures >= 3) {
  16.359 -        int i;
  16.360 -        for (i = 0; i < SDL_arraysize(data->shaders); ++i) {
  16.361 -            result = D3D9_CreatePixelShader(data->device, (D3D9_Shader)i, &data->shaders[i]);
  16.362 -            if (FAILED(result)) {
  16.363 -                D3D_SetError("CreatePixelShader()", result);
  16.364 -            }
  16.365 -        }
  16.366 -        if (data->shaders[SHADER_YUV_JPEG] && data->shaders[SHADER_YUV_BT601] && data->shaders[SHADER_YUV_BT709]) {
  16.367 -            renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;
  16.368 -            renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
  16.369 -        }
  16.370 -    }
  16.371 -    return renderer;
  16.372 -}
  16.373 -
  16.374  static void
  16.375  D3D_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
  16.376  {
  16.377 @@ -702,33 +432,6 @@
  16.378  }
  16.379  
  16.380  static int
  16.381 -D3D_BindTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWORD sampler)
  16.382 -{
  16.383 -    HRESULT result;
  16.384 -
  16.385 -    if (texture->dirty && texture->staging) {
  16.386 -        if (!texture->texture) {
  16.387 -            result = IDirect3DDevice9_CreateTexture(device, texture->w, texture->h, 1, texture->usage,
  16.388 -                PixelFormatToD3DFMT(texture->format), D3DPOOL_DEFAULT, &texture->texture, NULL);
  16.389 -            if (FAILED(result)) {
  16.390 -                return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
  16.391 -            }
  16.392 -        }
  16.393 -
  16.394 -        result = IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)texture->staging, (IDirect3DBaseTexture9 *)texture->texture);
  16.395 -        if (FAILED(result)) {
  16.396 -            return D3D_SetError("UpdateTexture()", result);
  16.397 -        }
  16.398 -        texture->dirty = SDL_FALSE;
  16.399 -    }
  16.400 -    result = IDirect3DDevice9_SetTexture(device, sampler, (IDirect3DBaseTexture9 *)texture->texture);
  16.401 -    if (FAILED(result)) {
  16.402 -        return D3D_SetError("SetTexture()", result);
  16.403 -    }
  16.404 -    return 0;
  16.405 -}
  16.406 -
  16.407 -static int
  16.408  D3D_RecreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture)
  16.409  {
  16.410      if (texture->texture) {
  16.411 @@ -1072,330 +775,254 @@
  16.412      return D3D_SetRenderTargetInternal(renderer, texture);
  16.413  }
  16.414  
  16.415 +
  16.416  static int
  16.417 -D3D_UpdateViewport(SDL_Renderer * renderer)
  16.418 +D3D_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd)
  16.419  {
  16.420 -    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  16.421 -    D3DVIEWPORT9 viewport;
  16.422 -    D3DMATRIX matrix;
  16.423 +    return 0;  /* nothing to do in this backend. */
  16.424 +}
  16.425  
  16.426 -    /* Set the viewport */
  16.427 -    viewport.X = renderer->viewport.x;
  16.428 -    viewport.Y = renderer->viewport.y;
  16.429 -    viewport.Width = renderer->viewport.w;
  16.430 -    viewport.Height = renderer->viewport.h;
  16.431 -    viewport.MinZ = 0.0f;
  16.432 -    viewport.MaxZ = 1.0f;
  16.433 -    IDirect3DDevice9_SetViewport(data->device, &viewport);
  16.434 +static int
  16.435 +D3D_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
  16.436 +{
  16.437 +    const DWORD color = D3DCOLOR_ARGB(cmd->data.draw.a, cmd->data.draw.r, cmd->data.draw.g, cmd->data.draw.b);
  16.438 +    const size_t vertslen = count * sizeof (Vertex);
  16.439 +    Vertex *verts = (Vertex *) SDL_AllocateRenderVertices(renderer, vertslen, 0, &cmd->data.draw.first);
  16.440 +    size_t i;
  16.441  
  16.442 -    /* Set an orthographic projection matrix */
  16.443 -    if (renderer->viewport.w && renderer->viewport.h) {
  16.444 -        matrix.m[0][0] = 2.0f / renderer->viewport.w;
  16.445 -        matrix.m[0][1] = 0.0f;
  16.446 -        matrix.m[0][2] = 0.0f;
  16.447 -        matrix.m[0][3] = 0.0f;
  16.448 -        matrix.m[1][0] = 0.0f;
  16.449 -        matrix.m[1][1] = -2.0f / renderer->viewport.h;
  16.450 -        matrix.m[1][2] = 0.0f;
  16.451 -        matrix.m[1][3] = 0.0f;
  16.452 -        matrix.m[2][0] = 0.0f;
  16.453 -        matrix.m[2][1] = 0.0f;
  16.454 -        matrix.m[2][2] = 1.0f;
  16.455 -        matrix.m[2][3] = 0.0f;
  16.456 -        matrix.m[3][0] = -1.0f;
  16.457 -        matrix.m[3][1] = 1.0f;
  16.458 -        matrix.m[3][2] = 0.0f;
  16.459 -        matrix.m[3][3] = 1.0f;
  16.460 -        IDirect3DDevice9_SetTransform(data->device, D3DTS_PROJECTION, &matrix);
  16.461 +    if (!verts) {
  16.462 +        return -1;
  16.463 +    }
  16.464 +
  16.465 +    SDL_memset(verts, '\0', vertslen);
  16.466 +    cmd->data.draw.count = count;
  16.467 +
  16.468 +    for (i = 0; i < count; i++, verts++, points++) {
  16.469 +        verts->x = points->x;
  16.470 +        verts->y = points->y;
  16.471 +        verts->color = color;
  16.472      }
  16.473  
  16.474      return 0;
  16.475  }
  16.476  
  16.477  static int
  16.478 -D3D_UpdateClipRect(SDL_Renderer * renderer)
  16.479 +D3D_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects, int count)
  16.480  {
  16.481 -    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  16.482 +    const DWORD color = D3DCOLOR_ARGB(cmd->data.draw.a, cmd->data.draw.r, cmd->data.draw.g, cmd->data.draw.b);
  16.483 +    const size_t vertslen = count * sizeof (Vertex) * 4;
  16.484 +    Vertex *verts = (Vertex *) SDL_AllocateRenderVertices(renderer, vertslen, 0, &cmd->data.draw.first);
  16.485 +    size_t i;
  16.486  
  16.487 -    if (renderer->clipping_enabled) {
  16.488 -        const SDL_Rect *rect = &renderer->clip_rect;
  16.489 -        RECT r;
  16.490 -        HRESULT result;
  16.491 +    if (!verts) {
  16.492 +        return -1;
  16.493 +    }
  16.494  
  16.495 -        IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, TRUE);
  16.496 -        r.left = renderer->viewport.x + rect->x;
  16.497 -        r.top = renderer->viewport.y + rect->y;
  16.498 -        r.right = renderer->viewport.x + rect->x + rect->w;
  16.499 -        r.bottom = renderer->viewport.y + rect->y + rect->h;
  16.500 +    SDL_memset(verts, '\0', vertslen);
  16.501 +    cmd->data.draw.count = count;
  16.502  
  16.503 -        result = IDirect3DDevice9_SetScissorRect(data->device, &r);
  16.504 -        if (result != D3D_OK) {
  16.505 -            D3D_SetError("SetScissor()", result);
  16.506 -            return -1;
  16.507 -        }
  16.508 -    } else {
  16.509 -        IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, FALSE);
  16.510 +    for (i = 0; i < count; i++) {
  16.511 +        const SDL_FRect *rect = &rects[i];
  16.512 +        const float minx = rect->x;
  16.513 +        const float maxx = rect->x + rect->w;
  16.514 +        const float miny = rect->y;
  16.515 +        const float maxy = rect->y + rect->h;
  16.516 +
  16.517 +        verts->x = minx;
  16.518 +        verts->y = miny;
  16.519 +        verts->color = color;
  16.520 +        verts++;
  16.521 +
  16.522 +        verts->x = maxx;
  16.523 +        verts->y = miny;
  16.524 +        verts->color = color;
  16.525 +        verts++;
  16.526 +
  16.527 +        verts->x = maxx;
  16.528 +        verts->y = maxy;
  16.529 +        verts->color = color;
  16.530 +        verts++;
  16.531 +
  16.532 +        verts->x = minx;
  16.533 +        verts->y = maxy;
  16.534 +        verts->color = color;
  16.535 +        verts++;
  16.536      }
  16.537 +
  16.538      return 0;
  16.539  }
  16.540  
  16.541  static int
  16.542 -D3D_RenderClear(SDL_Renderer * renderer)
  16.543 +D3D_QueueCopy(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
  16.544 +                          const SDL_Rect * srcrect, const SDL_FRect * dstrect)
  16.545  {
  16.546 -    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  16.547 -    DWORD color;
  16.548 -    HRESULT result;
  16.549 -    int BackBufferWidth, BackBufferHeight;
  16.550 +    const DWORD color = D3DCOLOR_ARGB(cmd->data.draw.a, cmd->data.draw.r, cmd->data.draw.g, cmd->data.draw.b);
  16.551 +    float minx, miny, maxx, maxy;
  16.552 +    float minu, maxu, minv, maxv;
  16.553 +    const size_t vertslen = sizeof (Vertex) * 4;
  16.554 +    Vertex *verts = (Vertex *) SDL_AllocateRenderVertices(renderer, vertslen, 0, &cmd->data.draw.first);
  16.555  
  16.556 -    if (D3D_ActivateRenderer(renderer) < 0) {
  16.557 +    if (!verts) {
  16.558          return -1;
  16.559      }
  16.560  
  16.561 -    color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
  16.562 +    cmd->data.draw.count = 1;
  16.563  
  16.564 -    if (renderer->target) {
  16.565 -        BackBufferWidth = renderer->target->w;
  16.566 -        BackBufferHeight = renderer->target->h;
  16.567 -    } else {
  16.568 -        BackBufferWidth = data->pparams.BackBufferWidth;
  16.569 -        BackBufferHeight = data->pparams.BackBufferHeight;
  16.570 +    minx = dstrect->x - 0.5f;
  16.571 +    miny = dstrect->y - 0.5f;
  16.572 +    maxx = dstrect->x + dstrect->w - 0.5f;
  16.573 +    maxy = dstrect->y + dstrect->h - 0.5f;
  16.574 +
  16.575 +    minu = (float) srcrect->x / texture->w;
  16.576 +    maxu = (float) (srcrect->x + srcrect->w) / texture->w;
  16.577 +    minv = (float) srcrect->y / texture->h;
  16.578 +    maxv = (float) (srcrect->y + srcrect->h) / texture->h;
  16.579 +
  16.580 +    verts->x = minx;
  16.581 +    verts->y = miny;
  16.582 +    verts->z = 0.0f;
  16.583 +    verts->color = color;
  16.584 +    verts->u = minu;
  16.585 +    verts->v = minv;
  16.586 +    verts++;
  16.587 +
  16.588 +    verts->x = maxx;
  16.589 +    verts->y = miny;
  16.590 +    verts->z = 0.0f;
  16.591 +    verts->color = color;
  16.592 +    verts->u = maxu;
  16.593 +    verts->v = minv;
  16.594 +    verts++;
  16.595 +
  16.596 +    verts->x = maxx;
  16.597 +    verts->y = maxy;
  16.598 +    verts->z = 0.0f;
  16.599 +    verts->color = color;
  16.600 +    verts->u = maxu;
  16.601 +    verts->v = maxv;
  16.602 +    verts++;
  16.603 +
  16.604 +    verts->x = minx;
  16.605 +    verts->y = maxy;
  16.606 +    verts->z = 0.0f;
  16.607 +    verts->color = color;
  16.608 +    verts->u = minu;
  16.609 +    verts->v = maxv;
  16.610 +    verts++;
  16.611 +
  16.612 +    return 0;
  16.613 +}
  16.614 +
  16.615 +static int
  16.616 +D3D_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
  16.617 +                        const SDL_Rect * srcquad, const SDL_FRect * dstrect,
  16.618 +                        const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
  16.619 +{
  16.620 +    const DWORD color = D3DCOLOR_ARGB(cmd->data.draw.a, cmd->data.draw.r, cmd->data.draw.g, cmd->data.draw.b);
  16.621 +    float minx, miny, maxx, maxy;
  16.622 +    float minu, maxu, minv, maxv;
  16.623 +    const size_t vertslen = sizeof (Vertex) * 5;
  16.624 +    Vertex *verts = (Vertex *) SDL_AllocateRenderVertices(renderer, vertslen, 0, &cmd->data.draw.first);
  16.625 +
  16.626 +    if (!verts) {
  16.627 +        return -1;
  16.628      }
  16.629  
  16.630 -    if (renderer->clipping_enabled) {
  16.631 -        IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, FALSE);
  16.632 +    cmd->data.draw.count = 1;
  16.633 +
  16.634 +    minx = -center->x;
  16.635 +    maxx = dstrect->w - center->x;
  16.636 +    miny = -center->y;
  16.637 +    maxy = dstrect->h - center->y;
  16.638 +
  16.639 +    if (flip & SDL_FLIP_HORIZONTAL) {
  16.640 +        minu = (float) (srcquad->x + srcquad->w) / texture->w;
  16.641 +        maxu = (float) srcquad->x / texture->w;
  16.642 +    } else {
  16.643 +        minu = (float) srcquad->x / texture->w;
  16.644 +        maxu = (float) (srcquad->x + srcquad->w) / texture->w;
  16.645      }
  16.646  
  16.647 -    /* Don't reset the viewport if we don't have to! */
  16.648 -    if (!renderer->viewport.x && !renderer->viewport.y &&
  16.649 -        renderer->viewport.w == BackBufferWidth &&
  16.650 -        renderer->viewport.h == BackBufferHeight) {
  16.651 -        result = IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
  16.652 +    if (flip & SDL_FLIP_VERTICAL) {
  16.653 +        minv = (float) (srcquad->y + srcquad->h) / texture->h;
  16.654 +        maxv = (float) srcquad->y / texture->h;
  16.655      } else {
  16.656 -        D3DVIEWPORT9 viewport;
  16.657 -
  16.658 -        /* Clear is defined to clear the entire render target */
  16.659 -        viewport.X = 0;
  16.660 -        viewport.Y = 0;
  16.661 -        viewport.Width = BackBufferWidth;
  16.662 -        viewport.Height = BackBufferHeight;
  16.663 -        viewport.MinZ = 0.0f;
  16.664 -        viewport.MaxZ = 1.0f;
  16.665 -        IDirect3DDevice9_SetViewport(data->device, &viewport);
  16.666 -
  16.667 -        result = IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
  16.668 -
  16.669 -        /* Reset the viewport */
  16.670 -        viewport.X = renderer->viewport.x;
  16.671 -        viewport.Y = renderer->viewport.y;
  16.672 -        viewport.Width = renderer->viewport.w;
  16.673 -        viewport.Height = renderer->viewport.h;
  16.674 -        viewport.MinZ = 0.0f;
  16.675 -        viewport.MaxZ = 1.0f;
  16.676 -        IDirect3DDevice9_SetViewport(data->device, &viewport);
  16.677 +        minv = (float) srcquad->y / texture->h;
  16.678 +        maxv = (float) (srcquad->y + srcquad->h) / texture->h;
  16.679      }
  16.680  
  16.681 -    if (renderer->clipping_enabled) {
  16.682 -        IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, TRUE);
  16.683 +    verts->x = minx;
  16.684 +    verts->y = miny;
  16.685 +    verts->z = 0.0f;
  16.686 +    verts->color = color;
  16.687 +    verts->u = minu;
  16.688 +    verts->v = minv;
  16.689 +    verts++;
  16.690 +
  16.691 +    verts->x = maxx;
  16.692 +    verts->y = miny;
  16.693 +    verts->z = 0.0f;
  16.694 +    verts->color = color;
  16.695 +    verts->u = maxu;
  16.696 +    verts->v = minv;
  16.697 +    verts++;
  16.698 +
  16.699 +    verts->x = maxx;
  16.700 +    verts->y = maxy;
  16.701 +    verts->z = 0.0f;
  16.702 +    verts->color = color;
  16.703 +    verts->u = maxu;
  16.704 +    verts->v = maxv;
  16.705 +    verts++;
  16.706 +
  16.707 +    verts->x = minx;
  16.708 +    verts->y = maxy;
  16.709 +    verts->z = 0.0f;
  16.710 +    verts->color = color;
  16.711 +    verts->u = minu;
  16.712 +    verts->v = maxv;
  16.713 +    verts++;
  16.714 +
  16.715 +    verts->x = dstrect->x + center->x - 0.5f;  /* X translation */
  16.716 +    verts->y = dstrect->y + center->y - 0.5f;  /* Y translation */
  16.717 +    verts->z = (float)(M_PI * (float) angle / 180.0f);  /* rotation */
  16.718 +    verts->color = 0;
  16.719 +    verts->u = 0.0f;
  16.720 +    verts->v = 0.0f;
  16.721 +    verts++;
  16.722 +
  16.723 +    return 0;
  16.724 +}
  16.725 +
  16.726 +static int
  16.727 +BindTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWORD sampler)
  16.728 +{
  16.729 +    HRESULT result;
  16.730 +
  16.731 +    if (texture->dirty && texture->staging) {
  16.732 +        if (!texture->texture) {
  16.733 +            result = IDirect3DDevice9_CreateTexture(device, texture->w, texture->h, 1, texture->usage,
  16.734 +                PixelFormatToD3DFMT(texture->format), D3DPOOL_DEFAULT, &texture->texture, NULL);
  16.735 +            if (FAILED(result)) {
  16.736 +                return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
  16.737 +            }
  16.738 +        }
  16.739 +
  16.740 +        result = IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)texture->staging, (IDirect3DBaseTexture9 *)texture->texture);
  16.741 +        if (FAILED(result)) {
  16.742 +            return D3D_SetError("UpdateTexture()", result);
  16.743 +        }
  16.744 +        texture->dirty = SDL_FALSE;
  16.745      }
  16.746 -
  16.747 +    result = IDirect3DDevice9_SetTexture(device, sampler, (IDirect3DBaseTexture9 *)texture->texture);
  16.748      if (FAILED(result)) {
  16.749 -        return D3D_SetError("Clear()", result);
  16.750 +        return D3D_SetError("SetTexture()", result);
  16.751      }
  16.752      return 0;
  16.753  }
  16.754  
  16.755  static void
  16.756 -D3D_SetBlendMode(D3D_RenderData * data, SDL_BlendMode blendMode)
  16.757 -{
  16.758 -    if (blendMode == SDL_BLENDMODE_NONE) {
  16.759 -        IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, FALSE);
  16.760 -    } else {
  16.761 -        IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, TRUE);
  16.762 -        IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
  16.763 -                                        GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blendMode)));
  16.764 -        IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
  16.765 -                                        GetBlendFunc(SDL_GetBlendModeDstColorFactor(blendMode)));
  16.766 -        if (data->enableSeparateAlphaBlend) {
  16.767 -            IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA,
  16.768 -                                            GetBlendFunc(SDL_GetBlendModeSrcAlphaFactor(blendMode)));
  16.769 -            IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA,
  16.770 -                                            GetBlendFunc(SDL_GetBlendModeDstAlphaFactor(blendMode)));
  16.771 -        }
  16.772 -    }
  16.773 -}
  16.774 -
  16.775 -static int
  16.776 -D3D_RenderDrawPoints(SDL_Renderer * renderer, const SDL_FPoint * points,
  16.777 -                     int count)
  16.778 -{
  16.779 -    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  16.780 -    DWORD color;
  16.781 -    Vertex *vertices;
  16.782 -    int i;
  16.783 -    HRESULT result;
  16.784 -
  16.785 -    if (D3D_ActivateRenderer(renderer) < 0) {
  16.786 -        return -1;
  16.787 -    }
  16.788 -
  16.789 -    D3D_SetBlendMode(data, renderer->blendMode);
  16.790 -
  16.791 -    result =
  16.792 -        IDirect3DDevice9_SetTexture(data->device, 0,
  16.793 -                                    (IDirect3DBaseTexture9 *) 0);
  16.794 -    if (FAILED(result)) {
  16.795 -        return D3D_SetError("SetTexture()", result);
  16.796 -    }
  16.797 -
  16.798 -    color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
  16.799 -
  16.800 -    vertices = SDL_stack_alloc(Vertex, count);
  16.801 -    for (i = 0; i < count; ++i) {
  16.802 -        vertices[i].x = points[i].x;
  16.803 -        vertices[i].y = points[i].y;
  16.804 -        vertices[i].z = 0.0f;
  16.805 -        vertices[i].color = color;
  16.806 -        vertices[i].u = 0.0f;
  16.807 -        vertices[i].v = 0.0f;
  16.808 -    }
  16.809 -    result =
  16.810 -        IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, count,
  16.811 -                                         vertices, sizeof(*vertices));
  16.812 -    SDL_stack_free(vertices);
  16.813 -    if (FAILED(result)) {
  16.814 -        return D3D_SetError("DrawPrimitiveUP()", result);
  16.815 -    }
  16.816 -    return 0;
  16.817 -}
  16.818 -
  16.819 -static int
  16.820 -D3D_RenderDrawLines(SDL_Renderer * renderer, const SDL_FPoint * points,
  16.821 -                    int count)
  16.822 -{
  16.823 -    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  16.824 -    DWORD color;
  16.825 -    Vertex *vertices;
  16.826 -    int i;
  16.827 -    HRESULT result;
  16.828 -
  16.829 -    if (D3D_ActivateRenderer(renderer) < 0) {
  16.830 -        return -1;
  16.831 -    }
  16.832 -
  16.833 -    D3D_SetBlendMode(data, renderer->blendMode);
  16.834 -
  16.835 -    result =
  16.836 -        IDirect3DDevice9_SetTexture(data->device, 0,
  16.837 -                                    (IDirect3DBaseTexture9 *) 0);
  16.838 -    if (FAILED(result)) {
  16.839 -        return D3D_SetError("SetTexture()", result);
  16.840 -    }
  16.841 -
  16.842 -    color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
  16.843 -
  16.844 -    vertices = SDL_stack_alloc(Vertex, count);
  16.845 -    for (i = 0; i < count; ++i) {
  16.846 -        vertices[i].x = points[i].x;
  16.847 -        vertices[i].y = points[i].y;
  16.848 -        vertices[i].z = 0.0f;
  16.849 -        vertices[i].color = color;
  16.850 -        vertices[i].u = 0.0f;
  16.851 -        vertices[i].v = 0.0f;
  16.852 -    }
  16.853 -    result =
  16.854 -        IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_LINESTRIP, count-1,
  16.855 -                                         vertices, sizeof(*vertices));
  16.856 -
  16.857 -    /* DirectX 9 has the same line rasterization semantics as GDI,
  16.858 -       so we need to close the endpoint of the line */
  16.859 -    if (count == 2 ||
  16.860 -        points[0].x != points[count-1].x || points[0].y != points[count-1].y) {
  16.861 -        vertices[0].x = points[count-1].x;
  16.862 -        vertices[0].y = points[count-1].y;
  16.863 -        result = IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, 1, vertices, sizeof(*vertices));
  16.864 -    }
  16.865 -
  16.866 -    SDL_stack_free(vertices);
  16.867 -    if (FAILED(result)) {
  16.868 -        return D3D_SetError("DrawPrimitiveUP()", result);
  16.869 -    }
  16.870 -    return 0;
  16.871 -}
  16.872 -
  16.873 -static int
  16.874 -D3D_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects,
  16.875 -                    int count)
  16.876 -{
  16.877 -    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  16.878 -    DWORD color;
  16.879 -    int i;
  16.880 -    float minx, miny, maxx, maxy;
  16.881 -    Vertex vertices[4];
  16.882 -    HRESULT result;
  16.883 -
  16.884 -    if (D3D_ActivateRenderer(renderer) < 0) {
  16.885 -        return -1;
  16.886 -    }
  16.887 -
  16.888 -    D3D_SetBlendMode(data, renderer->blendMode);
  16.889 -
  16.890 -    result =
  16.891 -        IDirect3DDevice9_SetTexture(data->device, 0,
  16.892 -                                    (IDirect3DBaseTexture9 *) 0);
  16.893 -    if (FAILED(result)) {
  16.894 -        return D3D_SetError("SetTexture()", result);
  16.895 -    }
  16.896 -
  16.897 -    color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
  16.898 -
  16.899 -    for (i = 0; i < count; ++i) {
  16.900 -        const SDL_FRect *rect = &rects[i];
  16.901 -
  16.902 -        minx = rect->x;
  16.903 -        miny = rect->y;
  16.904 -        maxx = rect->x + rect->w;
  16.905 -        maxy = rect->y + rect->h;
  16.906 -
  16.907 -        vertices[0].x = minx;
  16.908 -        vertices[0].y = miny;
  16.909 -        vertices[0].z = 0.0f;
  16.910 -        vertices[0].color = color;
  16.911 -        vertices[0].u = 0.0f;
  16.912 -        vertices[0].v = 0.0f;
  16.913 -
  16.914 -        vertices[1].x = maxx;
  16.915 -        vertices[1].y = miny;
  16.916 -        vertices[1].z = 0.0f;
  16.917 -        vertices[1].color = color;
  16.918 -        vertices[1].u = 0.0f;
  16.919 -        vertices[1].v = 0.0f;
  16.920 -
  16.921 -        vertices[2].x = maxx;
  16.922 -        vertices[2].y = maxy;
  16.923 -        vertices[2].z = 0.0f;
  16.924 -        vertices[2].color = color;
  16.925 -        vertices[2].u = 0.0f;
  16.926 -        vertices[2].v = 0.0f;
  16.927 -
  16.928 -        vertices[3].x = minx;
  16.929 -        vertices[3].y = maxy;
  16.930 -        vertices[3].z = 0.0f;
  16.931 -        vertices[3].color = color;
  16.932 -        vertices[3].u = 0.0f;
  16.933 -        vertices[3].v = 0.0f;
  16.934 -
  16.935 -        result =
  16.936 -            IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN,
  16.937 -                                             2, vertices, sizeof(*vertices));
  16.938 -        if (FAILED(result)) {
  16.939 -            return D3D_SetError("DrawPrimitiveUP()", result);
  16.940 -        }
  16.941 -    }
  16.942 -    return 0;
  16.943 -}
  16.944 -
  16.945 -static void
  16.946 -D3D_UpdateTextureScaleMode(D3D_RenderData *data, D3D_TextureData *texturedata, unsigned index)
  16.947 +UpdateTextureScaleMode(D3D_RenderData *data, D3D_TextureData *texturedata, unsigned index)
  16.948  {
  16.949      if (texturedata->scaleMode != data->scaleMode[index]) {
  16.950          IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MINFILTER,
  16.951 @@ -1411,22 +1038,20 @@
  16.952  }
  16.953  
  16.954  static int
  16.955 -D3D_RenderSetupTextureState(SDL_Renderer * renderer, SDL_Texture * texture, LPDIRECT3DPIXELSHADER9 *shader)
  16.956 +SetupTextureState(D3D_RenderData *data, SDL_Texture * texture, LPDIRECT3DPIXELSHADER9 *shader)
  16.957  {
  16.958 -    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  16.959 -    D3D_TextureData *texturedata;
  16.960 +    D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
  16.961  
  16.962 -    *shader = NULL;
  16.963 +    SDL_assert(*shader == NULL);
  16.964  
  16.965 -    texturedata = (D3D_TextureData *)texture->driverdata;
  16.966      if (!texturedata) {
  16.967          SDL_SetError("Texture is not currently available");
  16.968          return -1;
  16.969      }
  16.970  
  16.971 -    D3D_UpdateTextureScaleMode(data, texturedata, 0);
  16.972 +    UpdateTextureScaleMode(data, texturedata, 0);
  16.973  
  16.974 -    if (D3D_BindTextureRep(data->device, &texturedata->texture, 0) < 0) {
  16.975 +    if (BindTextureRep(data->device, &texturedata->texture, 0) < 0) {
  16.976          return -1;
  16.977      }
  16.978  
  16.979 @@ -1445,13 +1070,13 @@
  16.980              return SDL_SetError("Unsupported YUV conversion mode");
  16.981          }
  16.982  
  16.983 -        D3D_UpdateTextureScaleMode(data, texturedata, 1);
  16.984 -        D3D_UpdateTextureScaleMode(data, texturedata, 2);
  16.985 +        UpdateTextureScaleMode(data, texturedata, 1);
  16.986 +        UpdateTextureScaleMode(data, texturedata, 2);
  16.987  
  16.988 -        if (D3D_BindTextureRep(data->device, &texturedata->utexture, 1) < 0) {
  16.989 +        if (BindTextureRep(data->device, &texturedata->utexture, 1) < 0) {
  16.990              return -1;
  16.991          }
  16.992 -        if (D3D_BindTextureRep(data->device, &texturedata->vtexture, 2) < 0) {
  16.993 +        if (BindTextureRep(data->device, &texturedata->vtexture, 2) < 0) {
  16.994              return -1;
  16.995          }
  16.996      }
  16.997 @@ -1459,194 +1084,326 @@
  16.998  }
  16.999  
 16.1000  static int
 16.1001 -D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
 16.1002 -               const SDL_Rect * srcrect, const SDL_FRect * dstrect)
 16.1003 +SetDrawState(D3D_RenderData *data, const SDL_RenderCommand *cmd)
 16.1004 +{
 16.1005 +    const SDL_bool was_copy_ex = data->drawstate.is_copy_ex;
 16.1006 +    const SDL_bool is_copy_ex = (cmd->command == SDL_RENDERCMD_COPY_EX);
 16.1007 +    SDL_Texture *texture = cmd->data.draw.texture;
 16.1008 +    const SDL_BlendMode blend = cmd->data.draw.blend;
 16.1009 +
 16.1010 +    if (texture != data->drawstate.texture) {
 16.1011 +        D3D_TextureData *oldtexturedata = data->drawstate.texture ? (D3D_TextureData *) data->drawstate.texture->driverdata : NULL;
 16.1012 +        D3D_TextureData *newtexturedata = texture ? (D3D_TextureData *) texture->driverdata : NULL;
 16.1013 +        LPDIRECT3DPIXELSHADER9 shader = NULL;
 16.1014 +
 16.1015 +        /* disable any enabled textures we aren't going to use, let SetupTextureState() do the rest. */
 16.1016 +        if (texture == NULL) {
 16.1017 +            IDirect3DDevice9_SetTexture(data->device, 0, NULL);
 16.1018 +        }
 16.1019 +        if ((!newtexturedata || !newtexturedata->yuv) && (oldtexturedata && oldtexturedata->yuv)) {
 16.1020 +            IDirect3DDevice9_SetTexture(data->device, 1, NULL);
 16.1021 +            IDirect3DDevice9_SetTexture(data->device, 2, NULL);
 16.1022 +        }
 16.1023 +        if (texture && SetupTextureState(data, texture, &shader) < 0) {
 16.1024 +            return -1;
 16.1025 +        }
 16.1026 +
 16.1027 +        if (shader != data->drawstate.shader) {
 16.1028 +            const HRESULT result = IDirect3DDevice9_SetPixelShader(data->device, shader);
 16.1029 +            if (FAILED(result)) {
 16.1030 +                return D3D_SetError("IDirect3DDevice9_SetPixelShader()", result);
 16.1031 +            }
 16.1032 +            data->drawstate.shader = shader;
 16.1033 +        }
 16.1034 +
 16.1035 +        data->drawstate.texture = texture;
 16.1036 +    }
 16.1037 +
 16.1038 +    if (blend != data->drawstate.blend) {
 16.1039 +        if (blend == SDL_BLENDMODE_NONE) {
 16.1040 +            IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, FALSE);
 16.1041 +        } else {
 16.1042 +            IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, TRUE);
 16.1043 +            IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
 16.1044 +                                            GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blend)));
 16.1045 +            IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
 16.1046 +                                            GetBlendFunc(SDL_GetBlendModeDstColorFactor(blend)));
 16.1047 +            if (data->enableSeparateAlphaBlend) {
 16.1048 +                IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA,
 16.1049 +                                                GetBlendFunc(SDL_GetBlendModeSrcAlphaFactor(blend)));
 16.1050 +                IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA,
 16.1051 +                                                GetBlendFunc(SDL_GetBlendModeDstAlphaFactor(blend)));
 16.1052 +            }
 16.1053 +        }
 16.1054 +
 16.1055 +        data->drawstate.blend = blend;
 16.1056 +    }
 16.1057 +
 16.1058 +    if (is_copy_ex != was_copy_ex) {
 16.1059 +        if (!is_copy_ex) {  /* SDL_RENDERCMD_COPY_EX will set this, we only want to reset it here if necessary. */
 16.1060 +            const Float4X4 d3dmatrix = MatrixIdentity();
 16.1061 +            IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*) &d3dmatrix);
 16.1062 +        }
 16.1063 +        data->drawstate.is_copy_ex = is_copy_ex;
 16.1064 +    }
 16.1065 +
 16.1066 +    if (data->drawstate.viewport_dirty) {
 16.1067 +        const SDL_Rect *viewport = &data->drawstate.viewport;
 16.1068 +        const D3DVIEWPORT9 d3dviewport = { viewport->x, viewport->y, viewport->w, viewport->h, 0.0f, 1.0f };
 16.1069 +        IDirect3DDevice9_SetViewport(data->device, &d3dviewport);
 16.1070 +
 16.1071 +        /* Set an orthographic projection matrix */
 16.1072 +        if (viewport->w && viewport->h) {
 16.1073 +            D3DMATRIX d3dmatrix;
 16.1074 +            SDL_zero(d3dmatrix);
 16.1075 +            d3dmatrix.m[0][0] = 2.0f / viewport->w;
 16.1076 +            d3dmatrix.m[1][1] = -2.0f / viewport->h;
 16.1077 +            d3dmatrix.m[2][2] = 1.0f;
 16.1078 +            d3dmatrix.m[3][0] = -1.0f;
 16.1079 +            d3dmatrix.m[3][1] = 1.0f;
 16.1080 +            d3dmatrix.m[3][3] = 1.0f;
 16.1081 +            IDirect3DDevice9_SetTransform(data->device, D3DTS_PROJECTION, &d3dmatrix);
 16.1082 +        }
 16.1083 +
 16.1084 +        data->drawstate.viewport_dirty = SDL_FALSE;
 16.1085 +    }
 16.1086 +
 16.1087 +    if (data->drawstate.cliprect_enabled_dirty) {
 16.1088 +        IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, data->drawstate.cliprect_enabled ? TRUE : FALSE);
 16.1089 +        data->drawstate.cliprect_enabled_dirty = SDL_FALSE;
 16.1090 +    }
 16.1091 +
 16.1092 +    if (data->drawstate.cliprect_dirty) {
 16.1093 +        const SDL_Rect *viewport = &data->drawstate.viewport;
 16.1094 +        const SDL_Rect *rect = &cmd->data.cliprect.rect;
 16.1095 +        const RECT d3drect = { viewport->x + rect->x, viewport->y + rect->y, viewport->x + rect->x + rect->w, viewport->y + rect->y + rect->h };
 16.1096 +        IDirect3DDevice9_SetScissorRect(data->device, &d3drect);
 16.1097 +        data->drawstate.cliprect_dirty = SDL_FALSE;
 16.1098 +    }
 16.1099 +
 16.1100 +    return 0;
 16.1101 +}
 16.1102 +
 16.1103 +static int
 16.1104 +D3D_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
 16.1105  {
 16.1106      D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
 16.1107 -    LPDIRECT3DPIXELSHADER9 shader;
 16.1108 -    float minx, miny, maxx, maxy;
 16.1109 -    float minu, maxu, minv, maxv;
 16.1110 -    DWORD color;
 16.1111 -    Vertex vertices[4];
 16.1112 -    HRESULT result;
 16.1113 +    const int vboidx = data->currentVertexBuffer;
 16.1114 +    IDirect3DVertexBuffer9 *vbo = NULL;
 16.1115 +    const SDL_bool istarget = renderer->target != NULL;
 16.1116 +    size_t i;
 16.1117  
 16.1118      if (D3D_ActivateRenderer(renderer) < 0) {
 16.1119          return -1;
 16.1120      }
 16.1121  
 16.1122 -    minx = dstrect->x - 0.5f;
 16.1123 -    miny = dstrect->y - 0.5f;
 16.1124 -    maxx = dstrect->x + dstrect->w - 0.5f;
 16.1125 -    maxy = dstrect->y + dstrect->h - 0.5f;
 16.1126 +    /* upload the new VBO data for this set of commands. */
 16.1127 +    vbo = data->vertexBuffers[vboidx];
 16.1128 +    if (!vbo || (data->vertexBufferSize[vboidx] < vertsize)) {
 16.1129 +        const DWORD usage = D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY;
 16.1130 +        const DWORD fvf = D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1;
 16.1131 +        if (vbo) {
 16.1132 +            IDirect3DVertexBuffer9_Release(vbo);
 16.1133 +        }
 16.1134  
 16.1135 -    minu = (float) srcrect->x / texture->w;
 16.1136 -    maxu = (float) (srcrect->x + srcrect->w) / texture->w;
 16.1137 -    minv = (float) srcrect->y / texture->h;
 16.1138 -    maxv = (float) (srcrect->y + srcrect->h) / texture->h;
 16.1139 +        if (FAILED(IDirect3DDevice9_CreateVertexBuffer(data->device, vertsize, usage, fvf, D3DPOOL_DEFAULT, &vbo, NULL))) {
 16.1140 +            vbo = NULL;
 16.1141 +        }
 16.1142 +        data->vertexBuffers[vboidx] = vbo;
 16.1143 +        data->vertexBufferSize[vboidx] = vbo ? vertsize : 0;
 16.1144 +    }
 16.1145  
 16.1146 -    color = D3DCOLOR_ARGB(texture->a, texture->r, texture->g, texture->b);
 16.1147 -
 16.1148 -    vertices[0].x = minx;
 16.1149 -    vertices[0].y = miny;
 16.1150 -    vertices[0].z = 0.0f;
 16.1151 -    vertices[0].color = color;
 16.1152 -    vertices[0].u = minu;
 16.1153 -    vertices[0].v = minv;
 16.1154 -
 16.1155 -    vertices[1].x = maxx;
 16.1156 -    vertices[1].y = miny;
 16.1157 -    vertices[1].z = 0.0f;
 16.1158 -    vertices[1].color = color;
 16.1159 -    vertices[1].u = maxu;
 16.1160 -    vertices[1].v = minv;
 16.1161 -
 16.1162 -    vertices[2].x = maxx;
 16.1163 -    vertices[2].y = maxy;
 16.1164 -    vertices[2].z = 0.0f;
 16.1165 -    vertices[2].color = color;
 16.1166 -    vertices[2].u = maxu;
 16.1167 -    vertices[2].v = maxv;
 16.1168 -
 16.1169 -    vertices[3].x = minx;
 16.1170 -    vertices[3].y = maxy;
 16.1171 -    vertices[3].z = 0.0f;
 16.1172 -    vertices[3].color = color;
 16.1173 -    vertices[3].u = minu;
 16.1174 -    vertices[3].v = maxv;
 16.1175 -
 16.1176 -    D3D_SetBlendMode(data, texture->blendMode);
 16.1177 -
 16.1178 -    if (D3D_RenderSetupTextureState(renderer, texture, &shader) < 0) {
 16.1179 -        return -1;
 16.1180 -    }
 16.1181 -    
 16.1182 -    if (shader) {
 16.1183 -        result = IDirect3DDevice9_SetPixelShader(data->device, shader);
 16.1184 -        if (FAILED(result)) {
 16.1185 -            return D3D_SetError("SetShader()", result);
 16.1186 +    if (vbo) {
 16.1187 +        void *ptr;
 16.1188 +        if (FAILED(IDirect3DVertexBuffer9_Lock(vbo, 0, vertsize, &ptr, D3DLOCK_DISCARD))) {
 16.1189 +            vbo = NULL;  /* oh well, we'll do immediate mode drawing.  :(  */
 16.1190 +        } else {
 16.1191 +            SDL_memcpy(ptr, vertices, vertsize);
 16.1192 +            if (FAILED(IDirect3DVertexBuffer9_Unlock(vbo))) {
 16.1193 +                vbo = NULL;  /* oh well, we'll do immediate mode drawing.  :(  */
 16.1194 +            }
 16.1195          }
 16.1196      }
 16.1197 -    result = IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2,
 16.1198 -                                              vertices, sizeof(*vertices));
 16.1199 -    if (FAILED(result)) {
 16.1200 -        D3D_SetError("DrawPrimitiveUP()", result);
 16.1201 +
 16.1202 +    /* cycle through a few VBOs so D3D has some time with the data before we replace it. */
 16.1203 +    if (vbo) {
 16.1204 +        data->currentVertexBuffer++;
 16.1205 +        if (data->currentVertexBuffer >= SDL_arraysize(data->vertexBuffers)) {
 16.1206 +            data->currentVertexBuffer = 0;
 16.1207 +        }
 16.1208 +    } else if (!data->reportedVboProblem) {
 16.1209 +        SDL_LogError(SDL_LOG_CATEGORY_RENDER, "SDL failed to get a vertex buffer for this Direct3D 9 rendering batch!");
 16.1210 +        SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Dropping back to a slower method.");
 16.1211 +        SDL_LogError(SDL_LOG_CATEGORY_RENDER, "This might be a brief hiccup, but if performance is bad, this is probably why.");
 16.1212 +        SDL_LogError(SDL_LOG_CATEGORY_RENDER, "This error will not be logged again for this renderer.");
 16.1213 +        data->reportedVboProblem = SDL_TRUE;
 16.1214      }
 16.1215 -    if (shader) {
 16.1216 -        IDirect3DDevice9_SetPixelShader(data->device, NULL);
 16.1217 +
 16.1218 +    IDirect3DDevice9_SetStreamSource(data->device, 0, vbo, 0, sizeof (Vertex));
 16.1219 +
 16.1220 +    while (cmd) {
 16.1221 +        switch (cmd->command) {
 16.1222 +            case SDL_RENDERCMD_SETDRAWCOLOR: {
 16.1223 +                /* currently this is sent with each vertex, but if we move to
 16.1224 +                   shaders, we can put this in a uniform here and reduce vertex
 16.1225 +                   buffer bandwidth */
 16.1226 +                break;
 16.1227 +            }
 16.1228 +
 16.1229 +            case SDL_RENDERCMD_SETVIEWPORT: {
 16.1230 +                SDL_Rect *viewport = &data->drawstate.viewport;
 16.1231 +                if (SDL_memcmp(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect)) != 0) {
 16.1232 +                    SDL_memcpy(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect));
 16.1233 +                    data->drawstate.viewport_dirty = SDL_TRUE;
 16.1234 +                }
 16.1235 +                break;
 16.1236 +            }
 16.1237 +
 16.1238 +            case SDL_RENDERCMD_SETCLIPRECT: {
 16.1239 +                const SDL_Rect *rect = &cmd->data.cliprect.rect;
 16.1240 +                if (data->drawstate.cliprect_enabled != cmd->data.cliprect.enabled) {
 16.1241 +                    data->drawstate.cliprect_enabled = cmd->data.cliprect.enabled;
 16.1242 +                    data->drawstate.cliprect_enabled_dirty = SDL_TRUE;
 16.1243 +                }
 16.1244 +
 16.1245 +                if (SDL_memcmp(&data->drawstate.cliprect, rect, sizeof (SDL_Rect)) != 0) {
 16.1246 +                    SDL_memcpy(&data->drawstate.cliprect, rect, sizeof (SDL_Rect));
 16.1247 +                    data->drawstate.cliprect_dirty = SDL_TRUE;
 16.1248 +                }
 16.1249 +                break;
 16.1250 +            }
 16.1251 +
 16.1252 +            case SDL_RENDERCMD_CLEAR: {
 16.1253 +                const DWORD color = D3DCOLOR_ARGB(cmd->data.color.a, cmd->data.color.r, cmd->data.color.g, cmd->data.color.b);
 16.1254 +                const SDL_Rect *viewport = &data->drawstate.viewport;
 16.1255 +                const int backw = istarget ? renderer->target->w : data->pparams.BackBufferWidth;
 16.1256 +                const int backh = istarget ? renderer->target->h : data->pparams.BackBufferHeight;
 16.1257 +
 16.1258 +                if (data->drawstate.cliprect_enabled) {
 16.1259 +                    IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, FALSE);
 16.1260 +                    data->drawstate.cliprect_enabled_dirty = SDL_TRUE;
 16.1261 +                }
 16.1262 +
 16.1263 +                /* Don't reset the viewport if we don't have to! */
 16.1264 +                if (!viewport->x && !viewport->y && (viewport->w == backw) && (viewport->h == backh)) {
 16.1265 +                    IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
 16.1266 +                } else {
 16.1267 +                    /* Clear is defined to clear the entire render target */
 16.1268 +                    const D3DVIEWPORT9 wholeviewport = { 0, 0, backw, backh, 0.0f, 1.0f };
 16.1269 +                    IDirect3DDevice9_SetViewport(data->device, &wholeviewport);
 16.1270 +                    data->drawstate.viewport_dirty = SDL_TRUE;
 16.1271 +                    IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
 16.1272 +                }
 16.1273 +
 16.1274 +                break;
 16.1275 +            }
 16.1276 +
 16.1277 +            case SDL_RENDERCMD_DRAW_POINTS: {
 16.1278 +                const size_t count = cmd->data.draw.count;
 16.1279 +                const size_t first = cmd->data.draw.first;
 16.1280 +                SetDrawState(data, cmd);
 16.1281 +                if (vbo) {
 16.1282 +                    IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_POINTLIST, first / sizeof (Vertex), count);
 16.1283 +                } else {
 16.1284 +                    const Vertex *verts = (Vertex *) (((Uint8 *) vertices) + first);
 16.1285 +                    IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, count, vertices, sizeof (Vertex));
 16.1286 +                }
 16.1287 +                break;
 16.1288 +            }
 16.1289 +
 16.1290 +            case SDL_RENDERCMD_DRAW_LINES: {
 16.1291 +                const size_t count = cmd->data.draw.count;
 16.1292 +                const size_t first = cmd->data.draw.first;
 16.1293 +                const Vertex *verts = (Vertex *) (((Uint8 *) vertices) + first);
 16.1294 +
 16.1295 +                /* DirectX 9 has the same line rasterization semantics as GDI,
 16.1296 +                   so we need to close the endpoint of the line with a second draw call. */
 16.1297 +                const SDL_bool close_endpoint = ((count == 2) || (verts[0].x != verts[count-1].x) || (verts[0].y != verts[count-1].y));
 16.1298 +
 16.1299 +                SetDrawState(data, cmd);
 16.1300 +
 16.1301 +                if (vbo) {
 16.1302 +                    IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_LINESTRIP, first / sizeof (Vertex), count - 1);
 16.1303 +                    if (close_endpoint) {
 16.1304 +                        IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_POINTLIST, (first / sizeof (Vertex)) + (count - 1), 1);
 16.1305 +                    }
 16.1306 +                } else {
 16.1307 +                    IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_LINESTRIP, count - 1, verts, sizeof (Vertex));
 16.1308 +                    if (close_endpoint) {
 16.1309 +                        IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, 1, &verts[count-1], sizeof (Vertex));
 16.1310 +                    }
 16.1311 +                }
 16.1312 +                break;
 16.1313 +            }
 16.1314 +
 16.1315 +            case SDL_RENDERCMD_FILL_RECTS: {
 16.1316 +                const size_t count = cmd->data.draw.count;
 16.1317 +                const size_t first = cmd->data.draw.first;
 16.1318 +                SetDrawState(data, cmd);
 16.1319 +                if (vbo) {
 16.1320 +                    size_t offset = 0;
 16.1321 +                    for (i = 0; i < count; ++i, offset += 4) {
 16.1322 +                        IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_TRIANGLEFAN, (first / sizeof (Vertex)) + offset, 2);
 16.1323 +                    }
 16.1324 +                } else {
 16.1325 +                    const Vertex *verts = (Vertex *) (((Uint8 *) vertices) + first);
 16.1326 +                    for (i = 0; i < count; ++i, verts += 4) {
 16.1327 +                        IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2, verts, sizeof (Vertex));
 16.1328 +                    }
 16.1329 +                }
 16.1330 +                break;
 16.1331 +            }
 16.1332 +
 16.1333 +            case SDL_RENDERCMD_COPY: {
 16.1334 +                const size_t count = cmd->data.draw.count;
 16.1335 +                const size_t first = cmd->data.draw.first;
 16.1336 +                SetDrawState(data, cmd);
 16.1337 +                if (vbo) {
 16.1338 +                    size_t offset = 0;
 16.1339 +                    for (i = 0; i < count; ++i, offset += 4) {
 16.1340 +                        IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_TRIANGLEFAN, (first / sizeof (Vertex)) + offset, 2);
 16.1341 +                    }
 16.1342 +                } else {
 16.1343 +                    const Vertex *verts = (Vertex *) (((Uint8 *) vertices) + first);
 16.1344 +                    for (i = 0; i < count; ++i, verts += 4) {
 16.1345 +                        IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2, verts, sizeof (Vertex));
 16.1346 +                    }
 16.1347 +                }
 16.1348 +                break;
 16.1349 +            }
 16.1350 +
 16.1351 +            case SDL_RENDERCMD_COPY_EX: {
 16.1352 +                const size_t first = cmd->data.draw.first;
 16.1353 +                const Vertex *verts = (Vertex *) (((Uint8 *) vertices) + first);
 16.1354 +                const Vertex *transvert = verts + 4;
 16.1355 +                const float translatex = transvert->x;
 16.1356 +                const float translatey = transvert->y;
 16.1357 +                const float rotation = transvert->z;
 16.1358 +                const Float4X4 d3dmatrix = MatrixMultiply(MatrixRotationZ(rotation), MatrixTranslation(translatex, translatey, 0));
 16.1359 +                SetDrawState(data, cmd);
 16.1360 +
 16.1361 +                IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)&d3dmatrix);
 16.1362 +
 16.1363 +                if (vbo) {
 16.1364 +                    IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_TRIANGLEFAN, first / sizeof (Vertex), 2);
 16.1365 +                } else {
 16.1366 +                    IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2, verts, sizeof (Vertex));
 16.1367 +                }
 16.1368 +                break;
 16.1369 +            }
 16.1370 +
 16.1371 +            case SDL_RENDERCMD_NO_OP:
 16.1372 +                break;
 16.1373 +        }
 16.1374 +
 16.1375 +        cmd = cmd->next;
 16.1376      }
 16.1377 -    return FAILED(result) ? -1 : 0;
 16.1378 +
 16.1379 +    return 0;
 16.1380  }
 16.1381  
 16.1382  
 16.1383  static int
 16.1384 -D3D_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
 16.1385 -               const SDL_Rect * srcrect, const SDL_FRect * dstrect,
 16.1386 -               const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip)
 16.1387 -{
 16.1388 -    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
 16.1389 -    LPDIRECT3DPIXELSHADER9 shader = NULL;
 16.1390 -    float minx, miny, maxx, maxy;
 16.1391 -    float minu, maxu, minv, maxv;
 16.1392 -    float centerx, centery;
 16.1393 -    DWORD color;
 16.1394 -    Vertex vertices[4];
 16.1395 -    Float4X4 modelMatrix;
 16.1396 -    HRESULT result;
 16.1397 -
 16.1398 -    if (D3D_ActivateRenderer(renderer) < 0) {
 16.1399 -        return -1;
 16.1400 -    }
 16.1401 -
 16.1402 -    centerx = center->x;
 16.1403 -    centery = center->y;
 16.1404 -
 16.1405 -    minx = -centerx;
 16.1406 -    maxx = dstrect->w - centerx;
 16.1407 -    miny = -centery;
 16.1408 -    maxy = dstrect->h - centery;
 16.1409 -
 16.1410 -    minu = (float) srcrect->x / texture->w;
 16.1411 -    maxu = (float) (srcrect->x + srcrect->w) / texture->w;
 16.1412 -    minv = (float) srcrect->y / texture->h;
 16.1413 -    maxv = (float) (srcrect->y + srcrect->h) / texture->h;
 16.1414 -
 16.1415 -    if (flip & SDL_FLIP_HORIZONTAL) {
 16.1416 -        float tmp = maxu;
 16.1417 -        maxu = minu;
 16.1418 -        minu = tmp;
 16.1419 -    }
 16.1420 -    if (flip & SDL_FLIP_VERTICAL) {
 16.1421 -        float tmp = maxv;
 16.1422 -        maxv = minv;
 16.1423 -        minv = tmp;
 16.1424 -    }
 16.1425 -
 16.1426 -    color = D3DCOLOR_ARGB(texture->a, texture->r, texture->g, texture->b);
 16.1427 -
 16.1428 -    vertices[0].x = minx;
 16.1429 -    vertices[0].y = miny;
 16.1430 -    vertices[0].z = 0.0f;
 16.1431 -    vertices[0].color = color;
 16.1432 -    vertices[0].u = minu;
 16.1433 -    vertices[0].v = minv;
 16.1434 -
 16.1435 -    vertices[1].x = maxx;
 16.1436 -    vertices[1].y = miny;
 16.1437 -    vertices[1].z = 0.0f;
 16.1438 -    vertices[1].color = color;
 16.1439 -    vertices[1].u = maxu;
 16.1440 -    vertices[1].v = minv;
 16.1441 -
 16.1442 -    vertices[2].x = maxx;
 16.1443 -    vertices[2].y = maxy;
 16.1444 -    vertices[2].z = 0.0f;
 16.1445 -    vertices[2].color = color;
 16.1446 -    vertices[2].u = maxu;
 16.1447 -    vertices[2].v = maxv;
 16.1448 -
 16.1449 -    vertices[3].x = minx;
 16.1450 -    vertices[3].y = maxy;
 16.1451 -    vertices[3].z = 0.0f;
 16.1452 -    vertices[3].color = color;
 16.1453 -    vertices[3].u = minu;
 16.1454 -    vertices[3].v = maxv;
 16.1455 -
 16.1456 -    D3D_SetBlendMode(data, texture->blendMode);
 16.1457 -
 16.1458 -    if (D3D_RenderSetupTextureState(renderer, texture, &shader) < 0) {
 16.1459 -        return -1;
 16.1460 -    }
 16.1461 -
 16.1462 -    /* Rotate and translate */
 16.1463 -    modelMatrix = MatrixMultiply(
 16.1464 -            MatrixRotationZ((float)(M_PI * (float) angle / 180.0f)),
 16.1465 -            MatrixTranslation(dstrect->x + center->x - 0.5f, dstrect->y + center->y - 0.5f, 0));
 16.1466 -    IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)&modelMatrix);
 16.1467 -    
 16.1468 -    if (shader) {
 16.1469 -        result = IDirect3DDevice9_SetPixelShader(data->device, shader);
 16.1470 -        if (FAILED(result)) {
 16.1471 -            D3D_SetError("SetShader()", result);
 16.1472 -            goto done;
 16.1473 -        }
 16.1474 -    }
 16.1475 -    result = IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2,
 16.1476 -                                              vertices, sizeof(*vertices));
 16.1477 -    if (FAILED(result)) {
 16.1478 -        D3D_SetError("DrawPrimitiveUP()", result);
 16.1479 -    }
 16.1480 -done:
 16.1481 -    if (shader) {
 16.1482 -        IDirect3DDevice9_SetPixelShader(data->device, NULL);
 16.1483 -    }
 16.1484 -
 16.1485 -    modelMatrix = MatrixIdentity();
 16.1486 -    IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)&modelMatrix);
 16.1487 -
 16.1488 -    return FAILED(result) ? -1 : 0;
 16.1489 -}
 16.1490 -
 16.1491 -static int
 16.1492  D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
 16.1493                       Uint32 format, void * pixels, int pitch)
 16.1494  {
 16.1495 @@ -1782,6 +1539,249 @@
 16.1496      }
 16.1497      SDL_free(renderer);
 16.1498  }
 16.1499 +
 16.1500 +static int
 16.1501 +D3D_Reset(SDL_Renderer * renderer)
 16.1502 +{
 16.1503 +    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
 16.1504 +    HRESULT result;
 16.1505 +    SDL_Texture *texture;
 16.1506 +
 16.1507 +    /* Release the default render target before reset */
 16.1508 +    if (data->defaultRenderTarget) {
 16.1509 +        IDirect3DSurface9_Release(data->defaultRenderTarget);
 16.1510 +        data->defaultRenderTarget = NULL;
 16.1511 +    }
 16.1512 +    if (data->currentRenderTarget != NULL) {
 16.1513 +        IDirect3DSurface9_Release(data->currentRenderTarget);
 16.1514 +        data->currentRenderTarget = NULL;
 16.1515 +    }
 16.1516 +
 16.1517 +    /* Release application render targets */
 16.1518 +    for (texture = renderer->textures; texture; texture = texture->next) {
 16.1519 +        if (texture->access == SDL_TEXTUREACCESS_TARGET) {
 16.1520 +            D3D_DestroyTexture(renderer, texture);
 16.1521 +        } else {
 16.1522 +            D3D_RecreateTexture(renderer, texture);
 16.1523 +        }
 16.1524 +    }
 16.1525 +
 16.1526 +    result = IDirect3DDevice9_Reset(data->device, &data->pparams);
 16.1527 +    if (FAILED(result)) {
 16.1528 +        if (result == D3DERR_DEVICELOST) {
 16.1529 +            /* Don't worry about it, we'll reset later... */
 16.1530 +            return 0;
 16.1531 +        } else {
 16.1532 +            return D3D_SetError("Reset()", result);
 16.1533 +        }
 16.1534 +    }
 16.1535 +
 16.1536 +    /* Allocate application render targets */
 16.1537 +    for (texture = renderer->textures; texture; texture = texture->next) {
 16.1538 +        if (texture->access == SDL_TEXTUREACCESS_TARGET) {
 16.1539 +            D3D_CreateTexture(renderer, texture);
 16.1540 +        }
 16.1541 +    }
 16.1542 +
 16.1543 +    IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget);
 16.1544 +    D3D_InitRenderState(data);
 16.1545 +    D3D_SetRenderTargetInternal(renderer, renderer->target);
 16.1546 +    data->drawstate.viewport_dirty = SDL_TRUE;
 16.1547 +
 16.1548 +    /* Let the application know that render targets were reset */
 16.1549 +    {
 16.1550 +        SDL_Event event;
 16.1551 +        event.type = SDL_RENDER_TARGETS_RESET;
 16.1552 +        SDL_PushEvent(&event);
 16.1553 +    }
 16.1554 +
 16.1555 +    return 0;
 16.1556 +}
 16.1557 +
 16.1558 +SDL_Renderer *
 16.1559 +D3D_CreateRenderer(SDL_Window * window, Uint32 flags)
 16.1560 +{
 16.1561 +    SDL_Renderer *renderer;
 16.1562 +    D3D_RenderData *data;
 16.1563 +    SDL_SysWMinfo windowinfo;
 16.1564 +    HRESULT result;
 16.1565 +    D3DPRESENT_PARAMETERS pparams;
 16.1566 +    IDirect3DSwapChain9 *chain;
 16.1567 +    D3DCAPS9 caps;
 16.1568 +    DWORD device_flags;
 16.1569 +    Uint32 window_flags;
 16.1570 +    int w, h;
 16.1571 +    SDL_DisplayMode fullscreen_mode;
 16.1572 +    int displayIndex;
 16.1573 +
 16.1574 +    renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
 16.1575 +    if (!renderer) {
 16.1576 +        SDL_OutOfMemory();
 16.1577 +        return NULL;
 16.1578 +    }
 16.1579 +
 16.1580 +    data = (D3D_RenderData *) SDL_calloc(1, sizeof(*data));
 16.1581 +    if (!data) {
 16.1582 +        SDL_free(renderer);
 16.1583 +        SDL_OutOfMemory();
 16.1584 +        return NULL;
 16.1585 +    }
 16.1586 +
 16.1587 +    if (!D3D_LoadDLL(&data->d3dDLL, &data->d3d)) {
 16.1588 +        SDL_free(renderer);
 16.1589 +        SDL_free(data);
 16.1590 +        SDL_SetError("Unable to create Direct3D interface");
 16.1591 +        return NULL;
 16.1592 +    }
 16.1593 +
 16.1594 +    renderer->WindowEvent = D3D_WindowEvent;
 16.1595 +    renderer->SupportsBlendMode = D3D_SupportsBlendMode;
 16.1596 +    renderer->CreateTexture = D3D_CreateTexture;
 16.1597 +    renderer->UpdateTexture = D3D_UpdateTexture;
 16.1598 +    renderer->UpdateTextureYUV = D3D_UpdateTextureYUV;
 16.1599 +    renderer->LockTexture = D3D_LockTexture;
 16.1600 +    renderer->UnlockTexture = D3D_UnlockTexture;
 16.1601 +    renderer->SetRenderTarget = D3D_SetRenderTarget;
 16.1602 +    renderer->QueueSetViewport = D3D_QueueSetViewport;
 16.1603 +    renderer->QueueSetDrawColor = D3D_QueueSetViewport;  /* SetViewport and SetDrawColor are (currently) no-ops. */
 16.1604 +    renderer->QueueDrawPoints = D3D_QueueDrawPoints;
 16.1605 +    renderer->QueueDrawLines = D3D_QueueDrawPoints;  /* lines and points queue vertices the same way. */
 16.1606 +    renderer->QueueFillRects = D3D_QueueFillRects;
 16.1607 +    renderer->QueueCopy = D3D_QueueCopy;
 16.1608 +    renderer->QueueCopyEx = D3D_QueueCopyEx;
 16.1609 +    renderer->RunCommandQueue = D3D_RunCommandQueue;
 16.1610 +    renderer->RenderReadPixels = D3D_RenderReadPixels;
 16.1611 +    renderer->RenderPresent = D3D_RenderPresent;
 16.1612 +    renderer->DestroyTexture = D3D_DestroyTexture;
 16.1613 +    renderer->DestroyRenderer = D3D_DestroyRenderer;
 16.1614 +    renderer->info = D3D_RenderDriver.info;
 16.1615 +    renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
 16.1616 +    renderer->driverdata = data;
 16.1617 +
 16.1618 +    SDL_VERSION(&windowinfo.version);
 16.1619 +    SDL_GetWindowWMInfo(window, &windowinfo);
 16.1620 +
 16.1621 +    window_flags = SDL_GetWindowFlags(window);
 16.1622 +    SDL_GetWindowSize(window, &w, &h);
 16.1623 +    SDL_GetWindowDisplayMode(window, &fullscreen_mode);
 16.1624 +
 16.1625 +    SDL_zero(pparams);
 16.1626 +    pparams.hDeviceWindow = windowinfo.info.win.window;
 16.1627 +    pparams.BackBufferWidth = w;
 16.1628 +    pparams.BackBufferHeight = h;
 16.1629 +    pparams.BackBufferCount = 1;
 16.1630 +    pparams.SwapEffect = D3DSWAPEFFECT_DISCARD;
 16.1631 +
 16.1632 +    if (window_flags & SDL_WINDOW_FULLSCREEN && (window_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
 16.1633 +        pparams.Windowed = FALSE;
 16.1634 +        pparams.BackBufferFormat = PixelFormatToD3DFMT(fullscreen_mode.format);
 16.1635 +        pparams.FullScreen_RefreshRateInHz = fullscreen_mode.refresh_rate;
 16.1636 +    } else {
 16.1637 +        pparams.Windowed = TRUE;
 16.1638 +        pparams.BackBufferFormat = D3DFMT_UNKNOWN;
 16.1639 +        pparams.FullScreen_RefreshRateInHz = 0;
 16.1640 +    }
 16.1641 +    if (flags & SDL_RENDERER_PRESENTVSYNC) {
 16.1642 +        pparams.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
 16.1643 +    } else {
 16.1644 +        pparams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
 16.1645 +    }
 16.1646 +
 16.1647 +    /* Get the adapter for the display that the window is on */
 16.1648 +    displayIndex = SDL_GetWindowDisplayIndex(window);
 16.1649 +    data->adapter = SDL_Direct3D9GetAdapterIndex(displayIndex);
 16.1650 +
 16.1651 +    IDirect3D9_GetDeviceCaps(data->d3d, data->adapter, D3DDEVTYPE_HAL, &caps);
 16.1652 +
 16.1653 +    device_flags = D3DCREATE_FPU_PRESERVE;
 16.1654 +    if (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) {
 16.1655 +        device_flags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
 16.1656 +    } else {
 16.1657 +        device_flags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
 16.1658 +    }
 16.1659 +
 16.1660 +    if (SDL_GetHintBoolean(SDL_HINT_RENDER_DIRECT3D_THREADSAFE, SDL_FALSE)) {
 16.1661 +        device_flags |= D3DCREATE_MULTITHREADED;
 16.1662 +    }
 16.1663 +
 16.1664 +    result = IDirect3D9_CreateDevice(data->d3d, data->adapter,
 16.1665 +                                     D3DDEVTYPE_HAL,
 16.1666 +                                     pparams.hDeviceWindow,
 16.1667 +                                     device_flags,
 16.1668 +                                     &pparams, &data->device);
 16.1669 +    if (FAILED(result)) {
 16.1670 +        D3D_DestroyRenderer(renderer);
 16.1671 +        D3D_SetError("CreateDevice()", result);
 16.1672 +        return NULL;
 16.1673 +    }
 16.1674 +
 16.1675 +    /* Get presentation parameters to fill info */
 16.1676 +    result = IDirect3DDevice9_GetSwapChain(data->device, 0, &chain);
 16.1677 +    if (FAILED(result)) {
 16.1678 +        D3D_DestroyRenderer(renderer);
 16.1679 +        D3D_SetError("GetSwapChain()", result);
 16.1680 +        return NULL;
 16.1681 +    }
 16.1682 +    result = IDirect3DSwapChain9_GetPresentParameters(chain, &pparams);
 16.1683 +    if (FAILED(result)) {
 16.1684 +        IDirect3DSwapChain9_Release(chain);
 16.1685 +        D3D_DestroyRenderer(renderer);
 16.1686 +        D3D_SetError("GetPresentParameters()", result);
 16.1687 +        return NULL;
 16.1688 +    }
 16.1689 +    IDirect3DSwapChain9_Release(chain);
 16.1690 +    if (pparams.PresentationInterval == D3DPRESENT_INTERVAL_ONE) {
 16.1691 +        renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
 16.1692 +    }
 16.1693 +    data->pparams = pparams;
 16.1694 +
 16.1695 +    IDirect3DDevice9_GetDeviceCaps(data->device, &caps);
 16.1696 +    renderer->info.max_texture_width = caps.MaxTextureWidth;
 16.1697 +    renderer->info.max_texture_height = caps.MaxTextureHeight;
 16.1698 +    if (caps.NumSimultaneousRTs >= 2) {
 16.1699 +        renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE;
 16.1700 +    }
 16.1701 +
 16.1702 +    if (caps.PrimitiveMiscCaps & D3DPMISCCAPS_SEPARATEALPHABLEND) {
 16.1703 +        data->enableSeparateAlphaBlend = SDL_TRUE;
 16.1704 +    }
 16.1705 +
 16.1706 +    /* Store the default render target */
 16.1707 +    IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget);
 16.1708 +    data->currentRenderTarget = NULL;
 16.1709 +
 16.1710 +    /* Set up parameters for rendering */
 16.1711 +    D3D_InitRenderState(data);
 16.1712 +
 16.1713 +    if (caps.MaxSimultaneousTextures >= 3) {
 16.1714 +        int i;
 16.1715 +        for (i = 0; i < SDL_arraysize(data->shaders); ++i) {
 16.1716 +            result = D3D9_CreatePixelShader(data->device, (D3D9_Shader)i, &data->shaders[i]);
 16.1717 +            if (FAILED(result)) {
 16.1718 +                D3D_SetError("CreatePixelShader()", result);
 16.1719 +            }
 16.1720 +        }
 16.1721 +        if (data->shaders[SHADER_YUV_JPEG] && data->shaders[SHADER_YUV_BT601] && data->shaders[SHADER_YUV_BT709]) {
 16.1722 +            renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;
 16.1723 +            renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
 16.1724 +        }
 16.1725 +    }
 16.1726 +
 16.1727 +    data->drawstate.blend = SDL_BLENDMODE_INVALID;
 16.1728 +
 16.1729 +    return renderer;
 16.1730 +}
 16.1731 +
 16.1732 +SDL_RenderDriver D3D_RenderDriver = {
 16.1733 +    D3D_CreateRenderer,
 16.1734 +    {
 16.1735 +     "direct3d",
 16.1736 +     (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
 16.1737 +     1,
 16.1738 +     {SDL_PIXELFORMAT_ARGB8888},
 16.1739 +     0,
 16.1740 +     0}
 16.1741 +};
 16.1742  #endif /* SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED */
 16.1743  
 16.1744  #ifdef __WIN32__
    17.1 --- a/src/render/direct3d11/SDL_render_d3d11.c	Mon Oct 22 10:55:18 2018 -0400
    17.2 +++ b/src/render/direct3d11/SDL_render_d3d11.c	Wed Oct 31 15:03:41 2018 -0400
    17.3 @@ -56,6 +56,9 @@
    17.4  #define SAFE_RELEASE(X) if ((X)) { IUnknown_Release(SDL_static_cast(IUnknown*, X)); X = NULL; }
    17.5  
    17.6  
    17.7 +/* !!! FIXME: vertex buffer bandwidth could be significantly lower; move color to a uniform, only use UV coords
    17.8 +   !!! FIXME:  when textures are needed, and don't ever pass Z, since it's always zero. */
    17.9 +
   17.10  /* Vertex shader, common values */
   17.11  typedef struct
   17.12  {
   17.13 @@ -120,7 +123,8 @@
   17.14      ID3D11RenderTargetView *mainRenderTargetView;
   17.15      ID3D11RenderTargetView *currentOffscreenRenderTargetView;
   17.16      ID3D11InputLayout *inputLayout;
   17.17 -    ID3D11Buffer *vertexBuffer;
   17.18 +    ID3D11Buffer *vertexBuffers[8];
   17.19 +    size_t vertexBufferSizes[8];
   17.20      ID3D11VertexShader *vertexShader;
   17.21      ID3D11PixelShader *pixelShaders[NUM_SHADERS];
   17.22      int blendModesCount;
   17.23 @@ -145,6 +149,14 @@
   17.24      ID3D11PixelShader *currentShader;
   17.25      ID3D11ShaderResourceView *currentShaderResource;
   17.26      ID3D11SamplerState *currentSampler;
   17.27 +    SDL_bool cliprectDirty;
   17.28 +    SDL_bool currentCliprectEnabled;
   17.29 +    SDL_Rect currentCliprect;
   17.30 +    SDL_Rect currentViewport;
   17.31 +    int currentViewportRotation;
   17.32 +    SDL_bool viewportDirty;
   17.33 +    Float4X4 identity;
   17.34 +    int currentVertexBuffer;
   17.35  } D3D11_RenderData;
   17.36  
   17.37  
   17.38 @@ -175,75 +187,6 @@
   17.39  #endif
   17.40  
   17.41  
   17.42 -/* Direct3D 11.1 renderer implementation */
   17.43 -static SDL_Renderer *D3D11_CreateRenderer(SDL_Window * window, Uint32 flags);
   17.44 -static void D3D11_WindowEvent(SDL_Renderer * renderer,
   17.45 -                            const SDL_WindowEvent *event);
   17.46 -static SDL_bool D3D11_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode);
   17.47 -static int D3D11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
   17.48 -static int D3D11_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   17.49 -                             const SDL_Rect * rect, const void *srcPixels,
   17.50 -                             int srcPitch);
   17.51 -static int D3D11_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
   17.52 -                                  const SDL_Rect * rect,
   17.53 -                                  const Uint8 *Yplane, int Ypitch,
   17.54 -                                  const Uint8 *Uplane, int Upitch,
   17.55 -                                  const Uint8 *Vplane, int Vpitch);
   17.56 -static int D3D11_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   17.57 -                             const SDL_Rect * rect, void **pixels, int *pitch);
   17.58 -static void D3D11_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
   17.59 -static int D3D11_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture);
   17.60 -static int D3D11_UpdateViewport(SDL_Renderer * renderer);
   17.61 -static int D3D11_UpdateClipRect(SDL_Renderer * renderer);
   17.62 -static int D3D11_RenderClear(SDL_Renderer * renderer);
   17.63 -static int D3D11_RenderDrawPoints(SDL_Renderer * renderer,
   17.64 -                                  const SDL_FPoint * points, int count);
   17.65 -static int D3D11_RenderDrawLines(SDL_Renderer * renderer,
   17.66 -                                 const SDL_FPoint * points, int count);
   17.67 -static int D3D11_RenderFillRects(SDL_Renderer * renderer,
   17.68 -                                 const SDL_FRect * rects, int count);
   17.69 -static int D3D11_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   17.70 -                            const SDL_Rect * srcrect, const SDL_FRect * dstrect);
   17.71 -static int D3D11_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
   17.72 -                              const SDL_Rect * srcrect, const SDL_FRect * dstrect,
   17.73 -                              const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip);
   17.74 -static int D3D11_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
   17.75 -                                  Uint32 format, void * pixels, int pitch);
   17.76 -static void D3D11_RenderPresent(SDL_Renderer * renderer);
   17.77 -static void D3D11_DestroyTexture(SDL_Renderer * renderer,
   17.78 -                                 SDL_Texture * texture);
   17.79 -static void D3D11_DestroyRenderer(SDL_Renderer * renderer);
   17.80 -
   17.81 -/* Direct3D 11.1 Internal Functions */
   17.82 -static HRESULT D3D11_CreateDeviceResources(SDL_Renderer * renderer);
   17.83 -static HRESULT D3D11_CreateWindowSizeDependentResources(SDL_Renderer * renderer);
   17.84 -static HRESULT D3D11_UpdateForWindowSizeChange(SDL_Renderer * renderer);
   17.85 -static HRESULT D3D11_HandleDeviceLost(SDL_Renderer * renderer);
   17.86 -static void D3D11_ReleaseMainRenderTargetView(SDL_Renderer * renderer);
   17.87 -
   17.88 -SDL_RenderDriver D3D11_RenderDriver = {
   17.89 -    D3D11_CreateRenderer,
   17.90 -    {
   17.91 -        "direct3d11",
   17.92 -        (
   17.93 -            SDL_RENDERER_ACCELERATED |
   17.94 -            SDL_RENDERER_PRESENTVSYNC |
   17.95 -            SDL_RENDERER_TARGETTEXTURE
   17.96 -        ),                          /* flags.  see SDL_RendererFlags */
   17.97 -        6,                          /* num_texture_formats */
   17.98 -        {                           /* texture_formats */
   17.99 -            SDL_PIXELFORMAT_ARGB8888,
  17.100 -            SDL_PIXELFORMAT_RGB888,
  17.101 -            SDL_PIXELFORMAT_YV12,
  17.102 -            SDL_PIXELFORMAT_IYUV,
  17.103 -            SDL_PIXELFORMAT_NV12,
  17.104 -            SDL_PIXELFORMAT_NV21
  17.105 -        },
  17.106 -        0,                          /* max_texture_width: will be filled in later */
  17.107 -        0                           /* max_texture_height: will be filled in later */
  17.108 -    }
  17.109 -};
  17.110 -
  17.111  
  17.112  Uint32
  17.113  D3D11_DXGIFormatToSDLPixelFormat(DXGI_FORMAT dxgiFormat)
  17.114 @@ -276,84 +219,7 @@
  17.115      }
  17.116  }
  17.117  
  17.118 -SDL_Renderer *
  17.119 -D3D11_CreateRenderer(SDL_Window * window, Uint32 flags)
  17.120 -{
  17.121 -    SDL_Renderer *renderer;
  17.122 -    D3D11_RenderData *data;
  17.123 -
  17.124 -    renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
  17.125 -    if (!renderer) {
  17.126 -        SDL_OutOfMemory();
  17.127 -        return NULL;
  17.128 -    }
  17.129 -
  17.130 -    data = (D3D11_RenderData *) SDL_calloc(1, sizeof(*data));
  17.131 -    if (!data) {
  17.132 -        SDL_OutOfMemory();
  17.133 -        return NULL;
  17.134 -    }
  17.135 -
  17.136 -    renderer->WindowEvent = D3D11_WindowEvent;
  17.137 -    renderer->SupportsBlendMode = D3D11_SupportsBlendMode;
  17.138 -    renderer->CreateTexture = D3D11_CreateTexture;
  17.139 -    renderer->UpdateTexture = D3D11_UpdateTexture;
  17.140 -    renderer->UpdateTextureYUV = D3D11_UpdateTextureYUV;
  17.141 -    renderer->LockTexture = D3D11_LockTexture;
  17.142 -    renderer->UnlockTexture = D3D11_UnlockTexture;
  17.143 -    renderer->SetRenderTarget = D3D11_SetRenderTarget;
  17.144 -    renderer->UpdateViewport = D3D11_UpdateViewport;
  17.145 -    renderer->UpdateClipRect = D3D11_UpdateClipRect;
  17.146 -    renderer->RenderClear = D3D11_RenderClear;
  17.147 -    renderer->RenderDrawPoints = D3D11_RenderDrawPoints;
  17.148 -    renderer->RenderDrawLines = D3D11_RenderDrawLines;
  17.149 -    renderer->RenderFillRects = D3D11_RenderFillRects;
  17.150 -    renderer->RenderCopy = D3D11_RenderCopy;
  17.151 -    renderer->RenderCopyEx = D3D11_RenderCopyEx;
  17.152 -    renderer->RenderReadPixels = D3D11_RenderReadPixels;
  17.153 -    renderer->RenderPresent = D3D11_RenderPresent;
  17.154 -    renderer->DestroyTexture = D3D11_DestroyTexture;
  17.155 -    renderer->DestroyRenderer = D3D11_DestroyRenderer;
  17.156 -    renderer->info = D3D11_RenderDriver.info;
  17.157 -    renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
  17.158 -    renderer->driverdata = data;
  17.159 -
  17.160 -#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
  17.161 -    /* VSync is required in Windows Phone, at least for Win Phone 8.0 and 8.1.
  17.162 -     * Failure to use it seems to either result in:
  17.163 -     *
  17.164 -     *  - with the D3D11 debug runtime turned OFF, vsync seemingly gets turned
  17.165 -     *    off (framerate doesn't get capped), but nothing appears on-screen
  17.166 -     *
  17.167 -     *  - with the D3D11 debug runtime turned ON, vsync gets automatically
  17.168 -     *    turned back on, and the following gets output to the debug console:
  17.169 -     *    
  17.170 -     *    DXGI ERROR: IDXGISwapChain::Present: Interval 0 is not supported, changed to Interval 1. [ UNKNOWN ERROR #1024: ] 
  17.171 -     */
  17.172 -    renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
  17.173 -#else
  17.174 -    if ((flags & SDL_RENDERER_PRESENTVSYNC)) {
  17.175 -        renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
  17.176 -    }
  17.177 -#endif
  17.178 -
  17.179 -    /* HACK: make sure the SDL_Renderer references the SDL_Window data now, in
  17.180 -     * order to give init functions access to the underlying window handle:
  17.181 -     */
  17.182 -    renderer->window = window;
  17.183 -
  17.184 -    /* Initialize Direct3D resources */
  17.185 -    if (FAILED(D3D11_CreateDeviceResources(renderer))) {
  17.186 -        D3D11_DestroyRenderer(renderer);
  17.187 -        return NULL;
  17.188 -    }
  17.189 -    if (FAILED(D3D11_CreateWindowSizeDependentResources(renderer))) {
  17.190 -        D3D11_DestroyRenderer(renderer);
  17.191 -        return NULL;
  17.192 -    }
  17.193 -
  17.194 -    return renderer;
  17.195 -}
  17.196 +static void D3D11_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture);
  17.197  
  17.198  static void
  17.199  D3D11_ReleaseAll(SDL_Renderer * renderer)
  17.200 @@ -378,7 +244,9 @@
  17.201          SAFE_RELEASE(data->mainRenderTargetView);
  17.202          SAFE_RELEASE(data->currentOffscreenRenderTargetView);
  17.203          SAFE_RELEASE(data->inputLayout);
  17.204 -        SAFE_RELEASE(data->vertexBuffer);
  17.205 +        for (i = 0; i < SDL_arraysize(data->vertexBuffers); ++i) {
  17.206 +            SAFE_RELEASE(data->vertexBuffers[i]);
  17.207 +        }
  17.208          SAFE_RELEASE(data->vertexShader);
  17.209          for (i = 0; i < SDL_arraysize(data->pixelShaders); ++i) {
  17.210              SAFE_RELEASE(data->pixelShaders[i]);
  17.211 @@ -477,7 +345,7 @@
  17.212      }
  17.213  }
  17.214  
  17.215 -static SDL_bool
  17.216 +static ID3D11BlendState *
  17.217  D3D11_CreateBlendState(SDL_Renderer * renderer, SDL_BlendMode blendMode)
  17.218  {
  17.219      D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
  17.220 @@ -506,21 +374,21 @@
  17.221      result = ID3D11Device_CreateBlendState(data->d3dDevice, &blendDesc, &blendState);
  17.222      if (FAILED(result)) {
  17.223          WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateBlendState"), result);
  17.224 -        return SDL_FALSE;
  17.225 +        return NULL;
  17.226      }
  17.227  
  17.228      blendModes = (D3D11_BlendMode *)SDL_realloc(data->blendModes, (data->blendModesCount + 1) * sizeof(*blendModes));
  17.229      if (!blendModes) {
  17.230          SAFE_RELEASE(blendState);
  17.231          SDL_OutOfMemory();
  17.232 -        return SDL_FALSE;
  17.233 +        return NULL;
  17.234      }
  17.235      blendModes[data->blendModesCount].blendMode = blendMode;
  17.236      blendModes[data->blendModesCount].blendState = blendState;
  17.237      data->blendModes = blendModes;
  17.238      ++data->blendModesCount;
  17.239  
  17.240 -    return SDL_TRUE;
  17.241 +    return blendState;
  17.242  }
  17.243  
  17.244  /* Create resources that depend on the device. */
  17.245 @@ -964,6 +832,45 @@
  17.246      return result;
  17.247  }
  17.248  
  17.249 +static void
  17.250 +D3D11_ReleaseMainRenderTargetView(SDL_Renderer * renderer)
  17.251 +{
  17.252 +    D3D11_RenderData *data = (D3D11_RenderData *)renderer->driverdata;
  17.253 +    ID3D11DeviceContext_OMSetRenderTargets(data->d3dContext, 0, NULL, NULL);
  17.254 +    SAFE_RELEASE(data->mainRenderTargetView);
  17.255 +}
  17.256 +
  17.257 +static HRESULT D3D11_UpdateForWindowSizeChange(SDL_Renderer * renderer);
  17.258 +
  17.259 +
  17.260 +HRESULT
  17.261 +D3D11_HandleDeviceLost(SDL_Renderer * renderer)
  17.262 +{
  17.263 +    HRESULT result = S_OK;
  17.264 +
  17.265 +    D3D11_ReleaseAll(renderer);
  17.266 +
  17.267 +    result = D3D11_CreateDeviceResources(renderer);
  17.268 +    if (FAILED(result)) {
  17.269 +        /* D3D11_CreateDeviceResources will set the SDL error */
  17.270 +        return result;
  17.271 +    }
  17.272 +
  17.273 +    result = D3D11_UpdateForWindowSizeChange(renderer);
  17.274 +    if (FAILED(result)) {
  17.275 +        /* D3D11_UpdateForWindowSizeChange will set the SDL error */
  17.276 +        return result;
  17.277 +    }
  17.278 +
  17.279 +    /* Let the application know that the device has been reset */
  17.280 +    {
  17.281 +        SDL_Event event;
  17.282 +        event.type = SDL_RENDER_DEVICE_RESET;
  17.283 +        SDL_PushEvent(&event);
  17.284 +    }
  17.285 +
  17.286 +    return S_OK;
  17.287 +}
  17.288  
  17.289  /* Initialize all resources that change when the window's size changes. */
  17.290  static HRESULT
  17.291 @@ -1066,11 +973,7 @@
  17.292          goto done;
  17.293      }
  17.294  
  17.295 -    if (D3D11_UpdateViewport(renderer) != 0) {
  17.296 -        /* D3D11_UpdateViewport will set the SDL error if it fails. */
  17.297 -        result = E_FAIL;
  17.298 -        goto done;
  17.299 -    }
  17.300 +    data->viewportDirty = SDL_TRUE;
  17.301  
  17.302  done:
  17.303      SAFE_RELEASE(backBuffer);
  17.304 @@ -1084,35 +987,6 @@
  17.305      return D3D11_CreateWindowSizeDependentResources(renderer);
  17.306  }
  17.307  
  17.308 -HRESULT
  17.309 -D3D11_HandleDeviceLost(SDL_Renderer * renderer)
  17.310 -{
  17.311 -    HRESULT result = S_OK;
  17.312 -
  17.313 -    D3D11_ReleaseAll(renderer);
  17.314 -
  17.315 -    result = D3D11_CreateDeviceResources(renderer);
  17.316 -    if (FAILED(result)) {
  17.317 -        /* D3D11_CreateDeviceResources will set the SDL error */
  17.318 -        return result;
  17.319 -    }
  17.320 -
  17.321 -    result = D3D11_UpdateForWindowSizeChange(renderer);
  17.322 -    if (FAILED(result)) {
  17.323 -        /* D3D11_UpdateForWindowSizeChange will set the SDL error */
  17.324 -        return result;
  17.325 -    }
  17.326 -
  17.327 -    /* Let the application know that the device has been reset */
  17.328 -    {
  17.329 -        SDL_Event event;
  17.330 -        event.type = SDL_RENDER_DEVICE_RESET;
  17.331 -        SDL_PushEvent(&event);
  17.332 -    }
  17.333 -
  17.334 -    return S_OK;
  17.335 -}
  17.336 -
  17.337  void
  17.338  D3D11_Trim(SDL_Renderer * renderer)
  17.339  {
  17.340 @@ -1671,39 +1545,345 @@
  17.341      return 0;
  17.342  }
  17.343  
  17.344 -static void
  17.345 -D3D11_SetModelMatrix(SDL_Renderer *renderer, const Float4X4 *matrix)
  17.346 +static int
  17.347 +D3D11_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd)
  17.348  {
  17.349 -    D3D11_RenderData *data = (D3D11_RenderData *)renderer->driverdata;
  17.350 +    return 0;  /* nothing to do in this backend. */
  17.351 +}
  17.352  
  17.353 -    if (matrix) {
  17.354 -        data->vertexShaderConstantsData.model = *matrix;
  17.355 -    } else {
  17.356 -        data->vertexShaderConstantsData.model = MatrixIdentity();
  17.357 +static int
  17.358 +D3D11_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
  17.359 +{
  17.360 +    VertexPositionColor *verts = (VertexPositionColor *) SDL_AllocateRenderVertices(renderer, count * sizeof (VertexPositionColor), 0, &cmd->data.draw.first);
  17.361 +    const float r = (float)(cmd->data.draw.r / 255.0f);
  17.362 +    const float g = (float)(cmd->data.draw.g / 255.0f);
  17.363 +    const float b = (float)(cmd->data.draw.b / 255.0f);
  17.364 +    const float a = (float)(cmd->data.draw.a / 255.0f);
  17.365 +    size_t i;
  17.366 +
  17.367 +    if (!verts) {
  17.368 +        return -1;
  17.369      }
  17.370  
  17.371 -    ID3D11DeviceContext_UpdateSubresource(data->d3dContext,
  17.372 -        (ID3D11Resource *)data->vertexShaderConstants,
  17.373 -        0,
  17.374 -        NULL,
  17.375 -        &data->vertexShaderConstantsData,
  17.376 -        0,
  17.377 -        0
  17.378 -        );
  17.379 +    for (i = 0; i < count; i++) {
  17.380 +        verts->pos.x = points[i].x + 0.5f;
  17.381 +        verts->pos.y = points[i].y + 0.5f;
  17.382 +        verts->pos.z = 0.0f;
  17.383 +        verts->tex.x = 0.0f;
  17.384 +        verts->tex.y = 0.0f;
  17.385 +        verts->color.x = r;
  17.386 +        verts->color.y = g;
  17.387 +        verts->color.z = b;
  17.388 +        verts->color.w = a;
  17.389 +        verts++;
  17.390 +    }
  17.391 +
  17.392 +    return 0;
  17.393 +}
  17.394 +
  17.395 +static int
  17.396 +D3D11_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects, int count)
  17.397 +{
  17.398 +    VertexPositionColor *verts = (VertexPositionColor *) SDL_AllocateRenderVertices(renderer, count * 4 * sizeof (VertexPositionColor), 0, &cmd->data.draw.first);
  17.399 +    const float r = (float)(cmd->data.draw.r / 255.0f);
  17.400 +    const float g = (float)(cmd->data.draw.g / 255.0f);
  17.401 +    const float b = (float)(cmd->data.draw.b / 255.0f);
  17.402 +    const float a = (float)(cmd->data.draw.a / 255.0f);
  17.403 +    size_t i;
  17.404 +
  17.405 +    if (!verts) {
  17.406 +        return -1;
  17.407 +    }
  17.408 +
  17.409 +    for (i = 0; i < count; i++) {
  17.410 +        verts->pos.x = rects[i].x;
  17.411 +        verts->pos.y = rects[i].y;
  17.412 +        verts->pos.z = 0.0f;
  17.413 +        verts->tex.x = 0.0f;
  17.414 +        verts->tex.y = 0.0f;
  17.415 +        verts->color.x = r;
  17.416 +        verts->color.y = g;
  17.417 +        verts->color.z = b;
  17.418 +        verts->color.w = a;
  17.419 +        verts++;
  17.420 +
  17.421 +        verts->pos.x = rects[i].x;
  17.422 +        verts->pos.y = rects[i].y + rects[i].h;
  17.423 +        verts->pos.z = 0.0f;
  17.424 +        verts->tex.x = 0.0f;
  17.425 +        verts->tex.y = 0.0f;
  17.426 +        verts->color.x = r;
  17.427 +        verts->color.y = g;
  17.428 +        verts->color.z = b;
  17.429 +        verts->color.w = a;
  17.430 +        verts++;
  17.431 +
  17.432 +        verts->pos.x = rects[i].x + rects[i].w;
  17.433 +        verts->pos.y = rects[i].y;
  17.434 +        verts->pos.z = 0.0f;
  17.435 +        verts->tex.x = 0.0f;
  17.436 +        verts->tex.y = 0.0f;
  17.437 +        verts->color.x = r;
  17.438 +        verts->color.y = g;
  17.439 +        verts->color.z = b;
  17.440 +        verts->color.w = a;
  17.441 +        verts++;
  17.442 +
  17.443 +        verts->pos.x = rects[i].x + rects[i].w;
  17.444 +        verts->pos.y = rects[i].y + rects[i].h;
  17.445 +        verts->pos.z = 0.0f;
  17.446 +        verts->tex.x = 0.0f;
  17.447 +        verts->tex.y = 0.0f;
  17.448 +        verts->color.x = r;
  17.449 +        verts->color.y = g;
  17.450 +        verts->color.z = b;
  17.451 +        verts->color.w = a;
  17.452 +        verts++;
  17.453 +    }
  17.454 +
  17.455 +    return 0;
  17.456 +}
  17.457 +
  17.458 +static int
  17.459 +D3D11_QueueCopy(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
  17.460 +             const SDL_Rect * srcrect, const SDL_FRect * dstrect)
  17.461 +{
  17.462 +    VertexPositionColor *verts = (VertexPositionColor *) SDL_AllocateRenderVertices(renderer, 4 * sizeof (VertexPositionColor), 0, &cmd->data.draw.first);
  17.463 +    const float r = (float)(cmd->data.draw.r / 255.0f);
  17.464 +    const float g = (float)(cmd->data.draw.g / 255.0f);
  17.465 +    const float b = (float)(cmd->data.draw.b / 255.0f);
  17.466 +    const float a = (float)(cmd->data.draw.a / 255.0f);
  17.467 +    const float minu = (float) srcrect->x / texture->w;
  17.468 +    const float maxu = (float) (srcrect->x + srcrect->w) / texture->w;
  17.469 +    const float minv = (float) srcrect->y / texture->h;
  17.470 +    const float maxv = (float) (srcrect->y + srcrect->h) / texture->h;
  17.471 +
  17.472 +    if (!verts) {
  17.473 +        return -1;
  17.474 +    }
  17.475 +
  17.476 +    verts->pos.x = dstrect->x;
  17.477 +    verts->pos.y = dstrect->y;
  17.478 +    verts->pos.z = 0.0f;
  17.479 +    verts->tex.x = minu;
  17.480 +    verts->tex.y = minv;
  17.481 +    verts->color.x = r;
  17.482 +    verts->color.y = g;
  17.483 +    verts->color.z = b;
  17.484 +    verts->color.w = a;
  17.485 +    verts++;
  17.486 +
  17.487 +    verts->pos.x = dstrect->x;
  17.488 +    verts->pos.y = dstrect->y + dstrect->h;
  17.489 +    verts->pos.z = 0.0f;
  17.490 +    verts->tex.x = minu;
  17.491 +    verts->tex.y = maxv;
  17.492 +    verts->color.x = r;
  17.493 +    verts->color.y = g;
  17.494 +    verts->color.z = b;
  17.495 +    verts->color.w = a;
  17.496 +    verts++;
  17.497 +
  17.498 +    verts->pos.x = dstrect->x + dstrect->w;
  17.499 +    verts->pos.y = dstrect->y;
  17.500 +    verts->pos.z = 0.0f;
  17.501 +    verts->tex.x = maxu;
  17.502 +    verts->tex.y = minv;
  17.503 +    verts->color.x = r;
  17.504 +    verts->color.y = g;
  17.505 +    verts->color.z = b;
  17.506 +    verts->color.w = a;
  17.507 +    verts++;
  17.508 +
  17.509 +    verts->pos.x = dstrect->x + dstrect->w;
  17.510 +    verts->pos.y = dstrect->y + dstrect->h;
  17.511 +    verts->pos.z = 0.0f;
  17.512 +    verts->tex.x = maxu;
  17.513 +    verts->tex.y = maxv;
  17.514 +    verts->color.x = r;
  17.515 +    verts->color.y = g;
  17.516 +    verts->color.z = b;
  17.517 +    verts->color.w = a;
  17.518 +    verts++;
  17.519 +
  17.520 +    return 0;
  17.521 +}
  17.522 +
  17.523 +static int
  17.524 +D3D11_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
  17.525 +               const SDL_Rect * srcrect, const SDL_FRect * dstrect,
  17.526 +               const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
  17.527 +{
  17.528 +    VertexPositionColor *verts = (VertexPositionColor *) SDL_AllocateRenderVertices(renderer, 5 * sizeof (VertexPositionColor), 0, &cmd->data.draw.first);
  17.529 +    const float r = (float)(cmd->data.draw.r / 255.0f);
  17.530 +    const float g = (float)(cmd->data.draw.g / 255.0f);
  17.531 +    const float b = (float)(cmd->data.draw.b / 255.0f);
  17.532 +    const float a = (float)(cmd->data.draw.a / 255.0f);
  17.533 +    float minx, miny, maxx, maxy;
  17.534 +    float minu, maxu, minv, maxv;
  17.535 +
  17.536 +    if (flip & SDL_FLIP_HORIZONTAL) {
  17.537 +        minu = (float) srcrect->x / texture->w;
  17.538 +        maxu = (float) (srcrect->x + srcrect->w) / texture->w;
  17.539 +    } else {
  17.540 +        minu = (float) (srcrect->x + srcrect->w) / texture->w;
  17.541 +        maxu = (float) srcrect->x / texture->w;
  17.542 +    }
  17.543 +
  17.544 +    if (flip & SDL_FLIP_VERTICAL) {
  17.545 +        minv = (float) srcrect->y / texture->h;
  17.546 +        maxv = (float) (srcrect->y + srcrect->h) / texture->h;
  17.547 +    } else {
  17.548 +        minv = (float) (srcrect->y + srcrect->h) / texture->h;
  17.549 +        maxv = (float) srcrect->y / texture->h;
  17.550 +    }
  17.551 +
  17.552 +    minx = -center->x;
  17.553 +    maxx = dstrect->w - center->x;
  17.554 +    miny = -center->y;
  17.555 +    maxy = dstrect->h - center->y;
  17.556 +
  17.557 +    verts->pos.x = minx;
  17.558 +    verts->pos.y = miny;
  17.559 +    verts->pos.z = 0.0f;
  17.560 +    verts->tex.x = minu;
  17.561 +    verts->tex.y = minv;
  17.562 +    verts->color.x = r;
  17.563 +    verts->color.y = g;
  17.564 +    verts->color.z = b;
  17.565 +    verts->color.w = a;
  17.566 +    verts++;
  17.567 +
  17.568 +    verts->pos.x = minx;
  17.569 +    verts->pos.y = maxy;
  17.570 +    verts->pos.z = 0.0f;
  17.571 +    verts->tex.x = minu;
  17.572 +    verts->tex.y = maxv;
  17.573 +    verts->color.x = r;
  17.574 +    verts->color.y = g;
  17.575 +    verts->color.z = b;
  17.576 +    verts->color.w = a;
  17.577 +    verts++;
  17.578 +
  17.579 +    verts->pos.x = maxx;
  17.580 +    verts->pos.y = miny;
  17.581 +    verts->pos.z = 0.0f;
  17.582 +    verts->tex.x = maxu;
  17.583 +    verts->tex.y = minv;
  17.584 +    verts->color.x = r;
  17.585 +    verts->color.y = g;
  17.586 +    verts->color.z = b;
  17.587 +    verts->color.w = a;
  17.588 +    verts++;
  17.589 +
  17.590 +    verts->pos.x = maxx;
  17.591 +    verts->pos.y = maxy;
  17.592 +    verts->pos.z = 0.0f;
  17.593 +    verts->tex.x = maxu;
  17.594 +    verts->tex.y = maxv;
  17.595 +    verts->color.x = r;
  17.596 +    verts->color.y = g;
  17.597 +    verts->color.z = b;
  17.598 +    verts->color.w = a;
  17.599 +    verts++;
  17.600 +
  17.601 +    verts->pos.x = dstrect->x + center->x;  /* X translation */
  17.602 +    verts->pos.y = dstrect->y + center->y;  /* Y translation */
  17.603 +    verts->pos.z = (float)(M_PI * (float) angle / 180.0f);  /* rotation */
  17.604 +    verts->tex.x = 0.0f;
  17.605 +    verts->tex.y = 0.0f;
  17.606 +    verts->color.x = 0;
  17.607 +    verts->color.y = 0;
  17.608 +    verts->color.z = 0;
  17.609 +    verts->color.w = 0;
  17.610 +    verts++;
  17.611 +
  17.612 +    return 0;
  17.613 +}
  17.614 +
  17.615 +
  17.616 +static int
  17.617 +D3D11_UpdateVertexBuffer(SDL_Renderer *renderer,
  17.618 +                         const void * vertexData, size_t dataSizeInBytes)
  17.619 +{
  17.620 +    D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
  17.621 +    HRESULT result = S_OK;
  17.622 +    const int vbidx = rendererData->currentVertexBuffer;
  17.623 +
  17.624 +    if (rendererData->vertexBuffers[vbidx] && rendererData->vertexBufferSizes[vbidx] >= dataSizeInBytes) {
  17.625 +        D3D11_MAPPED_SUBRESOURCE mappedResource;
  17.626 +        result = ID3D11DeviceContext_Map(rendererData->d3dContext,
  17.627 +            (ID3D11Resource *)rendererData->vertexBuffers[vbidx],
  17.628 +            0,
  17.629 +            D3D11_MAP_WRITE_DISCARD,
  17.630 +            0,
  17.631 +            &mappedResource
  17.632 +            );
  17.633 +        if (FAILED(result)) {
  17.634 +            WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11DeviceContext1::Map [vertex buffer]"), result);
  17.635 +            return -1;
  17.636 +        }
  17.637 +        SDL_memcpy(mappedResource.pData, vertexData, dataSizeInBytes);
  17.638 +        ID3D11DeviceContext_Unmap(rendererData->d3dContext, (ID3D11Resource *)rendererData->vertexBuffers[vbidx], 0);
  17.639 +    } else {
  17.640 +        D3D11_BUFFER_DESC vertexBufferDesc;
  17.641 +        D3D11_SUBRESOURCE_DATA vertexBufferData;
  17.642 +        const UINT stride = sizeof(VertexPositionColor);
  17.643 +        const UINT offset = 0;
  17.644 +
  17.645 +        SAFE_RELEASE(rendererData->vertexBuffers[vbidx]);
  17.646 +
  17.647 +        SDL_zero(vertexBufferDesc);
  17.648 +        vertexBufferDesc.ByteWidth = (UINT) dataSizeInBytes;
  17.649 +        vertexBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
  17.650 +        vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
  17.651 +        vertexBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
  17.652 +
  17.653 +        SDL_zero(vertexBufferData);
  17.654 +        vertexBufferData.pSysMem = vertexData;
  17.655 +        vertexBufferData.SysMemPitch = 0;
  17.656 +        vertexBufferData.SysMemSlicePitch = 0;
  17.657 +
  17.658 +        result = ID3D11Device_CreateBuffer(rendererData->d3dDevice,
  17.659 +            &vertexBufferDesc,
  17.660 +            &vertexBufferData,
  17.661 +            &rendererData->vertexBuffers[vbidx]
  17.662 +            );
  17.663 +        if (FAILED(result)) {
  17.664 +            WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateBuffer [vertex buffer]"), result);
  17.665 +            return -1;
  17.666 +        }
  17.667 +
  17.668 +        ID3D11DeviceContext_IASetVertexBuffers(rendererData->d3dContext,
  17.669 +            0,
  17.670 +            1,
  17.671 +            &rendererData->vertexBuffers[vbidx],
  17.672 +            &stride,
  17.673 +            &offset
  17.674 +            );
  17.675 +    }
  17.676 +
  17.677 +    rendererData->currentVertexBuffer++;
  17.678 +    if (rendererData->currentVertexBuffer >= SDL_arraysize(rendererData->vertexBuffers)) {
  17.679 +        rendererData->currentVertexBuffer = 0;
  17.680 +    }
  17.681 +
  17.682 +    return 0;
  17.683  }
  17.684  
  17.685  static int
  17.686  D3D11_UpdateViewport(SDL_Renderer * renderer)
  17.687  {
  17.688      D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
  17.689 +    const SDL_Rect *viewport = &data->currentViewport;
  17.690      Float4X4 projection;
  17.691      Float4X4 view;
  17.692      SDL_FRect orientationAlignedViewport;
  17.693      BOOL swapDimensions;
  17.694 -    D3D11_VIEWPORT viewport;
  17.695 +    D3D11_VIEWPORT d3dviewport;
  17.696      const int rotation = D3D11_GetRotationForCurrentRenderTarget(renderer);
  17.697  
  17.698 -    if (renderer->viewport.w == 0 || renderer->viewport.h == 0) {
  17.699 +    if (viewport->w == 0 || viewport->h == 0) {
  17.700          /* If the viewport is empty, assume that it is because
  17.701           * SDL_CreateRenderer is calling it, and will call it again later
  17.702           * with a non-empty viewport.
  17.703 @@ -1735,21 +1915,12 @@
  17.704      }
  17.705  
  17.706      /* Update the view matrix */
  17.707 -    view.m[0][0] = 2.0f / renderer->viewport.w;
  17.708 -    view.m[0][1] = 0.0f;
  17.709 -    view.m[0][2] = 0.0f;
  17.710 -    view.m[0][3] = 0.0f;
  17.711 -    view.m[1][0] = 0.0f;
  17.712 -    view.m[1][1] = -2.0f / renderer->viewport.h;
  17.713 -    view.m[1][2] = 0.0f;
  17.714 -    view.m[1][3] = 0.0f;
  17.715 -    view.m[2][0] = 0.0f;
  17.716 -    view.m[2][1] = 0.0f;
  17.717 +    SDL_zero(view);
  17.718 +    view.m[0][0] = 2.0f / viewport->w;
  17.719 +    view.m[1][1] = -2.0f / viewport->h;
  17.720      view.m[2][2] = 1.0f;
  17.721 -    view.m[2][3] = 0.0f;
  17.722      view.m[3][0] = -1.0f;
  17.723      view.m[3][1] = 1.0f;
  17.724 -    view.m[3][2] = 0.0f;
  17.725      view.m[3][3] = 1.0f;
  17.726  
  17.727      /* Combine the projection + view matrix together now, as both only get
  17.728 @@ -1760,9 +1931,6 @@
  17.729              view,
  17.730              projection);
  17.731  
  17.732 -    /* Reset the model matrix */
  17.733 -    D3D11_SetModelMatrix(renderer, NULL);
  17.734 -
  17.735      /* Update the Direct3D viewport, which seems to be aligned to the
  17.736       * swap buffer's coordinate space, which is always in either
  17.737       * a landscape mode, for all Windows 8/RT devices, or a portrait mode,
  17.738 @@ -1770,158 +1938,58 @@
  17.739       */
  17.740      swapDimensions = D3D11_IsDisplayRotated90Degrees(rotation);
  17.741      if (swapDimensions) {
  17.742 -        orientationAlignedViewport.x = (float) renderer->viewport.y;
  17.743 -        orientationAlignedViewport.y = (float) renderer->viewport.x;
  17.744 -        orientationAlignedViewport.w = (float) renderer->viewport.h;
  17.745 -        orientationAlignedViewport.h = (float) renderer->viewport.w;
  17.746 +        orientationAlignedViewport.x = (float) viewport->y;
  17.747 +        orientationAlignedViewport.y = (float) viewport->x;
  17.748 +        orientationAlignedViewport.w = (float) viewport->h;
  17.749 +        orientationAlignedViewport.h = (float) viewport->w;
  17.750      } else {
  17.751 -        orientationAlignedViewport.x = (float) renderer->viewport.x;
  17.752 -        orientationAlignedViewport.y = (float) renderer->viewport.y;
  17.753 -        orientationAlignedViewport.w = (float) renderer->viewport.w;
  17.754 -        orientationAlignedViewport.h = (float) renderer->viewport.h;
  17.755 +        orientationAlignedViewport.x = (float) viewport->x;
  17.756 +        orientationAlignedViewport.y = (float) viewport->y;
  17.757 +        orientationAlignedViewport.w = (float) viewport->w;
  17.758 +        orientationAlignedViewport.h = (float) viewport->h;
  17.759      }
  17.760      /* TODO, WinRT: get custom viewports working with non-Landscape modes (Portrait, PortraitFlipped, and LandscapeFlipped) */
  17.761  
  17.762 -    viewport.TopLeftX = orientationAlignedViewport.x;
  17.763 -    viewport.TopLeftY = orientationAlignedViewport.y;
  17.764 -    viewport.Width = orientationAlignedViewport.w;
  17.765 -    viewport.Height = orientationAlignedViewport.h;
  17.766 -    viewport.MinDepth = 0.0f;
  17.767 -    viewport.MaxDepth = 1.0f;
  17.768 -    /* SDL_Log("%s: D3D viewport = {%f,%f,%f,%f}\n", __FUNCTION__, viewport.TopLeftX, viewport.TopLeftY, viewport.Width, viewport.Height); */
  17.769 -    ID3D11DeviceContext_RSSetViewports(data->d3dContext, 1, &viewport);
  17.770 +    d3dviewport.TopLeftX = orientationAlignedViewport.x;
  17.771 +    d3dviewport.TopLeftY = orientationAlignedViewport.y;
  17.772 +    d3dviewport.Width = orientationAlignedViewport.w;
  17.773 +    d3dviewport.Height = orientationAlignedViewport.h;
  17.774 +    d3dviewport.MinDepth = 0.0f;
  17.775 +    d3dviewport.MaxDepth = 1.0f;
  17.776 +    /* SDL_Log("%s: D3D viewport = {%f,%f,%f,%f}\n", __FUNCTION__, d3dviewport.TopLeftX, d3dviewport.TopLeftY, d3dviewport.Width, d3dviewport.Height); */
  17.777 +    ID3D11DeviceContext_RSSetViewports(data->d3dContext, 1, &d3dviewport);
  17.778 +
  17.779 +    data->viewportDirty = SDL_FALSE;
  17.780  
  17.781      return 0;
  17.782  }
  17.783  
  17.784 -static int
  17.785 -D3D11_UpdateClipRect(SDL_Renderer * renderer)
  17.786 -{
  17.787 -    D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
  17.788 -
  17.789 -    if (!renderer->clipping_enabled) {
  17.790 -        ID3D11DeviceContext_RSSetScissorRects(data->d3dContext, 0, NULL);
  17.791 -    } else {
  17.792 -        D3D11_RECT scissorRect;
  17.793 -        if (D3D11_GetViewportAlignedD3DRect(renderer, &renderer->clip_rect, &scissorRect, TRUE) != 0) {
  17.794 -            /* D3D11_GetViewportAlignedD3DRect will have set the SDL error */
  17.795 -            return -1;
  17.796 -        }
  17.797 -        ID3D11DeviceContext_RSSetScissorRects(data->d3dContext, 1, &scissorRect);
  17.798 -    }
  17.799 -
  17.800 -    return 0;
  17.801 -}
  17.802 -
  17.803 -static void
  17.804 -D3D11_ReleaseMainRenderTargetView(SDL_Renderer * renderer)
  17.805 -{
  17.806 -    D3D11_RenderData *data = (D3D11_RenderData *)renderer->driverdata;
  17.807 -    ID3D11DeviceContext_OMSetRenderTargets(data->d3dContext, 0, NULL, NULL);
  17.808 -    SAFE_RELEASE(data->mainRenderTargetView);
  17.809 -}
  17.810 -
  17.811  static ID3D11RenderTargetView *
  17.812  D3D11_GetCurrentRenderTargetView(SDL_Renderer * renderer)
  17.813  {
  17.814 -    D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
  17.815 +    D3D11_RenderData *data = (D3D11_RenderData *)renderer->driverdata;
  17.816      if (data->currentOffscreenRenderTargetView) {
  17.817          return data->currentOffscreenRenderTargetView;
  17.818 -    } else {
  17.819 +    }
  17.820 +    else {
  17.821          return data->mainRenderTargetView;
  17.822      }
  17.823  }
  17.824  
  17.825  static int
  17.826 -D3D11_RenderClear(SDL_Renderer * renderer)
  17.827 -{
  17.828 -    D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
  17.829 -    const float colorRGBA[] = {
  17.830 -        (renderer->r / 255.0f),
  17.831 -        (renderer->g / 255.0f),
  17.832 -        (renderer->b / 255.0f),
  17.833 -        (renderer->a / 255.0f)
  17.834 -    };
  17.835 -    ID3D11DeviceContext_ClearRenderTargetView(data->d3dContext,
  17.836 -        D3D11_GetCurrentRenderTargetView(renderer),
  17.837 -        colorRGBA
  17.838 -        );
  17.839 -    return 0;
  17.840 -}
  17.841 +D3D11_SetDrawState(SDL_Renderer * renderer, const SDL_RenderCommand *cmd, ID3D11PixelShader * shader,
  17.842 +                     const int numShaderResources, ID3D11ShaderResourceView ** shaderResources,
  17.843 +                     ID3D11SamplerState * sampler, const Float4X4 *matrix)
  17.844  
  17.845 -static int
  17.846 -D3D11_UpdateVertexBuffer(SDL_Renderer *renderer,
  17.847 -                         const void * vertexData, size_t dataSizeInBytes)
  17.848 -{
  17.849 -    D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
  17.850 -    D3D11_BUFFER_DESC vertexBufferDesc;
  17.851 -    HRESULT result = S_OK;
  17.852 -    D3D11_SUBRESOURCE_DATA vertexBufferData;
  17.853 -    const UINT stride = sizeof(VertexPositionColor);
  17.854 -    const UINT offset = 0;
  17.855 -
  17.856 -    if (rendererData->vertexBuffer) {
  17.857 -        ID3D11Buffer_GetDesc(rendererData->vertexBuffer, &vertexBufferDesc);
  17.858 -    } else {
  17.859 -        SDL_zero(vertexBufferDesc);
  17.860 -    }
  17.861 -
  17.862 -    if (rendererData->vertexBuffer && vertexBufferDesc.ByteWidth >= dataSizeInBytes) {
  17.863 -        D3D11_MAPPED_SUBRESOURCE mappedResource;
  17.864 -        result = ID3D11DeviceContext_Map(rendererData->d3dContext,
  17.865 -            (ID3D11Resource *)rendererData->vertexBuffer,
  17.866 -            0,
  17.867 -            D3D11_MAP_WRITE_DISCARD,
  17.868 -            0,
  17.869 -            &mappedResource
  17.870 -            );
  17.871 -        if (FAILED(result)) {
  17.872 -            WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11DeviceContext1::Map [vertex buffer]"), result);
  17.873 -            return -1;
  17.874 -        }
  17.875 -        SDL_memcpy(mappedResource.pData, vertexData, dataSizeInBytes);
  17.876 -        ID3D11DeviceContext_Unmap(rendererData->d3dContext, (ID3D11Resource *)rendererData->vertexBuffer, 0);
  17.877 -    } else {
  17.878 -        SAFE_RELEASE(rendererData->vertexBuffer);
  17.879 -
  17.880 -        vertexBufferDesc.ByteWidth = (UINT) dataSizeInBytes;
  17.881 -        vertexBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
  17.882 -        vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
  17.883 -        vertexBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
  17.884 -
  17.885 -        SDL_zero(vertexBufferData);
  17.886 -        vertexBufferData.pSysMem = vertexData;
  17.887 -        vertexBufferData.SysMemPitch = 0;
  17.888 -        vertexBufferData.SysMemSlicePitch = 0;
  17.889 -
  17.890 -        result = ID3D11Device_CreateBuffer(rendererData->d3dDevice,
  17.891 -            &vertexBufferDesc,
  17.892 -            &vertexBufferData,
  17.893 -            &rendererData->vertexBuffer
  17.894 -            );
  17.895 -        if (FAILED(result)) {
  17.896 -            WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateBuffer [vertex buffer]"), result);
  17.897 -            return -1;
  17.898 -        }
  17.899 -
  17.900 -        ID3D11DeviceContext_IASetVertexBuffers(rendererData->d3dContext,
  17.901 -            0,
  17.902 -            1,
  17.903 -            &rendererData->vertexBuffer,
  17.904 -            &stride,
  17.905 -            &offset
  17.906 -            );
  17.907 -    }
  17.908 -
  17.909 -    return 0;
  17.910 -}
  17.911 -
  17.912 -static void
  17.913 -D3D11_RenderStartDrawOp(SDL_Renderer * renderer)
  17.914  {
  17.915      D3D11_RenderData *rendererData = (D3D11_RenderData *)renderer->driverdata;
  17.916 +    const Float4X4 *newmatrix = matrix ? matrix : &rendererData->identity;
  17.917      ID3D11RasterizerState *rasterizerState;
  17.918      ID3D11RenderTargetView *renderTargetView = D3D11_GetCurrentRenderTargetView(renderer);
  17.919 +    ID3D11ShaderResourceView *shaderResource;
  17.920 +    const SDL_BlendMode blendMode = cmd->data.draw.blend;
  17.921 +    ID3D11BlendState *blendState = NULL;
  17.922 +
  17.923      if (renderTargetView != rendererData->currentRenderTargetView) {
  17.924          ID3D11DeviceContext_OMSetRenderTargets(rendererData->d3dContext,
  17.925              1,
  17.926 @@ -1931,7 +1999,25 @@
  17.927          rendererData->currentRenderTargetView = renderTargetView;
  17.928      }
  17.929  
  17.930 -    if (!renderer->clipping_enabled) {
  17.931 +    if (rendererData->viewportDirty) {
  17.932 +        D3D11_UpdateViewport(renderer);
  17.933 +    }
  17.934 +
  17.935 +    if (rendererData->cliprectDirty) {
  17.936 +        if (!rendererData->currentCliprectEnabled) {
  17.937 +            ID3D11DeviceContext_RSSetScissorRects(rendererData->d3dContext, 0, NULL);
  17.938 +        } else {
  17.939 +            D3D11_RECT scissorRect;
  17.940 +            if (D3D11_GetViewportAlignedD3DRect(renderer, &rendererData->currentCliprect, &scissorRect, TRUE) != 0) {
  17.941 +                /* D3D11_GetViewportAlignedD3DRect will have set the SDL error */
  17.942 +                return -1;
  17.943 +            }
  17.944 +            ID3D11DeviceContext_RSSetScissorRects(rendererData->d3dContext, 1, &scissorRect);
  17.945 +        }
  17.946 +        rendererData->cliprectDirty = SDL_FALSE;
  17.947 +    }
  17.948 +
  17.949 +    if (!rendererData->currentCliprectEnabled) {
  17.950          rasterizerState = rendererData->mainRasterizer;
  17.951      } else {
  17.952          rasterizerState = rendererData->clippedRasterizer;
  17.953 @@ -1940,13 +2026,7 @@
  17.954          ID3D11DeviceContext_RSSetState(rendererData->d3dContext, rasterizerState);
  17.955          rendererData->currentRasterizerState = rasterizerState;
  17.956      }
  17.957 -}
  17.958  
  17.959 -static void
  17.960 -D3D11_RenderSetBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
  17.961 -{
  17.962 -    D3D11_RenderData *rendererData = (D3D11_RenderData *)renderer->driverdata;
  17.963 -    ID3D11BlendState *blendState = NULL;
  17.964      if (blendMode != SDL_BLENDMODE_NONE) {
  17.965          int i;
  17.966          for (i = 0; i < rendererData->blendModesCount; ++i) {
  17.967 @@ -1956,28 +2036,17 @@
  17.968              }
  17.969          }
  17.970          if (!blendState) {
  17.971 -            if (D3D11_CreateBlendState(renderer, blendMode)) {
  17.972 -                /* Successfully created the blend state, try again */
  17.973 -                D3D11_RenderSetBlendMode(renderer, blendMode);
  17.974 +            blendState = D3D11_CreateBlendState(renderer, blendMode);
  17.975 +            if (!blendState) {
  17.976 +                return -1;
  17.977              }
  17.978 -            return;
  17.979          }
  17.980      }
  17.981      if (blendState != rendererData->currentBlendState) {
  17.982          ID3D11DeviceContext_OMSetBlendState(rendererData->d3dContext, blendState, 0, 0xFFFFFFFF);
  17.983          rendererData->currentBlendState = blendState;
  17.984      }
  17.985 -}
  17.986  
  17.987 -static void
  17.988 -D3D11_SetPixelShader(SDL_Renderer * renderer,
  17.989 -                     ID3D11PixelShader * shader,
  17.990 -                     int numShaderResources,
  17.991 -                     ID3D11ShaderResourceView ** shaderResources,
  17.992 -                     ID3D11SamplerState * sampler)
  17.993 -{
  17.994 -    D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
  17.995 -    ID3D11ShaderResourceView *shaderResource;
  17.996      if (shader != rendererData->currentShader) {
  17.997          ID3D11DeviceContext_PSSetShader(rendererData->d3dContext, shader, NULL, 0);
  17.998          rendererData->currentShader = shader;
  17.999 @@ -1995,146 +2064,26 @@
 17.1000          ID3D11DeviceContext_PSSetSamplers(rendererData->d3dContext, 0, 1, &sampler);
 17.1001          rendererData->currentSampler = sampler;
 17.1002      }
 17.1003 -}
 17.1004  
 17.1005 -static void
 17.1006 -D3D11_RenderFinishDrawOp(SDL_Renderer * renderer,
 17.1007 -                         D3D11_PRIMITIVE_TOPOLOGY primitiveTopology,
 17.1008 -                         UINT vertexCount)
 17.1009 -{
 17.1010 -    D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
 17.1011 -
 17.1012 -    ID3D11DeviceContext_IASetPrimitiveTopology(rendererData->d3dContext, primitiveTopology);
 17.1013 -    ID3D11DeviceContext_Draw(rendererData->d3dContext, vertexCount, 0);
 17.1014 -}
 17.1015 -
 17.1016 -static int
 17.1017 -D3D11_RenderDrawPoints(SDL_Renderer * renderer,
 17.1018 -                       const SDL_FPoint * points, int count)
 17.1019 -{
 17.1020 -    D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
 17.1021 -    float r, g, b, a;
 17.1022 -    VertexPositionColor *vertices;
 17.1023 -    int i;
 17.1024 -
 17.1025 -    r = (float)(renderer->r / 255.0f);
 17.1026 -    g = (float)(renderer->g / 255.0f);
 17.1027 -    b = (float)(renderer->b / 255.0f);
 17.1028 -    a = (float)(renderer->a / 255.0f);
 17.1029 -
 17.1030 -    vertices = SDL_stack_alloc(VertexPositionColor, count);
 17.1031 -    for (i = 0; i < count; ++i) {
 17.1032 -        const VertexPositionColor v = { { points[i].x + 0.5f, points[i].y + 0.5f, 0.0f }, { 0.0f, 0.0f }, { r, g, b, a } };
 17.1033 -        vertices[i] = v;
 17.1034 -    }
 17.1035 -
 17.1036 -    D3D11_RenderStartDrawOp(renderer);
 17.1037 -    D3D11_RenderSetBlendMode(renderer, renderer->blendMode);
 17.1038 -    if (D3D11_UpdateVertexBuffer(renderer, vertices, (unsigned int)count * sizeof(VertexPositionColor)) != 0) {
 17.1039 -        SDL_stack_free(vertices);
 17.1040 -        return -1;
 17.1041 -    }
 17.1042 -
 17.1043 -    D3D11_SetPixelShader(
 17.1044 -        renderer,
 17.1045 -        rendererData->pixelShaders[SHADER_SOLID],
 17.1046 -        0,
 17.1047 -        NULL,
 17.1048 -        NULL);
 17.1049 -
 17.1050 -    D3D11_RenderFinishDrawOp(renderer, D3D11_PRIMITIVE_TOPOLOGY_POINTLIST, count);
 17.1051 -    SDL_stack_free(vertices);
 17.1052 -    return 0;
 17.1053 -}
 17.1054 -
 17.1055 -static int
 17.1056 -D3D11_RenderDrawLines(SDL_Renderer * renderer,
 17.1057 -                      const SDL_FPoint * points, int count)
 17.1058 -{
 17.1059 -    D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
 17.1060 -    float r, g, b, a;
 17.1061 -    VertexPositionColor *vertices;
 17.1062 -    int i;
 17.1063 -
 17.1064 -    r = (float)(renderer->r / 255.0f);
 17.1065 -    g = (float)(renderer->g / 255.0f);
 17.1066 -    b = (float)(renderer->b / 255.0f);
 17.1067 -    a = (float)(renderer->a / 255.0f);
 17.1068 -
 17.1069 -    vertices = SDL_stack_alloc(VertexPositionColor, count);
 17.1070 -    for (i = 0; i < count; ++i) {
 17.1071 -        const VertexPositionColor v = { { points[i].x + 0.5f, points[i].y + 0.5f, 0.0f }, { 0.0f, 0.0f }, { r, g, b, a } };
 17.1072 -        vertices[i] = v;
 17.1073 -    }
 17.1074 -
 17.1075 -    D3D11_RenderStartDrawOp(renderer);
 17.1076 -    D3D11_RenderSetBlendMode(renderer, renderer->blendMode);
 17.1077 -    if (D3D11_UpdateVertexBuffer(renderer, vertices, (unsigned int)count * sizeof(VertexPositionColor)) != 0) {
 17.1078 -        SDL_stack_free(vertices);
 17.1079 -        return -1;
 17.1080 -    }
 17.1081 -
 17.1082 -    D3D11_SetPixelShader(
 17.1083 -        renderer,
 17.1084 -        rendererData->pixelShaders[SHADER_SOLID],
 17.1085 -        0,
 17.1086 -        NULL,
 17.1087 -        NULL);
 17.1088 -
 17.1089 -    D3D11_RenderFinishDrawOp(renderer, D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP, count);
 17.1090 -
 17.1091 -    if (points[0].x != points[count - 1].x || points[0].y != points[count - 1].y) {
 17.1092 -        ID3D11DeviceContext_IASetPrimitiveTopology(rendererData->d3dContext, D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
 17.1093 -        ID3D11DeviceContext_Draw(rendererData->d3dContext, 1, count - 1);
 17.1094 -    }
 17.1095 -
 17.1096 -    SDL_stack_free(vertices);
 17.1097 -    return 0;
 17.1098 -}
 17.1099 -
 17.1100 -static int
 17.1101 -D3D11_RenderFillRects(SDL_Renderer * renderer,
 17.1102 -                      const SDL_FRect * rects, int count)
 17.1103 -{
 17.1104 -    D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
 17.1105 -    float r, g, b, a;
 17.1106 -    int i;
 17.1107 -
 17.1108 -    r = (float)(renderer->r / 255.0f);
 17.1109 -    g = (float)(renderer->g / 255.0f);
 17.1110 -    b = (float)(renderer->b / 255.0f);
 17.1111 -    a = (float)(renderer->a / 255.0f);
 17.1112 -
 17.1113 -    for (i = 0; i < count; ++i) {
 17.1114 -        VertexPositionColor vertices[] = {
 17.1115 -            { { rects[i].x, rects[i].y, 0.0f },                             { 0.0f, 0.0f}, {r, g, b, a} },
 17.1116 -            { { rects[i].x, rects[i].y + rects[i].h, 0.0f },                { 0.0f, 0.0f }, { r, g, b, a } },
 17.1117 -            { { rects[i].x + rects[i].w, rects[i].y, 0.0f },                { 0.0f, 0.0f }, { r, g, b, a } },
 17.1118 -            { { rects[i].x + rects[i].w, rects[i].y + rects[i].h, 0.0f },   { 0.0f, 0.0f }, { r, g, b, a } },
 17.1119 -        };
 17.1120 -
 17.1121 -        D3D11_RenderStartDrawOp(renderer);
 17.1122 -        D3D11_RenderSetBlendMode(renderer, renderer->blendMode);
 17.1123 -        if (D3D11_UpdateVertexBuffer(renderer, vertices, sizeof(vertices)) != 0) {
 17.1124 -            return -1;
 17.1125 -        }
 17.1126 -
 17.1127 -        D3D11_SetPixelShader(
 17.1128 -            renderer,
 17.1129 -            rendererData->pixelShaders[SHADER_SOLID],
 17.1130 +    if (SDL_memcmp(&rendererData->vertexShaderConstantsData.model, newmatrix, sizeof (*newmatrix)) != 0) {
 17.1131 +        SDL_memcpy(&rendererData->vertexShaderConstantsData.model, newmatrix, sizeof (*newmatrix));
 17.1132 +        ID3D11DeviceContext_UpdateSubresource(rendererData->d3dContext,
 17.1133 +            (ID3D11Resource *)rendererData->vertexShaderConstants,
 17.1134              0,
 17.1135              NULL,
 17.1136 -            NULL);
 17.1137 -
 17.1138 -        D3D11_RenderFinishDrawOp(renderer, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, SDL_arraysize(vertices));
 17.1139 +            &rendererData->vertexShaderConstantsData,
 17.1140 +            0,
 17.1141 +            0
 17.1142 +            );
 17.1143      }
 17.1144  
 17.1145      return 0;
 17.1146  }
 17.1147  
 17.1148  static int
 17.1149 -D3D11_RenderSetupSampler(SDL_Renderer * renderer, SDL_Texture * texture)
 17.1150 +D3D11_SetCopyState(SDL_Renderer * renderer, const SDL_RenderCommand *cmd, const Float4X4 *matrix)
 17.1151  {
 17.1152 +    SDL_Texture *texture = cmd->data.draw.texture;
 17.1153      D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
 17.1154      D3D11_TextureData *textureData = (D3D11_TextureData *) texture->driverdata;
 17.1155      ID3D11SamplerState *textureSampler;
 17.1156 @@ -2172,12 +2121,8 @@
 17.1157              return SDL_SetError("Unsupported YUV conversion mode");
 17.1158          }
 17.1159  
 17.1160 -        D3D11_SetPixelShader(
 17.1161 -            renderer,
 17.1162 -            rendererData->pixelShaders[shader],
 17.1163 -            SDL_arraysize(shaderResources),
 17.1164 -            shaderResources,
 17.1165 -            textureSampler);
 17.1166 +        return D3D11_SetDrawState(renderer, cmd, rendererData->pixelShaders[shader],
 17.1167 +                                  SDL_arraysize(shaderResources), shaderResources, textureSampler, matrix);
 17.1168  
 17.1169      } else if (textureData->nv12) {
 17.1170          ID3D11ShaderResourceView *shaderResources[] = {
 17.1171 @@ -2200,189 +2145,141 @@
 17.1172              return SDL_SetError("Unsupported YUV conversion mode");
 17.1173          }
 17.1174  
 17.1175 -        D3D11_SetPixelShader(
 17.1176 -            renderer,
 17.1177 -            rendererData->pixelShaders[shader],
 17.1178 -            SDL_arraysize(shaderResources),
 17.1179 -            shaderResources,
 17.1180 -            textureSampler);
 17.1181 +        return D3D11_SetDrawState(renderer, cmd, rendererData->pixelShaders[shader],
 17.1182 +                                  SDL_arraysize(shaderResources), shaderResources, textureSampler, matrix);
 17.1183  
 17.1184 -    } else {
 17.1185 -        D3D11_SetPixelShader(
 17.1186 -            renderer,
 17.1187 -            rendererData->pixelShaders[SHADER_RGB],
 17.1188 -            1,
 17.1189 -            &textureData->mainTextureResourceView,
 17.1190 -            textureSampler);
 17.1191      }
 17.1192  
 17.1193 -    return 0;
 17.1194 +    return D3D11_SetDrawState(renderer, cmd, rendererData->pixelShaders[SHADER_RGB],
 17.1195 +                              1, &textureData->mainTextureResourceView, textureSampler, matrix);
 17.1196 +}
 17.1197 +
 17.1198 +static void
 17.1199 +D3D11_DrawPrimitives(SDL_Renderer * renderer, D3D11_PRIMITIVE_TOPOLOGY primitiveTopology, const size_t vertexStart, const size_t vertexCount)
 17.1200 +{
 17.1201 +    D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
 17.1202 +    ID3D11DeviceContext_IASetPrimitiveTopology(rendererData->d3dContext, primitiveTopology);
 17.1203 +    ID3D11DeviceContext_Draw(rendererData->d3dContext, (UINT) vertexCount, (UINT) vertexStart);
 17.1204  }
 17.1205  
 17.1206  static int
 17.1207 -D3D11_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
 17.1208 -                 const SDL_Rect * srcrect, const SDL_FRect * dstrect)
 17.1209 +D3D11_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
 17.1210  {
 17.1211 -    float minu, maxu, minv, maxv;
 17.1212 -    Float4 color;
 17.1213 -    VertexPositionColor vertices[4];
 17.1214 +    D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
 17.1215 +    const int viewportRotation = D3D11_GetRotationForCurrentRenderTarget(renderer);
 17.1216 +    size_t i;
 17.1217  
 17.1218 -    D3D11_RenderStartDrawOp(renderer);
 17.1219 -    D3D11_RenderSetBlendMode(renderer, texture->blendMode);
 17.1220 -
 17.1221 -    minu = (float) srcrect->x / texture->w;
 17.1222 -    maxu = (float) (srcrect->x + srcrect->w) / texture->w;
 17.1223 -    minv = (float) srcrect->y / texture->h;
 17.1224 -    maxv = (float) (srcrect->y + srcrect->h) / texture->h;
 17.1225 -
 17.1226 -    color.x = 1.0f;     /* red */
 17.1227 -    color.y = 1.0f;     /* green */
 17.1228 -    color.z = 1.0f;     /* blue */
 17.1229 -    color.w = 1.0f;     /* alpha */
 17.1230 -    if (texture->modMode & SDL_TEXTUREMODULATE_COLOR) {
 17.1231 -        color.x = (float)(texture->r / 255.0f);     /* red */
 17.1232 -        color.y = (float)(texture->g / 255.0f);     /* green */
 17.1233 -        color.z = (float)(texture->b / 255.0f);     /* blue */
 17.1234 -    }
 17.1235 -    if (texture->modMode & SDL_TEXTUREMODULATE_ALPHA) {
 17.1236 -        color.w = (float)(texture->a / 255.0f);     /* alpha */
 17.1237 +    if (rendererData->currentViewportRotation != viewportRotation) {
 17.1238 +        rendererData->currentViewportRotation = viewportRotation;
 17.1239 +        rendererData->viewportDirty = SDL_TRUE;
 17.1240      }
 17.1241  
 17.1242 -    vertices[0].pos.x = dstrect->x;
 17.1243 -    vertices[0].pos.y = dstrect->y;
 17.1244 -    vertices[0].pos.z = 0.0f;
 17.1245 -    vertices[0].tex.x = minu;
 17.1246 -    vertices[0].tex.y = minv;
 17.1247 -    vertices[0].color = color;
 17.1248 -
 17.1249 -    vertices[1].pos.x = dstrect->x;
 17.1250 -    vertices[1].pos.y = dstrect->y + dstrect->h;
 17.1251 -    vertices[1].pos.z = 0.0f;
 17.1252 -    vertices[1].tex.x = minu;
 17.1253 -    vertices[1].tex.y = maxv;
 17.1254 -    vertices[1].color = color;
 17.1255 -
 17.1256 -    vertices[2].pos.x = dstrect->x + dstrect->w;
 17.1257 -    vertices[2].pos.y = dstrect->y;
 17.1258 -    vertices[2].pos.z = 0.0f;
 17.1259 -    vertices[2].tex.x = maxu;
 17.1260 -    vertices[2].tex.y = minv;
 17.1261 -    vertices[2].color = color;
 17.1262 -
 17.1263 -    vertices[3].pos.x = dstrect->x + dstrect->w;
 17.1264 -    vertices[3].pos.y = dstrect->y + dstrect->h;
 17.1265 -    vertices[3].pos.z = 0.0f;
 17.1266 -    vertices[3].tex.x = maxu;
 17.1267 -    vertices[3].tex.y = maxv;
 17.1268 -    vertices[3].color = color;
 17.1269 -
 17.1270 -    if (D3D11_UpdateVertexBuffer(renderer, vertices, sizeof(vertices)) != 0) {
 17.1271 +    if (D3D11_UpdateVertexBuffer(renderer, vertices, vertsize) < 0) {
 17.1272          return -1;
 17.1273      }
 17.1274  
 17.1275 -    if (D3D11_RenderSetupSampler(renderer, texture) < 0) {
 17.1276 -        return -1;
 17.1277 +    while (cmd) {
 17.1278 +        switch (cmd->command) {
 17.1279 +            case SDL_RENDERCMD_SETDRAWCOLOR: {
 17.1280 +                break;  /* this isn't currently used in this render backend. */
 17.1281 +            }
 17.1282 +
 17.1283 +            case SDL_RENDERCMD_SETVIEWPORT: {
 17.1284 +                SDL_Rect *viewport = &rendererData->currentViewport;
 17.1285 +                if (SDL_memcmp(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect)) != 0) {
 17.1286 +                    SDL_memcpy(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect));
 17.1287 +                    rendererData->viewportDirty = SDL_TRUE;
 17.1288 +                }
 17.1289 +                break;
 17.1290 +            }
 17.1291 +
 17.1292 +            case SDL_RENDERCMD_SETCLIPRECT: {
 17.1293 +                const SDL_Rect *rect = &cmd->data.cliprect.rect;
 17.1294 +                if (rendererData->currentCliprectEnabled != cmd->data.cliprect.enabled) {
 17.1295 +                    rendererData->currentCliprectEnabled = cmd->data.cliprect.enabled;
 17.1296 +                    rendererData->cliprectDirty = SDL_TRUE;
 17.1297 +                }
 17.1298 +                if (SDL_memcmp(&rendererData->currentCliprect, rect, sizeof (SDL_Rect)) != 0) {
 17.1299 +                    SDL_memcpy(&rendererData->currentCliprect, rect, sizeof (SDL_Rect));
 17.1300 +                    rendererData->cliprectDirty = SDL_TRUE;
 17.1301 +                }
 17.1302 +                break;
 17.1303 +            }
 17.1304 +
 17.1305 +            case SDL_RENDERCMD_CLEAR: {
 17.1306 +                const float colorRGBA[] = {
 17.1307 +                    (cmd->data.color.r / 255.0f),
 17.1308 +                    (cmd->data.color.g / 255.0f),
 17.1309 +                    (cmd->data.color.b / 255.0f),
 17.1310 +                    (cmd->data.color.a / 255.0f)
 17.1311 +                };
 17.1312 +                ID3D11DeviceContext_ClearRenderTargetView(rendererData->d3dContext, D3D11_GetCurrentRenderTargetView(renderer), colorRGBA);
 17.1313 +                break;
 17.1314 +            }
 17.1315 +
 17.1316 +            case SDL_RENDERCMD_DRAW_POINTS: {
 17.1317 +                const size_t count = cmd->data.draw.count;
 17.1318 +                const size_t first = cmd->data.draw.first;
 17.1319 +                const size_t start = first / sizeof (VertexPositionColor);
 17.1320 +                D3D11_SetDrawState(renderer, cmd, rendererData->pixelShaders[SHADER_SOLID], 0, NULL, NULL, NULL);
 17.1321 +                D3D11_DrawPrimitives(renderer, D3D11_PRIMITIVE_TOPOLOGY_POINTLIST, start, count);
 17.1322 +                break;
 17.1323 +            }
 17.1324 +
 17.1325 +            case SDL_RENDERCMD_DRAW_LINES: {
 17.1326 +                const size_t count = cmd->data.draw.count;
 17.1327 +                const size_t first = cmd->data.draw.first;
 17.1328 +                const size_t start = first / sizeof (VertexPositionColor);
 17.1329 +                const VertexPositionColor *verts = (VertexPositionColor *) (((Uint8 *) vertices) + first);
 17.1330 +                D3D11_SetDrawState(renderer, cmd, rendererData->pixelShaders[SHADER_SOLID], 0, NULL, NULL, NULL);
 17.1331 +                D3D11_DrawPrimitives(renderer, D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP, start, count);
 17.1332 +                if (verts[0].pos.x != verts[count - 1].pos.x || verts[0].pos.y != verts[count - 1].pos.y) {
 17.1333 +                    D3D11_DrawPrimitives(renderer, D3D11_PRIMITIVE_TOPOLOGY_POINTLIST, start + (count-1), 1);
 17.1334 +                }
 17.1335 +                break;
 17.1336 +            }
 17.1337 +
 17.1338 +            case SDL_RENDERCMD_FILL_RECTS: {
 17.1339 +                const size_t count = cmd->data.draw.count;
 17.1340 +                const size_t first = cmd->data.draw.first;
 17.1341 +                const size_t start = first / sizeof (VertexPositionColor);
 17.1342 +                size_t offset = 0;
 17.1343 +                D3D11_SetDrawState(renderer, cmd, rendererData->pixelShaders[SHADER_SOLID], 0, NULL, NULL, NULL);
 17.1344 +                for (i = 0; i < count; i++, offset += 4) {
 17.1345 +                    D3D11_DrawPrimitives(renderer, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, start + offset, 4);
 17.1346 +                }
 17.1347 +                break;
 17.1348 +            }
 17.1349 +
 17.1350 +            case SDL_RENDERCMD_COPY: {
 17.1351 +                const size_t first = cmd->data.draw.first;
 17.1352 +                const size_t start = first / sizeof (VertexPositionColor);
 17.1353 +                D3D11_SetCopyState(renderer, cmd, NULL);
 17.1354 +                D3D11_DrawPrimitives(renderer, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, start, 4);
 17.1355 +                break;
 17.1356 +            }
 17.1357 +
 17.1358 +            case SDL_RENDERCMD_COPY_EX: {
 17.1359 +                const size_t first = cmd->data.draw.first;
 17.1360 +                const size_t start = first / sizeof (VertexPositionColor);
 17.1361 +                const VertexPositionColor *verts = (VertexPositionColor *) (((Uint8 *) vertices) + first);
 17.1362 +                const VertexPositionColor *transvert = verts + 4;
 17.1363 +                const float translatex = transvert->pos.x;
 17.1364 +                const float translatey = transvert->pos.y;
 17.1365 +                const float rotation = transvert->pos.z;
 17.1366 +                const Float4X4 matrix = MatrixMultiply(MatrixRotationZ(rotation), MatrixTranslation(translatex, translatey, 0));
 17.1367 +                D3D11_SetCopyState(renderer, cmd, &matrix);
 17.1368 +                D3D11_DrawPrimitives(renderer, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, start, 4);
 17.1369 +                break;
 17.1370 +            }
 17.1371 +
 17.1372 +            case SDL_RENDERCMD_NO_OP:
 17.1373 +                break;
 17.1374 +        }
 17.1375 +
 17.1376 +        cmd = cmd->next;
 17.1377      }
 17.1378  
 17.1379 -    D3D11_RenderFinishDrawOp(renderer, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, sizeof(vertices) / sizeof(VertexPositionColor));
 17.1380 -
 17.1381 -    return 0;
 17.1382 -}
 17.1383 -
 17.1384 -static int
 17.1385 -D3D11_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
 17.1386 -                   const SDL_Rect * srcrect, const SDL_FRect * dstrect,
 17.1387 -                   const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip)
 17.1388 -{
 17.1389 -    float minu, maxu, minv, maxv;
 17.1390 -    Float4 color;
 17.1391 -    Float4X4 modelMatrix;
 17.1392 -    float minx, maxx, miny, maxy;
 17.1393 -    VertexPositionColor vertices[4];
 17.1394 -
 17.1395 -    D3D11_RenderStartDrawOp(renderer);
 17.1396 -    D3D11_RenderSetBlendMode(renderer, texture->blendMode);
 17.1397 -
 17.1398 -    minu = (float) srcrect->x / texture->w;
 17.1399 -    maxu = (float) (srcrect->x + srcrect->w) / texture->w;
 17.1400 -    minv = (float) srcrect->y / texture->h;
 17.1401 -    maxv = (float) (srcrect->y + srcrect->h) / texture->h;
 17.1402 -
 17.1403 -    color.x = 1.0f;     /* red */
 17.1404 -    color.y = 1.0f;     /* green */
 17.1405 -    color.z = 1.0f;     /* blue */
 17.1406 -    color.w = 1.0f;     /* alpha */
 17.1407 -    if (texture->modMode & SDL_TEXTUREMODULATE_COLOR) {
 17.1408 -        color.x = (float)(texture->r / 255.0f);     /* red */
 17.1409 -        color.y = (float)(texture->g / 255.0f);     /* green */
 17.1410 -        color.z = (float)(texture->b / 255.0f);     /* blue */
 17.1411 -    }
 17.1412 -    if (texture->modMode & SDL_TEXTUREMODULATE_ALPHA) {
 17.1413 -        color.w = (float)(texture->a / 255.0f);     /* alpha */
 17.1414 -    }
 17.1415 -
 17.1416 -    if (flip & SDL_FLIP_HORIZONTAL) {
 17.1417 -        float tmp = maxu;
 17.1418 -        maxu = minu;
 17.1419 -        minu = tmp;
 17.1420 -    }
 17.1421 -    if (flip & SDL_FLIP_VERTICAL) {
 17.1422 -        float tmp = maxv;
 17.1423 -        maxv = minv;
 17.1424 -        minv = tmp;
 17.1425 -    }
 17.1426 -
 17.1427 -    modelMatrix = MatrixMultiply(
 17.1428 -            MatrixRotationZ((float)(M_PI * (float) angle / 180.0f)),
 17.1429 -            MatrixTranslation(dstrect->x + center->x, dstrect->y + center->y, 0)
 17.1430 -            );
 17.1431 -    D3D11_SetModelMatrix(renderer, &modelMatrix);
 17.1432 -
 17.1433 -    minx = -center->x;
 17.1434 -    maxx = dstrect->w - center->x;
 17.1435 -    miny = -center->y;
 17.1436 -    maxy = dstrect->h - center->y;
 17.1437 -
 17.1438 -    vertices[0].pos.x = minx;
 17.1439 -    vertices[0].pos.y = miny;
 17.1440 -    vertices[0].pos.z = 0.0f;
 17.1441 -    vertices[0].tex.x = minu;
 17.1442 -    vertices[0].tex.y = minv;
 17.1443 -    vertices[0].color = color;
 17.1444 -    
 17.1445 -    vertices[1].pos.x = minx;
 17.1446 -    vertices[1].pos.y = maxy;
 17.1447 -    vertices[1].pos.z = 0.0f;
 17.1448 -    vertices[1].tex.x = minu;
 17.1449 -    vertices[1].tex.y = maxv;
 17.1450 -    vertices[1].color = color;
 17.1451 -    
 17.1452 -    vertices[2].pos.x = maxx;
 17.1453 -    vertices[2].pos.y = miny;
 17.1454 -    vertices[2].pos.z = 0.0f;
 17.1455 -    vertices[2].tex.x = maxu;
 17.1456 -    vertices[2].tex.y = minv;
 17.1457 -    vertices[2].color = color;
 17.1458 -    
 17.1459 -    vertices[3].pos.x = maxx;
 17.1460 -    vertices[3].pos.y = maxy;
 17.1461 -    vertices[3].pos.z = 0.0f;
 17.1462 -    vertices[3].tex.x = maxu;
 17.1463 -    vertices[3].tex.y = maxv;
 17.1464 -    vertices[3].color = color;
 17.1465 -
 17.1466 -    if (D3D11_UpdateVertexBuffer(renderer, vertices, sizeof(vertices)) != 0) {
 17.1467 -        return -1;
 17.1468 -    }
 17.1469 -
 17.1470 -    if (D3D11_RenderSetupSampler(renderer, texture) < 0) {
 17.1471 -        return -1;
 17.1472 -    }
 17.1473 -
 17.1474 -    D3D11_RenderFinishDrawOp(renderer, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, sizeof(vertices) / sizeof(VertexPositionColor));
 17.1475 -
 17.1476 -    D3D11_SetModelMatrix(renderer, NULL);
 17.1477 -
 17.1478      return 0;
 17.1479  }
 17.1480  
 17.1481 @@ -2550,6 +2447,110 @@
 17.1482      }
 17.1483  }
 17.1484  
 17.1485 +SDL_Renderer *
 17.1486 +D3D11_CreateRenderer(SDL_Window * window, Uint32 flags)
 17.1487 +{
 17.1488 +    SDL_Renderer *renderer;
 17.1489 +    D3D11_RenderData *data;
 17.1490 +
 17.1491 +    renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
 17.1492 +    if (!renderer) {
 17.1493 +        SDL_OutOfMemory();
 17.1494 +        return NULL;
 17.1495 +    }
 17.1496 +
 17.1497 +    data = (D3D11_RenderData *) SDL_calloc(1, sizeof(*data));
 17.1498 +    if (!data) {
 17.1499 +        SDL_OutOfMemory();
 17.1500 +        return NULL;
 17.1501 +    }
 17.1502 +
 17.1503 +    data->identity = MatrixIdentity();
 17.1504 +
 17.1505 +    renderer->WindowEvent = D3D11_WindowEvent;
 17.1506 +    renderer->SupportsBlendMode = D3D11_SupportsBlendMode;
 17.1507 +    renderer->CreateTexture = D3D11_CreateTexture;
 17.1508 +    renderer->UpdateTexture = D3D11_UpdateTexture;
 17.1509 +    renderer->UpdateTextureYUV = D3D11_UpdateTextureYUV;
 17.1510 +    renderer->LockTexture = D3D11_LockTexture;
 17.1511 +    renderer->UnlockTexture = D3D11_UnlockTexture;
 17.1512 +    renderer->SetRenderTarget = D3D11_SetRenderTarget;
 17.1513 +    renderer->QueueSetViewport = D3D11_QueueSetViewport;
 17.1514 +    renderer->QueueSetDrawColor = D3D11_QueueSetViewport;  /* SetViewport and SetDrawColor are (currently) no-ops. */
 17.1515 +    renderer->QueueDrawPoints = D3D11_QueueDrawPoints;
 17.1516 +    renderer->QueueDrawLines = D3D11_QueueDrawPoints;  /* lines and points queue vertices the same way. */
 17.1517 +    renderer->QueueFillRects = D3D11_QueueFillRects;
 17.1518 +    renderer->QueueCopy = D3D11_QueueCopy;
 17.1519 +    renderer->QueueCopyEx = D3D11_QueueCopyEx;
 17.1520 +    renderer->RunCommandQueue = D3D11_RunCommandQueue;
 17.1521 +    renderer->RenderReadPixels = D3D11_RenderReadPixels;
 17.1522 +    renderer->RenderPresent = D3D11_RenderPresent;
 17.1523 +    renderer->DestroyTexture = D3D11_DestroyTexture;
 17.1524 +    renderer->DestroyRenderer = D3D11_DestroyRenderer;
 17.1525 +    renderer->info = D3D11_RenderDriver.info;
 17.1526 +    renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
 17.1527 +    renderer->driverdata = data;
 17.1528 +
 17.1529 +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
 17.1530 +    /* VSync is required in Windows Phone, at least for Win Phone 8.0 and 8.1.
 17.1531 +     * Failure to use it seems to either result in:
 17.1532 +     *
 17.1533 +     *  - with the D3D11 debug runtime turned OFF, vsync seemingly gets turned
 17.1534 +     *    off (framerate doesn't get capped), but nothing appears on-screen
 17.1535 +     *
 17.1536 +     *  - with the D3D11 debug runtime turned ON, vsync gets automatically
 17.1537 +     *    turned back on, and the following gets output to the debug console:
 17.1538 +     *    
 17.1539 +     *    DXGI ERROR: IDXGISwapChain::Present: Interval 0 is not supported, changed to Interval 1. [ UNKNOWN ERROR #1024: ] 
 17.1540 +     */
 17.1541 +    renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
 17.1542 +#else
 17.1543 +    if ((flags & SDL_RENDERER_PRESENTVSYNC)) {
 17.1544 +        renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
 17.1545 +    }
 17.1546 +#endif
 17.1547 +
 17.1548 +    /* HACK: make sure the SDL_Renderer references the SDL_Window data now, in
 17.1549 +     * order to give init functions access to the underlying window handle:
 17.1550 +     */
 17.1551 +    renderer->window = window;
 17.1552 +
 17.1553 +    /* Initialize Direct3D resources */
 17.1554 +    if (FAILED(D3D11_CreateDeviceResources(renderer))) {
 17.1555 +        D3D11_DestroyRenderer(renderer);
 17.1556 +        return NULL;
 17.1557 +    }
 17.1558 +    if (FAILED(D3D11_CreateWindowSizeDependentResources(renderer))) {
 17.1559 +        D3D11_DestroyRenderer(renderer);
 17.1560 +        return NULL;
 17.1561 +    }
 17.1562 +
 17.1563 +    return renderer;
 17.1564 +}
 17.1565 +
 17.1566 +SDL_RenderDriver D3D11_RenderDriver = {
 17.1567 +    D3D11_CreateRenderer,
 17.1568 +    {
 17.1569 +        "direct3d11",
 17.1570 +        (
 17.1571 +            SDL_RENDERER_ACCELERATED |
 17.1572 +            SDL_RENDERER_PRESENTVSYNC |
 17.1573 +            SDL_RENDERER_TARGETTEXTURE
 17.1574 +        ),                          /* flags.  see SDL_RendererFlags */
 17.1575 +        6,                          /* num_texture_formats */
 17.1576 +        {                           /* texture_formats */
 17.1577 +            SDL_PIXELFORMAT_ARGB8888,
 17.1578 +            SDL_PIXELFORMAT_RGB888,
 17.1579 +            SDL_PIXELFORMAT_YV12,
 17.1580 +            SDL_PIXELFORMAT_IYUV,
 17.1581 +            SDL_PIXELFORMAT_NV12,
 17.1582 +            SDL_PIXELFORMAT_NV21
 17.1583 +        },
 17.1584 +        0,                          /* max_texture_width: will be filled in later */
 17.1585 +        0                           /* max_texture_height: will be filled in later */
 17.1586 +    }
 17.1587 +};
 17.1588 +
 17.1589  #endif /* SDL_VIDEO_RENDER_D3D11 && !SDL_RENDER_DISABLED */
 17.1590  
 17.1591  /* vi: set ts=4 sw=4 expandtab: */
    18.1 --- a/src/render/metal/SDL_render_metal.m	Mon Oct 22 10:55:18 2018 -0400
    18.2 +++ b/src/render/metal/SDL_render_metal.m	Wed Oct 31 15:03:41 2018 -0400
    18.3 @@ -46,64 +46,6 @@
    18.4  
    18.5  /* Apple Metal renderer implementation */
    18.6  
    18.7 -static SDL_Renderer *METAL_CreateRenderer(SDL_Window * window, Uint32 flags);
    18.8 -static void METAL_WindowEvent(SDL_Renderer * renderer,
    18.9 -                           const SDL_WindowEvent *event);
   18.10 -static int METAL_GetOutputSize(SDL_Renderer * renderer, int *w, int *h);
   18.11 -static SDL_bool METAL_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode);
   18.12 -static int METAL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
   18.13 -static int METAL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   18.14 -                            const SDL_Rect * rect, const void *pixels,
   18.15 -                            int pitch);
   18.16 -static int METAL_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
   18.17 -                               const SDL_Rect * rect,
   18.18 -                               const Uint8 *Yplane, int Ypitch,
   18.19 -                               const Uint8 *Uplane, int Upitch,
   18.20 -                               const Uint8 *Vplane, int Vpitch);
   18.21 -static int METAL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   18.22 -                          const SDL_Rect * rect, void **pixels, int *pitch);
   18.23 -static void METAL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
   18.24 -static int METAL_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture);
   18.25 -static int METAL_UpdateViewport(SDL_Renderer * renderer);
   18.26 -static int METAL_UpdateClipRect(SDL_Renderer * renderer);
   18.27 -static int METAL_RenderClear(SDL_Renderer * renderer);
   18.28 -static int METAL_RenderDrawPoints(SDL_Renderer * renderer,
   18.29 -                               const SDL_FPoint * points, int count);
   18.30 -static int METAL_RenderDrawLines(SDL_Renderer * renderer,
   18.31 -                              const SDL_FPoint * points, int count);
   18.32 -static int METAL_RenderFillRects(SDL_Renderer * renderer,
   18.33 -                              const SDL_FRect * rects, int count);
   18.34 -static int METAL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   18.35 -                         const SDL_Rect * srcrect, const SDL_FRect * dstrect);
   18.36 -static int METAL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
   18.37 -                         const SDL_Rect * srcrect, const SDL_FRect * dstrect,
   18.38 -                         const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip);
   18.39 -static int METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
   18.40 -                               Uint32 pixel_format, void * pixels, int pitch);
   18.41 -static void METAL_RenderPresent(SDL_Renderer * renderer);
   18.42 -static void METAL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture);
   18.43 -static void METAL_DestroyRenderer(SDL_Renderer * renderer);
   18.44 -static void *METAL_GetMetalLayer(SDL_Renderer * renderer);
   18.45 -static void *METAL_GetMetalCommandEncoder(SDL_Renderer * renderer);
   18.46 -
   18.47 -SDL_RenderDriver METAL_RenderDriver = {
   18.48 -    METAL_CreateRenderer,
   18.49 -    {
   18.50 -        "metal",
   18.51 -        (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
   18.52 -        6,
   18.53 -        {
   18.54 -            SDL_PIXELFORMAT_ARGB8888,
   18.55 -            SDL_PIXELFORMAT_ABGR8888,
   18.56 -            SDL_PIXELFORMAT_YV12,
   18.57 -            SDL_PIXELFORMAT_IYUV,
   18.58 -            SDL_PIXELFORMAT_NV12,
   18.59 -            SDL_PIXELFORMAT_NV21
   18.60 -        },
   18.61 -    0, 0,
   18.62 -    }
   18.63 -};
   18.64 -
   18.65  /* macOS requires constants in a buffer to have a 256 byte alignment. */
   18.66  #ifdef __MACOSX__
   18.67  #define CONSTANT_ALIGN 256
   18.68 @@ -113,6 +55,7 @@
   18.69  
   18.70  #define ALIGN_CONSTANTS(size) ((size + CONSTANT_ALIGN - 1) & (~(CONSTANT_ALIGN - 1)))
   18.71  
   18.72 +static const size_t CONSTANTS_OFFSET_INVALID = 0xFFFFFFFF;
   18.73  static const size_t CONSTANTS_OFFSET_IDENTITY = 0;
   18.74  static const size_t CONSTANTS_OFFSET_HALF_PIXEL_TRANSFORM = ALIGN_CONSTANTS(CONSTANTS_OFFSET_IDENTITY + sizeof(float) * 16);
   18.75  static const size_t CONSTANTS_OFFSET_DECODE_JPEG = ALIGN_CONSTANTS(CONSTANTS_OFFSET_HALF_PIXEL_TRANSFORM + sizeof(float) * 16);
   18.76 @@ -457,248 +400,8 @@
   18.77      return MakePipelineState(data, cache, [NSString stringWithFormat:@" (blend=custom 0x%x)", blendmode], blendmode);
   18.78  }
   18.79  
   18.80 -static SDL_Renderer *
   18.81 -METAL_CreateRenderer(SDL_Window * window, Uint32 flags)
   18.82 -{ @autoreleasepool {
   18.83 -    SDL_Renderer *renderer = NULL;
   18.84 -    METAL_RenderData *data = NULL;
   18.85 -    id<MTLDevice> mtldevice = nil;
   18.86 -    SDL_SysWMinfo syswm;
   18.87 -
   18.88 -    SDL_VERSION(&syswm.version);
   18.89 -    if (!SDL_GetWindowWMInfo(window, &syswm)) {
   18.90 -        return NULL;
   18.91 -    }
   18.92 -
   18.93 -    if (IsMetalAvailable(&syswm) == -1) {
   18.94 -        return NULL;
   18.95 -    }
   18.96 -
   18.97 -    renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   18.98 -    if (!renderer) {
   18.99 -        SDL_OutOfMemory();
  18.100 -        return NULL;
  18.101 -    }
  18.102 -
  18.103 -    // !!! FIXME: MTLCopyAllDevices() can find other GPUs on macOS...
  18.104 -    mtldevice = MTLCreateSystemDefaultDevice();
  18.105 -
  18.106 -    if (mtldevice == nil) {
  18.107 -        SDL_free(renderer);
  18.108 -        SDL_SetError("Failed to obtain Metal device");
  18.109 -        return NULL;
  18.110 -    }
  18.111 -
  18.112 -    // !!! FIXME: error checking on all of this.
  18.113 -    data = [[METAL_RenderData alloc] init];
  18.114 -
  18.115 -    renderer->driverdata = (void*)CFBridgingRetain(data);
  18.116 -    renderer->window = window;
  18.117 -
  18.118 -#ifdef __MACOSX__
  18.119 -    NSView *view = Cocoa_Mtl_AddMetalView(window);
  18.120 -    CAMetalLayer *layer = (CAMetalLayer *)[view layer];
  18.121 -
  18.122 -    layer.device = mtldevice;
  18.123 -
  18.124 -    //layer.colorspace = nil;
  18.125 -
  18.126 -#else
  18.127 -    UIView *view = UIKit_Mtl_AddMetalView(window);
  18.128 -    CAMetalLayer *layer = (CAMetalLayer *)[view layer];
  18.129 -#endif
  18.130 -
  18.131 -    // Necessary for RenderReadPixels.
  18.132 -    layer.framebufferOnly = NO;
  18.133 -
  18.134 -    data.mtldevice = layer.device;
  18.135 -    data.mtllayer = layer;
  18.136 -    id<MTLCommandQueue> mtlcmdqueue = [data.mtldevice newCommandQueue];
  18.137 -    data.mtlcmdqueue = mtlcmdqueue;
  18.138 -    data.mtlcmdqueue.label = @"SDL Metal Renderer";
  18.139 -    data.mtlpassdesc = [MTLRenderPassDescriptor renderPassDescriptor];
  18.140 -
  18.141 -    NSError *err = nil;
  18.142 -
  18.143 -    // The compiled .metallib is embedded in a static array in a header file
  18.144 -    // but the original shader source code is in SDL_shaders_metal.metal.
  18.145 -    dispatch_data_t mtllibdata = dispatch_data_create(sdl_metallib, sdl_metallib_len, dispatch_get_global_queue(0, 0), ^{});
  18.146 -    id<MTLLibrary> mtllibrary = [data.mtldevice newLibraryWithData:mtllibdata error:&err];
  18.147 -    data.mtllibrary = mtllibrary;
  18.148 -    SDL_assert(err == nil);
  18.149 -#if !__has_feature(objc_arc)
  18.150 -    dispatch_release(mtllibdata);
  18.151 -#endif
  18.152 -    data.mtllibrary.label = @"SDL Metal renderer shader library";
  18.153 -
  18.154 -    /* Do some shader pipeline state loading up-front rather than on demand. */
  18.155 -    data.pipelinescount = 0;
  18.156 -    data.allpipelines = NULL;
  18.157 -    ChooseShaderPipelines(data, MTLPixelFormatBGRA8Unorm);
  18.158 -
  18.159 -    MTLSamplerDescriptor *samplerdesc = [[MTLSamplerDescriptor alloc] init];
  18.160 -
  18.161 -    samplerdesc.minFilter = MTLSamplerMinMagFilterNearest;
  18.162 -    samplerdesc.magFilter = MTLSamplerMinMagFilterNearest;
  18.163 -    id<MTLSamplerState> mtlsamplernearest = [data.mtldevice newSamplerStateWithDescriptor:samplerdesc];
  18.164 -    data.mtlsamplernearest = mtlsamplernearest;
  18.165 -
  18.166 -    samplerdesc.minFilter = MTLSamplerMinMagFilterLinear;
  18.167 -    samplerdesc.magFilter = MTLSamplerMinMagFilterLinear;
  18.168 -    id<MTLSamplerState> mtlsamplerlinear = [data.mtldevice newSamplerStateWithDescriptor:samplerdesc];
  18.169 -    data.mtlsamplerlinear = mtlsamplerlinear;
  18.170 -
  18.171 -    /* Note: matrices are column major. */
  18.172 -    float identitytransform[16] = {
  18.173 -        1.0f, 0.0f, 0.0f, 0.0f,
  18.174 -        0.0f, 1.0f, 0.0f, 0.0f,
  18.175 -        0.0f, 0.0f, 1.0f, 0.0f,
  18.176 -        0.0f, 0.0f, 0.0f, 1.0f,
  18.177 -    };
  18.178 -
  18.179 -    float halfpixeltransform[16] = {
  18.180 -        1.0f, 0.0f, 0.0f, 0.0f,
  18.181 -        0.0f, 1.0f, 0.0f, 0.0f,
  18.182 -        0.0f, 0.0f, 1.0f, 0.0f,
  18.183 -        0.5f, 0.5f, 0.0f, 1.0f,
  18.184 -    };
  18.185 -
  18.186 -    /* Metal pads float3s to 16 bytes. */
  18.187 -    float decodetransformJPEG[4*4] = {
  18.188 -        0.0, -0.501960814, -0.501960814, 0.0, /* offset */
  18.189 -        1.0000,  0.0000,  1.4020, 0.0,        /* Rcoeff */
  18.190 -        1.0000, -0.3441, -0.7141, 0.0,        /* Gcoeff */
  18.191 -        1.0000,  1.7720,  0.0000, 0.0,        /* Bcoeff */
  18.192 -    };
  18.193 -
  18.194 -    float decodetransformBT601[4*4] = {
  18.195 -        -0.0627451017, -0.501960814, -0.501960814, 0.0, /* offset */
  18.196 -        1.1644,  0.0000,  1.5960, 0.0,                  /* Rcoeff */
  18.197 -        1.1644, -0.3918, -0.8130, 0.0,                  /* Gcoeff */
  18.198 -        1.1644,  2.0172,  0.0000, 0.0,                  /* Bcoeff */
  18.199 -    };
  18.200 -
  18.201 -    float decodetransformBT709[4*4] = {
  18.202 -        0.0, -0.501960814, -0.501960814, 0.0, /* offset */
  18.203 -        1.0000,  0.0000,  1.4020, 0.0,        /* Rcoeff */
  18.204 -        1.0000, -0.3441, -0.7141, 0.0,        /* Gcoeff */
  18.205 -        1.0000,  1.7720,  0.0000, 0.0,        /* Bcoeff */
  18.206 -    };
  18.207 -
  18.208 -    float clearverts[6] = {0.0f, 0.0f,  0.0f, 2.0f,  2.0f, 0.0f};
  18.209 -
  18.210 -    id<MTLBuffer> mtlbufconstantstaging = [data.mtldevice newBufferWithLength:CONSTANTS_LENGTH options:MTLResourceStorageModeShared];
  18.211 -    mtlbufconstantstaging.label = @"SDL constant staging data";
  18.212 -
  18.213 -    id<MTLBuffer> mtlbufconstants = [data.mtldevice newBufferWithLength:CONSTANTS_LENGTH options:MTLResourceStorageModePrivate];
  18.214 -    data.mtlbufconstants = mtlbufconstants;
  18.215 -    data.mtlbufconstants.label = @"SDL constant data";
  18.216 -
  18.217 -    char *constantdata = [mtlbufconstantstaging contents];
  18.218 -    SDL_memcpy(constantdata + CONSTANTS_OFFSET_IDENTITY, identitytransform, sizeof(identitytransform));
  18.219 -    SDL_memcpy(constantdata + CONSTANTS_OFFSET_HALF_PIXEL_TRANSFORM, halfpixeltransform, sizeof(halfpixeltransform));
  18.220 -    SDL_memcpy(constantdata + CONSTANTS_OFFSET_DECODE_JPEG, decodetransformJPEG, sizeof(decodetransformJPEG));
  18.221 -    SDL_memcpy(constantdata + CONSTANTS_OFFSET_DECODE_BT601, decodetransformBT601, sizeof(decodetransformBT601));
  18.222 -    SDL_memcpy(constantdata + CONSTANTS_OFFSET_DECODE_BT709, decodetransformBT709, sizeof(decodetransformBT709));
  18.223 -    SDL_memcpy(constantdata + CONSTANTS_OFFSET_CLEAR_VERTS, clearverts, sizeof(clearverts));
  18.224 -
  18.225 -    id<MTLCommandBuffer> cmdbuffer = [data.mtlcmdqueue commandBuffer];
  18.226 -    id<MTLBlitCommandEncoder> blitcmd = [cmdbuffer blitCommandEncoder];
  18.227 -
  18.228 -    [blitcmd copyFromBuffer:mtlbufconstantstaging sourceOffset:0 toBuffer:data.mtlbufconstants destinationOffset:0 size:CONSTANTS_LENGTH];
  18.229 -
  18.230 -    [blitcmd endEncoding];
  18.231 -    [cmdbuffer commit];
  18.232 -
  18.233 -    // !!! FIXME: force more clears here so all the drawables are sane to start, and our static buffers are definitely flushed.
  18.234 -
  18.235 -    renderer->WindowEvent = METAL_WindowEvent;
  18.236 -    renderer->GetOutputSize = METAL_GetOutputSize;
  18.237 -    renderer->SupportsBlendMode = METAL_SupportsBlendMode;
  18.238 -    renderer->CreateTexture = METAL_CreateTexture;
  18.239 -    renderer->UpdateTexture = METAL_UpdateTexture;
  18.240 -    renderer->UpdateTextureYUV = METAL_UpdateTextureYUV;
  18.241 -    renderer->LockTexture = METAL_LockTexture;
  18.242 -    renderer->UnlockTexture = METAL_UnlockTexture;
  18.243 -    renderer->SetRenderTarget = METAL_SetRenderTarget;
  18.244 -    renderer->UpdateViewport = METAL_UpdateViewport;
  18.245 -    renderer->UpdateClipRect = METAL_UpdateClipRect;
  18.246 -    renderer->RenderClear = METAL_RenderClear;
  18.247 -    renderer->RenderDrawPoints = METAL_RenderDrawPoints;
  18.248 -    renderer->RenderDrawLines = METAL_RenderDrawLines;
  18.249 -    renderer->RenderFillRects = METAL_RenderFillRects;
  18.250 -    renderer->RenderCopy = METAL_RenderCopy;
  18.251 -    renderer->RenderCopyEx = METAL_RenderCopyEx;
  18.252 -    renderer->RenderReadPixels = METAL_RenderReadPixels;
  18.253 -    renderer->RenderPresent = METAL_RenderPresent;
  18.254 -    renderer->DestroyTexture = METAL_DestroyTexture;
  18.255 -    renderer->DestroyRenderer = METAL_DestroyRenderer;
  18.256 -    renderer->GetMetalLayer = METAL_GetMetalLayer;
  18.257 -    renderer->GetMetalCommandEncoder = METAL_GetMetalCommandEncoder;
  18.258 -
  18.259 -    renderer->info = METAL_RenderDriver.info;
  18.260 -    renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
  18.261 -
  18.262 -#if defined(__MACOSX__) && defined(MAC_OS_X_VERSION_10_13)
  18.263 -    if (@available(macOS 10.13, *)) {
  18.264 -        data.mtllayer.displaySyncEnabled = (flags & SDL_RENDERER_PRESENTVSYNC) != 0;
  18.265 -    } else
  18.266 -#endif
  18.267 -    {
  18.268 -        renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
  18.269 -    }
  18.270 -
  18.271 -    /* https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf */
  18.272 -    int maxtexsize = 4096;
  18.273 -#if defined(__MACOSX__)
  18.274 -    maxtexsize = 16384;
  18.275 -#elif defined(__TVOS__)
  18.276 -    maxtexsize = 8192;
  18.277 -#ifdef __TVOS_11_0
  18.278 -    if (@available(tvOS 11.0, *)) {
  18.279 -        if ([mtldevice supportsFeatureSet:MTLFeatureSet_tvOS_GPUFamily2_v1]) {
  18.280 -            maxtexsize = 16384;
  18.281 -        }
  18.282 -    }
  18.283 -#endif
  18.284 -#else
  18.285 -#ifdef __IPHONE_11_0
  18.286 -    if ([mtldevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily4_v1]) {
  18.287 -        maxtexsize = 16384;
  18.288 -    } else
  18.289 -#endif
  18.290 -#ifdef __IPHONE_10_0
  18.291 -    if ([mtldevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v1]) {
  18.292 -        maxtexsize = 16384;
  18.293 -    } else
  18.294 -#endif
  18.295 -    if ([mtldevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily2_v2] || [mtldevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily1_v2]) {
  18.296 -        maxtexsize = 8192;
  18.297 -    } else {
  18.298 -        maxtexsize = 4096;
  18.299 -    }
  18.300 -#endif
  18.301 -
  18.302 -    renderer->info.max_texture_width = maxtexsize;
  18.303 -    renderer->info.max_texture_height = maxtexsize;
  18.304 -
  18.305 -#if !__has_feature(objc_arc)
  18.306 -    [mtlcmdqueue release];
  18.307 -    [mtllibrary release];
  18.308 -    [samplerdesc release];
  18.309 -    [mtlsamplernearest release];
  18.310 -    [mtlsamplerlinear release];
  18.311 -    [mtlbufconstants release];
  18.312 -    [view release];
  18.313 -    [data release];
  18.314 -    [mtldevice release];
  18.315 -#endif
  18.316 -
  18.317 -    return renderer;
  18.318 -}}
  18.319 -
  18.320  static void
  18.321 -METAL_ActivateRenderCommandEncoder(SDL_Renderer * renderer, MTLLoadAction load)
  18.322 +METAL_ActivateRenderCommandEncoder(SDL_Renderer * renderer, MTLLoadAction load, MTLClearColor *clear_color)
  18.323  {
  18.324      METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
  18.325  
  18.326 @@ -725,8 +428,8 @@
  18.327          SDL_assert(mtltexture);
  18.328  
  18.329          if (load == MTLLoadActionClear) {
  18.330 -            MTLClearColor color = MTLClearColorMake(renderer->r/255.0, renderer->g/255.0, renderer->b/255.0, renderer->a/255.0);
  18.331 -            data.mtlpassdesc.colorAttachments[0].clearColor = color;
  18.332 +            SDL_assert(clear_color != NULL);
  18.333 +            data.mtlpassdesc.colorAttachments[0].clearColor = *clear_color;
  18.334          }
  18.335  
  18.336          data.mtlpassdesc.colorAttachments[0].loadAction = load;
  18.337 @@ -743,9 +446,10 @@
  18.338  
  18.339          data.activepipelines = ChooseShaderPipelines(data, mtltexture.pixelFormat);
  18.340  
  18.341 -        /* Make sure the viewport and clip rect are set on the new render pass. */
  18.342 -        METAL_UpdateViewport(renderer);
  18.343 -        METAL_UpdateClipRect(renderer);
  18.344 +        // make sure this has a definite place in the queue. This way it will
  18.345 +        //  execute reliably whether the app tries to make its own command buffers
  18.346 +        //  or whatever. This means we can _always_ batch rendering commands!
  18.347 +        [data.mtlcmdbuffer enqueue];
  18.348      }
  18.349  }
  18.350  
  18.351 @@ -849,7 +553,7 @@
  18.352          mtltexdesc.height = (texture->h + 1) / 2;
  18.353      }
  18.354  
  18.355 -    if (yuv || nv12) {
  18.356 +    if (yuv || nc12) {
  18.357          mtltexture_uv = [data.mtldevice newTextureWithDescriptor:mtltexdesc];
  18.358          if (mtltexture_uv == nil) {
  18.359  #if !__has_feature(objc_arc)
  18.360 @@ -1027,126 +731,6 @@
  18.361      return 0;
  18.362  }}
  18.363  
  18.364 -static int
  18.365 -METAL_SetOrthographicProjection(SDL_Renderer *renderer, int w, int h)
  18.366 -{ @autoreleasepool {
  18.367 -    METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
  18.368 -    float projection[4][4];
  18.369 -
  18.370 -    if (!w || !h) {
  18.371 -        return 0;
  18.372 -    }
  18.373 -
  18.374 -    /* Prepare an orthographic projection */
  18.375 -    projection[0][0] = 2.0f / w;
  18.376 -    projection[0][1] = 0.0f;
  18.377 -    projection[0][2] = 0.0f;
  18.378 -    projection[0][3] = 0.0f;
  18.379 -    projection[1][0] = 0.0f;
  18.380 -    projection[1][1] = -2.0f / h;
  18.381 -    projection[1][2] = 0.0f;
  18.382 -    projection[1][3] = 0.0f;
  18.383 -    projection[2][0] = 0.0f;
  18.384 -    projection[2][1] = 0.0f;
  18.385 -    projection[2][2] = 0.0f;
  18.386 -    projection[2][3] = 0.0f;
  18.387 -    projection[3][0] = -1.0f;
  18.388 -    projection[3][1] = 1.0f;
  18.389 -    projection[3][2] = 0.0f;
  18.390 -    projection[3][3] = 1.0f;
  18.391 -
  18.392 -    // !!! FIXME: This should be in a buffer...
  18.393 -    [data.mtlcmdencoder setVertexBytes:projection length:sizeof(float)*16 atIndex:2];
  18.394 -    return 0;
  18.395 -}}
  18.396 -
  18.397 -static int
  18.398 -METAL_UpdateViewport(SDL_Renderer * renderer)
  18.399 -{ @autoreleasepool {
  18.400 -    METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
  18.401 -    if (data.mtlcmdencoder) {
  18.402 -        MTLViewport viewport;
  18.403 -        viewport.originX = renderer->viewport.x;
  18.404 -        viewport.originY = renderer->viewport.y;
  18.405 -        viewport.width = renderer->viewport.w;
  18.406 -        viewport.height = renderer->viewport.h;
  18.407 -        viewport.znear = 0.0;
  18.408 -        viewport.zfar = 1.0;
  18.409 -        [data.mtlcmdencoder setViewport:viewport];
  18.410 -        METAL_SetOrthographicProjection(renderer, renderer->viewport.w, renderer->viewport.h);
  18.411 -    }
  18.412 -    return 0;
  18.413 -}}
  18.414 -
  18.415 -static int
  18.416 -METAL_UpdateClipRect(SDL_Renderer * renderer)
  18.417 -{ @autoreleasepool {
  18.418 -    METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
  18.419 -    if (data.mtlcmdencoder) {
  18.420 -        MTLScissorRect mtlrect;
  18.421 -        // !!! FIXME: should this care about the viewport?
  18.422 -        if (renderer->clipping_enabled) {
  18.423 -            const SDL_Rect *rect = &renderer->clip_rect;
  18.424 -            mtlrect.x = renderer->viewport.x + rect->x;
  18.425 -            mtlrect.y = renderer->viewport.x + rect->y;
  18.426 -            mtlrect.width = rect->w;
  18.427 -            mtlrect.height = rect->h;
  18.428 -        } else {
  18.429 -            mtlrect.x = renderer->viewport.x;
  18.430 -            mtlrect.y = renderer->viewport.y;
  18.431 -            mtlrect.width = renderer->viewport.w;
  18.432 -            mtlrect.height = renderer->viewport.h;
  18.433 -        }
  18.434 -        if (mtlrect.width > 0 && mtlrect.height > 0) {
  18.435 -            [data.mtlcmdencoder setScissorRect:mtlrect];
  18.436 -        }
  18.437 -    }
  18.438 -    return 0;
  18.439 -}}
  18.440 -
  18.441 -static int
  18.442 -METAL_RenderClear(SDL_Renderer * renderer)
  18.443 -{ @autoreleasepool {
  18.444 -    METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
  18.445 -
  18.446 -    /* Since we set up the render command encoder lazily when a draw is
  18.447 -     * requested, we can do the fast path hardware clear if no draws have
  18.448 -     * happened since the last SetRenderTarget. */
  18.449 -    if (data.mtlcmdencoder == nil) {
  18.450 -        METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionClear);
  18.451 -    } else {
  18.452 -        // !!! FIXME: render color should live in a dedicated uniform buffer.
  18.453 -        const float color[4] = { ((float)renderer->r) / 255.0f, ((float)renderer->g) / 255.0f, ((float)renderer->b) / 255.0f, ((float)renderer->a) / 255.0f };
  18.454 -
  18.455 -        MTLViewport viewport;  // RenderClear ignores the viewport state, though, so reset that.
  18.456 -        viewport.originX = viewport.originY = 0.0;
  18.457 -        viewport.width = data.mtlpassdesc.colorAttachments[0].texture.width;
  18.458 -        viewport.height = data.mtlpassdesc.colorAttachments[0].texture.height;
  18.459 -        viewport.znear = 0.0;
  18.460 -        viewport.zfar = 1.0;
  18.461 -
  18.462 -        // Slow path for clearing: draw a filled fullscreen triangle.
  18.463 -        METAL_SetOrthographicProjection(renderer, 1, 1);
  18.464 -        [data.mtlcmdencoder setViewport:viewport];
  18.465 -        [data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data, data.activepipelines, SDL_METAL_FRAGMENT_SOLID, SDL_BLENDMODE_NONE)];
  18.466 -        [data.mtlcmdencoder setVertexBuffer:data.mtlbufconstants offset:CONSTANTS_OFFSET_CLEAR_VERTS atIndex:0];
  18.467 -        [data.mtlcmdencoder setVertexBuffer:data.mtlbufconstants offset:CONSTANTS_OFFSET_IDENTITY atIndex:3];
  18.468 -        [data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
  18.469 -        [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:3];
  18.470 -
  18.471 -        // reset the viewport for the rest of our usual drawing work...
  18.472 -        viewport.originX = renderer->viewport.x;
  18.473 -        viewport.originY = renderer->viewport.y;
  18.474 -        viewport.width = renderer->viewport.w;
  18.475 -        viewport.height = renderer->viewport.h;
  18.476 -        viewport.znear = 0.0;
  18.477 -        viewport.zfar = 1.0;
  18.478 -        [data.mtlcmdencoder setViewport:viewport];
  18.479 -        METAL_SetOrthographicProjection(renderer, renderer->viewport.w, renderer->viewport.h);
  18.480 -    }
  18.481 -
  18.482 -    return 0;
  18.483 -}}
  18.484  
  18.485  // normalize a value from 0.0f to len into 0.0f to 1.0f.
  18.486  static inline float
  18.487 @@ -1156,145 +740,172 @@
  18.488  }
  18.489  
  18.490  static int
  18.491 -DrawVerts(SDL_Renderer * renderer, const SDL_FPoint * points, int count,
  18.492 -          const MTLPrimitiveType primtype)
  18.493 -{ @autoreleasepool {
  18.494 -    METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad);
  18.495 +METAL_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd)
  18.496 +{
  18.497 +    float projection[4][4];    /* Prepare an orthographic projection */
  18.498 +    const int w = cmd->data.viewport.rect.w;
  18.499 +    const int h = cmd->data.viewport.rect.h;
  18.500 +    const size_t matrixlen = sizeof (projection);
  18.501 +    float *matrix = (float *) SDL_AllocateRenderVertices(renderer, matrixlen, CONSTANT_ALIGN, &cmd->data.viewport.first);
  18.502 +    if (!matrix) {
  18.503 +        return -1;
  18.504 +    }
  18.505  
  18.506 -    const size_t vertlen = (sizeof (float) * 2) * count;
  18.507 -    METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
  18.508 -
  18.509 -    // !!! FIXME: render color should live in a dedicated uniform buffer.
  18.510 -    const float color[4] = { ((float)renderer->r) / 255.0f, ((float)renderer->g) / 255.0f, ((float)renderer->b) / 255.0f, ((float)renderer->a) / 255.0f };
  18.511 -
  18.512 -    [data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data, data.activepipelines, SDL_METAL_FRAGMENT_SOLID, renderer->blendMode)];
  18.513 -    [data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
  18.514 -
  18.515 -    [data.mtlcmdencoder setVertexBytes:points length:vertlen atIndex:0];
  18.516 -    [data.mtlcmdencoder setVertexBuffer:data.mtlbufconstants offset:CONSTANTS_OFFSET_HALF_PIXEL_TRANSFORM atIndex:3];
  18.517 -    [data.mtlcmdencoder drawPrimitives:primtype vertexStart:0 vertexCount:count];
  18.518 +    SDL_memset(projection, '\0', matrixlen);
  18.519 +    if (w && h) {
  18.520 +        projection[0][0] = 2.0f / w;
  18.521 +        projection[1][1] = -2.0f / h;
  18.522 +        projection[3][0] = -1.0f;
  18.523 +        projection[3][1] = 1.0f;
  18.524 +        projection[3][3] = 1.0f;
  18.525 +    }
  18.526 +    SDL_memcpy(matrix, projection, matrixlen);
  18.527  
  18.528      return 0;
  18.529 -}}
  18.530 -
  18.531 -static int
  18.532 -METAL_RenderDrawPoints(SDL_Renderer * renderer, const SDL_FPoint * points, int count)
  18.533 -{
  18.534 -    return DrawVerts(renderer, points, count, MTLPrimitiveTypePoint);
  18.535  }
  18.536  
  18.537  static int
  18.538 -METAL_RenderDrawLines(SDL_Renderer * renderer, const SDL_FPoint * points, int count)
  18.539 +METAL_QueueSetDrawColor(SDL_Renderer *renderer, SDL_RenderCommand *cmd)
  18.540  {
  18.541 -    return DrawVerts(renderer, points, count, MTLPrimitiveTypeLineStrip);
  18.542 +    const size_t vertlen = sizeof (float) * 4;
  18.543 +    float *verts = (float *) SDL_AllocateRenderVertices(renderer, vertlen, CONSTANT_ALIGN, &cmd->data.color.first);
  18.544 +    if (!verts) {
  18.545 +        return -1;
  18.546 +    }
  18.547 +    *(verts++) = ((float)cmd->data.color.r) / 255.0f;
  18.548 +    *(verts++) = ((float)cmd->data.color.g) / 255.0f;
  18.549 +    *(verts++) = ((float)cmd->data.color.b) / 255.0f;
  18.550 +    *(verts++) = ((float)cmd->data.color.a) / 255.0f;
  18.551 +    return 0;
  18.552  }
  18.553  
  18.554  static int
  18.555 -METAL_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects, int count)
  18.556 -{ @autoreleasepool {
  18.557 -    METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad);
  18.558 -    METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
  18.559 +METAL_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
  18.560 +{
  18.561 +    const size_t vertlen = (sizeof (float) * 2) * count;
  18.562 +    float *verts = (float *) SDL_AllocateRenderVertices(renderer, vertlen, 0, &cmd->data.draw.first);
  18.563 +    if (!verts) {
  18.564 +        return -1;
  18.565 +    }
  18.566 +    cmd->data.draw.count = count;
  18.567 +    SDL_memcpy(verts, points, vertlen);
  18.568 +    return 0;
  18.569 +}
  18.570  
  18.571 -    // !!! FIXME: render color should live in a dedicated uniform buffer.
  18.572 -    const float color[4] = { ((float)renderer->r) / 255.0f, ((float)renderer->g) / 255.0f, ((float)renderer->b) / 255.0f, ((float)renderer->a) / 255.0f };
  18.573 +static int
  18.574 +METAL_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects, int count)
  18.575 +{
  18.576 +    // !!! FIXME: use an index buffer
  18.577 +    const size_t vertlen = (sizeof (float) * 8) * count;
  18.578 +    float *verts = (float *) SDL_AllocateRenderVertices(renderer, vertlen, 0, &cmd->data.draw.first);
  18.579 +    if (!verts) {
  18.580 +        return -1;
  18.581 +    }
  18.582  
  18.583 -    [data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data, data.activepipelines, SDL_METAL_FRAGMENT_SOLID, renderer->blendMode)];
  18.584 -    [data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
  18.585 -    [data.mtlcmdencoder setVertexBuffer:data.mtlbufconstants offset:CONSTANTS_OFFSET_IDENTITY atIndex:3];
  18.586 +    cmd->data.draw.count = count;
  18.587  
  18.588      for (int i = 0; i < count; i++, rects++) {
  18.589 -        if ((rects->w <= 0.0f) || (rects->h <= 0.0f)) continue;
  18.590 +        if ((rects->w <= 0.0f) || (rects->h <= 0.0f)) {
  18.591 +            cmd->data.draw.count--;
  18.592 +        } else {
  18.593 +            *(verts++) = rects->x;
  18.594 +            *(verts++) = rects->y + rects->h;
  18.595 +            *(verts++) = rects->x;
  18.596 +            *(verts++) = rects->y;
  18.597 +            *(verts++) = rects->x + rects->w;
  18.598 +            *(verts++) = rects->y + rects->h;
  18.599 +            *(verts++) = rects->x + rects->w;
  18.600 +            *(verts++) = rects->y;
  18.601 +        }
  18.602 +    }
  18.603  
  18.604 -        const float verts[] = {
  18.605 -            rects->x, rects->y + rects->h,
  18.606 -            rects->x, rects->y,
  18.607 -            rects->x + rects->w, rects->y + rects->h,
  18.608 -            rects->x + rects->w, rects->y
  18.609 -        };
  18.610 -
  18.611 -        [data.mtlcmdencoder setVertexBytes:verts length:sizeof(verts) atIndex:0];
  18.612 -        [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
  18.613 +    if (cmd->data.draw.count == 0) {
  18.614 +        cmd->command = SDL_RENDERCMD_NO_OP;  // nothing to do, just skip this one later.
  18.615      }
  18.616  
  18.617      return 0;
  18.618 -}}
  18.619 -
  18.620 -static void
  18.621 -METAL_SetupRenderCopy(METAL_RenderData *data, SDL_Texture *texture, METAL_TextureData *texturedata)
  18.622 -{
  18.623 -    float color[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
  18.624 -    if (texture->modMode) {
  18.625 -        color[0] = ((float)texture->r) / 255.0f;
  18.626 -        color[1] = ((float)texture->g) / 255.0f;
  18.627 -        color[2] = ((float)texture->b) / 255.0f;
  18.628 -        color[3] = ((float)texture->a) / 255.0f;
  18.629 -    }
  18.630 -
  18.631 -    [data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data, data.activepipelines, texturedata.fragmentFunction, texture->blendMode)];
  18.632 -    [data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
  18.633 -    [data.mtlcmdencoder setFragmentSamplerState:texturedata.mtlsampler atIndex:0];
  18.634 -
  18.635 -    [data.mtlcmdencoder setFragmentTexture:texturedata.mtltexture atIndex:0];
  18.636 -
  18.637 -    if (texturedata.yuv || texturedata.nv12) {
  18.638 -        [data.mtlcmdencoder setFragmentTexture:texturedata.mtltexture_uv atIndex:1];
  18.639 -        [data.mtlcmdencoder setFragmentBuffer:data.mtlbufconstants offset:texturedata.conversionBufferOffset atIndex:1];
  18.640 -    }
  18.641  }
  18.642  
  18.643  static int
  18.644 -METAL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
  18.645 -              const SDL_Rect * srcrect, const SDL_FRect * dstrect)
  18.646 -{ @autoreleasepool {
  18.647 -    METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad);
  18.648 -    METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
  18.649 +METAL_QueueCopy(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
  18.650 +                const SDL_Rect * srcrect, const SDL_FRect * dstrect)
  18.651 +{
  18.652      METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->driverdata;
  18.653      const float texw = (float) texturedata.mtltexture.width;
  18.654      const float texh = (float) texturedata.mtltexture.height;
  18.655 +    // !!! FIXME: use an index buffer
  18.656 +    const size_t vertlen = (sizeof (float) * 16);
  18.657 +    float *verts = (float *) SDL_AllocateRenderVertices(renderer, vertlen, 0, &cmd->data.draw.first);
  18.658 +    if (!verts) {
  18.659 +        return -1;
  18.660 +    }
  18.661  
  18.662 -    METAL_SetupRenderCopy(data, texture, texturedata);
  18.663 +    cmd->data.draw.count = 1;
  18.664  
  18.665 -    const float xy[] = {
  18.666 -        dstrect->x, dstrect->y + dstrect->h,
  18.667 -        dstrect->x, dstrect->y,
  18.668 -        dstrect->x + dstrect->w, dstrect->y + dstrect->h,
  18.669 -        dstrect->x + dstrect->w, dstrect->y
  18.670 -    };
  18.671 +    *(verts++) = dstrect->x;
  18.672 +    *(verts++) = dstrect->y + dstrect->h;
  18.673 +    *(verts++) = dstrect->x;
  18.674 +    *(verts++) = dstrect->y;
  18.675 +    *(verts++) = dstrect->x + dstrect->w;
  18.676 +    *(verts++) = dstrect->y + dstrect->h;
  18.677 +    *(verts++) = dstrect->x + dstrect->w;
  18.678 +    *(verts++) = dstrect->y;
  18.679  
  18.680 -    const float uv[] = {
  18.681 -        normtex(srcrect->x, texw), normtex(srcrect->y + srcrect->h, texh),
  18.682 -        normtex(srcrect->x, texw), normtex(srcrect->y, texh),
  18.683 -        normtex(srcrect->x + srcrect->w, texw), normtex(srcrect->y + srcrect->h, texh),
  18.684 -        normtex(srcrect->x + srcrect->w, texw), normtex(srcrect->y, texh)
  18.685 -    };
  18.686 -
  18.687 -    [data.mtlcmdencoder setVertexBytes:xy length:sizeof(xy) atIndex:0];
  18.688 -    [data.mtlcmdencoder setVertexBytes:uv length:sizeof(uv) atIndex:1];
  18.689 -    [data.mtlcmdencoder setVertexBuffer:data.mtlbufconstants offset:CONSTANTS_OFFSET_IDENTITY atIndex:3];
  18.690 -    [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
  18.691 +    *(verts++) = normtex(srcrect->x, texw);
  18.692 +    *(verts++) = normtex(srcrect->y + srcrect->h, texh);
  18.693 +    *(verts++) = normtex(srcrect->x, texw);
  18.694 +    *(verts++) = normtex(srcrect->y, texh);
  18.695 +    *(verts++) = normtex(srcrect->x + srcrect->w, texw);
  18.696 +    *(verts++) = normtex(srcrect->y + srcrect->h, texh);
  18.697 +    *(verts++) = normtex(srcrect->x + srcrect->w, texw);
  18.698 +    *(verts++) = normtex(srcrect->y, texh);
  18.699  
  18.700      return 0;
  18.701 -}}
  18.702 +}
  18.703  
  18.704  static int
  18.705 -METAL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
  18.706 -              const SDL_Rect * srcrect, const SDL_FRect * dstrect,
  18.707 -              const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
  18.708 -{ @autoreleasepool {
  18.709 -    METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad);
  18.710 -    METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
  18.711 +METAL_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
  18.712 +                  const SDL_Rect * srcquad, const SDL_FRect * dstrect,
  18.713 +                  const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
  18.714 +{
  18.715      METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->driverdata;
  18.716      const float texw = (float) texturedata.mtltexture.width;
  18.717      const float texh = (float) texturedata.mtltexture.height;
  18.718 -    float transform[16];
  18.719 +    const float rads = (float)(M_PI * (float) angle / 180.0f);
  18.720 +    const float c = cosf(rads), s = sinf(rads);
  18.721      float minu, maxu, minv, maxv;
  18.722 +    const size_t vertlen = (sizeof (float) * 32);
  18.723 +    float *verts;
  18.724  
  18.725 -    METAL_SetupRenderCopy(data, texture, texturedata);
  18.726 +    // cheat and store this offset in (count) because it needs to be aligned in ways other fields don't and we aren't using count otherwise.
  18.727 +    verts = (float *) SDL_AllocateRenderVertices(renderer, vertlen, CONSTANT_ALIGN, &cmd->data.draw.count);
  18.728 +    if (!verts) {
  18.729 +        return -1;
  18.730 +    }
  18.731  
  18.732 -    minu = normtex(srcrect->x, texw);
  18.733 -    maxu = normtex(srcrect->x + srcrect->w, texw);
  18.734 -    minv = normtex(srcrect->y, texh);
  18.735 -    maxv = normtex(srcrect->y + srcrect->h, texh);
  18.736 +    // transform matrix
  18.737 +    SDL_memset(verts, '\0', sizeof (*verts) * 16);
  18.738 +    verts[10] = verts[15] = 1.0f;
  18.739 +    // rotation
  18.740 +    verts[0] = c;
  18.741 +    verts[1] = s;
  18.742 +    verts[4] = -s;
  18.743 +    verts[5] = c;
  18.744 +
  18.745 +    // translation
  18.746 +    verts[12] = dstrect->x + center->x;
  18.747 +    verts[13] = dstrect->y + center->y;
  18.748 +
  18.749 +    // rest of the vertices don't need the aggressive alignment. Pack them in.
  18.750 +    verts = (float *) SDL_AllocateRenderVertices(renderer, vertlen, 0, &cmd->data.draw.first);
  18.751 +    if (!verts) {
  18.752 +        return -1;
  18.753 +    }
  18.754 +
  18.755 +    minu = normtex(srcquad->x, texw);
  18.756 +    maxu = normtex(srcquad->x + srcquad->w, texw);
  18.757 +    minv = normtex(srcquad->y, texh);
  18.758 +    maxv = normtex(srcquad->y + srcquad->h, texh);
  18.759  
  18.760      if (flip & SDL_FLIP_HORIZONTAL) {
  18.761          float tmp = maxu;
  18.762 @@ -1307,42 +918,279 @@
  18.763          minv = tmp;
  18.764      }
  18.765  
  18.766 -    const float uv[] = {
  18.767 -        minu, maxv,
  18.768 -        minu, minv,
  18.769 -        maxu, maxv,
  18.770 -        maxu, minv
  18.771 -    };
  18.772 +    // vertices
  18.773 +    *(verts++) = -center->x;
  18.774 +    *(verts++) = dstrect->h - center->y;
  18.775 +    *(verts++) = -center->x;
  18.776 +    *(verts++) = -center->y;
  18.777 +    *(verts++) = dstrect->w - center->x;
  18.778 +    *(verts++) = dstrect->h - center->y;
  18.779 +    *(verts++) = dstrect->w - center->x;
  18.780 +    *(verts++) = -center->y;
  18.781  
  18.782 -    const float xy[] = {
  18.783 -        -center->x, dstrect->h - center->y,
  18.784 -        -center->x, -center->y,
  18.785 -        dstrect->w - center->x, dstrect->h - center->y,
  18.786 -        dstrect->w - center->x, -center->y
  18.787 -    };
  18.788 +    // texcoords
  18.789 +    *(verts++) = minu;
  18.790 +    *(verts++) = maxv;
  18.791 +    *(verts++) = minu;
  18.792 +    *(verts++) = minv;
  18.793 +    *(verts++) = maxu;
  18.794 +    *(verts++) = maxv;
  18.795 +    *(verts++) = maxu;
  18.796 +    *(verts++) = minv;
  18.797  
  18.798 -    {
  18.799 -        float rads = (float)(M_PI * (float) angle / 180.0f);
  18.800 -        float c = cosf(rads), s = sinf(rads);
  18.801 -        SDL_memset(transform, 0, sizeof(transform));
  18.802 +    return 0;
  18.803 +}
  18.804  
  18.805 -        transform[10] = transform[15] = 1.0f;
  18.806  
  18.807 -        /* Rotation */
  18.808 -        transform[0]  = c;
  18.809 -        transform[1]  = s;
  18.810 -        transform[4]  = -s;
  18.811 -        transform[5]  = c;
  18.812 +typedef struct
  18.813 +{
  18.814 +    #if __has_feature(objc_arc)
  18.815 +    __unsafe_unretained id<MTLRenderPipelineState> pipeline;
  18.816 +    #else
  18.817 +    id<MTLRenderPipelineState> pipeline;
  18.818 +    #endif
  18.819 +    size_t constants_offset;
  18.820 +    SDL_Texture *texture;
  18.821 +    SDL_bool cliprect_dirty;
  18.822 +    SDL_bool cliprect_enabled;
  18.823 +    SDL_Rect cliprect;
  18.824 +    SDL_bool viewport_dirty;
  18.825 +    SDL_Rect viewport;
  18.826 +    size_t projection_offset;
  18.827 +    SDL_bool color_dirty;
  18.828 +    size_t color_offset;
  18.829 +} METAL_DrawStateCache;
  18.830  
  18.831 -        /* Translation */
  18.832 -        transform[12] = dstrect->x + center->x;
  18.833 -        transform[13] = dstrect->y + center->y;
  18.834 +static void
  18.835 +SetDrawState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, const SDL_MetalFragmentFunction shader,
  18.836 +             const size_t constants_offset, id<MTLBuffer> mtlbufvertex, METAL_DrawStateCache *statecache)
  18.837 +{
  18.838 +    METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
  18.839 +    const SDL_BlendMode blend = cmd->data.draw.blend;
  18.840 +    size_t first = cmd->data.draw.first;
  18.841 +    id<MTLRenderPipelineState> newpipeline;
  18.842 +
  18.843 +    METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad, NULL);
  18.844 +
  18.845 +    if (statecache->viewport_dirty) {
  18.846 +        MTLViewport viewport;
  18.847 +        viewport.originX = statecache->viewport.x;
  18.848 +        viewport.originY = statecache->viewport.y;
  18.849 +        viewport.width = statecache->viewport.w;
  18.850 +        viewport.height = statecache->viewport.h;
  18.851 +        viewport.znear = 0.0;
  18.852 +        viewport.zfar = 1.0;
  18.853 +        [data.mtlcmdencoder setViewport:viewport];
  18.854 +        [data.mtlcmdencoder setVertexBuffer:mtlbufvertex offset:statecache->projection_offset atIndex:2];  // projection
  18.855 +        statecache->viewport_dirty = SDL_FALSE;
  18.856      }
  18.857  
  18.858 -    [data.mtlcmdencoder setVertexBytes:xy length:sizeof(xy) atIndex:0];
  18.859 -    [data.mtlcmdencoder setVertexBytes:uv length:sizeof(uv) atIndex:1];
  18.860 -    [data.mtlcmdencoder setVertexBytes:transform length:sizeof(transform) atIndex:3];
  18.861 -    [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
  18.862 +    if (statecache->cliprect_dirty) {
  18.863 +        MTLScissorRect mtlrect;
  18.864 +        if (statecache->cliprect_enabled) {
  18.865 +            const SDL_Rect *rect = &statecache->cliprect;
  18.866 +            mtlrect.x = statecache->viewport.x + rect->x;
  18.867 +            mtlrect.y = statecache->viewport.y + rect->y;
  18.868 +            mtlrect.width = rect->w;
  18.869 +            mtlrect.height = rect->h;
  18.870 +        } else {
  18.871 +            mtlrect.x = statecache->viewport.x;
  18.872 +            mtlrect.y = statecache->viewport.y;
  18.873 +            mtlrect.width = statecache->viewport.w;
  18.874 +            mtlrect.height = statecache->viewport.h;
  18.875 +        }
  18.876 +        if (mtlrect.width > 0 && mtlrect.height > 0) {
  18.877 +            [data.mtlcmdencoder setScissorRect:mtlrect];
  18.878 +        }
  18.879 +        statecache->cliprect_dirty = SDL_FALSE;
  18.880 +    }
  18.881 +
  18.882 +    if (statecache->color_dirty) {
  18.883 +        [data.mtlcmdencoder setFragmentBuffer:mtlbufvertex offset:statecache->color_offset atIndex:0];
  18.884 +        statecache->color_dirty = SDL_FALSE;
  18.885 +    }
  18.886 +
  18.887 +    newpipeline = ChoosePipelineState(data, data.activepipelines, shader, blend);
  18.888 +    if (newpipeline != statecache->pipeline) {
  18.889 +        [data.mtlcmdencoder setRenderPipelineState:newpipeline];
  18.890 +        statecache->pipeline = newpipeline;
  18.891 +    }
  18.892 +
  18.893 +    if (constants_offset != statecache->constants_offset) {
  18.894 +        if (constants_offset != CONSTANTS_OFFSET_INVALID) {
  18.895 +            [data.mtlcmdencoder setVertexBuffer:data.mtlbufconstants offset:constants_offset atIndex:3];
  18.896 +        }
  18.897 +        statecache->constants_offset = constants_offset;
  18.898 +    }
  18.899 +
  18.900 +    [data.mtlcmdencoder setVertexBuffer:mtlbufvertex offset:first atIndex:0];  // position
  18.901 +}
  18.902 +
  18.903 +static void
  18.904 +SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, const size_t constants_offset,
  18.905 +             id<MTLBuffer> mtlbufvertex, METAL_DrawStateCache *statecache)
  18.906 +{
  18.907 +    METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
  18.908 +    SDL_Texture *texture = cmd->data.draw.texture;
  18.909 +    METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->driverdata;
  18.910 +
  18.911 +    SetDrawState(renderer, cmd, texturedata.fragmentFunction, constants_offset, mtlbufvertex, statecache);
  18.912 +
  18.913 +    [data.mtlcmdencoder setVertexBuffer:mtlbufvertex offset:cmd->data.draw.first+(8*sizeof (float)) atIndex:1];  // texcoords
  18.914 +
  18.915 +    if (texture != statecache->texture) {
  18.916 +        METAL_TextureData *oldtexturedata = NULL;
  18.917 +        if (statecache->texture) {
  18.918 +            oldtexturedata = (__bridge METAL_TextureData *) statecache->texture->driverdata;
  18.919 +        }
  18.920 +        if (!oldtexturedata || (texturedata.mtlsampler != oldtexturedata.mtlsampler)) {
  18.921 +            [data.mtlcmdencoder setFragmentSamplerState:texturedata.mtlsampler atIndex:0];
  18.922 +        }
  18.923 +
  18.924 +        [data.mtlcmdencoder setFragmentTexture:texturedata.mtltexture atIndex:0];
  18.925 +        if (texturedata.yuv || texturedata.nv12) {
  18.926 +            [data.mtlcmdencoder setFragmentTexture:texturedata.mtltexture_uv atIndex:1];
  18.927 +            [data.mtlcmdencoder setFragmentBuffer:data.mtlbufconstants offset:texturedata.conversionBufferOffset atIndex:1];
  18.928 +        }
  18.929 +        statecache->texture = texture;
  18.930 +    }
  18.931 +}
  18.932 +
  18.933 +static int
  18.934 +METAL_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
  18.935 +{ @autoreleasepool {
  18.936 +    METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
  18.937 +    METAL_DrawStateCache statecache;
  18.938 +    id<MTLBuffer> mtlbufvertex = nil;
  18.939 +
  18.940 +    statecache.pipeline = nil;
  18.941 +    statecache.constants_offset = CONSTANTS_OFFSET_INVALID;
  18.942 +    statecache.texture = NULL;
  18.943 +    statecache.color_dirty = SDL_TRUE;
  18.944 +    statecache.cliprect_dirty = SDL_TRUE;
  18.945 +    statecache.viewport_dirty = SDL_TRUE;
  18.946 +    statecache.projection_offset = 0;
  18.947 +    statecache.color_offset = 0;
  18.948 +
  18.949 +    // !!! FIXME: have a ring of pre-made MTLBuffers we cycle through? How expensive is creation?
  18.950 +    if (vertsize > 0) {
  18.951 +        id<MTLBuffer> mtlbufvertexstaging = [data.mtldevice newBufferWithLength:vertsize options:MTLResourceStorageModeShared];
  18.952 +        #if !__has_feature(objc_arc)
  18.953 +        [mtlbufvertexstaging autorelease];
  18.954 +        #endif
  18.955 +        mtlbufvertexstaging.label = @"SDL vertex staging data";
  18.956 +        SDL_memcpy([mtlbufvertexstaging contents], vertices, vertsize);
  18.957 +
  18.958 +        // Move our new vertex buffer from system RAM to GPU memory so any draw calls can use it.
  18.959 +        mtlbufvertex = [data.mtldevice newBufferWithLength:vertsize options:MTLResourceStorageModePrivate];
  18.960 +        #if !__has_feature(objc_arc)
  18.961 +        [mtlbufvertex autorelease];
  18.962 +        #endif
  18.963 +        mtlbufvertex.label = @"SDL vertex data";
  18.964 +        id<MTLCommandBuffer> cmdbuffer = [data.mtlcmdqueue commandBuffer];
  18.965 +        id<MTLBlitCommandEncoder> blitcmd = [cmdbuffer blitCommandEncoder];
  18.966 +        [blitcmd copyFromBuffer:mtlbufvertexstaging sourceOffset:0 toBuffer:mtlbufvertex destinationOffset:0 size:vertsize];
  18.967 +        [blitcmd endEncoding];
  18.968 +        [cmdbuffer commit];
  18.969 +    }
  18.970 +
  18.971 +    // If there's a command buffer here unexpectedly (app requested one?). Commit it so we can start fresh.
  18.972 +    [data.mtlcmdencoder endEncoding];
  18.973 +    [data.mtlcmdbuffer commit];
  18.974 +    data.mtlcmdencoder = nil;
  18.975 +    data.mtlcmdbuffer = nil;
  18.976 +
  18.977 +    while (cmd) {
  18.978 +        switch (cmd->command) {
  18.979 +            case SDL_RENDERCMD_SETVIEWPORT: {
  18.980 +                SDL_memcpy(&statecache.viewport, &cmd->data.viewport.rect, sizeof (statecache.viewport));
  18.981 +                statecache.projection_offset = cmd->data.viewport.first;
  18.982 +                statecache.viewport_dirty = SDL_TRUE;
  18.983 +                break;
  18.984 +            }
  18.985 +
  18.986 +            case SDL_RENDERCMD_SETCLIPRECT: {
  18.987 +                SDL_memcpy(&statecache.cliprect, &cmd->data.cliprect.rect, sizeof (statecache.cliprect));
  18.988 +                statecache.cliprect_enabled = cmd->data.cliprect.enabled;
  18.989 +                statecache.cliprect_dirty = SDL_TRUE;
  18.990 +                break;
  18.991 +            }
  18.992 +
  18.993 +            case SDL_RENDERCMD_SETDRAWCOLOR: {
  18.994 +                statecache.color_offset = cmd->data.color.first;
  18.995 +                statecache.color_dirty = SDL_TRUE;
  18.996 +                break;
  18.997 +            }
  18.998 +
  18.999 +            case SDL_RENDERCMD_CLEAR: {
 18.1000 +                /* If we're already encoding a command buffer, dump it without committing it. We'd just
 18.1001 +                    clear all its work anyhow, and starting a new encoder will let us use a hardware clear
 18.1002 +                    operation via MTLLoadActionClear. */
 18.1003 +                if (data.mtlcmdencoder != nil) {
 18.1004 +                    [data.mtlcmdencoder endEncoding];
 18.1005 +
 18.1006 +                    // !!! FIXME: have to commit, or an uncommitted but enqueued buffer will prevent the frame from finishing.
 18.1007 +                    [data.mtlcmdbuffer commit];
 18.1008 +                    data.mtlcmdencoder = nil;
 18.1009 +                    data.mtlcmdbuffer = nil;
 18.1010 +                }
 18.1011 +
 18.1012 +                // force all this state to be reconfigured on next command buffer.
 18.1013 +                statecache.pipeline = nil;
 18.1014 +                statecache.constants_offset = CONSTANTS_OFFSET_INVALID;
 18.1015 +                statecache.texture = NULL;
 18.1016 +                statecache.color_dirty = SDL_TRUE;
 18.1017 +                statecache.cliprect_dirty = SDL_TRUE;
 18.1018 +                statecache.viewport_dirty = SDL_TRUE;
 18.1019 +
 18.1020 +                const Uint8 r = cmd->data.color.r;
 18.1021 +                const Uint8 g = cmd->data.color.g;
 18.1022 +                const Uint8 b = cmd->data.color.b;
 18.1023 +                const Uint8 a = cmd->data.color.a;
 18.1024 +                MTLClearColor color = MTLClearColorMake(r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f);
 18.1025 +
 18.1026 +                // get new command encoder, set up with an initial clear operation.
 18.1027 +                METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionClear, &color);
 18.1028 +                break;
 18.1029 +            }
 18.1030 +
 18.1031 +            case SDL_RENDERCMD_DRAW_POINTS:
 18.1032 +            case SDL_RENDERCMD_DRAW_LINES: {
 18.1033 +                const size_t count = cmd->data.draw.count;
 18.1034 +                const MTLPrimitiveType primtype = (cmd->command == SDL_RENDERCMD_DRAW_POINTS) ? MTLPrimitiveTypePoint : MTLPrimitiveTypeLineStrip;
 18.1035 +                SetDrawState(renderer, cmd, SDL_METAL_FRAGMENT_SOLID, CONSTANTS_OFFSET_HALF_PIXEL_TRANSFORM, mtlbufvertex, &statecache);
 18.1036 +                [data.mtlcmdencoder drawPrimitives:primtype vertexStart:0 vertexCount:count];
 18.1037 +                break;
 18.1038 +            }
 18.1039 +
 18.1040 +            case SDL_RENDERCMD_FILL_RECTS: {
 18.1041 +                const size_t count = cmd->data.draw.count;
 18.1042 +                size_t start = 0;
 18.1043 +                SetDrawState(renderer, cmd, SDL_METAL_FRAGMENT_SOLID, CONSTANTS_OFFSET_IDENTITY, mtlbufvertex, &statecache);
 18.1044 +                for (size_t i = 0; i < count; i++, start += 4) {   // !!! FIXME: can we do all of these this with a single draw call, using MTLPrimitiveTypeTriangle and an index buffer?
 18.1045 +                    [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:start vertexCount:4];
 18.1046 +                }
 18.1047 +                break;
 18.1048 +            }
 18.1049 +
 18.1050 +            case SDL_RENDERCMD_COPY: {
 18.1051 +                SetCopyState(renderer, cmd, CONSTANTS_OFFSET_IDENTITY, mtlbufvertex, &statecache);
 18.1052 +                [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
 18.1053 +                break;
 18.1054 +            }
 18.1055 +
 18.1056 +            case SDL_RENDERCMD_COPY_EX: {
 18.1057 +                SetCopyState(renderer, cmd, CONSTANTS_OFFSET_INVALID, mtlbufvertex, &statecache);
 18.1058 +                [data.mtlcmdencoder setVertexBuffer:mtlbufvertex offset:cmd->data.draw.count atIndex:3];  // transform
 18.1059 +                [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
 18.1060 +                break;
 18.1061 +            }
 18.1062 +
 18.1063 +            case SDL_RENDERCMD_NO_OP:
 18.1064 +                break;
 18.1065 +        }
 18.1066 +        cmd = cmd->next;
 18.1067 +    }
 18.1068  
 18.1069      return 0;
 18.1070  }}
 18.1071 @@ -1352,21 +1200,14 @@
 18.1072                      Uint32 pixel_format, void * pixels, int pitch)
 18.1073  { @autoreleasepool {
 18.1074      METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
 18.1075 +    METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad, NULL);
 18.1076  
 18.1077 -    /* Make sure we have a valid MTLTexture to read from, and an active command
 18.1078 -     * buffer we can wait for. */
 18.1079 -    METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad);
 18.1080 -
 18.1081 -    /* Wait for the current command buffer to finish, so we don't read from the
 18.1082 -     * texture before the GPU finishes rendering to it. */
 18.1083 -    if (data.mtlcmdencoder) {
 18.1084 -        [data.mtlcmdencoder endEncoding];
 18.1085 -        [data.mtlcmdbuffer commit];
 18.1086 -        [data.mtlcmdbuffer waitUntilCompleted];
 18.1087 -
 18.1088 -        data.mtlcmdencoder = nil;
 18.1089 -        data.mtlcmdbuffer = nil;
 18.1090 -    }
 18.1091 +    // Commit any current command buffer, and waitUntilCompleted, so any output is ready to be read.
 18.1092 +    [data.mtlcmdencoder endEncoding];
 18.1093 +    [data.mtlcmdbuffer commit];
 18.1094 +    [data.mtlcmdbuffer waitUntilCompleted];
 18.1095 +    data.mtlcmdencoder = nil;
 18.1096 +    data.mtlcmdbuffer = nil;
 18.1097  
 18.1098      id<MTLTexture> mtltexture = data.mtlpassdesc.colorAttachments[0].texture;
 18.1099      MTLRegion mtlregion = MTLRegionMake2D(rect->x, rect->y, rect->w, rect->h);
 18.1100 @@ -1383,13 +1224,6 @@
 18.1101      const Uint32 temp_format = (mtltexture.pixelFormat == MTLPixelFormatBGRA8Unorm) ? SDL_PIXELFORMAT_ARGB8888 : SDL_PIXELFORMAT_ABGR8888;
 18.1102      const int status = SDL_ConvertPixels(rect->w, rect->h, temp_format, temp_pixels, temp_pitch, pixel_format, pixels, pitch);
 18.1103      SDL_free(temp_pixels);
 18.1104 -
 18.1105 -    /* Set up an active command buffer and encoder once we're done. It will use
 18.1106 -     * the same texture that was active before (even if it's part of the swap
 18.1107 -     * chain), since we didn't clear that when waiting for the command buffer to
 18.1108 -     * complete. */
 18.1109 -    METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad);
 18.1110 -
 18.1111      return status;
 18.1112  }}
 18.1113  
 18.1114 @@ -1445,11 +1279,274 @@
 18.1115  static void *
 18.1116  METAL_GetMetalCommandEncoder(SDL_Renderer * renderer)
 18.1117  { @autoreleasepool {
 18.1118 -    METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad);
 18.1119 +    METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad, NULL);
 18.1120      METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
 18.1121      return (__bridge void*)data.mtlcmdencoder;
 18.1122  }}
 18.1123  
 18.1124 +static SDL_Renderer *
 18.1125 +METAL_CreateRenderer(SDL_Window * window, Uint32 flags)
 18.1126 +{ @autoreleasepool {
 18.1127 +    SDL_Renderer *renderer = NULL;
 18.1128 +    METAL_RenderData *data = NULL;
 18.1129 +    id<MTLDevice> mtldevice = nil;
 18.1130 +    SDL_SysWMinfo syswm;
 18.1131 +
 18.1132 +    SDL_VERSION(&syswm.version);
 18.1133 +    if (!SDL_GetWindowWMInfo(window, &syswm)) {
 18.1134 +        return NULL;
 18.1135 +    }
 18.1136 +
 18.1137 +    if (IsMetalAvailable(&syswm) == -1) {
 18.1138 +        return NULL;
 18.1139 +    }
 18.1140 +
 18.1141 +    renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
 18.1142 +    if (!renderer) {
 18.1143 +        SDL_OutOfMemory();
 18.1144 +        return NULL;
 18.1145 +    }
 18.1146 +
 18.1147 +    // !!! FIXME: MTLCopyAllDevices() can find other GPUs on macOS...
 18.1148 +    mtldevice = MTLCreateSystemDefaultDevice();
 18.1149 +
 18.1150 +    if (mtldevice == nil) {
 18.1151 +        SDL_free(renderer);
 18.1152 +        SDL_SetError("Failed to obtain Metal device");
 18.1153 +        return NULL;
 18.1154 +    }
 18.1155 +
 18.1156 +    // !!! FIXME: error checking on all of this.
 18.1157 +    data = [[METAL_RenderData alloc] init];
 18.1158 +
 18.1159 +    renderer->driverdata = (void*)CFBridgingRetain(data);
 18.1160 +    renderer->window = window;
 18.1161 +
 18.1162 +#ifdef __MACOSX__
 18.1163 +    NSView *view = Cocoa_Mtl_AddMetalView(window);
 18.1164 +    CAMetalLayer *layer = (CAMetalLayer *)[view layer];
 18.1165 +
 18.1166 +    layer.device = mtldevice;
 18.1167 +
 18.1168 +    //layer.colorspace = nil;
 18.1169 +
 18.1170 +#else
 18.1171 +    UIView *view = UIKit_Mtl_AddMetalView(window);
 18.1172 +    CAMetalLayer *layer = (CAMetalLayer *)[view layer];
 18.1173 +#endif
 18.1174 +
 18.1175 +    // Necessary for RenderReadPixels.
 18.1176 +    layer.framebufferOnly = NO;
 18.1177 +
 18.1178 +    data.mtldevice = layer.device;
 18.1179 +    data.mtllayer = layer;
 18.1180 +    id<MTLCommandQueue> mtlcmdqueue = [data.mtldevice newCommandQueue];
 18.1181 +    data.mtlcmdqueue = mtlcmdqueue;
 18.1182 +    data.mtlcmdqueue.label = @"SDL Metal Renderer";
 18.1183 +    data.mtlpassdesc = [MTLRenderPassDescriptor renderPassDescriptor];
 18.1184 +
 18.1185 +    NSError *err = nil;
 18.1186 +
 18.1187 +    // The compiled .metallib is embedded in a static array in a header file
 18.1188 +    // but the original shader source code is in SDL_shaders_metal.metal.
 18.1189 +    dispatch_data_t mtllibdata = dispatch_data_create(sdl_metallib, sdl_metallib_len, dispatch_get_global_queue(0, 0), ^{});
 18.1190 +    id<MTLLibrary> mtllibrary = [data.mtldevice newLibraryWithData:mtllibdata error:&err];
 18.1191 +    data.mtllibrary = mtllibrary;
 18.1192 +    SDL_assert(err == nil);
 18.1193 +#if !__has_feature(objc_arc)
 18.1194 +    dispatch_release(mtllibdata);
 18.1195 +#endif
 18.1196 +    data.mtllibrary.label = @"SDL Metal renderer shader library";
 18.1197 +
 18.1198 +    /* Do some shader pipeline state loading up-front rather than on demand. */
 18.1199 +    data.pipelinescount = 0;
 18.1200 +    data.allpipelines = NULL;
 18.1201 +    ChooseShaderPipelines(data, MTLPixelFormatBGRA8Unorm);
 18.1202 +
 18.1203 +    MTLSamplerDescriptor *samplerdesc = [[MTLSamplerDescriptor alloc] init];
 18.1204 +
 18.1205 +    samplerdesc.minFilter = MTLSamplerMinMagFilterNearest;
 18.1206 +    samplerdesc.magFilter = MTLSamplerMinMagFilterNearest;
 18.1207 +    id<MTLSamplerState> mtlsamplernearest = [data.mtldevice newSamplerStateWithDescriptor:samplerdesc];
 18.1208 +    data.mtlsamplernearest = mtlsamplernearest;
 18.1209 +
 18.1210 +    samplerdesc.minFilter = MTLSamplerMinMagFilterLinear;
 18.1211 +    samplerdesc.magFilter = MTLSamplerMinMagFilterLinear;
 18.1212 +    id<MTLSamplerState> mtlsamplerlinear = [data.mtldevice newSamplerStateWithDescriptor:samplerdesc];
 18.1213 +    data.mtlsamplerlinear = mtlsamplerlinear;
 18.1214 +
 18.1215 +    /* Note: matrices are column major. */
 18.1216 +    float identitytransform[16] = {
 18.1217 +        1.0f, 0.0f, 0.0f, 0.0f,
 18.1218 +        0.0f, 1.0f, 0.0f, 0.0f,
 18.1219 +        0.0f, 0.0f, 1.0f, 0.0f,
 18.1220 +        0.0f, 0.0f, 0.0f, 1.0f,
 18.1221 +    };
 18.1222 +
 18.1223 +    float halfpixeltransform[16] = {
 18.1224 +        1.0f, 0.0f, 0.0f, 0.0f,
 18.1225 +        0.0f, 1.0f, 0.0f, 0.0f,
 18.1226 +        0.0f, 0.0f, 1.0f, 0.0f,
 18.1227 +        0.5f, 0.5f, 0.0f, 1.0f,
 18.1228 +    };
 18.1229 +
 18.1230 +    /* Metal pads float3s to 16 bytes. */
 18.1231 +    float decodetransformJPEG[4*4] = {
 18.1232 +        0.0, -0.501960814, -0.501960814, 0.0, /* offset */
 18.1233 +        1.0000,  0.0000,  1.4020, 0.0,        /* Rcoeff */
 18.1234 +        1.0000, -0.3441, -0.7141, 0.0,        /* Gcoeff */
 18.1235 +        1.0000,  1.7720,  0.0000, 0.0,        /* Bcoeff */
 18.1236 +    };
 18.1237 +
 18.1238 +    float decodetransformBT601[4*4] = {
 18.1239 +        -0.0627451017, -0.501960814, -0.501960814, 0.0, /* offset */
 18.1240 +        1.1644,  0.0000,  1.5960, 0.0,                  /* Rcoeff */
 18.1241 +        1.1644, -0.3918, -0.8130, 0.0,                  /* Gcoeff */
 18.1242 +        1.1644,  2.0172,  0.0000, 0.0,                  /* Bcoeff */
 18.1243 +    };
 18.1244 +
 18.1245 +    float decodetransformBT709[4*4] = {
 18.1246 +        0.0, -0.501960814, -0.501960814, 0.0, /* offset */
 18.1247 +        1.0000,  0.0000,  1.4020, 0.0,        /* Rcoeff */
 18.1248 +        1.0000, -0.3441, -0.7141, 0.0,        /* Gcoeff */
 18.1249 +        1.0000,  1.7720,  0.0000, 0.0,        /* Bcoeff */
 18.1250 +    };
 18.1251 +
 18.1252 +    float clearverts[6] = {0.0f, 0.0f,  0.0f, 2.0f,  2.0f, 0.0f};
 18.1253 +
 18.1254 +    id<MTLBuffer> mtlbufconstantstaging = [data.mtldevice newBufferWithLength:CONSTANTS_LENGTH options:MTLResourceStorageModeShared];
 18.1255 +    #if !__has_feature(objc_arc)
 18.1256 +    [mtlbufconstantstaging autorelease];
 18.1257 +    #endif
 18.1258 +    mtlbufconstantstaging.label = @"SDL constant staging data";
 18.1259 +
 18.1260 +    id<MTLBuffer> mtlbufconstants = [data.mtldevice newBufferWithLength:CONSTANTS_LENGTH options:MTLResourceStorageModePrivate];
 18.1261 +    data.mtlbufconstants = mtlbufconstants;
 18.1262 +    data.mtlbufconstants.label = @"SDL constant data";
 18.1263 +
 18.1264 +    char *constantdata = [mtlbufconstantstaging contents];
 18.1265 +    SDL_memcpy(constantdata + CONSTANTS_OFFSET_IDENTITY, identitytransform, sizeof(identitytransform));
 18.1266 +    SDL_memcpy(constantdata + CONSTANTS_OFFSET_HALF_PIXEL_TRANSFORM, halfpixeltransform, sizeof(halfpixeltransform));
 18.1267 +    SDL_memcpy(constantdata + CONSTANTS_OFFSET_DECODE_JPEG, decodetransformJPEG, sizeof(decodetransformJPEG));
 18.1268 +    SDL_memcpy(constantdata + CONSTANTS_OFFSET_DECODE_BT601, decodetransformBT601, sizeof(decodetransformBT601));
 18.1269 +    SDL_memcpy(constantdata + CONSTANTS_OFFSET_DECODE_BT709, decodetransformBT709, sizeof(decodetransformBT709));
 18.1270 +    SDL_memcpy(constantdata + CONSTANTS_OFFSET_CLEAR_VERTS, clearverts, sizeof(clearverts));
 18.1271 +
 18.1272 +    id<MTLCommandBuffer> cmdbuffer = [data.mtlcmdqueue commandBuffer];
 18.1273 +    id<MTLBlitCommandEncoder> blitcmd = [cmdbuffer blitCommandEncoder];
 18.1274 +
 18.1275 +    [blitcmd copyFromBuffer:mtlbufconstantstaging sourceOffset:0 toBuffer:data.mtlbufconstants destinationOffset:0 size:CONSTANTS_LENGTH];
 18.1276 +
 18.1277 +    [blitcmd endEncoding];
 18.1278 +    [cmdbuffer commit];
 18.1279 +
 18.1280 +    // !!! FIXME: force more clears here so all the drawables are sane to start, and our static buffers are definitely flushed.
 18.1281 +
 18.1282 +    renderer->WindowEvent = METAL_WindowEvent;
 18.1283 +    renderer->GetOutputSize = METAL_GetOutputSize;
 18.1284 +    renderer->SupportsBlendMode = METAL_SupportsBlendMode;
 18.1285 +    renderer->CreateTexture = METAL_CreateTexture;
 18.1286 +    renderer->UpdateTexture = METAL_UpdateTexture;
 18.1287 +    renderer->UpdateTextureYUV = METAL_UpdateTextureYUV;
 18.1288 +    renderer->LockTexture = METAL_LockTexture;
 18.1289 +    renderer->UnlockTexture = METAL_UnlockTexture;
 18.1290 +    renderer->SetRenderTarget = METAL_SetRenderTarget;
 18.1291 +    renderer->QueueSetViewport = METAL_QueueSetViewport;
 18.1292 +    renderer->QueueSetDrawColor = METAL_QueueSetDrawColor;
 18.1293 +    renderer->QueueDrawPoints = METAL_QueueDrawPoints;
 18.1294 +    renderer->QueueDrawLines = METAL_QueueDrawPoints;  // lines and points queue the same way.
 18.1295 +    renderer->QueueFillRects = METAL_QueueFillRects;
 18.1296 +    renderer->QueueCopy = METAL_QueueCopy;
 18.1297 +    renderer->QueueCopyEx = METAL_QueueCopyEx;
 18.1298 +    renderer->RunCommandQueue = METAL_RunCommandQueue;
 18.1299 +    renderer->RenderReadPixels = METAL_RenderReadPixels;
 18.1300 +    renderer->RenderPresent = METAL_RenderPresent;
 18.1301 +    renderer->DestroyTexture = METAL_DestroyTexture;
 18.1302 +    renderer->DestroyRenderer = METAL_DestroyRenderer;
 18.1303 +    renderer->GetMetalLayer = METAL_GetMetalLayer;
 18.1304 +    renderer->GetMetalCommandEncoder = METAL_GetMetalCommandEncoder;
 18.1305 +
 18.1306 +    renderer->info = METAL_RenderDriver.info;
 18.1307 +    renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
 18.1308 +
 18.1309 +    renderer->always_batch = SDL_TRUE;
 18.1310 +
 18.1311 +#if defined(__MACOSX__) && defined(MAC_OS_X_VERSION_10_13)
 18.1312 +    if (@available(macOS 10.13, *)) {
 18.1313 +        data.mtllayer.displaySyncEnabled = (flags & SDL_RENDERER_PRESENTVSYNC) != 0;
 18.1314 +    } else
 18.1315 +#endif
 18.1316 +    {
 18.1317 +        renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
 18.1318 +    }
 18.1319 +
 18.1320 +    /* https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf */
 18.1321 +    int maxtexsize = 4096;
 18.1322 +#if defined(__MACOSX__)
 18.1323 +    maxtexsize = 16384;
 18.1324 +#elif defined(__TVOS__)
 18.1325 +    maxtexsize = 8192;
 18.1326 +#ifdef __TVOS_11_0
 18.1327 +    if (@available(tvOS 11.0, *)) {
 18.1328 +        if ([mtldevice supportsFeatureSet:MTLFeatureSet_tvOS_GPUFamily2_v1]) {
 18.1329 +            maxtexsize = 16384;
 18.1330 +        }
 18.1331 +    }
 18.1332 +#endif
 18.1333 +#else
 18.1334 +#ifdef __IPHONE_11_0
 18.1335 +    if ([mtldevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily4_v1]) {
 18.1336 +        maxtexsize = 16384;
 18.1337 +    } else
 18.1338 +#endif
 18.1339 +#ifdef __IPHONE_10_0
 18.1340 +    if ([mtldevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v1]) {
 18.1341 +        maxtexsize = 16384;
 18.1342 +    } else
 18.1343 +#endif
 18.1344 +    if ([mtldevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily2_v2] || [mtldevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily1_v2]) {
 18.1345 +        maxtexsize = 8192;
 18.1346 +    } else {
 18.1347 +        maxtexsize = 4096;
 18.1348 +    }
 18.1349 +#endif
 18.1350 +
 18.1351 +    renderer->info.max_texture_width = maxtexsize;
 18.1352 +    renderer->info.max_texture_height = maxtexsize;
 18.1353 +
 18.1354 +#if !__has_feature(objc_arc)
 18.1355 +    [mtlcmdqueue release];
 18.1356 +    [mtllibrary release];
 18.1357 +    [samplerdesc release];
 18.1358 +    [mtlsamplernearest release];
 18.1359 +    [mtlsamplerlinear release];
 18.1360 +    [mtlbufconstants release];
 18.1361 +    [view release];
 18.1362 +    [data release];
 18.1363 +    [mtldevice release];
 18.1364 +#endif
 18.1365 +
 18.1366 +    return renderer;
 18.1367 +}}
 18.1368 +
 18.1369 +SDL_RenderDriver METAL_RenderDriver = {
 18.1370 +    METAL_CreateRenderer,
 18.1371 +    {
 18.1372 +        "metal",
 18.1373 +        (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
 18.1374 +        6,
 18.1375 +        {
 18.1376 +            SDL_PIXELFORMAT_ARGB8888,
 18.1377 +            SDL_PIXELFORMAT_ABGR8888,
 18.1378 +            SDL_PIXELFORMAT_YV12,
 18.1379 +            SDL_PIXELFORMAT_IYUV,
 18.1380 +            SDL_PIXELFORMAT_NV12,
 18.1381 +            SDL_PIXELFORMAT_NV21
 18.1382 +        },
 18.1383 +    0, 0,
 18.1384 +    }
 18.1385 +};
 18.1386 +
 18.1387  #endif /* SDL_VIDEO_RENDER_METAL && !SDL_RENDER_DISABLED */
 18.1388  
 18.1389  /* vi: set ts=4 sw=4 expandtab: */
    19.1 --- a/src/render/opengl/SDL_render_gl.c	Mon Oct 22 10:55:18 2018 -0400
    19.2 +++ b/src/render/opengl/SDL_render_gl.c	Wed Oct 31 15:03:41 2018 -0400
    19.3 @@ -51,57 +51,6 @@
    19.4  
    19.5  static const float inv255f = 1.0f / 255.0f;
    19.6  
    19.7 -static SDL_Renderer *GL_CreateRenderer(SDL_Window * window, Uint32 flags);
    19.8 -static void GL_WindowEvent(SDL_Renderer * renderer,
    19.9 -                           const SDL_WindowEvent *event);
   19.10 -static int GL_GetOutputSize(SDL_Renderer * renderer, int *w, int *h);
   19.11 -static SDL_bool GL_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode);
   19.12 -static int GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
   19.13 -static int GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   19.14 -                            const SDL_Rect * rect, const void *pixels,
   19.15 -                            int pitch);
   19.16 -static int GL_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
   19.17 -                               const SDL_Rect * rect,
   19.18 -                               const Uint8 *Yplane, int Ypitch,
   19.19 -                               const Uint8 *Uplane, int Upitch,
   19.20 -                               const Uint8 *Vplane, int Vpitch);
   19.21 -static int GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   19.22 -                          const SDL_Rect * rect, void **pixels, int *pitch);
   19.23 -static void GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
   19.24 -static int GL_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture);
   19.25 -static int GL_UpdateViewport(SDL_Renderer * renderer);
   19.26 -static int GL_UpdateClipRect(SDL_Renderer * renderer);
   19.27 -static int GL_RenderClear(SDL_Renderer * renderer);
   19.28 -static int GL_RenderDrawPoints(SDL_Renderer * renderer,
   19.29 -                               const SDL_FPoint * points, int count);
   19.30 -static int GL_RenderDrawLines(SDL_Renderer * renderer,
   19.31 -                              const SDL_FPoint * points, int count);
   19.32 -static int GL_RenderFillRects(SDL_Renderer * renderer,
   19.33 -                              const SDL_FRect * rects, int count);
   19.34 -static int GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   19.35 -                         const SDL_Rect * srcrect, const SDL_FRect * dstrect);
   19.36 -static int GL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
   19.37 -                         const SDL_Rect * srcrect, const SDL_FRect * dstrect,
   19.38 -                         const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip);
   19.39 -static int GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
   19.40 -                               Uint32 pixel_format, void * pixels, int pitch);
   19.41 -static void GL_RenderPresent(SDL_Renderer * renderer);
   19.42 -static void GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture);
   19.43 -static void GL_DestroyRenderer(SDL_Renderer * renderer);
   19.44 -static int GL_BindTexture (SDL_Renderer * renderer, SDL_Texture *texture, float *texw, float *texh);
   19.45 -static int GL_UnbindTexture (SDL_Renderer * renderer, SDL_Texture *texture);
   19.46 -
   19.47 -SDL_RenderDriver GL_RenderDriver = {
   19.48 -    GL_CreateRenderer,
   19.49 -    {
   19.50 -     "opengl",
   19.51 -     (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
   19.52 -     1,
   19.53 -     {SDL_PIXELFORMAT_ARGB8888},
   19.54 -     0,
   19.55 -     0}
   19.56 -};
   19.57 -
   19.58  typedef struct GL_FBOList GL_FBOList;
   19.59  
   19.60  struct GL_FBOList
   19.61 @@ -113,6 +62,25 @@
   19.62  
   19.63  typedef struct
   19.64  {
   19.65 +    SDL_bool viewport_dirty;
   19.66 +    SDL_Rect viewport;
   19.67 +    SDL_Texture *texture;
   19.68 +    SDL_Texture *target;
   19.69 +    int drawablew;
   19.70 +    int drawableh;
   19.71 +    SDL_BlendMode blend;
   19.72 +    GL_Shader shader;
   19.73 +    SDL_bool cliprect_enabled_dirty;
   19.74 +    SDL_bool cliprect_enabled;
   19.75 +    SDL_bool cliprect_dirty;
   19.76 +    SDL_Rect cliprect;
   19.77 +    SDL_bool texturing;
   19.78 +    Uint32 color;
   19.79 +    Uint32 clear_color;
   19.80 +} GL_DrawStateCache;
   19.81 +
   19.82 +typedef struct
   19.83 +{
   19.84      SDL_GLContext context;
   19.85  
   19.86      SDL_bool debug_enabled;
   19.87 @@ -122,14 +90,10 @@
   19.88      GLDEBUGPROCARB next_error_callback;
   19.89      GLvoid *next_error_userparam;
   19.90  
   19.91 +    GLenum textype;
   19.92 +
   19.93      SDL_bool GL_ARB_texture_non_power_of_two_supported;
   19.94      SDL_bool GL_ARB_texture_rectangle_supported;
   19.95 -    struct {
   19.96 -        GL_Shader shader;
   19.97 -        Uint32 color;
   19.98 -        SDL_BlendMode blendMode;
   19.99 -    } current;
  19.100 -
  19.101      SDL_bool GL_EXT_framebuffer_object_supported;
  19.102      GL_FBOList *framebuffers;
  19.103  
  19.104 @@ -152,12 +116,12 @@
  19.105      /* Shader support */
  19.106      GL_ShaderContext *shaders;
  19.107  
  19.108 +    GL_DrawStateCache drawstate;
  19.109  } GL_RenderData;
  19.110  
  19.111  typedef struct
  19.112  {
  19.113      GLuint texture;
  19.114 -    GLenum type;
  19.115      GLfloat texw;
  19.116      GLfloat texh;
  19.117      GLenum format;
  19.118 @@ -284,21 +248,15 @@
  19.119      return 0;
  19.120  }
  19.121  
  19.122 -static SDL_GLContext SDL_CurrentContext = NULL;
  19.123 -
  19.124  static int
  19.125  GL_ActivateRenderer(SDL_Renderer * renderer)
  19.126  {
  19.127      GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  19.128  
  19.129 -    if (SDL_CurrentContext != data->context ||
  19.130 -        SDL_GL_GetCurrentContext() != data->context) {
  19.131 +    if (SDL_GL_GetCurrentContext() != data->context) {
  19.132          if (SDL_GL_MakeCurrent(renderer->window, data->context) < 0) {
  19.133              return -1;
  19.134          }
  19.135 -        SDL_CurrentContext = data->context;
  19.136 -
  19.137 -        GL_UpdateViewport(renderer);
  19.138      }
  19.139  
  19.140      GL_ClearErrors(renderer);
  19.141 @@ -306,33 +264,6 @@
  19.142      return 0;
  19.143  }
  19.144  
  19.145 -/* This is called if we need to invalidate all of the SDL OpenGL state */
  19.146 -static void
  19.147 -GL_ResetState(SDL_Renderer *renderer)
  19.148 -{
  19.149 -    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  19.150 -
  19.151 -    if (SDL_GL_GetCurrentContext() == data->context) {
  19.152 -        GL_UpdateViewport(renderer);
  19.153 -    } else {
  19.154 -        GL_ActivateRenderer(renderer);
  19.155 -    }
  19.156 -
  19.157 -    data->current.shader = SHADER_NONE;
  19.158 -    data->current.color = 0xffffffff;
  19.159 -    data->current.blendMode = SDL_BLENDMODE_INVALID;
  19.160 -
  19.161 -    data->glDisable(GL_DEPTH_TEST);
  19.162 -    data->glDisable(GL_CULL_FACE);
  19.163 -    /* This ended up causing video discrepancies between OpenGL and Direct3D */
  19.164 -    /* data->glEnable(GL_LINE_SMOOTH); */
  19.165 -
  19.166 -    data->glMatrixMode(GL_MODELVIEW);
  19.167 -    data->glLoadIdentity();
  19.168 -
  19.169 -    GL_CheckError("", renderer);
  19.170 -}
  19.171 -
  19.172  static void APIENTRY
  19.173  GL_HandleDebugMessage(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char *message, const void *userParam)
  19.174  {
  19.175 @@ -384,215 +315,6 @@
  19.176      return result;
  19.177  }
  19.178  
  19.179 -SDL_Renderer *
  19.180 -GL_CreateRenderer(SDL_Window * window, Uint32 flags)
  19.181 -{
  19.182 -    SDL_Renderer *renderer;
  19.183 -    GL_RenderData *data;
  19.184 -    GLint value;
  19.185 -    Uint32 window_flags;
  19.186 -    int profile_mask = 0, major = 0, minor = 0;
  19.187 -    SDL_bool changed_window = SDL_FALSE;
  19.188 -
  19.189 -    SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profile_mask);
  19.190 -    SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major);
  19.191 -    SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor);
  19.192 -    
  19.193 -    window_flags = SDL_GetWindowFlags(window);
  19.194 -    if (!(window_flags & SDL_WINDOW_OPENGL) ||
  19.195 -        profile_mask == SDL_GL_CONTEXT_PROFILE_ES || major != RENDERER_CONTEXT_MAJOR || minor != RENDERER_CONTEXT_MINOR) {
  19.196 -
  19.197 -        changed_window = SDL_TRUE;
  19.198 -        SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0);
  19.199 -        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, RENDERER_CONTEXT_MAJOR);
  19.200 -        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, RENDERER_CONTEXT_MINOR);
  19.201 -
  19.202 -        if (SDL_RecreateWindow(window, window_flags | SDL_WINDOW_OPENGL) < 0) {
  19.203 -            goto error;
  19.204 -        }
  19.205 -    }
  19.206 -
  19.207 -    renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
  19.208 -    if (!renderer) {
  19.209 -        SDL_OutOfMemory();
  19.210 -        goto error;
  19.211 -    }
  19.212 -
  19.213 -    data = (GL_RenderData *) SDL_calloc(1, sizeof(*data));
  19.214 -    if (!data) {
  19.215 -        SDL_free(renderer);
  19.216 -        SDL_OutOfMemory();
  19.217 -        goto error;
  19.218 -    }
  19.219 -
  19.220 -    renderer->WindowEvent = GL_WindowEvent;
  19.221 -    renderer->GetOutputSize = GL_GetOutputSize;
  19.222 -    renderer->SupportsBlendMode = GL_SupportsBlendMode;
  19.223 -    renderer->CreateTexture = GL_CreateTexture;
  19.224 -    renderer->UpdateTexture = GL_UpdateTexture;
  19.225 -    renderer->UpdateTextureYUV = GL_UpdateTextureYUV;
  19.226 -    renderer->LockTexture = GL_LockTexture;
  19.227 -    renderer->UnlockTexture = GL_UnlockTexture;
  19.228 -    renderer->SetRenderTarget = GL_SetRenderTarget;
  19.229 -    renderer->UpdateViewport = GL_UpdateViewport;
  19.230 -    renderer->UpdateClipRect = GL_UpdateClipRect;
  19.231 -    renderer->RenderClear = GL_RenderClear;
  19.232 -    renderer->RenderDrawPoints = GL_RenderDrawPoints;
  19.233 -    renderer->RenderDrawLines = GL_RenderDrawLines;
  19.234 -    renderer->RenderFillRects = GL_RenderFillRects;
  19.235 -    renderer->RenderCopy = GL_RenderCopy;
  19.236 -    renderer->RenderCopyEx = GL_RenderCopyEx;
  19.237 -    renderer->RenderReadPixels = GL_RenderReadPixels;
  19.238 -    renderer->RenderPresent = GL_RenderPresent;
  19.239 -    renderer->DestroyTexture = GL_DestroyTexture;
  19.240 -    renderer->DestroyRenderer = GL_DestroyRenderer;
  19.241 -    renderer->GL_BindTexture = GL_BindTexture;
  19.242 -    renderer->GL_UnbindTexture = GL_UnbindTexture;
  19.243 -    renderer->info = GL_RenderDriver.info;
  19.244 -    renderer->info.flags = SDL_RENDERER_ACCELERATED;
  19.245 -    renderer->driverdata = data;
  19.246 -    renderer->window = window;
  19.247 -
  19.248 -    data->context = SDL_GL_CreateContext(window);
  19.249 -    if (!data->context) {
  19.250 -        SDL_free(renderer);
  19.251 -        SDL_free(data);
  19.252 -        goto error;
  19.253 -    }
  19.254 -    if (SDL_GL_MakeCurrent(window, data->context) < 0) {
  19.255 -        SDL_GL_DeleteContext(data->context);
  19.256 -        SDL_free(renderer);
  19.257 -        SDL_free(data);
  19.258 -        goto error;
  19.259 -    }
  19.260 -
  19.261 -    if (GL_LoadFunctions(data) < 0) {
  19.262 -        SDL_GL_DeleteContext(data->context);
  19.263 -        SDL_free(renderer);
  19.264 -        SDL_free(data);
  19.265 -        goto error;
  19.266 -    }
  19.267 -
  19.268 -#ifdef __MACOSX__
  19.269 -    /* Enable multi-threaded rendering */
  19.270 -    /* Disabled until Ryan finishes his VBO/PBO code...
  19.271 -       CGLEnable(CGLGetCurrentContext(), kCGLCEMPEngine);
  19.272 -     */
  19.273 -#endif
  19.274 -
  19.275 -    if (flags & SDL_RENDERER_PRESENTVSYNC) {
  19.276 -        SDL_GL_SetSwapInterval(1);
  19.277 -    } else {
  19.278 -        SDL_GL_SetSwapInterval(0);
  19.279 -    }
  19.280 -    if (SDL_GL_GetSwapInterval() > 0) {
  19.281 -        renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
  19.282 -    }
  19.283 -
  19.284 -    /* Check for debug output support */
  19.285 -    if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_FLAGS, &value) == 0 &&
  19.286 -        (value & SDL_GL_CONTEXT_DEBUG_FLAG)) {
  19.287 -        data->debug_enabled = SDL_TRUE;
  19.288 -    }
  19.289 -    if (data->debug_enabled && SDL_GL_ExtensionSupported("GL_ARB_debug_output")) {
  19.290 -        PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARBFunc = (PFNGLDEBUGMESSAGECALLBACKARBPROC) SDL_GL_GetProcAddress("glDebugMessageCallbackARB");
  19.291 -
  19.292 -        data->GL_ARB_debug_output_supported = SDL_TRUE;
  19.293 -        data->glGetPointerv(GL_DEBUG_CALLBACK_FUNCTION_ARB, (GLvoid **)(char *)&data->next_error_callback);
  19.294 -        data->glGetPointerv(GL_DEBUG_CALLBACK_USER_PARAM_ARB, &data->next_error_userparam);
  19.295 -        glDebugMessageCallbackARBFunc(GL_HandleDebugMessage, renderer);
  19.296 -
  19.297 -        /* Make sure our callback is called when errors actually happen */
  19.298 -        data->glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
  19.299 -    }
  19.300 -
  19.301 -    if (SDL_GL_ExtensionSupported("GL_ARB_texture_non_power_of_two")) {
  19.302 -        data->GL_ARB_texture_non_power_of_two_supported = SDL_TRUE;
  19.303 -    } else if (SDL_GL_ExtensionSupported("GL_ARB_texture_rectangle") ||
  19.304 -               SDL_GL_ExtensionSupported("GL_EXT_texture_rectangle")) {
  19.305 -        data->GL_ARB_texture_rectangle_supported = SDL_TRUE;
  19.306 -    }
  19.307 -    if (data->GL_ARB_texture_rectangle_supported) {
  19.308 -        data->glGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB, &value);
  19.309 -        renderer->info.max_texture_width = value;
  19.310 -        renderer->info.max_texture_height = value;
  19.311 -    } else {
  19.312 -        data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
  19.313 -        renderer->info.max_texture_width = value;
  19.314 -        renderer->info.max_texture_height = value;
  19.315 -    }
  19.316 -
  19.317 -    /* Check for multitexture support */
  19.318 -    if (SDL_GL_ExtensionSupported("GL_ARB_multitexture")) {
  19.319 -        data->glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC) SDL_GL_GetProcAddress("glActiveTextureARB");
  19.320 -        if (data->glActiveTextureARB) {
  19.321 -            data->GL_ARB_multitexture_supported = SDL_TRUE;
  19.322 -            data->glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &data->num_texture_units);
  19.323 -        }
  19.324 -    }
  19.325 -
  19.326 -    /* Check for shader support */
  19.327 -    if (SDL_GetHintBoolean(SDL_HINT_RENDER_OPENGL_SHADERS, SDL_TRUE)) {
  19.328 -        data->shaders = GL_CreateShaderContext();
  19.329 -    }
  19.330 -    SDL_LogInfo(SDL_LOG_CATEGORY_RENDER, "OpenGL shaders: %s",
  19.331 -                data->shaders ? "ENABLED" : "DISABLED");
  19.332 -
  19.333 -    /* We support YV12 textures using 3 textures and a shader */
  19.334 -    if (data->shaders && data->num_texture_units >= 3) {
  19.335 -        renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;
  19.336 -        renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
  19.337 -        renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_NV12;
  19.338 -        renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_NV21;
  19.339 -    }
  19.340 -
  19.341 -#ifdef __MACOSX__
  19.342 -    renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_UYVY;
  19.343 -#endif
  19.344 -
  19.345 -    if (SDL_GL_ExtensionSupported("GL_EXT_framebuffer_object")) {
  19.346 -        data->GL_EXT_framebuffer_object_supported = SDL_TRUE;
  19.347 -        data->glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC)
  19.348 -            SDL_GL_GetProcAddress("glGenFramebuffersEXT");
  19.349 -        data->glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC)
  19.350 -            SDL_GL_GetProcAddress("glDeleteFramebuffersEXT");
  19.351 -        data->glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)
  19.352 -            SDL_GL_GetProcAddress("glFramebufferTexture2DEXT");
  19.353 -        data->glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)
  19.354 -            SDL_GL_GetProcAddress("glBindFramebufferEXT");
  19.355 -        data->glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)
  19.356 -            SDL_GL_GetProcAddress("glCheckFramebufferStatusEXT");
  19.357 -        renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE;
  19.358 -    }
  19.359 -    data->framebuffers = NULL;
  19.360 -
  19.361 -    /* Set up parameters for rendering */
  19.362 -    GL_ResetState(renderer);
  19.363 -
  19.364 -    return renderer;
  19.365 -
  19.366 -error:
  19.367 -    if (changed_window) {
  19.368 -        /* Uh oh, better try to put it back... */
  19.369 -        SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profile_mask);
  19.370 -        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major);
  19.371 -        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minor);
  19.372 -        SDL_RecreateWindow(window, window_flags);
  19.373 -    }
  19.374 -    return NULL;
  19.375 -}
  19.376 -
  19.377 -static void
  19.378 -GL_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
  19.379 -{
  19.380 -    if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED ||
  19.381 -        event->event == SDL_WINDOWEVENT_SHOWN ||
  19.382 -        event->event == SDL_WINDOWEVENT_HIDDEN) {
  19.383 -        /* Rebind the context to the window area and update matrices */
  19.384 -        SDL_CurrentContext = NULL;
  19.385 -    }
  19.386 -}
  19.387 -
  19.388  static int
  19.389  GL_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
  19.390  {
  19.391 @@ -712,6 +434,7 @@
  19.392  GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  19.393  {
  19.394      GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
  19.395 +    const GLenum textype = renderdata->textype;
  19.396      GL_TextureData *data;
  19.397      GLint internalFormat;
  19.398      GLenum format, type;
  19.399 @@ -775,19 +498,16 @@
  19.400      texture->driverdata = data;
  19.401  
  19.402      if (renderdata->GL_ARB_texture_non_power_of_two_supported) {
  19.403 -        data->type = GL_TEXTURE_2D;
  19.404          texture_w = texture->w;
  19.405          texture_h = texture->h;
  19.406          data->texw = 1.0f;
  19.407          data->texh = 1.0f;
  19.408      } else if (renderdata->GL_ARB_texture_rectangle_supported) {
  19.409 -        data->type = GL_TEXTURE_RECTANGLE_ARB;
  19.410          texture_w = texture->w;
  19.411          texture_h = texture->h;
  19.412          data->texw = (GLfloat) texture_w;
  19.413          data->texh = (GLfloat) texture_h;
  19.414      } else {
  19.415 -        data->type = GL_TEXTURE_2D;
  19.416          texture_w = power_of_2(texture->w);
  19.417          texture_h = power_of_2(texture->h);
  19.418          data->texw = (GLfloat) (texture->w) / texture_w;
  19.419 @@ -797,17 +517,17 @@
  19.420      data->format = format;
  19.421      data->formattype = type;
  19.422      scaleMode = (texture->scaleMode == SDL_ScaleModeNearest) ? GL_NEAREST : GL_LINEAR;
  19.423 -    renderdata->glEnable(data->type);
  19.424 -    renderdata->glBindTexture(data->type, data->texture);
  19.425 -    renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER, scaleMode);
  19.426 -    renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER, scaleMode);
  19.427 +    renderdata->glEnable(textype);
  19.428 +    renderdata->glBindTexture(textype, data->texture);
  19.429 +    renderdata->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, scaleMode);
  19.430 +    renderdata->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, scaleMode);
  19.431      /* According to the spec, CLAMP_TO_EDGE is the default for TEXTURE_RECTANGLE
  19.432         and setting it causes an INVALID_ENUM error in the latest NVidia drivers.
  19.433      */
  19.434 -    if (data->type != GL_TEXTURE_RECTANGLE_ARB) {
  19.435 -        renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
  19.436 +    if (textype != GL_TEXTURE_RECTANGLE_ARB) {
  19.437 +        renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_S,
  19.438                                      GL_CLAMP_TO_EDGE);
  19.439 -        renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
  19.440 +        renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_T,
  19.441                                      GL_CLAMP_TO_EDGE);
  19.442      }
  19.443  #ifdef __MACOSX__
  19.444 @@ -821,10 +541,10 @@
  19.445  #define STORAGE_SHARED_APPLE                0x85BF
  19.446  #endif
  19.447      if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
  19.448 -        renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
  19.449 +        renderdata->glTexParameteri(textype, GL_TEXTURE_STORAGE_HINT_APPLE,
  19.450                                      GL_STORAGE_SHARED_APPLE);
  19.451      } else {
  19.452 -        renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
  19.453 +        renderdata->glTexParameteri(textype, GL_TEXTURE_STORAGE_HINT_APPLE,
  19.454                                      GL_STORAGE_CACHED_APPLE);
  19.455      }
  19.456      if (texture->access == SDL_TEXTUREACCESS_STREAMING
  19.457 @@ -834,17 +554,17 @@
  19.458          renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  19.459          renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH,
  19.460                            (data->pitch / SDL_BYTESPERPIXEL(texture->format)));
  19.461 -        renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
  19.462 +        renderdata->glTexImage2D(textype, 0, internalFormat, texture_w,
  19.463                                   texture_h, 0, format, type, data->pixels);
  19.464          renderdata->glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
  19.465      }
  19.466      else
  19.467  #endif
  19.468      {
  19.469 -        renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
  19.470 +        renderdata->glTexImage2D(textype, 0, internalFormat, texture_w,
  19.471                                   texture_h, 0, format, type, NULL);
  19.472      }
  19.473 -    renderdata->glDisable(data->type);
  19.474 +    renderdata->glDisable(textype);
  19.475      if (GL_CheckError("glTexImage2D()", renderer) < 0) {
  19.476          return -1;
  19.477      }
  19.478 @@ -855,33 +575,33 @@
  19.479  
  19.480          renderdata->glGenTextures(1, &data->utexture);
  19.481          renderdata->glGenTextures(1, &data->vtexture);
  19.482 -        renderdata->glEnable(data->type);
  19.483 +        renderdata->glEnable(textype);
  19.484  
  19.485 -        renderdata->glBindTexture(data->type, data->utexture);
  19.486 -        renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
  19.487 +        renderdata->glBindTexture(textype, data->utexture);
  19.488 +        renderdata->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER,
  19.489                                      scaleMode);
  19.490 -        renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
  19.491 +        renderdata->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER,
  19.492                                      scaleMode);
  19.493 -        renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
  19.494 +        renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_S,
  19.495                                      GL_CLAMP_TO_EDGE);
  19.496 -        renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
  19.497 +        renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_T,
  19.498                                      GL_CLAMP_TO_EDGE);
  19.499 -        renderdata->glTexImage2D(data->type, 0, internalFormat, (texture_w+1)/2,
  19.500 +        renderdata->glTexImage2D(textype, 0, internalFormat, (texture_w+1)/2,
  19.501                                   (texture_h+1)/2, 0, format, type, NULL);
  19.502  
  19.503 -        renderdata->glBindTexture(data->type, data->vtexture);
  19.504 -        renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
  19.505 +        renderdata->glBindTexture(textype, data->vtexture);
  19.506 +        renderdata->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER,
  19.507                                      scaleMode);
  19.508 -        renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
  19.509 +        renderdata->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER,
  19.510                                      scaleMode);
  19.511 -        renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
  19.512 +        renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_S,
  19.513                                      GL_CLAMP_TO_EDGE);
  19.514 -        renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
  19.515 +        renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_T,
  19.516                                      GL_CLAMP_TO_EDGE);
  19.517 -        renderdata->glTexImage2D(data->type, 0, internalFormat, (texture_w+1)/2,
  19.518 +        renderdata->glTexImage2D(textype, 0, internalFormat, (texture_w+1)/2,
  19.519                                   (texture_h+1)/2, 0, format, type, NULL);
  19.520  
  19.521 -        renderdata->glDisable(data->type);
  19.522 +        renderdata->glDisable(textype);
  19.523      }
  19.524  
  19.525      if (texture->format == SDL_PIXELFORMAT_NV12 ||
  19.526 @@ -889,20 +609,20 @@
  19.527          data->nv12 = SDL_TRUE;
  19.528  
  19.529          renderdata->glGenTextures(1, &data->utexture);
  19.530 -        renderdata->glEnable(data->type);
  19.531 +        renderdata->glEnable(textype);
  19.532  
  19.533 -        renderdata->glBindTexture(data->type, data->utexture);
  19.534 -        renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
  19.535 +        renderdata->glBindTexture(textype, data->utexture);
  19.536 +        renderdata->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER,
  19.537                                      scaleMode);
  19.538 -        renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
  19.539 +        renderdata->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER,
  19.540                                      scaleMode);
  19.541 -        renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
  19.542 +        renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_S,
  19.543                                      GL_CLAMP_TO_EDGE);
  19.544 -        renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
  19.545 +        renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_T,
  19.546                                      GL_CLAMP_TO_EDGE);
  19.547 -        renderdata->glTexImage2D(data->type, 0, GL_LUMINANCE_ALPHA, (texture_w+1)/2,
  19.548 +        renderdata->glTexImage2D(textype, 0, GL_LUMINANCE_ALPHA, (texture_w+1)/2,
  19.549                                   (texture_h+1)/2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL);
  19.550 -        renderdata->glDisable(data->type);
  19.551 +        renderdata->glDisable(textype);
  19.552      }
  19.553  
  19.554      return GL_CheckError("", renderer);
  19.555 @@ -913,6 +633,7 @@
  19.556                   const SDL_Rect * rect, const void *pixels, int pitch)
  19.557  {
  19.558      GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
  19.559 +    const GLenum textype = renderdata->textype;
  19.560      GL_TextureData *data = (GL_TextureData *) texture->driverdata;
  19.561      const int texturebpp = SDL_BYTESPERPIXEL(texture->format);
  19.562  
  19.563 @@ -920,11 +641,11 @@
  19.564  
  19.565      GL_ActivateRenderer(renderer);
  19.566  
  19.567 -    renderdata->glEnable(data->type);
  19.568 -    renderdata->glBindTexture(data->type, data->texture);
  19.569 +    renderdata->glEnable(textype);
  19.570 +    renderdata->glBindTexture(textype, data->texture);
  19.571      renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  19.572      renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, (pitch / texturebpp));
  19.573 -    renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w,
  19.574 +    renderdata->glTexSubImage2D(textype, 0, rect->x, rect->y, rect->w,
  19.575                                  rect->h, data->format, data->formattype,
  19.576                                  pixels);
  19.577      if (data->yuv) {
  19.578 @@ -933,22 +654,22 @@
  19.579          /* Skip to the correct offset into the next texture */
  19.580          pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
  19.581          if (texture->format == SDL_PIXELFORMAT_YV12) {
  19.582 -            renderdata->glBindTexture(data->type, data->vtexture);
  19.583 +            renderdata->glBindTexture(textype, data->vtexture);
  19.584          } else {
  19.585 -            renderdata->glBindTexture(data->type, data->utexture);
  19.586 +            renderdata->glBindTexture(textype, data->utexture);
  19.587          }
  19.588 -        renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
  19.589 +        renderdata->glTexSubImage2D(textype, 0, rect->x/2, rect->y/2,
  19.590                                      (rect->w+1)/2, (rect->h+1)/2,
  19.591                                      data->format, data->formattype, pixels);
  19.592  
  19.593          /* Skip to the correct offset into the next texture */
  19.594          pixels = (const void*)((const Uint8*)pixels + ((rect->h + 1) / 2) * ((pitch + 1) / 2));
  19.595          if (texture->format == SDL_PIXELFORMAT_YV12) {
  19.596 -            renderdata->glBindTexture(data->type, data->utexture);
  19.597 +            renderdata->glBindTexture(textype, data->utexture);
  19.598          } else {
  19.599 -            renderdata->glBindTexture(data->type, data->vtexture);
  19.600 +            renderdata->glBindTexture(textype, data->vtexture);
  19.601          }
  19.602 -        renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
  19.603 +        renderdata->glTexSubImage2D(textype, 0, rect->x/2, rect->y/2,
  19.604                                      (rect->w+1)/2, (rect->h+1)/2,
  19.605                                      data->format, data->formattype, pixels);
  19.606      }
  19.607 @@ -958,12 +679,12 @@
  19.608  
  19.609          /* Skip to the correct offset into the next texture */
  19.610          pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
  19.611 -        renderdata->glBindTexture(data->type, data->utexture);
  19.612 -        renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
  19.613 +        renderdata->glBindTexture(textype, data->utexture);
  19.614 +        renderdata->glTexSubImage2D(textype, 0, rect->x/2, rect->y/2,
  19.615                                      (rect->w + 1)/2, (rect->h + 1)/2,
  19.616                                      GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, pixels);
  19.617      }
  19.618 -    renderdata->glDisable(data->type);
  19.619 +    renderdata->glDisable(textype);
  19.620  
  19.621      return GL_CheckError("glTexSubImage2D()", renderer);
  19.622  }
  19.623 @@ -976,30 +697,31 @@
  19.624                      const Uint8 *Vplane, int Vpitch)
  19.625  {
  19.626      GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
  19.627 +    const GLenum textype = renderdata->textype;
  19.628      GL_TextureData *data = (GL_TextureData *) texture->driverdata;
  19.629  
  19.630      GL_ActivateRenderer(renderer);
  19.631  
  19.632 -    renderdata->glEnable(data->type);
  19.633 -    renderdata->glBindTexture(data->type, data->texture);
  19.634 +    renderdata->glEnable(textype);
  19.635 +    renderdata->glBindTexture(textype, data->texture);
  19.636      renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  19.637      renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, Ypitch);
  19.638 -    renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w,
  19.639 +    renderdata->glTexSubImage2D(textype, 0, rect->x, rect->y, rect->w,
  19.640                                  rect->h, data->format, data->formattype,
  19.641                                  Yplane);
  19.642  
  19.643      renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, Upitch);
  19.644 -    renderdata->glBindTexture(data->type, data->utexture);
  19.645 -    renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
  19.646 +    renderdata->glBindTexture(textype, data->utexture);
  19.647 +    renderdata->glTexSubImage2D(textype, 0, rect->x/2, rect->y/2,
  19.648                                  (rect->w + 1)/2, (rect->h + 1)/2,
  19.649                                  data->format, data->formattype, Uplane);
  19.650  
  19.651      renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, Vpitch);
  19.652 -    renderdata->glBindTexture(data->type, data->vtexture);
  19.653 -    renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
  19.654 +    renderdata->glBindTexture(textype, data->vtexture);
  19.655 +    renderdata->glTexSubImage2D(textype, 0, rect->x/2, rect->y/2,
  19.656                                  (rect->w + 1)/2, (rect->h + 1)/2,
  19.657                                  data->format, data->formattype, Vplane);
  19.658 -    renderdata->glDisable(data->type);
  19.659 +    renderdata->glDisable(textype);
  19.660  
  19.661      return GL_CheckError("glTexSubImage2D()", renderer);
  19.662  }
  19.663 @@ -1053,7 +775,7 @@
  19.664      texturedata = (GL_TextureData *) texture->driverdata;
  19.665      data->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, texturedata->fbo->FBO);
  19.666      /* TODO: check if texture pixel format allows this operation */
  19.667 -    data->glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, texturedata->type, texturedata->texture, 0);
  19.668 +    data->glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, data->textype, texturedata->texture, 0);
  19.669      /* Check FBO status */
  19.670      status = data->glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
  19.671      if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
  19.672 @@ -1062,337 +784,71 @@
  19.673      return 0;
  19.674  }
  19.675  
  19.676 +/* !!! FIXME: all these Queue* calls set up the vertex buffer the way the immediate mode
  19.677 +   !!! FIXME:  renderer wants it, but this might want to operate differently if we move to
  19.678 +   !!! FIXME:  VBOs at some point. */
  19.679  static int
  19.680 -GL_UpdateViewport(SDL_Renderer * renderer)
  19.681 +GL_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd)
  19.682  {
  19.683 -    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  19.684 -
  19.685 -    if (SDL_CurrentContext != data->context) {
  19.686 -        /* We'll update the viewport after we rebind the context */
  19.687 -        return 0;
  19.688 -    }
  19.689 -
  19.690 -    if (renderer->target) {
  19.691 -        data->glViewport(renderer->viewport.x, renderer->viewport.y,
  19.692 -                         renderer->viewport.w, renderer->viewport.h);
  19.693 -    } else {
  19.694 -        int w, h;
  19.695 -
  19.696 -        SDL_GL_GetDrawableSize(renderer->window, &w, &h);
  19.697 -        data->glViewport(renderer->viewport.x, (h - renderer->viewport.y - renderer->viewport.h),
  19.698 -                         renderer->viewport.w, renderer->viewport.h);
  19.699 -    }
  19.700 -
  19.701 -    data->glMatrixMode(GL_PROJECTION);
  19.702 -    data->glLoadIdentity();
  19.703 -    if (renderer->viewport.w && renderer->viewport.h) {
  19.704 -        if (renderer->target) {
  19.705 -            data->glOrtho((GLdouble) 0,
  19.706 -                          (GLdouble) renderer->viewport.w,
  19.707 -                          (GLdouble) 0,
  19.708 -                          (GLdouble) renderer->viewport.h,
  19.709 -                           0.0, 1.0);
  19.710 -        } else {
  19.711 -            data->glOrtho((GLdouble) 0,
  19.712 -                          (GLdouble) renderer->viewport.w,
  19.713 -                          (GLdouble) renderer->viewport.h,
  19.714 -                          (GLdouble) 0,
  19.715 -                           0.0, 1.0);
  19.716 -        }
  19.717 -    }
  19.718 -    data->glMatrixMode(GL_MODELVIEW);
  19.719 -
  19.720 -    return GL_CheckError("", renderer);
  19.721 +    return 0;  /* nothing to do in this backend. */
  19.722  }
  19.723  
  19.724  static int
  19.725 -GL_UpdateClipRect(SDL_Renderer * renderer)
  19.726 +GL_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
  19.727  {
  19.728 -    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
  19.729 +    GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, count * 2 * sizeof (GLfloat), 0, &cmd->data.draw.first);
  19.730 +    size_t i;
  19.731  
  19.732 -    if (renderer->clipping_enabled) {
  19.733 -        const SDL_Rect *rect = &renderer->clip_rect;
  19.734 -        data->glEnable(GL_SCISSOR_TEST);
  19.735 -        if (renderer->target) {
  19.736 -            data->glScissor(renderer->viewport.x + rect->x, renderer->viewport.y + rect->y, rect->w, rect->h);
  19.737 -        } else {
  19.738 -            int w, h;
  19.739 -
  19.740 -            SDL_GL_GetDrawableSize(renderer->window, &w, &h);
  19.741 -            data->glScissor(renderer->viewport.x + rect->x, h - renderer->viewport.y - rect->y - rect->h, rect->w, rect->h);
  19.742 -        }
  19.743 -    } else {
  19.744 -        data->glDisable(GL_SCISSOR_TEST);
  19.745 -    }
  19.746 -    return 0;
  19.747 -}
  19.748 -
  19.749 -static void
  19.750 -GL_SetShader(GL_RenderData * data, GL_Shader shader)
  19.751 -{
  19.752 -    if (data->shaders && shader != data->current.shader) {