summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan C. Gordon <icculus@icculus.org>2018-10-31 15:03:41 -0400
committerRyan C. Gordon <icculus@icculus.org>2018-10-31 15:03:41 -0400
commitd8c11a112cbb30e1bd433ca8423faf83d3889de2 (patch)
tree3ea5e35a632398e54872f860b3a74a063be0b060
parentb3ffbe64440ac62068eee70890cf65239857bea1 (diff)
parent48f849039637b543aba06a9baf61b2b549c85df4 (diff)
Merge SDL-ryan-batching-renderer branch to default.
-rw-r--r--include/SDL_hints.h25
-rw-r--r--include/SDL_rect.h30
-rw-r--r--include/SDL_render.h167
-rw-r--r--src/SDL_assert.c1
-rw-r--r--src/SDL_internal.h4
-rw-r--r--src/SDL_log.c8
-rw-r--r--src/core/android/SDL_android.c5
-rw-r--r--src/dynapi/SDL_dynapi_overrides.h11
-rw-r--r--src/dynapi/SDL_dynapi_procs.h11
-rw-r--r--src/file/SDL_rwops.c1
-rw-r--r--src/joystick/SDL_gamecontroller.c5
-rw-r--r--src/joystick/SDL_joystick.c5
-rw-r--r--src/loadso/dlopen/SDL_sysloadso.c5
-rw-r--r--src/render/SDL_render.c1257
-rw-r--r--src/render/SDL_sysrender.h124
-rw-r--r--src/render/direct3d/SDL_render_d3d.c1494
-rw-r--r--src/render/direct3d11/SDL_render_d3d11.c1325
-rw-r--r--src/render/metal/SDL_render_metal.m1247
-rw-r--r--src/render/opengl/SDL_render_gl.c1449
-rw-r--r--src/render/opengl/SDL_shaders_gl.c5
-rw-r--r--src/render/opengl/SDL_shaders_gl.h1
-rw-r--r--src/render/opengles/SDL_render_gles.c1094
-rw-r--r--src/render/opengles2/SDL_gles2funcs.h1
-rw-r--r--src/render/opengles2/SDL_render_gles2.c2037
-rw-r--r--src/render/opengles2/SDL_shaders_gles2.c28
-rw-r--r--src/render/psp/SDL_render_psp.c975
-rw-r--r--src/render/software/SDL_render_sw.c727
-rw-r--r--src/video/cocoa/SDL_cocoamodes.m7
-rw-r--r--src/video/wayland/SDL_waylandvideo.c6
-rw-r--r--src/video/wayland/SDL_waylandvideo.h1
-rw-r--r--src/video/wayland/SDL_waylandwindow.c25
-rw-r--r--src/video/wayland/SDL_waylandwindow.h2
-rw-r--r--src/video/windows/SDL_windowsevents.c13
-rw-r--r--src/video/windows/SDL_windowsframebuffer.c5
-rw-r--r--src/video/windows/SDL_windowsmouse.c5
-rw-r--r--src/video/windows/SDL_windowswindow.c12
-rw-r--r--test/testsprite2.c25
-rw-r--r--wayland-protocols/org-kde-kwin-server-decoration-manager.xml94
38 files changed, 6818 insertions, 5419 deletions
diff --git a/include/SDL_hints.h b/include/SDL_hints.h
index 4ee72e97d6..b000ee90c3 100644
--- a/include/SDL_hints.h
+++ b/include/SDL_hints.h
@@ -1044,6 +1044,31 @@ extern "C" {
#define SDL_HINT_AUDIO_CATEGORY "SDL_AUDIO_CATEGORY"
/**
+ * \brief A variable controlling whether the 2D render API is compatible or efficient.
+ *
+ * This variable can be set to the following values:
+ *
+ * "0" - Don't use batching to make rendering more efficient.
+ * "1" - Use batching, but might cause problems if app makes its own direct OpenGL calls.
+ *
+ * Up to SDL 2.0.9, the render API would draw immediately when requested. Now
+ * it batches up draw requests and sends them all to the GPU only when forced
+ * to (during SDL_RenderPresent, when changing render targets, by updating a
+ * texture that the batch needs, etc). This is significantly more efficient,
+ * but it can cause problems for apps that expect to render on top of the
+ * render API's output. As such, SDL will disable batching if a specific
+ * render backend is requested (since this might indicate that the app is
+ * planning to use the underlying graphics API directly). This hint can
+ * be used to explicitly request batching in this instance. It is a contract
+ * that you will either never use the underlying graphics API directly, or
+ * if you do, you will call SDL_RenderFlush() before you do so any current
+ * batch goes to the GPU before your work begins. Not following this contract
+ * will result in undefined behavior.
+ */
+#define SDL_HINT_RENDER_BATCHING "SDL_RENDER_BATCHING"
+
+
+/**
* \brief An enumeration of hint priorities
*/
typedef enum
diff --git a/include/SDL_rect.h b/include/SDL_rect.h
index 543bb61869..986764cd69 100644
--- a/include/SDL_rect.h
+++ b/include/SDL_rect.h
@@ -40,7 +40,7 @@ extern "C" {
#endif
/**
- * \brief The structure that defines a point
+ * \brief The structure that defines a point (integer)
*
* \sa SDL_EnclosePoints
* \sa SDL_PointInRect
@@ -52,7 +52,20 @@ typedef struct SDL_Point
} SDL_Point;
/**
- * \brief A rectangle, with the origin at the upper left.
+ * \brief The structure that defines a point (floating point)
+ *
+ * \sa SDL_EnclosePoints
+ * \sa SDL_PointInRect
+ */
+typedef struct SDL_FPoint
+{
+ float x;
+ float y;
+} SDL_FPoint;
+
+
+/**
+ * \brief A rectangle, with the origin at the upper left (integer).
*
* \sa SDL_RectEmpty
* \sa SDL_RectEquals
@@ -67,6 +80,19 @@ typedef struct SDL_Rect
int w, h;
} SDL_Rect;
+
+/**
+ * \brief A rectangle, with the origin at the upper left (floating point).
+ */
+typedef struct SDL_FRect
+{
+ float x;
+ float y;
+ float w;
+ float h;
+} SDL_FRect;
+
+
/**
* \brief Returns true if point resides inside a rectangle.
*/
diff --git a/include/SDL_render.h b/include/SDL_render.h
index d336192974..738b7392a6 100644
--- a/include/SDL_render.h
+++ b/include/SDL_render.h
@@ -835,6 +835,148 @@ extern DECLSPEC int SDLCALL SDL_RenderCopyEx(SDL_Renderer * renderer,
const SDL_Point *center,
const SDL_RendererFlip flip);
+
+/**
+ * \brief Draw a point on the current rendering target.
+ *
+ * \param renderer The renderer which should draw a point.
+ * \param x The x coordinate of the point.
+ * \param y The y coordinate of the point.
+ *
+ * \return 0 on success, or -1 on error
+ */
+extern DECLSPEC int SDLCALL SDL_RenderDrawPointF(SDL_Renderer * renderer,
+ float x, float y);
+
+/**
+ * \brief Draw multiple points on the current rendering target.
+ *
+ * \param renderer The renderer which should draw multiple points.
+ * \param points The points to draw
+ * \param count The number of points to draw
+ *
+ * \return 0 on success, or -1 on error
+ */
+extern DECLSPEC int SDLCALL SDL_RenderDrawPointsF(SDL_Renderer * renderer,
+ const SDL_FPoint * points,
+ int count);
+
+/**
+ * \brief Draw a line on the current rendering target.
+ *
+ * \param renderer The renderer which should draw a line.
+ * \param x1 The x coordinate of the start point.
+ * \param y1 The y coordinate of the start point.
+ * \param x2 The x coordinate of the end point.
+ * \param y2 The y coordinate of the end point.
+ *
+ * \return 0 on success, or -1 on error
+ */
+extern DECLSPEC int SDLCALL SDL_RenderDrawLineF(SDL_Renderer * renderer,
+ float x1, float y1, float x2, float y2);
+
+/**
+ * \brief Draw a series of connected lines on the current rendering target.
+ *
+ * \param renderer The renderer which should draw multiple lines.
+ * \param points The points along the lines
+ * \param count The number of points, drawing count-1 lines
+ *
+ * \return 0 on success, or -1 on error
+ */
+extern DECLSPEC int SDLCALL SDL_RenderDrawLinesF(SDL_Renderer * renderer,
+ const SDL_FPoint * points,
+ int count);
+
+/**
+ * \brief Draw a rectangle on the current rendering target.
+ *
+ * \param renderer The renderer which should draw a rectangle.
+ * \param rect A pointer to the destination rectangle, or NULL to outline the entire rendering target.
+ *
+ * \return 0 on success, or -1 on error
+ */
+extern DECLSPEC int SDLCALL SDL_RenderDrawRectF(SDL_Renderer * renderer,
+ const SDL_FRect * rect);
+
+/**
+ * \brief Draw some number of rectangles on the current rendering target.
+ *
+ * \param renderer The renderer which should draw multiple rectangles.
+ * \param rects A pointer to an array of destination rectangles.
+ * \param count The number of rectangles.
+ *
+ * \return 0 on success, or -1 on error
+ */
+extern DECLSPEC int SDLCALL SDL_RenderDrawRectsF(SDL_Renderer * renderer,
+ const SDL_FRect * rects,
+ int count);
+
+/**
+ * \brief Fill a rectangle on the current rendering target with the drawing color.
+ *
+ * \param renderer The renderer which should fill a rectangle.
+ * \param rect A pointer to the destination rectangle, or NULL for the entire
+ * rendering target.
+ *
+ * \return 0 on success, or -1 on error
+ */
+extern DECLSPEC int SDLCALL SDL_RenderFillRectF(SDL_Renderer * renderer,
+ const SDL_FRect * rect);
+
+/**
+ * \brief Fill some number of rectangles on the current rendering target with the drawing color.
+ *
+ * \param renderer The renderer which should fill multiple rectangles.
+ * \param rects A pointer to an array of destination rectangles.
+ * \param count The number of rectangles.
+ *
+ * \return 0 on success, or -1 on error
+ */
+extern DECLSPEC int SDLCALL SDL_RenderFillRectsF(SDL_Renderer * renderer,
+ const SDL_FRect * rects,
+ int count);
+
+/**
+ * \brief Copy a portion of the texture to the current rendering target.
+ *
+ * \param renderer The renderer which should copy parts of a texture.
+ * \param texture The source texture.
+ * \param srcrect A pointer to the source rectangle, or NULL for the entire
+ * texture.
+ * \param dstrect A pointer to the destination rectangle, or NULL for the
+ * entire rendering target.
+ *
+ * \return 0 on success, or -1 on error
+ */
+extern DECLSPEC int SDLCALL SDL_RenderCopyF(SDL_Renderer * renderer,
+ SDL_Texture * texture,
+ const SDL_Rect * srcrect,
+ const SDL_FRect * dstrect);
+
+/**
+ * \brief Copy a portion of the source texture to the current rendering target, rotating it by angle around the given center
+ *
+ * \param renderer The renderer which should copy parts of a texture.
+ * \param texture The source texture.
+ * \param srcrect A pointer to the source rectangle, or NULL for the entire
+ * texture.
+ * \param dstrect A pointer to the destination rectangle, or NULL for the
+ * entire rendering target.
+ * \param angle An angle in degrees that indicates the rotation that will be applied to dstrect, rotating it in a clockwise direction
+ * \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).
+ * \param flip An SDL_RendererFlip value stating which flipping actions should be performed on the texture
+ *
+ * \return 0 on success, or -1 on error
+ */
+extern DECLSPEC int SDLCALL SDL_RenderCopyExF(SDL_Renderer * renderer,
+ SDL_Texture * texture,
+ const SDL_Rect * srcrect,
+ const SDL_FRect * dstrect,
+ const double angle,
+ const SDL_FPoint *center,
+ const SDL_RendererFlip flip);
+
/**
* \brief Read pixels from the current rendering target.
*
@@ -876,6 +1018,31 @@ extern DECLSPEC void SDLCALL SDL_DestroyTexture(SDL_Texture * texture);
*/
extern DECLSPEC void SDLCALL SDL_DestroyRenderer(SDL_Renderer * renderer);
+/**
+ * \brief Force the rendering context to flush any pending commands to the
+ * underlying rendering API.
+ *
+ * You do not need to (and in fact, shouldn't) call this function unless
+ * you are planning to call into OpenGL/Direct3D/Metal/whatever directly
+ * in addition to using an SDL_Renderer.
+ *
+ * This is for a very-specific case: if you are using SDL's render API,
+ * you asked for a specific renderer backend (OpenGL, Direct3D, etc),
+ * you set SDL_HINT_RENDER_BATCHING to "1", and you plan to make
+ * OpenGL/D3D/whatever calls in addition to SDL render API calls. If all of
+ * this applies, you should call SDL_RenderFlush() between calls to SDL's
+ * render API and the low-level API you're using in cooperation.
+ *
+ * In all other cases, you can ignore this function. This is only here to
+ * get maximum performance out of a specific situation. In all other cases,
+ * SDL will do the right thing, perhaps at a performance loss.
+ *
+ * This function is first available in SDL 2.0.10, and is not needed in
+ * 2.0.9 and earlier, as earlier versions did not queue rendering commands
+ * at all, instead flushing them to the OS immediately.
+ */
+extern DECLSPEC int SDLCALL SDL_RenderFlush(SDL_Renderer * renderer);
+
/**
* \brief Bind the texture to the current OpenGL/ES/ES2 context for use with
diff --git a/src/SDL_assert.c b/src/SDL_assert.c
index 1ca083ad4c..5a9556d4ec 100644
--- a/src/SDL_assert.c
+++ b/src/SDL_assert.c
@@ -178,6 +178,7 @@ SDL_PromptAssertion(const SDL_assert_data *data, void *userdata)
(void) userdata; /* unused in default handler. */
+ /* !!! FIXME: why is this using SDL_stack_alloc and not just "char message[SDL_MAX_LOG_MESSAGE];" ? */
message = SDL_stack_alloc(char, SDL_MAX_LOG_MESSAGE);
if (!message) {
/* Uh oh, we're in real trouble now... */
diff --git a/src/SDL_internal.h b/src/SDL_internal.h
index e0ba2a82c3..f8215bf34a 100644
--- a/src/SDL_internal.h
+++ b/src/SDL_internal.h
@@ -35,6 +35,10 @@
#define SDL_VARIABLE_LENGTH_ARRAY
#endif
+#define SDL_MAX_SMALL_ALLOC_STACKSIZE 128
+#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))) )
+#define SDL_small_free(ptr, isstack) if ((isstack)) { SDL_stack_free(ptr); } else { SDL_free(ptr); }
+
#include "dynapi/SDL_dynapi.h"
#if SDL_DYNAMIC_API
diff --git a/src/SDL_log.c b/src/SDL_log.c
index b1bf27d7a1..b89f7ee3a8 100644
--- a/src/SDL_log.c
+++ b/src/SDL_log.c
@@ -282,6 +282,7 @@ SDL_LogMessageV(int category, SDL_LogPriority priority, const char *fmt, va_list
return;
}
+ /* !!! FIXME: why not just "char message[SDL_MAX_LOG_MESSAGE];" ? */
message = SDL_stack_alloc(char, SDL_MAX_LOG_MESSAGE);
if (!message) {
return;
@@ -321,6 +322,7 @@ SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
char *output;
size_t length;
LPTSTR tstr;
+ SDL_bool isstack;
#if !defined(HAVE_STDIO_H) && !defined(__WINRT__)
BOOL attachResult;
@@ -364,7 +366,7 @@ SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
#endif /* !defined(HAVE_STDIO_H) && !defined(__WINRT__) */
length = SDL_strlen(SDL_priority_prefixes[priority]) + 2 + SDL_strlen(message) + 1 + 1 + 1;
- output = SDL_stack_alloc(char, length);
+ output = SDL_small_alloc(char, length, &isstack);
SDL_snprintf(output, length, "%s: %s\r\n", SDL_priority_prefixes[priority], message);
tstr = WIN_UTF8ToString(output);
@@ -389,7 +391,7 @@ SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
#endif /* !defined(HAVE_STDIO_H) && !defined(__WINRT__) */
SDL_free(tstr);
- SDL_stack_free(output);
+ SDL_small_free(output, isstack);
}
#elif defined(__ANDROID__)
{
@@ -404,7 +406,7 @@ SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
extern void SDL_NSLog(const char *text);
{
char *text;
-
+ /* !!! FIXME: why not just "char text[SDL_MAX_LOG_MESSAGE];" ? */
text = SDL_stack_alloc(char, SDL_MAX_LOG_MESSAGE);
if (text) {
SDL_snprintf(text, SDL_MAX_LOG_MESSAGE, "%s: %s", SDL_priority_prefixes[priority], message);
diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c
index a56575e09d..2c6115fd9e 100644
--- a/src/core/android/SDL_android.c
+++ b/src/core/android/SDL_android.c
@@ -481,10 +481,11 @@ JNIEXPORT int JNICALL SDL_JAVA_INTERFACE(nativeRunMain)(JNIEnv* env, jclass cls,
int argc;
int len;
char **argv;
+ SDL_bool isstack;
/* Prepare the arguments. */
len = (*env)->GetArrayLength(env, array);
- argv = SDL_stack_alloc(char*, 1 + len + 1);
+ argv = SDL_small_alloc(char*, 1 + len + 1, &isstack); /* !!! FIXME: check for NULL */
argc = 0;
/* Use the name "app_process" so PHYSFS_platformCalcBaseDir() works.
https://bitbucket.org/MartinFelis/love-android-sdl2/issue/23/release-build-crash-on-start
@@ -517,7 +518,7 @@ JNIEXPORT int JNICALL SDL_JAVA_INTERFACE(nativeRunMain)(JNIEnv* env, jclass cls,
for (i = 0; i < argc; ++i) {
SDL_free(argv[i]);
}
- SDL_stack_free(argv);
+ SDL_small_free(argv, isstack);
} else {
__android_log_print(ANDROID_LOG_ERROR, "SDL", "nativeRunMain(): Couldn't find function %s in library %s", function_name, library_file);
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index 745421382c..73767fbaef 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -701,3 +701,14 @@
#define SDL_JoystickGetDevicePlayerIndex SDL_JoystickGetDevicePlayerIndex_REAL
#define SDL_JoystickGetPlayerIndex SDL_JoystickGetPlayerIndex_REAL
#define SDL_GameControllerGetPlayerIndex SDL_GameControllerGetPlayerIndex_REAL
+#define SDL_RenderFlush SDL_RenderFlush_REAL
+#define SDL_RenderDrawPointF SDL_RenderDrawPointF_REAL
+#define SDL_RenderDrawPointsF SDL_RenderDrawPointsF_REAL
+#define SDL_RenderDrawLineF SDL_RenderDrawLineF_REAL
+#define SDL_RenderDrawLinesF SDL_RenderDrawLinesF_REAL
+#define SDL_RenderDrawRectF SDL_RenderDrawRectF_REAL
+#define SDL_RenderDrawRectsF SDL_RenderDrawRectsF_REAL
+#define SDL_RenderFillRectF SDL_RenderFillRectF_REAL
+#define SDL_RenderFillRectsF SDL_RenderFillRectsF_REAL
+#define SDL_RenderCopyF SDL_RenderCopyF_REAL
+#define SDL_RenderCopyExF SDL_RenderCopyExF_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index 0a1f3aefa5..076205ef09 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -755,3 +755,14 @@ SDL_DYNAPI_PROC(SDL_Thread*,SDL_CreateThreadWithStackSize,(SDL_ThreadFunction a,
SDL_DYNAPI_PROC(int,SDL_JoystickGetDevicePlayerIndex,(int a),(a),return)
SDL_DYNAPI_PROC(int,SDL_JoystickGetPlayerIndex,(SDL_Joystick *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_GameControllerGetPlayerIndex,(SDL_GameController *a),(a),return)
+SDL_DYNAPI_PROC(int,SDL_RenderFlush,(SDL_Renderer *a),(a),return)
+SDL_DYNAPI_PROC(int,SDL_RenderDrawPointF,(SDL_Renderer *a, float b, float c),(a,b,c),return)
+SDL_DYNAPI_PROC(int,SDL_RenderDrawPointsF,(SDL_Renderer *a, const SDL_FPoint *b, int c),(a,b,c),return)
+SDL_DYNAPI_PROC(int,SDL_RenderDrawLineF,(SDL_Renderer *a, float b, float c, float d, float e),(a,b,c,d,e),return)
+SDL_DYNAPI_PROC(int,SDL_RenderDrawLinesF,(SDL_Renderer *a, const SDL_FPoint *b, int c),(a,b,c),return)
+SDL_DYNAPI_PROC(int,SDL_RenderDrawRectF,(SDL_Renderer *a, const SDL_FRect *b),(a,b),return)
+SDL_DYNAPI_PROC(int,SDL_RenderDrawRectsF,(SDL_Renderer *a, const SDL_FRect *b, int c),(a,b,c),return)
+SDL_DYNAPI_PROC(int,SDL_RenderFillRectF,(SDL_Renderer *a, const SDL_FRect *b),(a,b),return)
+SDL_DYNAPI_PROC(int,SDL_RenderFillRectsF,(SDL_Renderer *a, const SDL_FRect *b, int c),(a,b,c),return)
+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)
+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)
diff --git a/src/file/SDL_rwops.c b/src/file/SDL_rwops.c
index cf5d3aa0b9..5b0969d56f 100644
--- a/src/file/SDL_rwops.c
+++ b/src/file/SDL_rwops.c
@@ -528,6 +528,7 @@ SDL_RWFromFile(const char *file, const char *mode)
char *path;
FILE *fp;
+ /* !!! FIXME: why not just "char path[PATH_MAX];" ? */
path = SDL_stack_alloc(char, PATH_MAX);
if (path) {
SDL_snprintf(path, PATH_MAX, "%s/%s",
diff --git a/src/joystick/SDL_gamecontroller.c b/src/joystick/SDL_gamecontroller.c
index eb1ef06546..65645f187d 100644
--- a/src/joystick/SDL_gamecontroller.c
+++ b/src/joystick/SDL_gamecontroller.c
@@ -202,13 +202,14 @@ static void UpdateEventsForDeviceRemoval()
{
int i, num_events;
SDL_Event *events;
+ SDL_bool isstack;
num_events = SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEADDED);
if (num_events <= 0) {
return;
}
- events = SDL_stack_alloc(SDL_Event, num_events);
+ events = SDL_small_alloc(SDL_Event, num_events, &isstack);
if (!events) {
return;
}
@@ -219,7 +220,7 @@ static void UpdateEventsForDeviceRemoval()
}
SDL_PeepEvents(events, num_events, SDL_ADDEVENT, 0, 0);
- SDL_stack_free(events);
+ SDL_small_free(events, isstack);
}
static SDL_bool HasSameOutput(SDL_ExtendedGameControllerBind *a, SDL_ExtendedGameControllerBind *b)
diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c
index 02903f5f96..8c784aec7f 100644
--- a/src/joystick/SDL_joystick.c
+++ b/src/joystick/SDL_joystick.c
@@ -777,13 +777,14 @@ static void UpdateEventsForDeviceRemoval()
{
int i, num_events;
SDL_Event *events;
+ SDL_bool isstack;
num_events = SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, SDL_JOYDEVICEADDED, SDL_JOYDEVICEADDED);
if (num_events <= 0) {
return;
}
- events = SDL_stack_alloc(SDL_Event, num_events);
+ events = SDL_small_alloc(SDL_Event, num_events, &isstack);
if (!events) {
return;
}
@@ -794,7 +795,7 @@ static void UpdateEventsForDeviceRemoval()
}
SDL_PeepEvents(events, num_events, SDL_ADDEVENT, 0, 0);
- SDL_stack_free(events);
+ SDL_small_free(events, isstack);
}
void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance)
diff --git a/src/loadso/dlopen/SDL_sysloadso.c b/src/loadso/dlopen/SDL_sysloadso.c
index 18b4b84369..ed89a211d7 100644
--- a/src/loadso/dlopen/SDL_sysloadso.c
+++ b/src/loadso/dlopen/SDL_sysloadso.c
@@ -61,12 +61,13 @@ SDL_LoadFunction(void *handle, const char *name)
void *symbol = dlsym(handle, name);
if (symbol == NULL) {
/* append an underscore for platforms that need that. */
+ SDL_bool isstack;
size_t len = 1 + SDL_strlen(name) + 1;
- char *_name = SDL_stack_alloc(char, len);
+ char *_name = SDL_small_alloc(char, len, &isstack);
_name[0] = '_';
SDL_strlcpy(&_name[1], name, len);
symbol = dlsym(handle, _name);
- SDL_stack_free(_name);
+ SDL_small_free(_name, isstack);
if (symbol == NULL) {
SDL_SetError("Failed loading %s: %s", name,
(const char *) dlerror());
diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c
index 4985b16ba2..6af7d10c17 100644
--- a/src/render/SDL_render.c
+++ b/src/render/SDL_render.c
@@ -105,6 +105,519 @@ static const SDL_RenderDriver *render_drivers[] = {
static char renderer_magic;
static char texture_magic;
+static SDL_INLINE void
+DebugLogRenderCommands(const SDL_RenderCommand *cmd)
+{
+#if 0
+ unsigned int i = 1;
+ SDL_Log("Render commands to flush:");
+ while (cmd) {
+ switch (cmd->command) {
+ case SDL_RENDERCMD_NO_OP:
+ SDL_Log(" %u. no-op", i++);
+ break;
+
+ case SDL_RENDERCMD_SETVIEWPORT:
+ SDL_Log(" %u. set viewport (first=%u, rect={(%d, %d), %dx%d})", i++,
+ (unsigned int) cmd->data.viewport.first,
+ cmd->data.viewport.rect.x, cmd->data.viewport.rect.y,
+ cmd->data.viewport.rect.w, cmd->data.viewport.rect.h);
+ break;
+
+ case SDL_RENDERCMD_SETCLIPRECT:
+ SDL_Log(" %u. set cliprect (enabled=%s, rect={(%d, %d), %dx%d})", i++,
+ cmd->data.cliprect.enabled ? "true" : "false",
+ cmd->data.cliprect.rect.x, cmd->data.cliprect.rect.y,
+ cmd->data.cliprect.rect.w, cmd->data.cliprect.rect.h);
+ break;
+
+ case SDL_RENDERCMD_SETDRAWCOLOR:
+ SDL_Log(" %u. set draw color (first=%u, r=%d, g=%d, b=%d, a=%d)", i++,
+ (unsigned int) cmd->data.color.first,
+ (int) cmd->data.color.r, (int) cmd->data.color.g,
+ (int) cmd->data.color.b, (int) cmd->data.color.a);
+ break;
+
+ case SDL_RENDERCMD_CLEAR:
+ SDL_Log(" %u. clear (first=%u, r=%d, g=%d, b=%d, a=%d)", i++,
+ (unsigned int) cmd->data.color.first,
+ (int) cmd->data.color.r, (int) cmd->data.color.g,
+ (int) cmd->data.color.b, (int) cmd->data.color.a);
+ break;
+
+ case SDL_RENDERCMD_DRAW_POINTS:
+ SDL_Log(" %u. draw points (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d)", i++,
+ (unsigned int) cmd->data.draw.first,
+ (unsigned int) cmd->data.draw.count,
+ (int) cmd->data.draw.r, (int) cmd->data.draw.g,
+ (int) cmd->data.draw.b, (int) cmd->data.draw.a,
+ (int) cmd->data.draw.blend);
+ break;
+
+ case SDL_RENDERCMD_DRAW_LINES:
+ SDL_Log(" %u. draw lines (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d)", i++,
+ (unsigned int) cmd->data.draw.first,
+ (unsigned int) cmd->data.draw.count,
+ (int) cmd->data.draw.r, (int) cmd->data.draw.g,
+ (int) cmd->data.draw.b, (int) cmd->data.draw.a,
+ (int) cmd->data.draw.blend);
+ break;
+
+ case SDL_RENDERCMD_FILL_RECTS:
+ SDL_Log(" %u. fill rects (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d)", i++,
+ (unsigned int) cmd->data.draw.first,
+ (unsigned int) cmd->data.draw.count,
+ (int) cmd->data.draw.r, (int) cmd->data.draw.g,
+ (int) cmd->data.draw.b, (int) cmd->data.draw.a,
+ (int) cmd->data.draw.blend);
+ break;
+
+ case SDL_RENDERCMD_COPY:
+ SDL_Log(" %u. copy (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d, tex=%p)", i++,
+ (unsigned int) cmd->data.draw.first,
+ (unsigned int) cmd->data.draw.count,
+ (int) cmd->data.draw.r, (int) cmd->data.draw.g,
+ (int) cmd->data.draw.b, (int) cmd->data.draw.a,
+ (int) cmd->data.draw.blend, cmd->data.draw.texture);
+ break;
+
+
+ case SDL_RENDERCMD_COPY_EX:
+ SDL_Log(" %u. copyex (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d, tex=%p)", i++,
+ (unsigned int) cmd->data.draw.first,
+ (unsigned int) cmd->data.draw.count,
+ (int) cmd->data.draw.r, (int) cmd->data.draw.g,
+ (int) cmd->data.draw.b, (int) cmd->data.draw.a,
+ (int) cmd->data.draw.blend, cmd->data.draw.texture);
+ break;
+ }
+ cmd = cmd->next;
+ }
+#endif
+}
+
+static int
+FlushRenderCommands(SDL_Renderer *renderer)
+{
+ SDL_AllocVertGap *prevgap = &renderer->vertex_data_gaps;
+ SDL_AllocVertGap *gap = prevgap;
+ int retval;
+
+ SDL_assert((renderer->render_commands == NULL) == (renderer->render_commands_tail == NULL));
+
+ if (renderer->render_commands == NULL) { /* nothing to do! */
+ SDL_assert(renderer->vertex_data_used == 0);
+ return 0;
+ }
+
+ DebugLogRenderCommands(renderer->render_commands);
+
+ retval = renderer->RunCommandQueue(renderer, renderer->render_commands, renderer->vertex_data, renderer->vertex_data_used);
+
+ while (gap) {
+ prevgap = gap;
+ gap = gap->next;
+ }
+ prevgap->next = renderer->vertex_data_gaps_pool;
+ renderer->vertex_data_gaps_pool = renderer->vertex_data_gaps.next;
+ renderer->vertex_data_gaps.next = NULL;
+
+ /* Move the whole render command queue to the unused pool so we can reuse them next time. */
+ if (renderer->render_commands_tail != NULL) {
+ renderer->render_commands_tail->next = renderer->render_commands_pool;
+ renderer->render_commands_pool = renderer->render_commands;
+ renderer->render_commands_tail = NULL;
+ renderer->render_commands = NULL;
+ }
+ renderer->vertex_data_used = 0;
+ renderer->render_command_generation++;
+ renderer->color_queued = SDL_FALSE;
+ renderer->viewport_queued = SDL_FALSE;
+ renderer->cliprect_queued = SDL_FALSE;
+ return retval;
+}
+
+static int
+FlushRenderCommandsIfTextureNeeded(SDL_Texture *texture)
+{
+ SDL_Renderer *renderer = texture->renderer;
+ if (texture->last_command_generation == renderer->render_command_generation) {
+ /* the current command queue depends on this texture, flush the queue now before it changes */
+ return FlushRenderCommands(renderer);
+ }
+ return 0;
+}
+
+static SDL_INLINE int
+FlushRenderCommandsIfNotBatching(SDL_Renderer *renderer)
+{
+ return renderer->batching ? 0 : FlushRenderCommands(renderer);
+}
+
+int
+SDL_RenderFlush(SDL_Renderer * renderer)
+{
+ return FlushRenderCommands(renderer);
+}
+
+static SDL_AllocVertGap *
+AllocateVertexGap(SDL_Renderer *renderer)
+{
+ SDL_AllocVertGap *retval = renderer->vertex_data_gaps_pool;
+ if (retval) {
+ renderer->vertex_data_gaps_pool = retval->next;
+ retval->next = NULL;
+ } else {
+ retval = (SDL_AllocVertGap *) SDL_malloc(sizeof (SDL_AllocVertGap));
+ if (!retval) {
+ SDL_OutOfMemory();
+ }
+ }
+ return retval;
+}
+
+
+void *
+SDL_AllocateRenderVertices(SDL_Renderer *renderer, const size_t numbytes, const size_t alignment, size_t *offset)
+{
+ const size_t needed = renderer->vertex_data_used + numbytes + alignment;
+ size_t aligner, aligned;
+ void *retval;
+
+ SDL_AllocVertGap *prevgap = &renderer->vertex_data_gaps;
+ SDL_AllocVertGap *gap = prevgap->next;
+ while (gap) {
+ const size_t gapoffset = gap->offset;
+ aligner = (alignment && ((gap->offset % alignment) != 0)) ? (alignment - (gap->offset % alignment)) : 0;
+ aligned = gapoffset + aligner;
+
+ /* Can we use this gap? */
+ if ((aligner < gap->len) && ((gap->len - aligner) >= numbytes)) {
+ /* we either finished this gap off, trimmed the left, trimmed the right, or split it into two gaps. */
+ if (gap->len == numbytes) { /* finished it off, remove it */
+ SDL_assert(aligned == gapoffset);
+ prevgap->next = gap->next;
+ gap->next = renderer->vertex_data_gaps_pool;
+ renderer->vertex_data_gaps_pool = gap;
+ } else if (aligned == gapoffset) { /* trimmed the left */
+ gap->offset += numbytes;
+ gap->len -= numbytes;
+ } else if (((aligned - gapoffset) + numbytes) == gap->len) { /* trimmed the right */
+ gap->len -= numbytes;
+ } else { /* split into two gaps */
+ SDL_AllocVertGap *newgap = AllocateVertexGap(renderer);
+ if (!newgap) {
+ return NULL;
+ }
+ newgap->offset = aligned + numbytes;
+ newgap->len = gap->len - (aligner + numbytes);
+ newgap->next = gap->next;
+ // gap->offset doesn't change.
+ gap->len = aligner;
+ gap->next = newgap;
+ }
+
+ if (offset) {
+ *offset = aligned;
+ }
+ return ((Uint8 *) renderer->vertex_data) + aligned;
+ }
+
+ /* Try the next gap */
+ prevgap = gap;
+ gap = gap->next;
+ }
+
+ /* no gaps with enough space; get a new piece of the vertex buffer */
+ while (needed > renderer->vertex_data_allocation) {
+ const size_t current_allocation = renderer->vertex_data ? renderer->vertex_data_allocation : 1024;
+ const size_t newsize = current_allocation * 2;
+ void *ptr = SDL_realloc(renderer->vertex_data, newsize);
+ if (ptr == NULL) {
+ SDL_OutOfMemory();
+ return NULL;
+ }
+ renderer->vertex_data = ptr;
+ renderer->vertex_data_allocation = newsize;
+ }
+
+ aligner = (alignment && ((renderer->vertex_data_used % alignment) != 0)) ? (alignment - (renderer->vertex_data_used % alignment)) : 0;
+ aligned = renderer->vertex_data_used + aligner;
+
+ retval = ((Uint8 *) renderer->vertex_data) + aligned;
+ if (offset) {
+ *offset = aligned;
+ }
+
+ if (aligner) { /* made a new gap... */
+ SDL_AllocVertGap *newgap = AllocateVertexGap(renderer);
+ if (newgap) { /* just let it slide as lost space if malloc fails. */
+ newgap->offset = renderer->vertex_data_used;
+ newgap->len = aligner;
+ newgap->next = NULL;
+ prevgap->next = newgap;
+ }
+ }
+
+ renderer->vertex_data_used += aligner + numbytes;
+
+ return retval;
+}
+
+static SDL_RenderCommand *
+AllocateRenderCommand(SDL_Renderer *renderer)
+{
+ SDL_RenderCommand *retval = NULL;
+
+ /* !!! FIXME: are there threading limitations in SDL's render API? If not, we need to mutex this. */
+ retval = renderer->render_commands_pool;
+ if (retval != NULL) {
+ renderer->render_commands_pool = retval->next;
+ retval->next = NULL;
+ } else {
+ retval = SDL_calloc(1, sizeof (*retval));
+ if (!retval) {
+ SDL_OutOfMemory();
+ return NULL;
+ }
+ }
+
+ SDL_assert((renderer->render_commands == NULL) == (renderer->render_commands_tail == NULL));
+ if (renderer->render_commands_tail != NULL) {
+ renderer->render_commands_tail->next = retval;
+ } else {
+ renderer->render_commands = retval;
+ }
+ renderer->render_commands_tail = retval;
+
+ return retval;
+}
+
+static int
+QueueCmdSetViewport(SDL_Renderer *renderer)
+{
+ int retval = 0;
+ if (!renderer->viewport_queued || (SDL_memcmp(&renderer->viewport, &renderer->last_queued_viewport, sizeof (SDL_Rect)) != 0)) {
+ SDL_RenderCommand *cmd = AllocateRenderCommand(renderer);
+ retval = -1;
+ if (cmd != NULL) {
+ cmd->command = SDL_RENDERCMD_SETVIEWPORT;
+ cmd->data.viewport.first = 0; /* render backend will fill this in. */
+ SDL_memcpy(&cmd->data.viewport.rect, &renderer->viewport, sizeof (renderer->viewport));
+ retval = renderer->QueueSetViewport(renderer, cmd);
+ if (retval < 0) {
+ cmd->command = SDL_RENDERCMD_NO_OP;
+ } else {
+ SDL_memcpy(&renderer->last_queued_viewport, &renderer->viewport, sizeof (SDL_Rect));
+ renderer->viewport_queued = SDL_TRUE;
+ }
+ }
+ }
+ return retval;
+}
+
+static int
+QueueCmdSetClipRect(SDL_Renderer *renderer)
+{
+ int retval = 0;
+ if ((!renderer->cliprect_queued) ||
+ (renderer->clipping_enabled != renderer->last_queued_cliprect_enabled) ||
+ (SDL_memcmp(&renderer->clip_rect, &renderer->last_queued_cliprect, sizeof (SDL_Rect)) != 0)) {
+ SDL_RenderCommand *cmd = AllocateRenderCommand(renderer);
+ if (cmd == NULL) {
+ retval = -1;
+ } else {
+ cmd->command = SDL_RENDERCMD_SETCLIPRECT;
+ cmd->data.cliprect.enabled = renderer->clipping_enabled;
+ SDL_memcpy(&cmd->data.cliprect.rect, &renderer->clip_rect, sizeof (cmd->data.cliprect.rect));
+ SDL_memcpy(&renderer->last_queued_cliprect, &renderer->clip_rect, sizeof (SDL_Rect));
+ renderer->last_queued_cliprect_enabled = renderer->clipping_enabled;
+ renderer->cliprect_queued = SDL_TRUE;
+ }
+ }
+ return retval;
+}
+
+static int
+QueueCmdSetDrawColor(SDL_Renderer *renderer, const Uint8 r, const Uint8 g, const Uint8 b, const Uint8 a)
+{
+ const Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b);
+ int retval = 0;
+
+ if (!renderer->color_queued || (color != renderer->last_queued_color)) {
+ SDL_RenderCommand *cmd = AllocateRenderCommand(renderer);
+ retval = -1;
+
+ if (cmd != NULL) {
+ cmd->command = SDL_RENDERCMD_SETDRAWCOLOR;
+ cmd->data.color.first = 0; /* render backend will fill this in. */
+ cmd->data.color.r = r;
+ cmd->data.color.g = g;
+ cmd->data.color.b = b;
+ cmd->data.color.a = a;
+ retval = renderer->QueueSetDrawColor(renderer, cmd);
+ if (retval < 0) {
+ cmd->command = SDL_RENDERCMD_NO_OP;
+ } else {
+ renderer->last_queued_color = color;
+ renderer->color_queued = SDL_TRUE;
+ }
+ }
+ }
+ return retval;
+}
+
+static int
+QueueCmdClear(SDL_Renderer *renderer)
+{
+ SDL_RenderCommand *cmd = AllocateRenderCommand(renderer);
+ if (cmd == NULL) {
+ return -1;
+ }
+
+ cmd->command = SDL_RENDERCMD_CLEAR;
+ cmd->data.color.first = 0;
+ cmd->data.color.r = renderer->r;
+ cmd->data.color.g = renderer->g;
+ cmd->data.color.b = renderer->b;
+ cmd->data.color.a = renderer->a;
+ return 0;
+}
+
+static int
+PrepQueueCmdDraw(SDL_Renderer *renderer, const Uint8 r, const Uint8 g, const Uint8 b, const Uint8 a)
+{
+ int retval = 0;
+ if (retval == 0) {
+ retval = QueueCmdSetDrawColor(renderer, r, g, b, a);
+ }
+ if (retval == 0) {
+ retval = QueueCmdSetViewport(renderer);
+ }
+ if (retval == 0) {
+ retval = QueueCmdSetClipRect(renderer);
+ }
+ return retval;
+}
+
+static SDL_RenderCommand *
+PrepQueueCmdDrawSolid(SDL_Renderer *renderer, const SDL_RenderCommandType cmdtype)
+{
+ /* !!! FIXME: drop this draw if viewport w or h is zero. */
+ SDL_RenderCommand *cmd = NULL;
+ if (PrepQueueCmdDraw(renderer, renderer->r, renderer->g, renderer->b, renderer->a) == 0) {
+ cmd = AllocateRenderCommand(renderer);
+ if (cmd != NULL) {
+ cmd->command = cmdtype;
+ cmd->data.draw.first = 0; /* render backend will fill this in. */
+ cmd->data.draw.count = 0; /* render backend will fill this in. */
+ cmd->data.draw.r = renderer->r;
+ cmd->data.draw.g = renderer->g;
+ cmd->data.draw.b = renderer->b;
+ cmd->data.draw.a = renderer->a;
+ cmd->data.draw.blend = renderer->blendMode;
+ cmd->data.draw.texture = NULL; /* no texture. */
+ }
+ }
+ return cmd;
+}
+
+static int
+QueueCmdDrawPoints(SDL_Renderer *renderer, const SDL_FPoint * points, const int count)
+{
+ SDL_RenderCommand *cmd = PrepQueueCmdDrawSolid(renderer, SDL_RENDERCMD_DRAW_POINTS);
+ int retval = -1;
+ if (cmd != NULL) {
+ retval = renderer->QueueDrawPoints(renderer, cmd, points, count);
+ if (retval < 0) {
+ cmd->command = SDL_RENDERCMD_NO_OP;
+ }
+ }
+ return retval;
+}
+
+static int
+QueueCmdDrawLines(SDL_Renderer *renderer, const SDL_FPoint * points, const int count)
+{
+ SDL_RenderCommand *cmd = PrepQueueCmdDrawSolid(renderer, SDL_RENDERCMD_DRAW_LINES);
+ int retval = -1;
+ if (cmd != NULL) {
+ retval = renderer->QueueDrawLines(renderer, cmd, points, count);
+ if (retval < 0) {
+ cmd->command = SDL_RENDERCMD_NO_OP;
+ }
+ }
+ return retval;
+}
+
+static int
+QueueCmdFillRects(SDL_Renderer *renderer, const SDL_FRect * rects, const int count)
+{
+ SDL_RenderCommand *cmd = PrepQueueCmdDrawSolid(renderer, SDL_RENDERCMD_FILL_RECTS);
+ int retval = -1;
+ if (cmd != NULL) {
+ retval = renderer->QueueFillRects(renderer, cmd, rects, count);
+ if (retval < 0) {
+ cmd->command = SDL_RENDERCMD_NO_OP;
+ }
+ }
+ return retval;
+}
+
+static SDL_RenderCommand *
+PrepQueueCmdDrawTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_RenderCommandType cmdtype)
+{
+ /* !!! FIXME: drop this draw if viewport w or h is zero. */
+ SDL_RenderCommand *cmd = NULL;
+ if (PrepQueueCmdDraw(renderer, texture->r, texture->g, texture->b, texture->a) == 0) {
+ cmd = AllocateRenderCommand(renderer);
+ if (cmd != NULL) {
+ cmd->command = cmdtype;
+ cmd->data.draw.first = 0; /* render backend will fill this in. */
+ cmd->data.draw.count = 0; /* render backend will fill this in. */
+ cmd->data.draw.r = texture->r;
+ cmd->data.draw.g = texture->g;
+ cmd->data.draw.b = texture->b;
+ cmd->data.draw.a = texture->a;
+ cmd->data.draw.blend = texture->blendMode;
+ cmd->data.draw.texture = texture;
+ }
+ }
+ return cmd;
+}
+
+static int
+QueueCmdCopy(SDL_Renderer *renderer, SDL_Texture * texture, const SDL_Rect * srcrect, const SDL_FRect * dstrect)
+{
+ SDL_RenderCommand *cmd = PrepQueueCmdDrawTexture(renderer, texture, SDL_RENDERCMD_COPY);
+ int retval = -1;
+ if (cmd != NULL) {
+ retval = renderer->QueueCopy(renderer, cmd, texture, srcrect, dstrect);
+ if (retval < 0) {
+ cmd->command = SDL_RENDERCMD_NO_OP;
+ }
+ }
+ return retval;
+}
+
+static int
+QueueCmdCopyEx(SDL_Renderer *renderer, SDL_Texture * texture,
+ const SDL_Rect * srcquad, const SDL_FRect * dstrect,
+ const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
+{
+ SDL_RenderCommand *cmd = PrepQueueCmdDrawTexture(renderer, texture, SDL_RENDERCMD_COPY_EX);
+ int retval = -1;
+ SDL_assert(renderer->QueueCopyEx != NULL); /* should have caught at higher level. */
+ if (cmd != NULL) {
+ retval = renderer->QueueCopyEx(renderer, cmd, texture, srcquad, dstrect, angle, center, flip);
+ if (retval < 0) {
+ cmd->command = SDL_RENDERCMD_NO_OP;
+ }
+ }
+ return retval;
+}
+
+
static int UpdateLogicalSize(SDL_Renderer *renderer);
int
@@ -183,7 +696,8 @@ SDL_RendererEventWatch(void *userdata, SDL_Event *event)
renderer->viewport.y = 0;
renderer->viewport.w = w;
renderer->viewport.h = h;
- renderer->UpdateViewport(renderer);
+ QueueCmdSetViewport(renderer);
+ FlushRenderCommandsIfNotBatching(renderer);
}
}
@@ -300,12 +814,27 @@ SDL_CreateWindowAndRenderer(int width, int height, Uint32 window_flags,
return 0;
}
+static SDL_INLINE
+void VerifyDrawQueueFunctions(const SDL_Renderer *renderer)
+{
+ /* all of these functions are required to be implemented, even as no-ops, so we don't
+ have to check that they aren't NULL over and over. */
+ SDL_assert(renderer->QueueSetViewport != NULL);
+ SDL_assert(renderer->QueueSetDrawColor != NULL);
+ SDL_assert(renderer->QueueDrawPoints != NULL);
+ SDL_assert(renderer->QueueDrawLines != NULL);
+ SDL_assert(renderer->QueueFillRects != NULL);
+ SDL_assert(renderer->QueueCopy != NULL);
+ SDL_assert(renderer->RunCommandQueue != NULL);
+}
+
SDL_Renderer *
SDL_CreateRenderer(SDL_Window * window, int index, Uint32 flags)
{
#if !SDL_RENDER_DISABLED
SDL_Renderer *renderer = NULL;
int n = SDL_GetNumRenderDrivers();
+ SDL_bool batching = SDL_TRUE;
const char *hint;
if (!window) {
@@ -335,6 +864,9 @@ SDL_CreateRenderer(SDL_Window * window, int index, Uint32 flags)
if (SDL_strcasecmp(hint, driver->info.name) == 0) {
/* Create a new renderer instance */
renderer = driver->CreateRenderer(window, flags);
+ if (renderer) {
+ batching = SDL_FALSE;
+ }
break;
}
}
@@ -366,9 +898,20 @@ SDL_CreateRenderer(SDL_Window * window, int index, Uint32 flags)
}
/* Create a new renderer instance */
renderer = render_drivers[index]->CreateRenderer(window, flags);
+ batching = SDL_FALSE;
}
if (renderer) {
+ VerifyDrawQueueFunctions(renderer);
+
+ /* let app/user override batching decisions. */
+ if (renderer->always_batch) {
+ batching = SDL_TRUE;
+ } else if (SDL_GetHint(SDL_HINT_RENDER_BATCHING)) {
+ batching = SDL_GetHintBoolean(SDL_HINT_RENDER_BATCHING, SDL_TRUE);
+ }
+
+ renderer->batching = batching;
renderer->magic = &renderer_magic;
renderer->window = window;
renderer->target_mutex = SDL_CreateMutex();
@@ -377,6 +920,9 @@ SDL_CreateRenderer(SDL_Window * window, int index, Uint32 flags)
renderer->dpi_scale.x = 1.0f;
renderer->dpi_scale.y = 1.0f;
+ /* new textures start at zero, so we start at 1 so first render doesn't flush by accident. */
+ renderer->render_command_generation = 1;
+
if (window && renderer->GetOutputSize) {
int window_w, window_h;
int output_w, output_h;
@@ -418,11 +964,15 @@ SDL_CreateSoftwareRenderer(SDL_Surface * surface)
renderer = SW_CreateRendererForSurface(surface);
if (renderer) {
+ VerifyDrawQueueFunctions(renderer);
renderer->magic = &renderer_magic;
renderer->target_mutex = SDL_CreateMutex();
renderer->scale.x = 1.0f;
renderer->scale.y = 1.0f;
+ /* new textures start at zero, so we start at 1 so first render doesn't flush by accident. */
+ renderer->render_command_generation = 1;
+
SDL_RenderSetViewport(renderer, NULL);
}
return renderer;
@@ -744,11 +1294,8 @@ SDL_QueryTexture(SDL_Texture * texture, Uint32 * format, int *access,
int
SDL_SetTextureColorMod(SDL_Texture * texture, Uint8 r, Uint8 g, Uint8 b)
{
- SDL_Renderer *renderer;
-
CHECK_TEXTURE_MAGIC(texture, -1);
- renderer = texture->renderer;
if (r < 255 || g < 255 || b < 255) {
texture->modMode |= SDL_TEXTUREMODULATE_COLOR;
} else {
@@ -759,11 +1306,8 @@ SDL_SetTextureColorMod(SDL_Texture * texture, Uint8 r, Uint8 g, Uint8 b)
texture->b = b;
if (texture->native) {
return SDL_SetTextureColorMod(texture->native, r, g, b);
- } else if (renderer->SetTextureColorMod) {
- return renderer->SetTextureColorMod(renderer, texture);
- } else {
- return 0;
}
+ return 0;
}
int
@@ -787,11 +1331,8 @@ SDL_GetTextureColorMod(SDL_Texture * texture, Uint8 * r, Uint8 * g,
int
SDL_SetTextureAlphaMod(SDL_Texture * texture, Uint8 alpha)
{
- SDL_Renderer *renderer;
-
CHECK_TEXTURE_MAGIC(texture, -1);
- renderer = texture->renderer;
if (alpha < 255) {
texture->modMode |= SDL_TEXTUREMODULATE_ALPHA;
} else {
@@ -800,11 +1341,8 @@ SDL_SetTextureAlphaMod(SDL_Texture * texture, Uint8 alpha)
texture->a = alpha;
if (texture->native) {
return SDL_SetTextureAlphaMod(texture->native, alpha);
- } else if (renderer->SetTextureAlphaMod) {
- return renderer->SetTextureAlphaMod(renderer, texture);
- } else {
- return 0;
}
+ return 0;
}
int
@@ -832,11 +1370,8 @@ SDL_SetTextureBlendMode(SDL_Texture * texture, SDL_BlendMode blendMode)
texture->blendMode = blendMode;
if (texture->native) {
return SDL_SetTextureBlendMode(texture->native, blendMode);
- } else if (renderer->SetTextureBlendMode) {
- return renderer->SetTextureBlendMode(renderer, texture);
- } else {
- return 0;
}
+ return 0;
}
int
@@ -941,7 +1476,6 @@ int
SDL_UpdateTexture(SDL_Texture * texture, const SDL_Rect * rect,
const void *pixels, int pitch)
{
- SDL_Renderer *renderer;
SDL_Rect full_rect;
CHECK_TEXTURE_MAGIC(texture, -1);
@@ -968,7 +1502,10 @@ SDL_UpdateTexture(SDL_Texture * texture, const SDL_Rect * rect,
} else if (texture->native) {
return SDL_UpdateTextureNative(texture, rect, pixels, pitch);
} else {
- renderer = texture->renderer;
+ SDL_Renderer *renderer = texture->renderer;
+ if (FlushRenderCommandsIfTextureNeeded(texture) < 0) {
+ return -1;
+ }
return renderer->UpdateTexture(renderer, texture, rect, pixels, pitch);
}
}
@@ -1078,6 +1615,9 @@ int SDL_UpdateYUVTexture(SDL_Texture * texture, const SDL_Rect * rect,
renderer = texture->renderer;
SDL_assert(renderer->UpdateTextureYUV);
if (renderer->UpdateTextureYUV) {
+ if (FlushRenderCommandsIfTextureNeeded(texture) < 0) {
+ return -1;
+ }
return renderer->UpdateTextureYUV(renderer, texture, rect, Yplane, Ypitch, Uplane, Upitch, Vplane, Vpitch);
} else {
return SDL_Unsupported();
@@ -1108,7 +1648,6 @@ int
SDL_LockTexture(SDL_Texture * texture, const SDL_Rect * rect,
void **pixels, int *pitch)
{
- SDL_Renderer *renderer;
SDL_Rect full_rect;
CHECK_TEXTURE_MAGIC(texture, -1);
@@ -1126,11 +1665,18 @@ SDL_LockTexture(SDL_Texture * texture, const SDL_Rect * rect,
}
if (texture->yuv) {
+ if (FlushRenderCommandsIfTextureNeeded(texture) < 0) {
+ return -1;
+ }
return SDL_LockTextureYUV(texture, rect, pixels, pitch);
} else if (texture->native) {
+ /* Calls a real SDL_LockTexture/SDL_UnlockTexture on unlock, flushing then. */
return SDL_LockTextureNative(texture, rect, pixels, pitch);
} else {
- renderer = texture->renderer;
+ SDL_Renderer *renderer = texture->renderer;
+ if (FlushRenderCommandsIfTextureNeeded(texture) < 0) {
+ return -1;
+ }
return renderer->LockTexture(renderer, texture, rect, pixels, pitch);
}
}
@@ -1180,8 +1726,6 @@ SDL_UnlockTextureNative(SDL_Texture * texture)
void
SDL_UnlockTexture(SDL_Texture * texture)
{
- SDL_Renderer *renderer;
-
CHECK_TEXTURE_MAGIC(texture, );
if (texture->access != SDL_TEXTUREACCESS_STREAMING) {
@@ -1192,7 +1736,7 @@ SDL_UnlockTexture(SDL_Texture * texture)
} else if (texture->native) {
SDL_UnlockTextureNative(texture);
} else {
- renderer = texture->renderer;
+ SDL_Renderer *renderer = texture->renderer;
renderer->UnlockTexture(renderer, texture);
}
}
@@ -1217,6 +1761,8 @@ SDL_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
return 0;
}
+ FlushRenderCommands(renderer); /* time to send everything to the GPU! */
+
/* texture == NULL is valid and means reset the target to the window */
if (texture) {
CHECK_TEXTURE_MAGIC(texture, -1);
@@ -1272,15 +1818,15 @@ SDL_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
SDL_UnlockMutex(renderer->target_mutex);
- if (renderer->UpdateViewport(renderer) < 0) {
+ if (QueueCmdSetViewport(renderer) < 0) {
return -1;
}
- if (renderer->UpdateClipRect(renderer) < 0) {
+ if (QueueCmdSetClipRect(renderer) < 0) {
return -1;
}
/* All set! */
- return 0;
+ return FlushRenderCommandsIfNotBatching(renderer);
}
SDL_Texture *
@@ -1452,6 +1998,7 @@ SDLCALL SDL_RenderGetIntegerScale(SDL_Renderer * renderer)
int
SDL_RenderSetViewport(SDL_Renderer * renderer, const SDL_Rect * rect)
{
+ int retval;
CHECK_RENDERER_MAGIC(renderer, -1);
if (rect) {
@@ -1466,7 +2013,8 @@ SDL_RenderSetViewport(SDL_Renderer * renderer, const SDL_Rect * rect)
return -1;
}
}
- return renderer->UpdateViewport(renderer);
+ retval = QueueCmdSetViewport(renderer);
+ return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
}
void
@@ -1485,6 +2033,7 @@ SDL_RenderGetViewport(SDL_Renderer * renderer, SDL_Rect * rect)
int
SDL_RenderSetClipRect(SDL_Renderer * renderer, const SDL_Rect * rect)
{
+ int retval;
CHECK_RENDERER_MAGIC(renderer, -1)
if (rect) {
@@ -1497,7 +2046,9 @@ SDL_RenderSetClipRect(SDL_Renderer * renderer, const SDL_Rect * rect)
renderer->clipping_enabled = SDL_FALSE;
SDL_zero(renderer->clip_rect);
}
- return renderer->UpdateClipRect(renderer);
+
+ retval = QueueCmdSetClipRect(renderer);
+ return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
}
void
@@ -1601,37 +2152,43 @@ SDL_GetRenderDrawBlendMode(SDL_Renderer * renderer, SDL_BlendMode *blendMode)
int
SDL_RenderClear(SDL_Renderer * renderer)
{
+ int retval;
CHECK_RENDERER_MAGIC(renderer, -1);
-
- /* Don't draw while we're hidden */
- if (renderer->hidden) {
- return 0;
- }
- return renderer->RenderClear(renderer);
+ retval = QueueCmdClear(renderer);
+ return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
}
+
+/* !!! FIXME: delete all the duplicate code for the integer versions in 2.1,
+ !!! FIXME: making the floating point versions the only available APIs. */
+
int
SDL_RenderDrawPoint(SDL_Renderer * renderer, int x, int y)
{
- SDL_Point point;
+ const SDL_FPoint fpoint = { (float) x, (float) y };
+ return SDL_RenderDrawPointsF(renderer, &fpoint, 1);
+}
- point.x = x;
- point.y = y;
- return SDL_RenderDrawPoints(renderer, &point, 1);
+int
+SDL_RenderDrawPointF(SDL_Renderer * renderer, float x, float y)
+{
+ const SDL_FPoint fpoint = { x, y };
+ return SDL_RenderDrawPointsF(renderer, &fpoint, 1);
}
static int
RenderDrawPointsWithRects(SDL_Renderer * renderer,
- const SDL_Point * points, int count)
+ const SDL_Point * points, const int count)
{
- SDL_FRect *frects;
+ int retval = -1;
+ SDL_bool isstack;
+ SDL_FRect *frects = SDL_small_alloc(SDL_FRect, count, &isstack);
int i;
- int status;
- frects = SDL_stack_alloc(SDL_FRect, count);
if (!frects) {
return SDL_OutOfMemory();
}
+
for (i = 0; i < count; ++i) {
frects[i].x = points[i].x * renderer->scale.x;
frects[i].y = points[i].y * renderer->scale.y;
@@ -1639,11 +2196,11 @@ RenderDrawPointsWithRects(SDL_Renderer * renderer,
frects[i].h = renderer->scale.y;
}
- status = renderer->RenderFillRects(renderer, frects, count);
+ retval = QueueCmdFillRects(renderer, frects, count);
- SDL_stack_free(frects);
+ SDL_small_free(frects, isstack);
- return status;
+ return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
}
int
@@ -1652,7 +2209,8 @@ SDL_RenderDrawPoints(SDL_Renderer * renderer,
{
SDL_FPoint *fpoints;
int i;
- int status;
+ int retval;
+ SDL_bool isstack;
CHECK_RENDERER_MAGIC(renderer, -1);
@@ -1672,7 +2230,77 @@ SDL_RenderDrawPoints(SDL_Renderer * renderer,
return RenderDrawPointsWithRects(renderer, points, count);
}
- fpoints = SDL_stack_alloc(SDL_FPoint, count);
+ fpoints = SDL_small_alloc(SDL_FPoint, count, &isstack);
+ if (!fpoints) {
+ return SDL_OutOfMemory();
+ }
+ for (i = 0; i < count; ++i) {
+ fpoints[i].x = points[i].x * renderer->scale.x;
+ fpoints[i].y = points[i].y * renderer->scale.y;
+ }
+
+ retval = QueueCmdDrawPoints(renderer, fpoints, count);
+
+ SDL_small_free(fpoints, isstack);
+
+ return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
+}
+
+static int
+RenderDrawPointsWithRectsF(SDL_Renderer * renderer,
+ const SDL_FPoint * fpoints, const int count)
+{
+ int retval = -1;
+ SDL_bool isstack;
+ SDL_FRect *frects = SDL_small_alloc(SDL_FRect, count, &isstack);
+ int i;
+
+ if (!frects) {
+ return SDL_OutOfMemory();
+ }
+
+ for (i = 0; i < count; ++i) {
+ frects[i].x = fpoints[i].x * renderer->scale.x;
+ frects[i].y = fpoints[i].y * renderer->scale.y;
+ frects[i].w = renderer->scale.x;
+ frects[i].h = renderer->scale.y;
+ }
+
+ retval = QueueCmdFillRects(renderer, frects, count);
+
+ SDL_small_free(frects, isstack);
+
+ return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
+}
+
+int
+SDL_RenderDrawPointsF(SDL_Renderer * renderer,
+ const SDL_FPoint * points, int count)
+{
+ SDL_FPoint *fpoints;
+ int i;
+ int retval;
+ SDL_bool isstack;
+
+ CHECK_RENDERER_MAGIC(renderer, -1);
+
+ if (!points) {
+ return SDL_SetError("SDL_RenderDrawFPoints(): Passed NULL points");
+ }
+ if (count < 1) {
+ return 0;
+ }
+
+ /* Don't draw while we're hidden */
+ if (renderer->hidden) {
+ return 0;
+ }
+
+ if (renderer->scale.x != 1.0f || renderer->scale.y != 1.0f) {
+ return RenderDrawPointsWithRectsF(renderer, points, count);
+ }
+
+ fpoints = SDL_small_alloc(SDL_FPoint, count, &isstack);
if (!fpoints) {
return SDL_OutOfMemory();
}
@@ -1681,46 +2309,102 @@ SDL_RenderDrawPoints(SDL_Renderer * renderer,
fpoints[i].y = points[i].y * renderer->scale.y;
}
- status = renderer->RenderDrawPoints(renderer, fpoints, count);
+ retval = QueueCmdDrawPoints(renderer, fpoints, count);
- SDL_stack_free(fpoints);
+ SDL_small_free(fpoints, isstack);
- return status;
+ return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
}
int
SDL_RenderDrawLine(SDL_Renderer * renderer, int x1, int y1, int x2, int y2)
{
- SDL_Point points[2];
+ const SDL_FPoint points[2] = { { (float) x1, (float) y1 }, { (float) x2, (float) y2 } };
+ return SDL_RenderDrawLinesF(renderer, points, 2);
+}
- points[0].x = x1;
- points[0].y = y1;
- points[1].x = x2;
- points[1].y = y2;
- return SDL_RenderDrawLines(renderer, points, 2);
+int
+SDL_RenderDrawLineF(SDL_Renderer * renderer, float x1, float y1, float x2, float y2)
+{
+ const SDL_FPoint points[2] = { { x1, y1 }, { x2, y2 } };
+ return SDL_RenderDrawLinesF(renderer, points, 2);
}
static int
RenderDrawLinesWithRects(SDL_Renderer * renderer,
- const SDL_Point * points, int count)
+ const SDL_Point * points, const int count)
+{
+ SDL_FRect *frect;
+ SDL_FRect *frects;
+ SDL_FPoint fpoints[2];
+ int i, nrects = 0;
+ int retval = 0;
+ SDL_bool isstack;
+
+ frects = SDL_small_alloc(SDL_FRect, count-1, &isstack);
+ if (!frects) {
+ return SDL_OutOfMemory();
+ }
+
+ for (i = 0; i < count-1; ++i) {
+ if (points[i].x == points[i+1].x) {
+ const int minY = SDL_min(points[i].y, points[i+1].y);
+ const int maxY = SDL_max(points[i].y, points[i+1].y);
+
+ frect = &frects[nrects++];
+ frect->x = points[i].x * renderer->scale.x;
+ frect->y = minY * renderer->scale.y;
+ frect->w = renderer->scale.x;
+ frect->h = (maxY - minY + 1) * renderer->scale.y;
+ } else if (points[i].y == points[i+1].y) {
+ const int minX = SDL_min(points[i].x, points[i+1].x);
+ const int maxX = SDL_max(points[i].x, points[i+1].x);
+
+ frect = &frects[nrects++];
+ frect->x = minX * renderer->scale.x;
+ frect->y = points[i].y * renderer->scale.y;
+ frect->w = (maxX - minX + 1) * renderer->scale.x;
+ frect->h = renderer->scale.y;
+ } else {
+ /* FIXME: We can't use a rect for this line... */
+ fpoints[0].x = points[i].x * renderer->scale.x;
+ fpoints[0].y = points[i].y * renderer->scale.y;
+ fpoints[1].x = points[i+1].x * renderer->scale.x;
+ fpoints[1].y = points[i+1].y * renderer->scale.y;
+ retval += QueueCmdDrawLines(renderer, fpoints, 2);
+ }
+ }
+
+ retval += QueueCmdFillRects(renderer, frects, nrects);
+
+ SDL_small_free(frects, isstack);
+
+ if (retval < 0) {
+ retval = -1;
+ }
+ return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
+}
+
+static int
+RenderDrawLinesWithRectsF(SDL_Renderer * renderer,
+ const SDL_FPoint * points, const int count)
{
SDL_FRect *frect;
SDL_FRect *frects;
SDL_FPoint fpoints[2];
- int i, nrects;
- int status;
+ int i, nrects = 0;
+ int retval = 0;
+ SDL_bool isstack;
- frects = SDL_stack_alloc(SDL_FRect, count-1);
+ frects = SDL_small_alloc(SDL_FRect, count-1, &isstack);
if (!frects) {
return SDL_OutOfMemory();
}
- status = 0;
- nrects = 0;
for (i = 0; i < count-1; ++i) {
if (points[i].x == points[i+1].x) {
- int minY = SDL_min(points[i].y, points[i+1].y);
- int maxY = SDL_max(points[i].y, points[i+1].y);
+ const int minY = SDL_min(points[i].y, points[i+1].y);
+ const int maxY = SDL_max(points[i].y, points[i+1].y);
frect = &frects[nrects++];
frect->x = points[i].x * renderer->scale.x;
@@ -1728,8 +2412,8 @@ RenderDrawLinesWithRects(SDL_Renderer * renderer,
frect->w = renderer->scale.x;
frect->h = (maxY - minY + 1) * renderer->scale.y;
} else if (points[i].y == points[i+1].y) {
- int minX = SDL_min(points[i].x, points[i+1].x);
- int maxX = SDL_max(points[i].x, points[i+1].x);
+ const int minX = SDL_min(points[i].x, points[i+1].x);
+ const int maxX = SDL_max(points[i].x, points[i+1].x);
frect = &frects[nrects++];
frect->x = minX * renderer->scale.x;
@@ -1742,18 +2426,18 @@ RenderDrawLinesWithRects(SDL_Renderer * renderer,
fpoints[0].y = points[i].y * renderer->scale.y;
fpoints[1].x = points[i+1].x * renderer->scale.x;
fpoints[1].y = points[i+1].y * renderer->scale.y;
- status += renderer->RenderDrawLines(renderer, fpoints, 2);
+ retval += QueueCmdDrawLines(renderer, fpoints, 2);
}
}
- status += renderer->RenderFillRects(renderer, frects, nrects);
+ retval += QueueCmdFillRects(renderer, frects, nrects);
- SDL_stack_free(frects);
+ SDL_small_free(frects, isstack);
- if (status < 0) {
- status = -1;
+ if (retval < 0) {
+ retval = -1;
}
- return status;
+ return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
}
int
@@ -1762,7 +2446,8 @@ SDL_RenderDrawLines(SDL_Renderer * renderer,
{
SDL_FPoint *fpoints;
int i;
- int status;
+ int retval;
+ SDL_bool isstack;
CHECK_RENDERER_MAGIC(renderer, -1);
@@ -1782,7 +2467,50 @@ SDL_RenderDrawLines(SDL_Renderer * renderer,
return RenderDrawLinesWithRects(renderer, points, count);
}
- fpoints = SDL_stack_alloc(SDL_FPoint, count);
+ fpoints = SDL_small_alloc(SDL_FPoint, count, &isstack);
+ if (!fpoints) {
+ return SDL_OutOfMemory();
+ }
+ for (i = 0; i < count; ++i) {
+ fpoints[i].x = points[i].x * renderer->scale.x;
+ fpoints[i].y = points[i].y * renderer->scale.y;
+ }
+
+ retval = QueueCmdDrawLines(renderer, fpoints, count);
+
+ SDL_small_free(fpoints, isstack);
+
+ return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
+}
+
+int
+SDL_RenderDrawLinesF(SDL_Renderer * renderer,
+ const SDL_FPoint * points, int count)
+{
+ SDL_FPoint *fpoints;
+ int i;
+ int retval;
+ SDL_bool isstack;
+
+ CHECK_RENDERER_MAGIC(renderer, -1);
+
+ if (!points) {
+ return SDL_SetError("SDL_RenderDrawLines(): Passed NULL points");
+ }
+ if (count < 2) {
+ return 0;
+ }
+
+ /* Don't draw while we're hidden */
+ if (renderer->hidden) {
+ return 0;
+ }
+
+ if (renderer->scale.x != 1.0f || renderer->scale.y != 1.0f) {
+ return RenderDrawLinesWithRectsF(renderer, points, count);
+ }
+
+ fpoints = SDL_small_alloc(SDL_FPoint, count, &isstack);
if (!fpoints) {
return SDL_OutOfMemory();
}
@@ -1791,27 +2519,47 @@ SDL_RenderDrawLines(SDL_Renderer * renderer,
fpoints[i].y = points[i].y * renderer->scale.y;
}
- status = renderer->RenderDrawLines(renderer, fpoints, count);
+ retval = QueueCmdDrawLines(renderer, fpoints, count);
- SDL_stack_free(fpoints);
+ SDL_small_free(fpoints, isstack);
- return status;
+ return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
}
int
SDL_RenderDrawRect(SDL_Renderer * renderer, const SDL_Rect * rect)
{
- SDL_Rect full_rect;
- SDL_Point points[5];
+ SDL_FRect frect;
+ SDL_FRect *prect = NULL;
+
+ if (rect) {
+ frect.x = (float) rect->x;
+ frect.y = (float) rect->y;
+ frect.w = (float) rect->w;
+ frect.h = (float) rect->h;
+ prect = &frect;
+ }
+
+ return SDL_RenderDrawRectF(renderer, prect);
+}
+
+int
+SDL_RenderDrawRectF(SDL_Renderer * renderer, const SDL_FRect * rect)
+{
+ SDL_FRect frect;
+ SDL_FPoint points[5];
CHECK_RENDERER_MAGIC(renderer, -1);
/* If 'rect' == NULL, then outline the whole surface */
if (!rect) {
- SDL_RenderGetViewport(renderer, &full_rect);
- full_rect.x = 0;
- full_rect.y = 0;
- rect = &full_rect;
+ SDL_Rect r;
+ SDL_RenderGetViewport(renderer, &r);
+ frect.x = 0.0f;
+ frect.y = 0.0f;
+ frect.w = (float) r.w;
+ frect.h = (float) r.h;
+ rect = &frect;
}
points[0].x = rect->x;
@@ -1824,7 +2572,7 @@ SDL_RenderDrawRect(SDL_Renderer * renderer, const SDL_Rect * rect)
points[3].y = rect->y+rect->h-1;
points[4].x = rect->x;
points[4].y = rect->y;
- return SDL_RenderDrawLines(renderer, points, 5);
+ return SDL_RenderDrawLinesF(renderer, points, 5);
}
int
@@ -1856,20 +2604,75 @@ SDL_RenderDrawRects(SDL_Renderer * renderer,
}
int
+SDL_RenderDrawRectsF(SDL_Renderer * renderer,
+ const SDL_FRect * rects, int count)
+{
+ int i;
+
+ CHECK_RENDERER_MAGIC(renderer, -1);
+
+ if (!rects) {
+ return SDL_SetError("SDL_RenderDrawRects(): Passed NULL rects");
+ }
+ if (count < 1) {
+ return 0;
+ }
+
+ /* Don't draw while we're hidden */
+ if (renderer->hidden) {
+ return 0;
+ }
+
+ for (i = 0; i < count; ++i) {
+ if (SDL_RenderDrawRectF(renderer, &rects[i]) < 0) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int
SDL_RenderFillRect(SDL_Renderer * renderer, const SDL_Rect * rect)
{
- SDL_Rect full_rect = { 0, 0, 0, 0 };
+ SDL_FRect frect;
+
+ CHECK_RENDERER_MAGIC(renderer, -1);
+
+ /* If 'rect' == NULL, then outline the whole surface */
+ if (rect) {
+ frect.x = (float) rect->x;
+ frect.y = (float) rect->y;
+ frect.w = (float) rect->w;
+ frect.h = (float) rect->h;
+ } else {
+ SDL_Rect r;
+ SDL_RenderGetViewport(renderer, &r);
+ frect.x = 0.0f;
+ frect.y = 0.0f;
+ frect.w = (float) r.w;
+ frect.h = (float) r.h;
+ }
+ return SDL_RenderFillRectsF(renderer, &frect, 1);
+}
+
+int
+SDL_RenderFillRectF(SDL_Renderer * renderer, const SDL_FRect * rect)
+{
+ SDL_FRect frect;
CHECK_RENDERER_MAGIC(renderer, -1);
/* If 'rect' == NULL, then outline the whole surface */
if (!rect) {
- SDL_RenderGetViewport(renderer, &full_rect);
- full_rect.x = 0;
- full_rect.y = 0;
- rect = &full_rect;
+ SDL_Rect r;
+ SDL_RenderGetViewport(renderer, &r);
+ frect.x = 0.0f;
+ frect.y = 0.0f;
+ frect.w = (float) r.w;
+ frect.h = (float) r.h;
+ rect = &frect;
}
- return SDL_RenderFillRects(renderer, rect, 1);
+ return SDL_RenderFillRectsF(renderer, rect, 1);
}
int
@@ -1878,7 +2681,8 @@ SDL_RenderFillRects(SDL_Renderer * renderer,
{
SDL_FRect *frects;
int i;
- int status;
+ int retval;
+ SDL_bool isstack;
CHECK_RENDERER_MAGIC(renderer, -1);
@@ -1894,7 +2698,7 @@ SDL_RenderFillRects(SDL_Renderer * renderer,
return 0;
}
- frects = SDL_stack_alloc(SDL_FRect, count);
+ frects = SDL_small_alloc(SDL_FRect, count, &isstack);
if (!frects) {
return SDL_OutOfMemory();
}
@@ -1905,20 +2709,132 @@ SDL_RenderFillRects(SDL_Renderer * renderer,
frects[i].h = rects[i].h * renderer->scale.y;
}
- status = renderer->RenderFillRects(renderer, frects, count);
+ retval = QueueCmdFillRects(renderer, frects, count);
- SDL_stack_free(frects);
+ SDL_small_free(frects, isstack);
- return status;
+ return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
+}
+
+int
+SDL_RenderFillRectsF(SDL_Renderer * renderer,
+ const SDL_FRect * rects, int count)
+{
+ SDL_FRect *frects;
+ int i;
+ int retval;
+ SDL_bool isstack;
+
+ CHECK_RENDERER_MAGIC(renderer, -1);
+
+ if (!rects) {
+ return SDL_SetError("SDL_RenderFillFRects(): Passed NULL rects");
+ }
+ if (count < 1) {
+ return 0;
+ }
+
+ /* Don't draw while we're hidden */
+ if (renderer->hidden) {
+ return 0;
+ }
+
+ frects = SDL_small_alloc(SDL_FRect, count, &isstack);
+ if (!frects) {
+ return SDL_OutOfMemory();
+ }
+ for (i = 0; i < count; ++i) {
+ frects[i].x = rects[i].x * renderer->scale.x;
+ frects[i].y = rects[i].y * renderer->scale.y;
+ frects[i].w = rects[i].w * renderer->scale.x;
+ frects[i].h = rects[i].h * renderer->scale.y;
+ }
+
+ retval = QueueCmdFillRects(renderer, frects, count);
+
+ SDL_small_free(frects, isstack);
+
+ return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
+}
+
+/* !!! FIXME: move this to a public API if we want to do float versions of all of these later */
+SDL_FORCE_INLINE SDL_bool SDL_FRectEmpty(const SDL_FRect *r)
+{
+ return ((!r) || (r->w <= 0.0f) || (r->h <= 0.0f)) ? SDL_TRUE : SDL_FALSE;
+}
+
+/* !!! FIXME: move this to a public API if we want to do float versions of all of these later */
+static SDL_bool
+SDL_HasIntersectionF(const SDL_FRect * A, const SDL_FRect * B)
+{
+ float Amin, Amax, Bmin, Bmax;
+
+ if (!A) {
+ SDL_InvalidParamError("A");
+ return SDL_FALSE;
+ }
+
+ if (!B) {
+ SDL_InvalidParamError("B");
+ return SDL_FALSE;
+ }
+
+ /* Special cases for empty rects */
+ if (SDL_FRectEmpty(A) || SDL_FRectEmpty(B)) {
+ return SDL_FALSE;
+ }
+
+ /* Horizontal intersection */
+ Amin = A->x;
+ Amax = Amin + A->w;
+ Bmin = B->x;
+ Bmax = Bmin + B->w;
+ if (Bmin > Amin)
+ Amin = Bmin;
+ if (Bmax < Amax)
+ Amax = Bmax;
+ if (Amax <= Amin)
+ return SDL_FALSE;
+
+ /* Vertical intersection */
+ Amin = A->y;
+ Amax = Amin + A->h;
+ Bmin = B->y;
+ Bmax = Bmin + B->h;
+ if (Bmin > Amin)
+ Amin = Bmin;
+ if (Bmax < Amax)
+ Amax = Bmax;
+ if (Amax <= Amin)
+ return SDL_FALSE;
+
+ return SDL_TRUE;
}
int
SDL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
const SDL_Rect * srcrect, const SDL_Rect * dstrect)
{
- SDL_Rect real_srcrect = { 0, 0, 0, 0 };
- SDL_Rect real_dstrect = { 0, 0, 0, 0 };
- SDL_FRect frect;
+ SDL_FRect dstfrect;
+ SDL_FRect *pdstfrect = NULL;
+ if (dstrect) {
+ dstfrect.x = (float) dstrect->x;
+ dstfrect.y = (float) dstrect->y;
+ dstfrect.w = (float) dstrect->w;
+ dstfrect.h = (float) dstrect->h;
+ pdstfrect = &dstfrect;
+ }
+ return SDL_RenderCopyF(renderer, texture, srcrect, pdstfrect);
+}
+
+int
+SDL_RenderCopyF(SDL_Renderer * renderer, SDL_Texture * texture,
+ const SDL_Rect * srcrect, const SDL_FRect * dstrect)
+{
+ SDL_Rect real_srcrect;
+ SDL_FRect real_dstrect;
+ SDL_Rect r;
+ int retval;
CHECK_RENDERER_MAGIC(renderer, -1);
CHECK_TEXTURE_MAGIC(texture, -1);
@@ -1942,11 +2858,13 @@ SDL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
}
}
- SDL_RenderGetViewport(renderer, &real_dstrect);
- real_dstrect.x = 0;
- real_dstrect.y = 0;
+ SDL_RenderGetViewport(renderer, &r);
+ real_dstrect.x = 0.0f;
+ real_dstrect.y = 0.0f;
+ real_dstrect.w = (float) r.w;
+ real_dstrect.h = (float) r.h;
if (dstrect) {
- if (!SDL_HasIntersection(dstrect, &real_dstrect)) {
+ if (!SDL_HasIntersectionF(dstrect, &real_dstrect)) {
return 0;
}
real_dstrect = *dstrect;
@@ -1956,28 +2874,56 @@ SDL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
texture = texture->native;
}
- frect.x = real_dstrect.x * renderer->scale.x;
- frect.y = real_dstrect.y * renderer->scale.y;
- frect.w = real_dstrect.w * renderer->scale.x;
- frect.h = real_dstrect.h * renderer->scale.y;
+ real_dstrect.x *= renderer->scale.x;
+ real_dstrect.y *= renderer->scale.y;
+ real_dstrect.w *= renderer->scale.x;
+ real_dstrect.h *= renderer->scale.y;
- return renderer->RenderCopy(renderer, texture, &real_srcrect, &frect);
-}
+ texture->last_command_generation = renderer->render_command_generation;
+ retval = QueueCmdCopy(renderer, texture, &real_srcrect, &real_dstrect);
+ return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
+}
int
SDL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
const SDL_Rect * srcrect, const SDL_Rect * dstrect,
const double angle, const SDL_Point *center, const SDL_RendererFlip flip)
{
- SDL_Rect real_srcrect = { 0, 0, 0, 0 };
- SDL_Rect real_dstrect = { 0, 0, 0, 0 };
- SDL_Point real_center;
- SDL_FRect frect;
+ SDL_FRect dstfrect;
+ SDL_FRect *pdstfrect = NULL;
SDL_FPoint fcenter;
+ SDL_FPoint *pfcenter = NULL;
+
+ if (dstrect) {
+ dstfrect.x = (float) dstrect->x;
+ dstfrect.y = (float) dstrect->y;
+ dstfrect.w = (float) dstrect->w;
+ dstfrect.h = (float) dstrect->h;
+ pdstfrect = &dstfrect;
+ }
+
+ if (center) {
+ fcenter.x = (float) center->x;
+ fcenter.y = (float) center->y;
+ pfcenter = &fcenter;
+ }
+
+ return SDL_RenderCopyExF(renderer, texture, srcrect, pdstfrect, angle, pfcenter, flip);
+}
+
+int
+SDL_RenderCopyExF(SDL_Renderer * renderer, SDL_Texture * texture,
+ const SDL_Rect * srcrect, const SDL_FRect * dstrect,
+ const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
+{
+ SDL_Rect real_srcrect;
+ SDL_FRect real_dstrect;
+ SDL_FPoint real_center;
+ int retval;
if (flip == SDL_FLIP_NONE && (int)(angle/360) == angle/360) { /* fast path when we don't need rotation or flipping */
- return SDL_RenderCopy(renderer, texture, srcrect, dstrect);
+ return SDL_RenderCopyF(renderer, texture, srcrect, dstrect);
}
CHECK_RENDERER_MAGIC(renderer, -1);
@@ -1986,7 +2932,7 @@ SDL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
if (renderer != texture->renderer) {
return SDL_SetError("Texture was not created with this renderer");
}
- if (!renderer->RenderCopyEx) {
+ if (!renderer->QueueCopyEx) {
return SDL_SetError("Renderer does not support RenderCopyEx");
}
@@ -2009,9 +2955,12 @@ SDL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
if (dstrect) {
real_dstrect = *dstrect;
} else {
- SDL_RenderGetViewport(renderer, &real_dstrect);
- real_dstrect.x = 0;
- real_dstrect.y = 0;
+ SDL_Rect r;
+ SDL_RenderGetViewport(renderer, &r);
+ real_dstrect.x = 0.0f;
+ real_dstrect.y = 0.0f;
+ real_dstrect.w = (float) r.w;
+ real_dstrect.h = (float) r.h;
}
if (texture->native) {
@@ -2021,19 +2970,22 @@ SDL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
if (center) {
real_center = *center;
} else {
- real_center.x = real_dstrect.w/2;
- real_center.y = real_dstrect.h/2;
+ real_center.x = real_dstrect.w / 2.0f;
+ real_center.y = real_dstrect.h / 2.0f;
}
- frect.x = real_dstrect.x * renderer->scale.x;
- frect.y = real_dstrect.y * renderer->scale.y;
- frect.w = real_dstrect.w * renderer->scale.x;
- frect.h = real_dstrect.h * renderer->scale.y;
+ real_dstrect.x *= renderer->scale.x;
+ real_dstrect.y *= renderer->scale.y;
+ real_dstrect.w *= renderer->scale.x;
+ real_dstrect.h *= renderer->scale.y;
- fcenter.x = real_center.x * renderer->scale.x;
- fcenter.y = real_center.y * renderer->scale.y;
+ real_center.x *= renderer->scale.x;
+ real_center.y *= renderer->scale.y;
- return renderer->RenderCopyEx(renderer, texture, &real_srcrect, &frect, angle, &fcenter, flip);
+ texture->last_command_generation = renderer->render_command_generation;
+
+ retval = QueueCmdCopyEx(renderer, texture, &real_srcrect, &real_dstrect, angle, &real_center, flip);
+ return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
}
int
@@ -2048,6 +3000,8 @@ SDL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
return SDL_Unsupported();
}
+ FlushRenderCommands(renderer); /* we need to render before we read the results. */
+
if (!format) {
format = SDL_GetWindowPixelFormat(renderer->window);
}
@@ -2078,7 +3032,9 @@ SDL_RenderPresent(SDL_Renderer * renderer)
{
CHECK_RENDERER_MAGIC(renderer, );
- /* Don't draw while we're hidden */
+ FlushRenderCommands(renderer); /* time to send everything to the GPU! */
+
+ /* Don't present while we're hidden */
if (renderer->hidden) {
return;
}
@@ -2094,7 +3050,9 @@ SDL_DestroyTexture(SDL_Texture * texture)
renderer = texture->renderer;
if (texture == renderer->target) {
- SDL_SetRenderTarget(renderer, NULL);
+ SDL_SetRenderTarget(renderer, NULL); /* implies command queue flush */
+ } else {
+ FlushRenderCommandsIfTextureNeeded(texture);
}
texture->magic = NULL;
@@ -2123,10 +3081,43 @@ SDL_DestroyTexture(SDL_Texture * texture)
void
SDL_DestroyRenderer(SDL_Renderer * renderer)
{
+ SDL_RenderCommand *cmd;
+ SDL_AllocVertGap *gap;
+ SDL_AllocVertGap *nextgap;
+
CHECK_RENDERER_MAGIC(renderer, );
SDL_DelEventWatch(SDL_RendererEventWatch, renderer);
+ if (renderer->render_commands_tail != NULL) {
+ renderer->render_commands_tail->next = renderer->render_commands_pool;
+ cmd = renderer->render_commands;
+ } else {
+ cmd = renderer->render_commands_pool;
+ }
+
+ renderer->render_commands_pool = NULL;
+ renderer->render_commands_tail = NULL;
+ renderer->render_commands = NULL;
+
+ while (cmd != NULL) {
+ SDL_RenderCommand *next = cmd->next;
+ SDL_free(cmd);
+ cmd = next;
+ }
+
+ SDL_free(renderer->vertex_data);
+
+ for (gap = renderer->vertex_data_gaps.next; gap; gap = nextgap) {
+ nextgap = gap->next;
+ SDL_free(gap);
+ }
+
+ for (gap = renderer->vertex_data_gaps_pool; gap; gap = nextgap) {
+ nextgap = gap->next;
+ SDL_free(gap);
+ }
+
/* Free existing textures for this renderer */
while (renderer->textures) {
SDL_Texture *tex = renderer->textures; (void) tex;
@@ -2158,6 +3149,7 @@ int SDL_GL_BindTexture(SDL_Texture *texture, float *texw, float *texh)
if (texture->native) {
return SDL_GL_BindTexture(texture->native, texw, texh);
} else if (renderer && renderer->GL_BindTexture) {
+ FlushRenderCommandsIfTextureNeeded(texture); /* in case the app is going to mess with it. */
return renderer->GL_BindTexture(renderer, texture, texw, texh);
} else {
return SDL_Unsupported();
@@ -2173,6 +3165,7 @@ int SDL_GL_UnbindTexture(SDL_Texture *texture)
if (texture->native) {
return SDL_GL_UnbindTexture(texture->native);
} else if (renderer && renderer->GL_UnbindTexture) {
+ FlushRenderCommandsIfTextureNeeded(texture); /* in case the app messed with it. */
return renderer->GL_UnbindTexture(renderer, texture);
}
@@ -2185,6 +3178,7 @@ SDL_RenderGetMetalLayer(SDL_Renderer * renderer)
CHECK_RENDERER_MAGIC(renderer, NULL);
if (renderer->GetMetalLayer) {
+ FlushRenderCommands(renderer); /* in case the app is going to mess with it. */
return renderer->GetMetalLayer(renderer);
}
return NULL;
@@ -2196,6 +3190,7 @@ SDL_RenderGetMetalCommandEncoder(SDL_Renderer * renderer)
CHECK_RENDERER_MAGIC(renderer, NULL);
if (renderer->GetMetalCommandEncoder) {
+ FlushRenderCommands(renderer); /* in case the app is going to mess with it. */
return renderer->GetMetalCommandEncoder(renderer);
}
return NULL;
diff --git a/src/render/SDL_sysrender.h b/src/render/SDL_sysrender.h
index 940bebcc1d..87586f1bb9 100644
--- a/src/render/SDL_sysrender.h
+++ b/src/render/SDL_sysrender.h
@@ -39,20 +39,6 @@ typedef enum
SDL_ScaleModeBest
} SDL_ScaleMode;
-typedef struct
-{
- float x;
- float y;
-} SDL_FPoint;
-
-typedef struct
-{
- float x;
- float y;
- float w;
- float h;
-} SDL_FRect;
-
/* Define the SDL texture structure */
struct SDL_Texture
{
@@ -75,12 +61,63 @@ struct SDL_Texture
int pitch;
SDL_Rect locked_rect;
+ Uint32 last_command_generation; /* last command queue generation this texture was in. */
+
void *driverdata; /**< Driver specific texture representation */
SDL_Texture *prev;
SDL_Texture *next;
};
+typedef enum
+{
+ SDL_RENDERCMD_NO_OP,
+ SDL_RENDERCMD_SETVIEWPORT,
+ SDL_RENDERCMD_SETCLIPRECT,
+ SDL_RENDERCMD_SETDRAWCOLOR,
+ SDL_RENDERCMD_CLEAR,
+ SDL_RENDERCMD_DRAW_POINTS,
+ SDL_RENDERCMD_DRAW_LINES,
+ SDL_RENDERCMD_FILL_RECTS,
+ SDL_RENDERCMD_COPY,
+ SDL_RENDERCMD_COPY_EX
+} SDL_RenderCommandType;
+
+typedef struct SDL_RenderCommand
+{
+ SDL_RenderCommandType command;
+ union {
+ struct {
+ size_t first;
+ SDL_Rect rect;
+ } viewport;
+ struct {
+ SDL_bool enabled;
+ SDL_Rect rect;
+ } cliprect;
+ struct {
+ size_t first;
+ size_t count;
+ Uint8 r, g, b, a;
+ SDL_BlendMode blend;
+ SDL_Texture *texture;
+ } draw;
+ struct {
+ size_t first;
+ Uint8 r, g, b, a;
+ } color;
+ } data;
+ struct SDL_RenderCommand *next;
+} SDL_RenderCommand;
+
+typedef struct SDL_AllocVertGap
+{
+ size_t offset;
+ size_t len;
+ struct SDL_AllocVertGap *next;
+} SDL_AllocVertGap;
+
+
/* Define the SDL renderer structure */
struct SDL_Renderer
{
@@ -90,12 +127,20 @@ struct SDL_Renderer
int (*GetOutputSize) (SDL_Renderer * renderer, int *w, int *h);
SDL_bool (*SupportsBlendMode)(SDL_Renderer * renderer, SDL_BlendMode blendMode);
int (*CreateTexture) (SDL_Renderer * renderer, SDL_Texture * texture);
- int (*SetTextureColorMod) (SDL_Renderer * renderer,
- SDL_Texture * texture);
- int (*SetTextureAlphaMod) (SDL_Renderer * renderer,
- SDL_Texture * texture);
- int (*SetTextureBlendMode) (SDL_Renderer * renderer,
- SDL_Texture * texture);
+ int (*QueueSetViewport) (SDL_Renderer * renderer, SDL_RenderCommand *cmd);
+ int (*QueueSetDrawColor) (SDL_Renderer * renderer, SDL_RenderCommand *cmd);
+ int (*QueueDrawPoints) (SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points,
+ int count);
+ int (*QueueDrawLines) (SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points,
+ int count);
+ int (*QueueFillRects) (SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects,
+ int count);
+ int (*QueueCopy) (SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
+ const SDL_Rect * srcrect, const SDL_FRect * dstrect);
+ int (*QueueCopyEx) (SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
+ const SDL_Rect * srcquad, const SDL_FRect * dstrect,
+ const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip);
+ int (*RunCommandQueue) (SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize);
int (*UpdateTexture) (SDL_Renderer * renderer, SDL_Texture * texture,
const SDL_Rect * rect, const void *pixels,
int pitch);
@@ -108,20 +153,6 @@ struct SDL_Renderer
const SDL_Rect * rect, void **pixels, int *pitch);
void (*UnlockTexture) (SDL_Renderer * renderer, SDL_Texture * texture);
int (*SetRenderTarget) (SDL_Renderer * renderer, SDL_Texture * texture);
- int (*UpdateViewport) (SDL_Renderer * renderer);
- int (*UpdateClipRect) (SDL_Renderer * renderer);
- int (*RenderClear) (SDL_Renderer * renderer);
- int (*RenderDrawPoints) (SDL_Renderer * renderer, const SDL_FPoint * points,
- int count);
- int (*RenderDrawLines) (SDL_Renderer * renderer, const SDL_FPoint * points,
- int count);
- int (*RenderFillRects) (SDL_Renderer * renderer, const SDL_FRect * rects,
- int count);
- int (*RenderCopy) (SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * srcrect, const SDL_FRect * dstrect);
- int (*RenderCopyEx) (SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * srcquad, const SDL_FRect * dstrect,
- const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip);
int (*RenderReadPixels) (SDL_Renderer * renderer, const SDL_Rect * rect,
Uint32 format, void * pixels, int pitch);
void (*RenderPresent) (SDL_Renderer * renderer);
@@ -178,6 +209,26 @@ struct SDL_Renderer
Uint8 r, g, b, a; /**< Color for drawing operations values */
SDL_BlendMode blendMode; /**< The drawing blend mode */
+ SDL_bool always_batch;
+ SDL_bool batching;
+ SDL_RenderCommand *render_commands;
+ SDL_RenderCommand *render_commands_tail;
+ SDL_RenderCommand *render_commands_pool;
+ Uint32 render_command_generation;
+ Uint32 last_queued_color;
+ SDL_Rect last_queued_viewport;
+ SDL_Rect last_queued_cliprect;
+ SDL_bool last_queued_cliprect_enabled;
+ SDL_bool color_queued;
+ SDL_bool viewport_queued;
+ SDL_bool cliprect_queued;
+
+ void *vertex_data;
+ size_t vertex_data_used;
+ size_t vertex_data_allocation;
+ SDL_AllocVertGap vertex_data_gaps;
+ SDL_AllocVertGap *vertex_data_gaps_pool;
+
void *driverdata;
};
@@ -209,6 +260,11 @@ extern SDL_BlendFactor SDL_GetBlendModeSrcAlphaFactor(SDL_BlendMode blendMode);
extern SDL_BlendFactor SDL_GetBlendModeDstAlphaFactor(SDL_BlendMode blendMode);
extern SDL_BlendOperation SDL_GetBlendModeAlphaOperation(SDL_BlendMode blendMode);
+/* drivers call this during their Queue*() methods to make space in a array that are used
+ for a vertex buffer during RunCommandQueue(). Pointers returned here are only valid until
+ the next call, because it might be in an array that gets realloc()'d. */
+extern void *SDL_AllocateRenderVertices(SDL_Renderer *renderer, const size_t numbytes, const size_t alignment, size_t *offset);
+
#endif /* SDL_sysrender_h_ */
/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/render/direct3d/SDL_render_d3d.c b/src/render/direct3d/SDL_render_d3d.c
index 69a9dff547..9d000ccdd1 100644
--- a/src/render/direct3d/SDL_render_d3d.c
+++ b/src/render/direct3d/SDL_render_d3d.c
@@ -30,6 +30,8 @@
#include "SDL_hints.h"
#include "SDL_loadso.h"
#include "SDL_syswm.h"
+#include "SDL_log.h"
+#include "SDL_assert.h"
#include "../SDL_sysrender.h"
#include "../SDL_d3dmath.h"
#include "../../video/windows/SDL_windowsvideo.h"
@@ -41,60 +43,22 @@
#include "SDL_shaders_d3d.h"
-
-/* Direct3D renderer implementation */
-
-static SDL_Renderer *D3D_CreateRenderer(SDL_Window * window, Uint32 flags);
-static void D3D_WindowEvent(SDL_Renderer * renderer,
- const SDL_WindowEvent *event);
-static SDL_bool D3D_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode);
-static int D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
-static int D3D_RecreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
-static int D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * rect, const void *pixels,
- int pitch);
-static int D3D_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * rect,
- const Uint8 *Yplane, int Ypitch,
- const Uint8 *Uplane, int Upitch,
- const Uint8 *Vplane, int Vpitch);
-static int D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * rect, void **pixels, int *pitch);
-static void D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
-static int D3D_SetRenderTargetInternal(SDL_Renderer * renderer, SDL_Texture * texture);
-static int D3D_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture);
-static int D3D_UpdateViewport(SDL_Renderer * renderer);
-static int D3D_UpdateClipRect(SDL_Renderer * renderer);
-static int D3D_RenderClear(SDL_Renderer * renderer);
-static int D3D_RenderDrawPoints(SDL_Renderer * renderer,
- const SDL_FPoint * points, int count);
-static int D3D_RenderDrawLines(SDL_Renderer * renderer,
- const SDL_FPoint * points, int count);
-static int D3D_RenderFillRects(SDL_Renderer * renderer,
- const SDL_FRect * rects, int count);
-static int D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * srcrect, const SDL_FRect * dstrect);
-static int D3D_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * srcrect, const SDL_FRect * dstrect,
- const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip);
-static int D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
- Uint32 format, void * pixels, int pitch);
-static void D3D_RenderPresent(SDL_Renderer * renderer);
-static void D3D_DestroyTexture(SDL_Renderer * renderer,
- SDL_Texture * texture);
-static void D3D_DestroyRenderer(SDL_Renderer * renderer);
+typedef struct
+{
+ SDL_Rect viewport;
+ SDL_bool viewport_dirty;
+ SDL_Texture *texture;
+ SDL_BlendMode blend;
+ SDL_bool cliprect_enabled;
+ SDL_bool cliprect_enabled_dirty;
+ SDL_Rect cliprect;
+ SDL_bool cliprect_dirty;
+ SDL_bool is_copy_ex;
+ LPDIRECT3DPIXELSHADER9 shader;
+} D3D_DrawStateCache;
-SDL_RenderDriver D3D_RenderDriver = {
- D3D_CreateRenderer,
- {
- "direct3d",
- (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
- 1,
- {SDL_PIXELFORMAT_ARGB8888},
- 0,
- 0}
-};
+/* Direct3D renderer implementation */
typedef struct
{
@@ -111,6 +75,11 @@ typedef struct
IDirect3DSurface9 *currentRenderTarget;
void* d3dxDLL;
LPDIRECT3DPIXELSHADER9 shaders[NUM_SHADERS];
+ LPDIRECT3DVERTEXBUFFER9 vertexBuffers[8];
+ size_t vertexBufferSize[8];
+ int currentVertexBuffer;
+ SDL_bool reportedVboProblem;
+ D3D_DrawStateCache drawstate;
} D3D_RenderData;
typedef struct
@@ -265,9 +234,8 @@ D3D_InitRenderState(D3D_RenderData *data)
D3DMATRIX matrix;
IDirect3DDevice9 *device = data->device;
-
- IDirect3DDevice9_SetVertexShader(device, NULL);
IDirect3DDevice9_SetFVF(device, D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);
+ IDirect3DDevice9_SetVertexShader(device, NULL);
IDirect3DDevice9_SetRenderState(device, D3DRS_ZENABLE, D3DZB_FALSE);
IDirect3DDevice9_SetRenderState(device, D3DRS_CULLMODE, D3DCULL_NONE);
IDirect3DDevice9_SetRenderState(device, D3DRS_LIGHTING, FALSE);
@@ -300,21 +268,10 @@ D3D_InitRenderState(D3D_RenderData *data)
D3DTOP_DISABLE);
/* Set an identity world and view matrix */
+ SDL_zero(matrix);
matrix.m[0][0] = 1.0f;
- matrix.m[0][1] = 0.0f;
- matrix.m[0][2] = 0.0f;
- matrix.m[0][3] = 0.0f;
- matrix.m[1][0] = 0.0f;
matrix.m[1][1] = 1.0f;
- matrix.m[1][2] = 0.0f;
- matrix.m[1][3] = 0.0f;
- matrix.m[2][0] = 0.0f;
- matrix.m[2][1] = 0.0f;
matrix.m[2][2] = 1.0f;
- matrix.m[2][3] = 0.0f;
- matrix.m[3][0] = 0.0f;
- matrix.m[3][1] = 0.0f;
- matrix.m[3][2] = 0.0f;
matrix.m[3][3] = 1.0f;
IDirect3DDevice9_SetTransform(device, D3DTS_WORLD, &matrix);
IDirect3DDevice9_SetTransform(device, D3DTS_VIEW, &matrix);
@@ -326,63 +283,7 @@ D3D_InitRenderState(D3D_RenderData *data)
data->beginScene = SDL_TRUE;
}
-static int
-D3D_Reset(SDL_Renderer * renderer)
-{
- D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
- HRESULT result;
- SDL_Texture *texture;
-
- /* Release the default render target before reset */
- if (data->defaultRenderTarget) {
- IDirect3DSurface9_Release(data->defaultRenderTarget);
- data->defaultRenderTarget = NULL;
- }
- if (data->currentRenderTarget != NULL) {
- IDirect3DSurface9_Release(data->currentRenderTarget);
- data->currentRenderTarget = NULL;
- }
-
- /* Release application render targets */
- for (texture = renderer->textures; texture; texture = texture->next) {
- if (texture->access == SDL_TEXTUREACCESS_TARGET) {
- D3D_DestroyTexture(renderer, texture);
- } else {
- D3D_RecreateTexture(renderer, texture);
- }
- }
-
- result = IDirect3DDevice9_Reset(data->device, &data->pparams);
- if (FAILED(result)) {
- if (result == D3DERR_DEVICELOST) {
- /* Don't worry about it, we'll reset later... */
- return 0;
- } else {
- return D3D_SetError("Reset()", result);
- }
- }
-
- /* Allocate application render targets */
- for (texture = renderer->textures; texture; texture = texture->next) {
- if (texture->access == SDL_TEXTUREACCESS_TARGET) {
- D3D_CreateTexture(renderer, texture);
- }
- }
-
- IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget);
- D3D_InitRenderState(data);
- D3D_SetRenderTargetInternal(renderer, renderer->target);
- D3D_UpdateViewport(renderer);
-
- /* Let the application know that render targets were reset */
- {
- SDL_Event event;
- event.type = SDL_RENDER_TARGETS_RESET;
- SDL_PushEvent(&event);
- }
-
- return 0;
-}
+static int D3D_Reset(SDL_Renderer * renderer);
static int
D3D_ActivateRenderer(SDL_Renderer * renderer)
@@ -431,177 +332,6 @@ D3D_ActivateRenderer(SDL_Renderer * renderer)
return 0;
}
-SDL_Renderer *
-D3D_CreateRenderer(SDL_Window * window, Uint32 flags)
-{
- SDL_Renderer *renderer;
- D3D_RenderData *data;
- SDL_SysWMinfo windowinfo;
- HRESULT result;
- D3DPRESENT_PARAMETERS pparams;
- IDirect3DSwapChain9 *chain;
- D3DCAPS9 caps;
- DWORD device_flags;
- Uint32 window_flags;
- int w, h;
- SDL_DisplayMode fullscreen_mode;
- int displayIndex;
-
- renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
- if (!renderer) {
- SDL_OutOfMemory();
- return NULL;
- }
-
- data = (D3D_RenderData *) SDL_calloc(1, sizeof(*data));
- if (!data) {
- SDL_free(renderer);
- SDL_OutOfMemory();
- return NULL;
- }
-
- if (!D3D_LoadDLL(&data->d3dDLL, &data->d3d)) {
- SDL_free(renderer);
- SDL_free(data);
- SDL_SetError("Unable to create Direct3D interface");
- return NULL;
- }
-
- renderer->WindowEvent = D3D_WindowEvent;
- renderer->SupportsBlendMode = D3D_SupportsBlendMode;
- renderer->CreateTexture = D3D_CreateTexture;
- renderer->UpdateTexture = D3D_UpdateTexture;
- renderer->UpdateTextureYUV = D3D_UpdateTextureYUV;
- renderer->LockTexture = D3D_LockTexture;
- renderer->UnlockTexture = D3D_UnlockTexture;
- renderer->SetRenderTarget = D3D_SetRenderTarget;
- renderer->UpdateViewport = D3D_UpdateViewport;
- renderer->UpdateClipRect = D3D_UpdateClipRect;
- renderer->RenderClear = D3D_RenderClear;
- renderer->RenderDrawPoints = D3D_RenderDrawPoints;
- renderer->RenderDrawLines = D3D_RenderDrawLines;
- renderer->RenderFillRects = D3D_RenderFillRects;
- renderer->RenderCopy = D3D_RenderCopy;
- renderer->RenderCopyEx = D3D_RenderCopyEx;
- renderer->RenderReadPixels = D3D_RenderReadPixels;
- renderer->RenderPresent = D3D_RenderPresent;
- renderer->DestroyTexture = D3D_DestroyTexture;
- renderer->DestroyRenderer = D3D_DestroyRenderer;
- renderer->info = D3D_RenderDriver.info;
- renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
- renderer->driverdata = data;
-
- SDL_VERSION(&windowinfo.version);
- SDL_GetWindowWMInfo(window, &windowinfo);
-
- window_flags = SDL_GetWindowFlags(window);
- SDL_GetWindowSize(window, &w, &h);
- SDL_GetWindowDisplayMode(window, &fullscreen_mode);
-
- SDL_zero(pparams);
- pparams.hDeviceWindow = windowinfo.info.win.window;
- pparams.BackBufferWidth = w;
- pparams.BackBufferHeight = h;
- pparams.BackBufferCount = 1;
- pparams.SwapEffect = D3DSWAPEFFECT_DISCARD;
-
- if (window_flags & SDL_WINDOW_FULLSCREEN && (window_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
- pparams.Windowed = FALSE;
- pparams.BackBufferFormat = PixelFormatToD3DFMT(fullscreen_mode.format);
- pparams.FullScreen_RefreshRateInHz = fullscreen_mode.refresh_rate;
- } else {
- pparams.Windowed = TRUE;
- pparams.BackBufferFormat = D3DFMT_UNKNOWN;
- pparams.FullScreen_RefreshRateInHz = 0;
- }
- if (flags & SDL_RENDERER_PRESENTVSYNC) {
- pparams.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
- } else {
- pparams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
- }
-
- /* Get the adapter for the display that the window is on */
- displayIndex = SDL_GetWindowDisplayIndex(window);
- data->adapter = SDL_Direct3D9GetAdapterIndex(displayIndex);
-
- IDirect3D9_GetDeviceCaps(data->d3d, data->adapter, D3DDEVTYPE_HAL, &caps);
-
- device_flags = D3DCREATE_FPU_PRESERVE;
- if (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) {
- device_flags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
- } else {
- device_flags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
- }
-
- if (SDL_GetHintBoolean(SDL_HINT_RENDER_DIRECT3D_THREADSAFE, SDL_FALSE)) {
- device_flags |= D3DCREATE_MULTITHREADED;
- }
-
- result = IDirect3D9_CreateDevice(data->d3d, data->adapter,
- D3DDEVTYPE_HAL,
- pparams.hDeviceWindow,
- device_flags,
- &pparams, &data->device);
- if (FAILED(result)) {
- D3D_DestroyRenderer(renderer);
- D3D_SetError("CreateDevice()", result);
- return NULL;
- }
-
- /* Get presentation parameters to fill info */
- result = IDirect3DDevice9_GetSwapChain(data->device, 0, &chain);
- if (FAILED(result)) {
- D3D_DestroyRenderer(renderer);
- D3D_SetError("GetSwapChain()", result);
- return NULL;
- }
- result = IDirect3DSwapChain9_GetPresentParameters(chain, &pparams);
- if (FAILED(result)) {
- IDirect3DSwapChain9_Release(chain);
- D3D_DestroyRenderer(renderer);
- D3D_SetError("GetPresentParameters()", result);
- return NULL;
- }
- IDirect3DSwapChain9_Release(chain);
- if (pparams.PresentationInterval == D3DPRESENT_INTERVAL_ONE) {
- renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
- }
- data->pparams = pparams;
-
- IDirect3DDevice9_GetDeviceCaps(data->device, &caps);
- renderer->info.max_texture_width = caps.MaxTextureWidth;
- renderer->info.max_texture_height = caps.MaxTextureHeight;
- if (caps.NumSimultaneousRTs >= 2) {
- renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE;
- }
-
- if (caps.PrimitiveMiscCaps & D3DPMISCCAPS_SEPARATEALPHABLEND) {
- data->enableSeparateAlphaBlend = SDL_TRUE;
- }
-
- /* Store the default render target */
- IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget);
- data->currentRenderTarget = NULL;
-
- /* Set up parameters for rendering */
- D3D_InitRenderState(data);
-
- if (caps.MaxSimultaneousTextures >= 3) {
- int i;
- for (i = 0; i < SDL_arraysize(data->shaders); ++i) {
- result = D3D9_CreatePixelShader(data->device, (D3D9_Shader)i, &data->shaders[i]);
- if (FAILED(result)) {
- D3D_SetError("CreatePixelShader()", result);
- }
- }
- if (data->shaders[SHADER_YUV_JPEG] && data->shaders[SHADER_YUV_BT601] && data->shaders[SHADER_YUV_BT709]) {
- renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;
- renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
- }
- }
- return renderer;
-}
-
static void
D3D_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
{
@@ -702,33 +432,6 @@ D3D_CreateStagingTexture(IDirect3DDevice9 *device, D3D_TextureRep *texture)
}
static int
-D3D_BindTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWORD sampler)
-{
- HRESULT result;
-
- if (texture->dirty && texture->staging) {
- if (!texture->texture) {
- result = IDirect3DDevice9_CreateTexture(device, texture->w, texture->h, 1, texture->usage,
- PixelFormatToD3DFMT(texture->format), D3DPOOL_DEFAULT, &texture->texture, NULL);
- if (FAILED(result)) {
- return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
- }
- }
-
- result = IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)texture->staging, (IDirect3DBaseTexture9 *)texture->texture);
- if (FAILED(result)) {
- return D3D_SetError("UpdateTexture()", result);
- }
- texture->dirty = SDL_FALSE;
- }
- result = IDirect3DDevice9_SetTexture(device, sampler, (IDirect3DBaseTexture9 *)texture->texture);
- if (FAILED(result)) {
- return D3D_SetError("SetTexture()", result);
- }
- return 0;
-}
-
-static int
D3D_RecreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture)
{
if (texture->texture) {
@@ -1072,330 +775,254 @@ D3D_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
return D3D_SetRenderTargetInternal(renderer, texture);
}
+
static int
-D3D_UpdateViewport(SDL_Renderer * renderer)
+D3D_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd)
{
- D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
- D3DVIEWPORT9 viewport;
- D3DMATRIX matrix;
-
- /* Set the viewport */
- viewport.X = renderer->viewport.x;
- viewport.Y = renderer->viewport.y;
- viewport.Width = renderer->viewport.w;
- viewport.Height = renderer->viewport.h;
- viewport.MinZ = 0.0f;
- viewport.MaxZ = 1.0f;
- IDirect3DDevice9_SetViewport(data->device, &viewport);
-
- /* Set an orthographic projection matrix */
- if (renderer->viewport.w && renderer->viewport.h) {
- matrix.m[0][0] = 2.0f / renderer->viewport.w;
- matrix.m[0][1] = 0.0f;
- matrix.m[0][2] = 0.0f;
- matrix.m[0][3] = 0.0f;
- matrix.m[1][0] = 0.0f;
- matrix.m[1][1] = -2.0f / renderer->viewport.h;
- matrix.m[1][2] = 0.0f;
- matrix.m[1][3] = 0.0f;
- matrix.m[2][0] = 0.0f;
- matrix.m[2][1] = 0.0f;
- matrix.m[2][2] = 1.0f;
- matrix.m[2][3] = 0.0f;
- matrix.m[3][0] = -1.0f;
- matrix.m[3][1] = 1.0f;
- matrix.m[3][2] = 0.0f;
- matrix.m[3][3] = 1.0f;
- IDirect3DDevice9_SetTransform(data->device, D3DTS_PROJECTION, &matrix);
- }
-
- return 0;
+ return 0; /* nothing to do in this backend. */
}
static int
-D3D_UpdateClipRect(SDL_Renderer * renderer)
+D3D_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
{
- D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
+ const DWORD color = D3DCOLOR_ARGB(cmd->data.draw.a, cmd->data.draw.r, cmd->data.draw.g, cmd->data.draw.b);
+ const size_t vertslen = count * sizeof (Vertex);
+ Vertex *verts = (Vertex *) SDL_AllocateRenderVertices(renderer, vertslen, 0, &cmd->data.draw.first);
+ size_t i;
- if (renderer->clipping_enabled) {
- const SDL_Rect *rect = &renderer->clip_rect;
- RECT r;
- HRESULT result;
+ if (!verts) {
+ return -1;
+ }
- IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, TRUE);
- r.left = renderer->viewport.x + rect->x;
- r.top = renderer->viewport.y + rect->y;
- r.right = renderer->viewport.x + rect->x + rect->w;
- r.bottom = renderer->viewport.y + rect->y + rect->h;
+ SDL_memset(verts, '\0', vertslen);
+ cmd->data.draw.count = count;
- result = IDirect3DDevice9_SetScissorRect(data->device, &r);
- if (result != D3D_OK) {
- D3D_SetError("SetScissor()", result);
- return -1;
- }
- } else {
- IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, FALSE);
+ for (i = 0; i < count; i++, verts++, points++) {
+ verts->x = points->x;
+ verts->y = points->y;
+ verts->color = color;
}
+
return 0;
}
static int
-D3D_RenderClear(SDL_Renderer * renderer)
+D3D_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects, int count)
{
- D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
- DWORD color;
- HRESULT result;
- int BackBufferWidth, BackBufferHeight;
+ const DWORD color = D3DCOLOR_ARGB(cmd->data.draw.a, cmd->data.draw.r, cmd->data.draw.g, cmd->data.draw.b);
+ const size_t vertslen = count * sizeof (Vertex) * 4;
+ Vertex *verts = (Vertex *) SDL_AllocateRenderVertices(renderer, vertslen, 0, &cmd->data.draw.first);
+ size_t i;
- if (D3D_ActivateRenderer(renderer) < 0) {
+ if (!verts) {
return -1;
}
- color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
-
- if (renderer->target) {
- BackBufferWidth = renderer->target->w;
- BackBufferHeight = renderer->target->h;
- } else {
- BackBufferWidth = data->pparams.BackBufferWidth;
- BackBufferHeight = data->pparams.BackBufferHeight;
- }
+ SDL_memset(verts, '\0', vertslen);
+ cmd->data.draw.count = count;
- if (renderer->clipping_enabled) {
- IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, FALSE);
- }
+ for (i = 0; i < count; i++) {
+ const SDL_FRect *rect = &rects[i];
+ const float minx = rect->x;
+ const float maxx = rect->x + rect->w;
+ const float miny = rect->y;
+ const float maxy = rect->y + rect->h;
- /* Don't reset the viewport if we don't have to! */
- if (!renderer->viewport.x && !renderer->viewport.y &&
- renderer->viewport.w == BackBufferWidth &&
- renderer->viewport.h == BackBufferHeight) {
- result = IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
- } else {
- D3DVIEWPORT9 viewport;
+ verts->x = minx;
+ verts->y = miny;
+ verts->color = color;
+ verts++;
- /* Clear is defined to clear the entire render target */
- viewport.X = 0;
- viewport.Y = 0;
- viewport.Width = BackBufferWidth;
- viewport.Height = BackBufferHeight;
- viewport.MinZ = 0.0f;
- viewport.MaxZ = 1.0f;
- IDirect3DDevice9_SetViewport(data->device, &viewport);
+ verts->x = maxx;
+ verts->y = miny;
+ verts->color = color;
+ verts++;
- result = IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
+ verts->x = maxx;
+ verts->y = maxy;
+ verts->color = color;
+ verts++;
- /* Reset the viewport */
- viewport.X = renderer->viewport.x;
- viewport.Y = renderer->viewport.y;
- viewport.Width = renderer->viewport.w;
- viewport.Height = renderer->viewport.h;
- viewport.MinZ = 0.0f;
- viewport.MaxZ = 1.0f;
- IDirect3DDevice9_SetViewport(data->device, &viewport);
+ verts->x = minx;
+ verts->y = maxy;
+ verts->color = color;
+ verts++;
}
- if (renderer->clipping_enabled) {
- IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, TRUE);
- }
-
- if (FAILED(result)) {
- return D3D_SetError("Clear()", result);
- }
return 0;
}
-static void
-D3D_SetBlendMode(D3D_RenderData * data, SDL_BlendMode blendMode)
-{
- if (blendMode == SDL_BLENDMODE_NONE) {
- IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, FALSE);
- } else {
- IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, TRUE);
- IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
- GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blendMode)));
- IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
- GetBlendFunc(SDL_GetBlendModeDstColorFactor(blendMode)));
- if (data->enableSeparateAlphaBlend) {
- IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA,
- GetBlendFunc(SDL_GetBlendModeSrcAlphaFactor(blendMode)));
- IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA,
- GetBlendFunc(SDL_GetBlendModeDstAlphaFactor(blendMode)));
- }
- }
-}
-
static int
-D3D_RenderDrawPoints(SDL_Renderer * renderer, const SDL_FPoint * points,
- int count)
+D3D_QueueCopy(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
+ const SDL_Rect * srcrect, const SDL_FRect * dstrect)
{
- D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
- DWORD color;
- Vertex *vertices;
- int i;
- HRESULT result;
+ const DWORD color = D3DCOLOR_ARGB(cmd->data.draw.a, cmd->data.draw.r, cmd->data.draw.g, cmd->data.draw.b);
+ float minx, miny, maxx, maxy;
+ float minu, maxu, minv, maxv;
+ const size_t vertslen = sizeof (Vertex) * 4;
+ Vertex *verts = (Vertex *) SDL_AllocateRenderVertices(renderer, vertslen, 0, &cmd->data.draw.first);
- if (D3D_ActivateRenderer(renderer) < 0) {
+ if (!verts) {
return -1;
}
- D3D_SetBlendMode(data, renderer->blendMode);
+ cmd->data.draw.count = 1;
- result =
- IDirect3DDevice9_SetTexture(data->device, 0,
- (IDirect3DBaseTexture9 *) 0);
- if (FAILED(result)) {
- return D3D_SetError("SetTexture()", result);
- }
+ minx = dstrect->x - 0.5f;
+ miny = dstrect->y - 0.5f;
+ maxx = dstrect->x + dstrect->w - 0.5f;
+ maxy = dstrect->y + dstrect->h - 0.5f;
- color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
+ minu = (float) srcrect->x / texture->w;
+ maxu = (float) (srcrect->x + srcrect->w) / texture->w;
+ minv = (float) srcrect->y / texture->h;
+ maxv = (float) (srcrect->y + srcrect->h) / texture->h;
+
+ verts->x = minx;
+ verts->y = miny;
+ verts->z = 0.0f;
+ verts->color = color;
+ verts->u = minu;
+ verts->v = minv;
+ verts++;
+
+ verts->x = maxx;
+ verts->y = miny;
+ verts->z = 0.0f;
+ verts->color = color;
+ verts->u = maxu;
+ verts->v = minv;
+ verts++;
+
+ verts->x = maxx;
+ verts->y = maxy;
+ verts->z = 0.0f;
+ verts->color = color;
+ verts->u = maxu;
+ verts->v = maxv;
+ verts++;
+
+ verts->x = minx;
+ verts->y = maxy;
+ verts->z = 0.0f;
+ verts->color = color;
+ verts->u = minu;
+ verts->v = maxv;
+ verts++;
- vertices = SDL_stack_alloc(Vertex, count);
- for (i = 0; i < count; ++i) {
- vertices[i].x = points[i].x;
- vertices[i].y = points[i].y;
- vertices[i].z = 0.0f;
- vertices[i].color = color;
- vertices[i].u = 0.0f;
- vertices[i].v = 0.0f;
- }
- result =
- IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, count,
- vertices, sizeof(*vertices));
- SDL_stack_free(vertices);
- if (FAILED(result)) {
- return D3D_SetError("DrawPrimitiveUP()", result);
- }
return 0;
}
static int
-D3D_RenderDrawLines(SDL_Renderer * renderer, const SDL_FPoint * points,
- int count)
+D3D_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
+ const SDL_Rect * srcquad, const SDL_FRect * dstrect,
+ const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
{
- D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
- DWORD color;
- Vertex *vertices;
- int i;
- HRESULT result;
+ const DWORD color = D3DCOLOR_ARGB(cmd->data.draw.a, cmd->data.draw.r, cmd->data.draw.g, cmd->data.draw.b);
+ float minx, miny, maxx, maxy;
+ float minu, maxu, minv, maxv;
+ const size_t vertslen = sizeof (Vertex) * 5;
+ Vertex *verts = (Vertex *) SDL_AllocateRenderVertices(renderer, vertslen, 0, &cmd->data.draw.first);
- if (D3D_ActivateRenderer(renderer) < 0) {
+ if (!verts) {
return -1;
}
- D3D_SetBlendMode(data, renderer->blendMode);
+ cmd->data.draw.count = 1;
- result =
- IDirect3DDevice9_SetTexture(data->device, 0,
- (IDirect3DBaseTexture9 *) 0);
- if (FAILED(result)) {
- return D3D_SetError("SetTexture()", result);
- }
+ minx = -center->x;
+ maxx = dstrect->w - center->x;
+ miny = -center->y;
+ maxy = dstrect->h - center->y;
- color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
-
- vertices = SDL_stack_alloc(Vertex, count);
- for (i = 0; i < count; ++i) {
- vertices[i].x = points[i].x;
- vertices[i].y = points[i].y;
- vertices[i].z = 0.0f;
- vertices[i].color = color;
- vertices[i].u = 0.0f;
- vertices[i].v = 0.0f;
+ if (flip & SDL_FLIP_HORIZONTAL) {
+ minu = (float) (srcquad->x + srcquad->w) / texture->w;
+ maxu = (float) srcquad->x / texture->w;
+ } else {
+ minu = (float) srcquad->x / texture->w;
+ maxu = (float) (srcquad->x + srcquad->w) / texture->w;
}
- result =
- IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_LINESTRIP, count-1,
- vertices, sizeof(*vertices));
- /* DirectX 9 has the same line rasterization semantics as GDI,
- so we need to close the endpoint of the line */
- if (count == 2 ||
- points[0].x != points[count-1].x || points[0].y != points[count-1].y) {
- vertices[0].x = points[count-1].x;
- vertices[0].y = points[count-1].y;
- result = IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, 1, vertices, sizeof(*vertices));
- }
+ if (flip & SDL_FLIP_VERTICAL) {
+ minv = (float) (srcquad->y + srcquad->h) / texture->h;
+ maxv = (float) srcquad->y / texture->h;
+ } else {
+ minv = (float) srcquad->y / texture->h;
+ maxv = (float) (srcquad->y + srcquad->h) / texture->h;
+ }
+
+ verts->x = minx;
+ verts->y = miny;
+ verts->z = 0.0f;
+ verts->color = color;
+ verts->u = minu;
+ verts->v = minv;
+ verts++;
+
+ verts->x = maxx;
+ verts->y = miny;
+ verts->z = 0.0f;
+ verts->color = color;
+ verts->u = maxu;
+ verts->v = minv;
+ verts++;
+
+ verts->x = maxx;
+ verts->y = maxy;
+ verts->z = 0.0f;
+ verts->color = color;
+ verts->u = maxu;
+ verts->v = maxv;
+ verts++;
+
+ verts->x = minx;
+ verts->y = maxy;
+ verts->z = 0.0f;
+ verts->color = color;
+ verts->u = minu;
+ verts->v = maxv;
+ verts++;
+
+ verts->x = dstrect->x + center->x - 0.5f; /* X translation */
+ verts->y = dstrect->y + center->y - 0.5f; /* Y translation */
+ verts->z = (float)(M_PI * (float) angle / 180.0f); /* rotation */
+ verts->color = 0;
+ verts->u = 0.0f;
+ verts->v = 0.0f;
+ verts++;
- SDL_stack_free(vertices);
- if (FAILED(result)) {
- return D3D_SetError("DrawPrimitiveUP()", result);
- }
return 0;
}
static int
-D3D_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects,
- int count)
+BindTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWORD sampler)
{
- D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
- DWORD color;
- int i;
- float minx, miny, maxx, maxy;
- Vertex vertices[4];
HRESULT result;
- if (D3D_ActivateRenderer(renderer) < 0) {
- return -1;
- }
-
- D3D_SetBlendMode(data, renderer->blendMode);
-
- result =
- IDirect3DDevice9_SetTexture(data->device, 0,
- (IDirect3DBaseTexture9 *) 0);
- if (FAILED(result)) {
- return D3D_SetError("SetTexture()", result);
- }
-
- color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
-
- for (i = 0; i < count; ++i) {
- const SDL_FRect *rect = &rects[i];
+ if (texture->dirty && texture->staging) {
+ if (!texture->texture) {
+ result = IDirect3DDevice9_CreateTexture(device, texture->w, texture->h, 1, texture->usage,
+ PixelFormatToD3DFMT(texture->format), D3DPOOL_DEFAULT, &texture->texture, NULL);
+ if (FAILED(result)) {
+ return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
+ }
+ }
- minx = rect->x;
- miny = rect->y;
- maxx = rect->x + rect->w;
- maxy = rect->y + rect->h;
-
- vertices[0].x = minx;
- vertices[0].y = miny;
- vertices[0].z = 0.0f;
- vertices[0].color = color;
- vertices[0].u = 0.0f;
- vertices[0].v = 0.0f;
-
- vertices[1].x = maxx;
- vertices[1].y = miny;
- vertices[1].z = 0.0f;
- vertices[1].color = color;
- vertices[1].u = 0.0f;
- vertices[1].v = 0.0f;
-
- vertices[2].x = maxx;
- vertices[2].y = maxy;
- vertices[2].z = 0.0f;
- vertices[2].color = color;
- vertices[2].u = 0.0f;
- vertices[2].v = 0.0f;
-
- vertices[3].x = minx;
- vertices[3].y = maxy;
- vertices[3].z = 0.0f;
- vertices[3].color = color;
- vertices[3].u = 0.0f;
- vertices[3].v = 0.0f;
-
- result =
- IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN,
- 2, vertices, sizeof(*vertices));
+ result = IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)texture->staging, (IDirect3DBaseTexture9 *)texture->texture);
if (FAILED(result)) {
- return D3D_SetError("DrawPrimitiveUP()", result);
+ return D3D_SetError("UpdateTexture()", result);
}
+ texture->dirty = SDL_FALSE;
+ }
+ result = IDirect3DDevice9_SetTexture(device, sampler, (IDirect3DBaseTexture9 *)texture->texture);
+ if (FAILED(result)) {
+ return D3D_SetError("SetTexture()", result);
}
return 0;
}
static void
-D3D_UpdateTextureScaleMode(D3D_RenderData *data, D3D_TextureData *texturedata, unsigned index)
+UpdateTextureScaleMode(D3D_RenderData *data, D3D_TextureData *texturedata, unsigned index)
{
if (texturedata->scaleMode != data->scaleMode[index]) {
IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MINFILTER,
@@ -1411,22 +1038,20 @@ D3D_UpdateTextureScaleMode(D3D_RenderData *data, D3D_TextureData *texturedata, u
}
static int
-D3D_RenderSetupTextureState(SDL_Renderer * renderer, SDL_Texture * texture, LPDIRECT3DPIXELSHADER9 *shader)
+SetupTextureState(D3D_RenderData *data, SDL_Texture * texture, LPDIRECT3DPIXELSHADER9 *shader)
{
- D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
- D3D_TextureData *texturedata;
+ D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
- *shader = NULL;
+ SDL_assert(*shader == NULL);
- texturedata = (D3D_TextureData *)texture->driverdata;
if (!texturedata) {
SDL_SetError("Texture is not currently available");
return -1;
}
- D3D_UpdateTextureScaleMode(data, texturedata, 0);
+ UpdateTextureScaleMode(data, texturedata, 0);
- if (D3D_BindTextureRep(data->device, &texturedata->texture, 0) < 0) {
+ if (BindTextureRep(data->device, &texturedata->texture, 0) < 0) {
return -1;
}
@@ -1445,13 +1070,13 @@ D3D_RenderSetupTextureState(SDL_Renderer * renderer, SDL_Texture * texture, LPDI
return SDL_SetError("Unsupported YUV conversion mode");
}
- D3D_UpdateTextureScaleMode(data, texturedata, 1);
- D3D_UpdateTextureScaleMode(data, texturedata, 2);
+ UpdateTextureScaleMode(data, texturedata, 1);
+ UpdateTextureScaleMode(data, texturedata, 2);
- if (D3D_BindTextureRep(data->device, &texturedata->utexture, 1) < 0) {
+ if (BindTextureRep(data->device, &texturedata->utexture, 1) < 0) {
return -1;
}
- if (D3D_BindTextureRep(data->device, &texturedata->vtexture, 2) < 0) {
+ if (BindTextureRep(data->device, &texturedata->vtexture, 2) < 0) {
return -1;
}
}
@@ -1459,193 +1084,325 @@ D3D_RenderSetupTextureState(SDL_Renderer * renderer, SDL_Texture * texture, LPDI
}
static int
-D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * srcrect, const SDL_FRect * dstrect)
+SetDrawState(D3D_RenderData *data, const SDL_RenderCommand *cmd)
{
- D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
- LPDIRECT3DPIXELSHADER9 shader;
- float minx, miny, maxx, maxy;
- float minu, maxu, minv, maxv;
- DWORD color;
- Vertex vertices[4];
- HRESULT result;
+ const SDL_bool was_copy_ex = data->drawstate.is_copy_ex;
+ const SDL_bool is_copy_ex = (cmd->command == SDL_RENDERCMD_COPY_EX);
+ SDL_Texture *texture = cmd->data.draw.texture;
+ const SDL_BlendMode blend = cmd->data.draw.blend;
+
+ if (texture != data->drawstate.texture) {
+ D3D_TextureData *oldtexturedata = data->drawstate.texture ? (D3D_TextureData *) data->drawstate.texture->driverdata : NULL;
+ D3D_TextureData *newtexturedata = texture ? (D3D_TextureData *) texture->driverdata : NULL;
+ LPDIRECT3DPIXELSHADER9 shader = NULL;
+
+ /* disable any enabled textures we aren't going to use, let SetupTextureState() do the rest. */
+ if (texture == NULL) {
+ IDirect3DDevice9_SetTexture(data->device, 0, NULL);
+ }
+ if ((!newtexturedata || !newtexturedata->yuv) && (oldtexturedata && oldtexturedata->yuv)) {
+ IDirect3DDevice9_SetTexture(data->device, 1, NULL);
+ IDirect3DDevice9_SetTexture(data->device, 2, NULL);
+ }
+ if (texture && SetupTextureState(data, texture, &shader) < 0) {
+ return -1;
+ }
- if (D3D_ActivateRenderer(renderer) < 0) {
- return -1;
- }
+ if (shader != data->drawstate.shader) {
+ const HRESULT result = IDirect3DDevice9_SetPixelShader(data->device, shader);
+ if (FAILED(result)) {
+ return D3D_SetError("IDirect3DDevice9_SetPixelShader()", result);
+ }
+ data->drawstate.shader = shader;
+ }
- minx = dstrect->x - 0.5f;
- miny = dstrect->y - 0.5f;
- maxx = dstrect->x + dstrect->w - 0.5f;
- maxy = dstrect->y + dstrect->h - 0.5f;
+ data->drawstate.texture = texture;
+ }
- minu = (float) srcrect->x / texture->w;
- maxu = (float) (srcrect->x + srcrect->w) / texture->w;
- minv = (float) srcrect->y / texture->h;
- maxv = (float) (srcrect->y + srcrect->h) / texture->h;
+ if (blend != data->drawstate.blend) {
+ if (blend == SDL_BLENDMODE_NONE) {
+ IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, FALSE);
+ } else {
+ IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, TRUE);
+ IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
+ GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blend)));
+ IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
+ GetBlendFunc(SDL_GetBlendModeDstColorFactor(blend)));
+ if (data->enableSeparateAlphaBlend) {
+ IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA,
+ GetBlendFunc(SDL_GetBlendModeSrcAlphaFactor(blend)));
+ IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA,
+ GetBlendFunc(SDL_GetBlendModeDstAlphaFactor(blend)));
+ }
+ }
- color = D3DCOLOR_ARGB(texture->a, texture->r, texture->g, texture->b);
-
- vertices[0].x = minx;
- vertices[0].y = miny;
- vertices[0].z = 0.0f;
- vertices[0].color = color;
- vertices[0].u = minu;
- vertices[0].v = minv;
-
- vertices[1].x = maxx;
- vertices[1].y = miny;
- vertices[1].z = 0.0f;
- vertices[1].color = color;
- vertices[1].u = maxu;
- vertices[1].v = minv;
-
- vertices[2].x = maxx;
- vertices[2].y = maxy;
- vertices[2].z = 0.0f;
- vertices[2].color = color;
- vertices[2].u = maxu;
- vertices[2].v = maxv;
-
- vertices[3].x = minx;
- vertices[3].y = maxy;
- vertices[3].z = 0.0f;
- vertices[3].color = color;
- vertices[3].u = minu;
- vertices[3].v = maxv;
-
- D3D_SetBlendMode(data, texture->blendMode);
-
- if (D3D_RenderSetupTextureState(renderer, texture, &shader) < 0) {
- return -1;
+ data->drawstate.blend = blend;
}
-
- if (shader) {
- result = IDirect3DDevice9_SetPixelShader(data->device, shader);
- if (FAILED(result)) {
- return D3D_SetError("SetShader()", result);
+
+ if (is_copy_ex != was_copy_ex) {
+ if (!is_copy_ex) { /* SDL_RENDERCMD_COPY_EX will set this, we only want to reset it here if necessary. */
+ const Float4X4 d3dmatrix = MatrixIdentity();
+ IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*) &d3dmatrix);
}
+ data->drawstate.is_copy_ex = is_copy_ex;
+ }
+
+ if (data->drawstate.viewport_dirty) {
+ const SDL_Rect *viewport = &data->drawstate.viewport;
+ const D3DVIEWPORT9 d3dviewport = { viewport->x, viewport->y, viewport->w, viewport->h, 0.0f, 1.0f };
+ IDirect3DDevice9_SetViewport(data->device, &d3dviewport);
+
+ /* Set an orthographic projection matrix */
+ if (viewport->w && viewport->h) {
+ D3DMATRIX d3dmatrix;
+ SDL_zero(d3dmatrix);
+ d3dmatrix.m[0][0] = 2.0f / viewport->w;
+ d3dmatrix.m[1][1] = -2.0f / viewport->h;
+ d3dmatrix.m[2][2] = 1.0f;
+ d3dmatrix.m[3][0] = -1.0f;
+ d3dmatrix.m[3][1] = 1.0f;
+ d3dmatrix.m[3][3] = 1.0f;
+ IDirect3DDevice9_SetTransform(data->device, D3DTS_PROJECTION, &d3dmatrix);
+ }
+
+ data->drawstate.viewport_dirty = SDL_FALSE;
}
- result = IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2,
- vertices, sizeof(*vertices));
- if (FAILED(result)) {
- D3D_SetError("DrawPrimitiveUP()", result);
+
+ if (data->drawstate.cliprect_enabled_dirty) {
+ IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, data->drawstate.cliprect_enabled ? TRUE : FALSE);
+ data->drawstate.cliprect_enabled_dirty = SDL_FALSE;
}
- if (shader) {
- IDirect3DDevice9_SetPixelShader(data->device, NULL);
+
+ if (data->drawstate.cliprect_dirty) {
+ const SDL_Rect *viewport = &data->drawstate.viewport;
+ const SDL_Rect *rect = &cmd->data.cliprect.rect;
+ const RECT d3drect = { viewport->x + rect->x, viewport->y + rect->y, viewport->x + rect->x + rect->w, viewport->y + rect->y + rect->h };
+ IDirect3DDevice9_SetScissorRect(data->device, &d3drect);
+ data->drawstate.cliprect_dirty = SDL_FALSE;
}
- return FAILED(result) ? -1 : 0;
-}
+ return 0;
+}
static int
-D3D_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * srcrect, const SDL_FRect * dstrect,
- const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip)
+D3D_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
{
D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
- LPDIRECT3DPIXELSHADER9 shader = NULL;
- float minx, miny, maxx, maxy;
- float minu, maxu, minv, maxv;
- float centerx, centery;
- DWORD color;
- Vertex vertices[4];
- Float4X4 modelMatrix;
- HRESULT result;
+ const int vboidx = data->currentVertexBuffer;
+ IDirect3DVertexBuffer9 *vbo = NULL;
+ const SDL_bool istarget = renderer->target != NULL;
+ size_t i;
if (D3D_ActivateRenderer(renderer) < 0) {
return -1;
}
- centerx = center->x;
- centery = center->y;
-
- minx = -centerx;
- maxx = dstrect->w - centerx;
- miny = -centery;
- maxy = dstrect->h - centery;
-
- minu = (float) srcrect->x / texture->w;
- maxu = (float) (srcrect->x + srcrect->w) / texture->w;
- minv = (float) srcrect->y / texture->h;
- maxv = (float) (srcrect->y + srcrect->h) / texture->h;
+ /* upload the new VBO data for this set of commands. */
+ vbo = data->vertexBuffers[vboidx];
+ if (!vbo || (data->vertexBufferSize[vboidx] < vertsize)) {
+ const DWORD usage = D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY;
+ const DWORD fvf = D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1;
+ if (vbo) {
+ IDirect3DVertexBuffer9_Release(vbo);
+ }
- if (flip & SDL_FLIP_HORIZONTAL) {
- float tmp = maxu;
- maxu = minu;
- minu = tmp;
- }
- if (flip & SDL_FLIP_VERTICAL) {
- float tmp = maxv;
- maxv = minv;
- minv = tmp;
- }
-
- color = D3DCOLOR_ARGB(texture->a, texture->r, texture->g, texture->b);
-
- vertices[0].x = minx;
- vertices[0].y = miny;
- vertices[0].z = 0.0f;
- vertices[0].color = color;
- vertices[0].u = minu;
- vertices[0].v = minv;
-
- vertices[1].x = maxx;
- vertices[1].y = miny;
- vertices[1].z = 0.0f;
- vertices[1].color = color;
- vertices[1].u = maxu;
- vertices[1].v = minv;
-
- vertices[2].x = maxx;
- vertices[2].y = maxy;
- vertices[2].z = 0.0f;
- vertices[2].color = color;
- vertices[2].u = maxu;
- vertices[2].v = maxv;
-
- vertices[3].x = minx;
- vertices[3].y = maxy;
- vertices[3].z = 0.0f;
- vertices[3].color = color;
- vertices[3].u = minu;
- vertices[3].v = maxv;
-
- D3D_SetBlendMode(data, texture->blendMode);
-
- if (D3D_RenderSetupTextureState(renderer, texture, &shader) < 0) {
- return -1;
+ if (FAILED(IDirect3DDevice9_CreateVertexBuffer(data->device, vertsize, usage, fvf, D3DPOOL_DEFAULT, &vbo, NULL))) {
+ vbo = NULL;
+ }
+ data->vertexBuffers[vboidx] = vbo;
+ data->vertexBufferSize[vboidx] = vbo ? vertsize : 0;
}
- /* Rotate and translate */
- modelMatrix = MatrixMultiply(
- MatrixRotationZ((float)(M_PI * (float) angle / 180.0f)),
- MatrixTranslation(dstrect->x + center->x - 0.5f, dstrect->y + center->y - 0.5f, 0));
- IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)&modelMatrix);
-
- if (shader) {
- result = IDirect3DDevice9_SetPixelShader(data->device, shader);
- if (FAILED(result)) {
- D3D_SetError("SetShader()", result);
- goto done;
+ if (vbo) {
+ void *ptr;
+ if (FAILED(IDirect3DVertexBuffer9_Lock(vbo, 0, vertsize, &ptr, D3DLOCK_DISCARD))) {
+ vbo = NULL; /* oh well, we'll do immediate mode drawing. :( */
+ } else {
+ SDL_memcpy(ptr, vertices, vertsize);
+ if (FAILED(IDirect3DVertexBuffer9_Unlock(vbo))) {
+ vbo = NULL; /* oh well, we'll do immediate mode drawing. :( */
+ }
}
}
- result = IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2,
- vertices, sizeof(*vertices));
- if (FAILED(result)) {
- D3D_SetError("DrawPrimitiveUP()", result);
- }
-done:
- if (shader) {
- IDirect3DDevice9_SetPixelShader(data->device, NULL);
- }
- modelMatrix = MatrixIdentity();
- IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)&modelMatrix);
+ /* cycle through a few VBOs so D3D has some time with the data before we replace it. */
+ if (vbo) {
+ data->currentVertexBuffer++;
+ if (data->currentVertexBuffer >= SDL_arraysize(data->vertexBuffers)) {
+ data->currentVertexBuffer = 0;
+ }
+ } else if (!data->reportedVboProblem) {
+ SDL_LogError(SDL_LOG_CATEGORY_RENDER, "SDL failed to get a vertex buffer for this Direct3D 9 rendering batch!");
+ SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Dropping back to a slower method.");
+ SDL_LogError(SDL_LOG_CATEGORY_RENDER, "This might be a brief hiccup, but if performance is bad, this is probably why.");
+ SDL_LogError(SDL_LOG_CATEGORY_RENDER, "This error will not be logged again for this renderer.");
+ data->reportedVboProblem = SDL_TRUE;
+ }
+
+ IDirect3DDevice9_SetStreamSource(data->device, 0, vbo, 0, sizeof (Vertex));
+
+ while (cmd) {
+ switch (cmd->command) {
+ case SDL_RENDERCMD_SETDRAWCOLOR: {
+ /* currently this is sent with each vertex, but if we move to
+ shaders, we can put this in a uniform here and reduce vertex
+ buffer bandwidth */
+ break;
+ }
+
+ case SDL_RENDERCMD_SETVIEWPORT: {
+ SDL_Rect *viewport = &data->drawstate.viewport;
+ if (SDL_memcmp(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect)) != 0) {
+ SDL_memcpy(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect));
+ data->drawstate.viewport_dirty = SDL_TRUE;
+ }
+ break;
+ }
+
+ case SDL_RENDERCMD_SETCLIPRECT: {
+ const SDL_Rect *rect = &cmd->data.cliprect.rect;
+ if (data->drawstate.cliprect_enabled != cmd->data.cliprect.enabled) {
+ data->drawstate.cliprect_enabled = cmd->data.cliprect.enabled;
+ data->drawstate.cliprect_enabled_dirty = SDL_TRUE;
+ }
+
+ if (SDL_memcmp(&data->drawstate.cliprect, rect, sizeof (SDL_Rect)) != 0) {
+ SDL_memcpy(&data->drawstate.cliprect, rect, sizeof (SDL_Rect));
+ data->drawstate.cliprect_dirty = SDL_TRUE;
+ }
+ break;
+ }
+
+ case SDL_RENDERCMD_CLEAR: {
+ const DWORD color = D3DCOLOR_ARGB(cmd->data.color.a, cmd->data.color.r, cmd->data.color.g, cmd->data.color.b);
+ const SDL_Rect *viewport = &data->drawstate.viewport;
+ const int backw = istarget ? renderer->target->w : data->pparams.BackBufferWidth;
+ const int backh = istarget ? renderer->target->h : data->pparams.BackBufferHeight;
+
+ if (data->drawstate.cliprect_enabled) {
+ IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, FALSE);
+ data->drawstate.cliprect_enabled_dirty = SDL_TRUE;
+ }
+
+ /* Don't reset the viewport if we don't have to! */
+ if (!viewport->x && !viewport->y && (viewport->w == backw) && (viewport->h == backh)) {
+ IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
+ } else {
+ /* Clear is defined to clear the entire render target */
+ const D3DVIEWPORT9 wholeviewport = { 0, 0, backw, backh, 0.0f, 1.0f };
+ IDirect3DDevice9_SetViewport(data->device, &wholeviewport);
+ data->drawstate.viewport_dirty = SDL_TRUE;
+ IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
+ }
+
+ break;
+ }
+
+ case SDL_RENDERCMD_DRAW_POINTS: {
+ const size_t count = cmd->data.draw.count;
+ const size_t first = cmd->data.draw.first;
+ SetDrawState(data, cmd);
+ if (vbo) {
+ IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_POINTLIST, first / sizeof (Vertex), count);
+ } else {
+ const Vertex *verts = (Vertex *) (((Uint8 *) vertices) + first);
+ IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, count, vertices, sizeof (Vertex));
+ }
+ break;
+ }
+
+ case SDL_RENDERCMD_DRAW_LINES: {
+ const size_t count = cmd->data.draw.count;
+ const size_t first = cmd->data.draw.first;
+ const Vertex *verts = (Vertex *) (((Uint8 *) vertices) + first);
+
+ /* DirectX 9 has the same line rasterization semantics as GDI,
+ so we need to close the endpoint of the line with a second draw call. */
+ const SDL_bool close_endpoint = ((count == 2) || (verts[0].x != verts[count-1].x) || (verts[0].y != verts[count-1].y));
+
+ SetDrawState(data, cmd);
+
+ if (vbo) {
+ IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_LINESTRIP, first / sizeof (Vertex), count - 1);
+ if (close_endpoint) {
+ IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_POINTLIST, (first / sizeof (Vertex)) + (count - 1), 1);
+ }
+ } else {
+ IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_LINESTRIP, count - 1, verts, sizeof (Vertex));
+ if (close_endpoint) {
+ IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, 1, &verts[count-1], sizeof (Vertex));
+ }
+ }
+ break;
+ }
+
+ case SDL_RENDERCMD_FILL_RECTS: {
+ const size_t count = cmd->data.draw.count;
+ const size_t first = cmd->data.draw.first;
+ SetDrawState(data, cmd);
+ if (vbo) {
+ size_t offset = 0;
+ for (i = 0; i < count; ++i, offset += 4) {
+ IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_TRIANGLEFAN, (first / sizeof (Vertex)) + offset, 2);
+ }
+ } else {
+ const Vertex *verts = (Vertex *) (((Uint8 *) vertices) + first);
+ for (i = 0; i < count; ++i, verts += 4) {
+ IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2, verts, sizeof (Vertex));
+ }
+ }
+ break;
+ }
+
+ case SDL_RENDERCMD_COPY: {
+ const size_t count = cmd->data.draw.count;
+ const size_t first = cmd->data.draw.first;
+ SetDrawState(data, cmd);
+ if (vbo) {
+ size_t offset = 0;
+ for (i = 0; i < count; ++i, offset += 4) {
+ IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_TRIANGLEFAN, (first / sizeof (Vertex)) + offset, 2);
+ }
+ } else {
+ const Vertex *verts = (Vertex *) (((Uint8 *) vertices) + first);
+ for (i = 0; i < count; ++i, verts += 4) {
+ IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2, verts, sizeof (Vertex));
+ }
+ }
+ break;
+ }
+
+ case SDL_RENDERCMD_COPY_EX: {
+ const size_t first = cmd->data.draw.first;
+ const Vertex *verts = (Vertex *) (((Uint8 *) vertices) + first);
+ const Vertex *transvert = verts + 4;
+ const float translatex = transvert->x;
+ const float translatey = transvert->y;
+ const float rotation = transvert->z;
+ const Float4X4 d3dmatrix = MatrixMultiply(MatrixRotationZ(rotation), MatrixTranslation(translatex, translatey, 0));
+ SetDrawState(data, cmd);
+
+ IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)&d3dmatrix);
+
+ if (vbo) {
+ IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_TRIANGLEFAN, first / sizeof (Vertex), 2);
+ } else {
+ IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2, verts, sizeof (Vertex));
+ }
+ break;
+ }
+
+ case SDL_RENDERCMD_NO_OP:
+ break;
+ }
- return FAILED(result) ? -1 : 0;
+ cmd = cmd->next;
+ }
+
+ return 0;
}
+
static int
D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
Uint32 format, void * pixels, int pitch)
@@ -1782,6 +1539,249 @@ D3D_DestroyRenderer(SDL_Renderer * renderer)
}
SDL_free(renderer);
}
+
+static int
+D3D_Reset(SDL_Renderer * renderer)
+{
+ D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
+ HRESULT result;
+ SDL_Texture *texture;
+
+ /* Release the default render target before reset */
+ if (data->defaultRenderTarget) {
+ IDirect3DSurface9_Release(data->defaultRenderTarget);
+ data->defaultRenderTarget = NULL;
+ }
+ if (data->currentRenderTarget != NULL) {
+ IDirect3DSurface9_Release(data->currentRenderTarget);
+ data->currentRenderTarget = NULL;
+ }
+
+ /* Release application render targets */
+ for (texture = renderer->textures; texture; texture = texture->next) {
+ if (texture->access == SDL_TEXTUREACCESS_TARGET) {
+ D3D_DestroyTexture(renderer, texture);
+ } else {
+ D3D_RecreateTexture(renderer, texture);
+ }
+ }
+
+ result = IDirect3DDevice9_Reset(data->device, &data->pparams);
+ if (FAILED(result)) {
+ if (result == D3DERR_DEVICELOST) {
+ /* Don't worry about it, we'll reset later... */
+ return 0;
+ } else {
+ return D3D_SetError("Reset()", result);
+ }
+ }
+
+ /* Allocate application render targets */
+ for (texture = renderer->textures; texture; texture = texture->next) {
+ if (texture->access == SDL_TEXTUREACCESS_TARGET) {
+ D3D_CreateTexture(renderer, texture);
+ }
+ }
+
+ IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget);
+ D3D_InitRenderState(data);
+ D3D_SetRenderTargetInternal(renderer, renderer->target);
+ data->drawstate.viewport_dirty = SDL_TRUE;
+
+ /* Let the application know that render targets were reset */
+ {
+ SDL_Event event;
+ event.type = SDL_RENDER_TARGETS_RESET;
+ SDL_PushEvent(&event);
+ }
+
+ return 0;
+}
+
+SDL_Renderer *
+D3D_CreateRenderer(SDL_Window * window, Uint32 flags)
+{
+ SDL_Renderer *renderer;
+ D3D_RenderData *data;
+ SDL_SysWMinfo windowinfo;
+ HRESULT result;
+ D3DPRESENT_PARAMETERS pparams;
+ IDirect3DSwapChain9 *chain;
+ D3DCAPS9 caps;
+ DWORD device_flags;
+ Uint32 window_flags;
+ int w, h;
+ SDL_DisplayMode fullscreen_mode;
+ int displayIndex;
+
+ renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
+ if (!renderer) {
+ SDL_OutOfMemory();
+ return NULL;
+ }
+
+ data = (D3D_RenderData *) SDL_calloc(1, sizeof(*data));
+ if (!data) {
+ SDL_free(renderer);
+ SDL_OutOfMemory();
+ return NULL;
+ }
+
+ if (!D3D_LoadDLL(&data->d3dDLL, &data->d3d)) {
+ SDL_free(renderer);
+ SDL_free(data);
+ SDL_SetError("Unable to create Direct3D interface");
+ return NULL;
+ }
+
+ renderer->WindowEvent = D3D_WindowEvent;
+ renderer->SupportsBlendMode = D3D_SupportsBlendMode;
+ renderer->CreateTexture = D3D_CreateTexture;
+ renderer->UpdateTexture = D3D_UpdateTexture;
+ renderer->UpdateTextureYUV = D3D_UpdateTextureYUV;
+ renderer->LockTexture = D3D_LockTexture;
+ renderer->UnlockTexture = D3D_UnlockTexture;
+ renderer->SetRenderTarget = D3D_SetRenderTarget;
+ renderer->QueueSetViewport = D3D_QueueSetViewport;
+ renderer->QueueSetDrawColor = D3D_QueueSetViewport; /* SetViewport and SetDrawColor are (currently) no-ops. */
+ renderer->QueueDrawPoints = D3D_QueueDrawPoints;
+ renderer->QueueDrawLines = D3D_QueueDrawPoints; /* lines and points queue vertices the same way. */
+ renderer->QueueFillRects = D3D_QueueFillRects;
+ renderer->QueueCopy = D3D_QueueCopy;
+ renderer->QueueCopyEx = D3D_QueueCopyEx;
+ renderer->RunCommandQueue = D3D_RunCommandQueue;
+ renderer->RenderReadPixels = D3D_RenderReadPixels;
+ renderer->RenderPresent = D3D_RenderPresent;
+ renderer->DestroyTexture = D3D_DestroyTexture;
+ renderer->DestroyRenderer = D3D_DestroyRenderer;
+ renderer->info = D3D_RenderDriver.info;
+ renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
+ renderer->driverdata = data;
+
+ SDL_VERSION(&windowinfo.version);
+ SDL_GetWindowWMInfo(window, &windowinfo);
+
+ window_flags = SDL_GetWindowFlags(window);
+ SDL_GetWindowSize(window, &w, &h);
+ SDL_GetWindowDisplayMode(window, &fullscreen_mode);
+
+ SDL_zero(pparams);
+ pparams.hDeviceWindow = windowinfo.info.win.window;
+ pparams.BackBufferWidth = w;
+ pparams.BackBufferHeight = h;
+ pparams.BackBufferCount = 1;
+ pparams.SwapEffect = D3DSWAPEFFECT_DISCARD;
+
+ if (window_flags & SDL_WINDOW_FULLSCREEN && (window_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
+ pparams.Windowed = FALSE;
+ pparams.BackBufferFormat = PixelFormatToD3DFMT(fullscreen_mode.format);
+ pparams.FullScreen_RefreshRateInHz = fullscreen_mode.refresh_rate;
+ } else {
+ pparams.Windowed = TRUE;
+ pparams.BackBufferFormat = D3DFMT_UNKNOWN;
+ pparams.FullScreen_RefreshRateInHz = 0;
+ }
+ if (flags & SDL_RENDERER_PRESENTVSYNC) {
+ pparams.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
+ } else {
+ pparams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
+ }
+
+ /* Get the adapter for the display that the window is on */
+ displayIndex = SDL_GetWindowDisplayIndex(window);
+ data->adapter = SDL_Direct3D9GetAdapterIndex(displayIndex);
+
+ IDirect3D9_GetDeviceCaps(data->d3d, data->adapter, D3DDEVTYPE_HAL, &caps);
+
+ device_flags = D3DCREATE_FPU_PRESERVE;
+ if (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) {
+ device_flags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
+ } else {
+ device_flags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
+ }
+
+ if (SDL_GetHintBoolean(SDL_HINT_RENDER_DIRECT3D_THREADSAFE, SDL_FALSE)) {
+ device_flags |= D3DCREATE_MULTITHREADED;
+ }
+
+ result = IDirect3D9_CreateDevice(data->d3d, data->adapter,
+ D3DDEVTYPE_HAL,
+ pparams.hDeviceWindow,
+ device_flags,
+ &pparams, &data->device);
+ if (FAILED(result)) {
+ D3D_DestroyRenderer(renderer);
+ D3D_SetError("CreateDevice()", result);
+ return NULL;
+ }
+
+ /* Get presentation parameters to fill info */
+ result = IDirect3DDevice9_GetSwapChain(data->device, 0, &chain);
+ if (FAILED(result)) {
+ D3D_DestroyRenderer(renderer);
+ D3D_SetError("GetSwapChain()", result);
+ return NULL;
+ }
+ result = IDirect3DSwapChain9_GetPresentParameters(chain, &pparams);
+ if (FAILED(result)) {
+ IDirect3DSwapChain9_Release(chain);
+ D3D_DestroyRenderer(renderer);
+ D3D_SetError("GetPresentParameters()", result);
+ return NULL;
+ }
+ IDirect3DSwapChain9_Release(chain);
+ if (pparams.PresentationInterval == D3DPRESENT_INTERVAL_ONE) {
+ renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
+ }
+ data->pparams = pparams;
+
+ IDirect3DDevice9_GetDeviceCaps(data->device, &caps);
+ renderer->info.max_texture_width = caps.MaxTextureWidth;
+ renderer->info.max_texture_height = caps.MaxTextureHeight;
+ if (caps.NumSimultaneousRTs >= 2) {
+ renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE;
+ }
+
+ if (caps.PrimitiveMiscCaps & D3DPMISCCAPS_SEPARATEALPHABLEND) {
+ data->enableSeparateAlphaBlend = SDL_TRUE;
+ }
+
+ /* Store the default render target */
+ IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget);
+ data->currentRenderTarget = NULL;
+
+ /* Set up parameters for rendering */
+ D3D_InitRenderState(data);
+
+ if (caps.MaxSimultaneousTextures >= 3) {
+ int i;
+ for (i = 0; i < SDL_arraysize(data->shaders); ++i) {
+ result = D3D9_CreatePixelShader(data->device, (D3D9_Shader)i, &data->shaders[i]);
+ if (FAILED(result)) {
+ D3D_SetError("CreatePixelShader()", result);
+ }
+ }
+ if (data->shaders[SHADER_YUV_JPEG] && data->shaders[SHADER_YUV_BT601] && data->shaders[SHADER_YUV_BT709]) {
+ renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;
+ renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
+ }
+ }
+
+ data->drawstate.blend = SDL_BLENDMODE_INVALID;
+
+ return renderer;
+}
+
+SDL_RenderDriver D3D_RenderDriver = {
+ D3D_CreateRenderer,
+ {
+ "direct3d",
+ (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
+ 1,
+ {SDL_PIXELFORMAT_ARGB8888},
+ 0,
+ 0}
+};
#endif /* SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED */
#ifdef __WIN32__
diff --git a/src/render/direct3d11/SDL_render_d3d11.c b/src/render/direct3d11/SDL_render_d3d11.c
index 7a370392fa..ea2fd3a5e8 100644
--- a/src/render/direct3d11/SDL_render_d3d11.c
+++ b/src/render/direct3d11/SDL_render_d3d11.c
@@ -56,6 +56,9 @@ extern ISwapChainBackgroundPanelNative * WINRT_GlobalSwapChainBackgroundPanelNat
#define SAFE_RELEASE(X) if ((X)) { IUnknown_Release(SDL_static_cast(IUnknown*, X)); X = NULL; }
+/* !!! FIXME: vertex buffer bandwidth could be significantly lower; move color to a uniform, only use UV coords
+ !!! FIXME: when textures are needed, and don't ever pass Z, since it's always zero. */
+
/* Vertex shader, common values */
typedef struct
{
@@ -120,7 +123,8 @@ typedef struct
ID3D11RenderTargetView *mainRenderTargetView;
ID3D11RenderTargetView *currentOffscreenRenderTargetView;
ID3D11InputLayout *inputLayout;
- ID3D11Buffer *vertexBuffer;
+ ID3D11Buffer *vertexBuffers[8];
+ size_t vertexBufferSizes[8];
ID3D11VertexShader *vertexShader;
ID3D11PixelShader *pixelShaders[NUM_SHADERS];
int blendModesCount;
@@ -145,6 +149,14 @@ typedef struct
ID3D11PixelShader *currentShader;
ID3D11ShaderResourceView *currentShaderResource;
ID3D11SamplerState *currentSampler;
+ SDL_bool cliprectDirty;
+ SDL_bool currentCliprectEnabled;
+ SDL_Rect currentCliprect;
+ SDL_Rect currentViewport;
+ int currentViewportRotation;
+ SDL_bool viewportDirty;
+ Float4X4 identity;
+ int currentVertexBuffer;
} D3D11_RenderData;
@@ -175,75 +187,6 @@ static const GUID SDL_IID_ID3D11Debug = { 0x79cf2233, 0x7536, 0x4948, { 0x9d, 0x
#endif
-/* Direct3D 11.1 renderer implementation */
-static SDL_Renderer *D3D11_CreateRenderer(SDL_Window * window, Uint32 flags);
-static void D3D11_WindowEvent(SDL_Renderer * renderer,
- const SDL_WindowEvent *event);
-static SDL_bool D3D11_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode);
-static int D3D11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
-static int D3D11_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * rect, const void *srcPixels,
- int srcPitch);
-static int D3D11_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * rect,
- const Uint8 *Yplane, int Ypitch,
- const Uint8 *Uplane, int Upitch,
- const Uint8 *Vplane, int Vpitch);
-static int D3D11_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * rect, void **pixels, int *pitch);
-static void D3D11_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
-static int D3D11_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture);
-static int D3D11_UpdateViewport(SDL_Renderer * renderer);
-static int D3D11_UpdateClipRect(SDL_Renderer * renderer);
-static int D3D11_RenderClear(SDL_Renderer * renderer);
-static int D3D11_RenderDrawPoints(SDL_Renderer * renderer,
- const SDL_FPoint * points, int count);
-static int D3D11_RenderDrawLines(SDL_Renderer * renderer,
- const SDL_FPoint * points, int count);
-static int D3D11_RenderFillRects(SDL_Renderer * renderer,
- const SDL_FRect * rects, int count);
-static int D3D11_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * srcrect, const SDL_FRect * dstrect);
-static int D3D11_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * srcrect, const SDL_FRect * dstrect,
- const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip);
-static int D3D11_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
- Uint32 format, void * pixels, int pitch);
-static void D3D11_RenderPresent(SDL_Renderer * renderer);
-static void D3D11_DestroyTexture(SDL_Renderer * renderer,
- SDL_Texture * texture);
-static void D3D11_DestroyRenderer(SDL_Renderer * renderer);
-
-/* Direct3D 11.1 Internal Functions */
-static HRESULT D3D11_CreateDeviceResources(SDL_Renderer * renderer);
-static HRESULT D3D11_CreateWindowSizeDependentResources(SDL_Renderer * renderer);
-static HRESULT D3D11_UpdateForWindowSizeChange(SDL_Renderer * renderer);
-static HRESULT D3D11_HandleDeviceLost(SDL_Renderer * renderer);
-static void D3D11_ReleaseMainRenderTargetView(SDL_Renderer * renderer);
-
-SDL_RenderDriver D3D11_RenderDriver = {
- D3D11_CreateRenderer,
- {
- "direct3d11",
- (
- SDL_RENDERER_ACCELERATED |
- SDL_RENDERER_PRESENTVSYNC |
- SDL_RENDERER_TARGETTEXTURE
- ), /* flags. see SDL_RendererFlags */
- 6, /* num_texture_formats */
- { /* texture_formats */
- SDL_PIXELFORMAT_ARGB8888,
- SDL_PIXELFORMAT_RGB888,
- SDL_PIXELFORMAT_YV12,
- SDL_PIXELFORMAT_IYUV,
- SDL_PIXELFORMAT_NV12,
- SDL_PIXELFORMAT_NV21
- },
- 0, /* max_texture_width: will be filled in later */
- 0 /* max_texture_height: will be filled in later */
- }
-};
-
Uint32
D3D11_DXGIFormatToSDLPixelFormat(DXGI_FORMAT dxgiFormat)
@@ -276,84 +219,7 @@ SDLPixelFormatToDXGIFormat(Uint32 sdlFormat)
}
}
-SDL_Renderer *
-D3D11_CreateRenderer(SDL_Window * window, Uint32 flags)
-{
- SDL_Renderer *renderer;
- D3D11_RenderData *data;
-
- renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
- if (!renderer) {
- SDL_OutOfMemory();
- return NULL;
- }
-
- data = (D3D11_RenderData *) SDL_calloc(1, sizeof(*data));
- if (!data) {
- SDL_OutOfMemory();
- return NULL;
- }
-
- renderer->WindowEvent = D3D11_WindowEvent;
- renderer->SupportsBlendMode = D3D11_SupportsBlendMode;
- renderer->CreateTexture = D3D11_CreateTexture;
- renderer->UpdateTexture = D3D11_UpdateTexture;
- renderer->UpdateTextureYUV = D3D11_UpdateTextureYUV;
- renderer->LockTexture = D3D11_LockTexture;
- renderer->UnlockTexture = D3D11_UnlockTexture;
- renderer->SetRenderTarget = D3D11_SetRenderTarget;
- renderer->UpdateViewport = D3D11_UpdateViewport;
- renderer->UpdateClipRect = D3D11_UpdateClipRect;
- renderer->RenderClear = D3D11_RenderClear;
- renderer->RenderDrawPoints = D3D11_RenderDrawPoints;
- renderer->RenderDrawLines = D3D11_RenderDrawLines;
- renderer->RenderFillRects = D3D11_RenderFillRects;
- renderer->RenderCopy = D3D11_RenderCopy;
- renderer->RenderCopyEx = D3D11_RenderCopyEx;
- renderer->RenderReadPixels = D3D11_RenderReadPixels;
- renderer->RenderPresent = D3D11_RenderPresent;
- renderer->DestroyTexture = D3D11_DestroyTexture;
- renderer->DestroyRenderer = D3D11_DestroyRenderer;
- renderer->info = D3D11_RenderDriver.info;
- renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
- renderer->driverdata = data;
-
-#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
- /* VSync is required in Windows Phone, at least for Win Phone 8.0 and 8.1.
- * Failure to use it seems to either result in:
- *
- * - with the D3D11 debug runtime turned OFF, vsync seemingly gets turned
- * off (framerate doesn't get capped), but nothing appears on-screen
- *
- * - with the D3D11 debug runtime turned ON, vsync gets automatically
- * turned back on, and the following gets output to the debug console:
- *
- * DXGI ERROR: IDXGISwapChain::Present: Interval 0 is not supported, changed to Interval 1. [ UNKNOWN ERROR #1024: ]
- */
- renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
-#else
- if ((flags & SDL_RENDERER_PRESENTVSYNC)) {
- renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
- }
-#endif
-
- /* HACK: make sure the SDL_Renderer references the SDL_Window data now, in
- * order to give init functions access to the underlying window handle:
- */
- renderer->window = window;
-
- /* Initialize Direct3D resources */
- if (FAILED(D3D11_CreateDeviceResources(renderer))) {
- D3D11_DestroyRenderer(renderer);
- return NULL;
- }
- if (FAILED(D3D11_CreateWindowSizeDependentResources(renderer))) {
- D3D11_DestroyRenderer(renderer);
- return NULL;
- }
-
- return renderer;
-}
+static void D3D11_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture);
static void
D3D11_ReleaseAll(SDL_Renderer * renderer)
@@ -378,7 +244,9 @@ D3D11_ReleaseAll(SDL_Renderer * renderer)
SAFE_RELEASE(data->mainRenderTargetView);
SAFE_RELEASE(data->currentOffscreenRenderTargetView);
SAFE_RELEASE(data->inputLayout);
- SAFE_RELEASE(data->vertexBuffer);
+ for (i = 0; i < SDL_arraysize(data->vertexBuffers); ++i) {
+ SAFE_RELEASE(data->vertexBuffers[i]);
+ }
SAFE_RELEASE(data->vertexShader);
for (i = 0; i < SDL_arraysize(data->pixelShaders); ++i) {
SAFE_RELEASE(data->pixelShaders[i]);
@@ -477,7 +345,7 @@ static D3D11_BLEND_OP GetBlendEquation(SDL_BlendOperation operation)
}
}
-static SDL_bool
+static ID3D11BlendState *
D3D11_CreateBlendState(SDL_Renderer * renderer, SDL_BlendMode blendMode)
{
D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
@@ -506,21 +374,21 @@ D3D11_CreateBlendState(SDL_Renderer * renderer, SDL_BlendMode blendMode)
result = ID3D11Device_CreateBlendState(data->d3dDevice, &blendDesc, &blendState);
if (FAILED(result)) {
WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateBlendState"), result);
- return SDL_FALSE;
+ return NULL;
}
blendModes = (D3D11_BlendMode *)SDL_realloc(data->blendModes, (data->blendModesCount + 1) * sizeof(*blendModes));
if (!blendModes) {
SAFE_RELEASE(blendState);
SDL_OutOfMemory();
- return SDL_FALSE;
+ return NULL;
}
blendModes[data->blendModesCount].blendMode = blendMode;
blendModes[data->blendModesCount].blendState = blendState;
data->blendModes = blendModes;
++data->blendModesCount;
- return SDL_TRUE;
+ return blendState;
}
/* Create resources that depend on the device. */
@@ -964,6 +832,45 @@ done:
return result;
}
+static void
+D3D11_ReleaseMainRenderTargetView(SDL_Renderer * renderer)
+{
+ D3D11_RenderData *data = (D3D11_RenderData *)renderer->driverdata;
+ ID3D11DeviceContext_OMSetRenderTargets(data->d3dContext, 0, NULL, NULL);
+ SAFE_RELEASE(data->mainRenderTargetView);
+}
+
+static HRESULT D3D11_UpdateForWindowSizeChange(SDL_Renderer * renderer);
+
+
+HRESULT
+D3D11_HandleDeviceLost(SDL_Renderer * renderer)
+{
+ HRESULT result = S_OK;
+
+ D3D11_ReleaseAll(renderer);
+
+ result = D3D11_CreateDeviceResources(renderer);
+ if (FAILED(result)) {
+ /* D3D11_CreateDeviceResources will set the SDL error */
+ return result;
+ }
+
+ result = D3D11_UpdateForWindowSizeChange(renderer);
+ if (FAILED(result)) {
+ /* D3D11_UpdateForWindowSizeChange will set the SDL error */
+ return result;
+ }
+
+ /* Let the application know that the device has been reset */
+ {
+ SDL_Event event;
+ event.type = SDL_RENDER_DEVICE_RESET;
+ SDL_PushEvent(&event);
+ }
+
+ return S_OK;
+}
/* Initialize all resources that change when the window's size changes. */
static HRESULT
@@ -1066,11 +973,7 @@ D3D11_CreateWindowSizeDependentResources(SDL_Renderer * renderer)
goto done;
}
- if (D3D11_UpdateViewport(renderer) != 0) {
- /* D3D11_UpdateViewport will set the SDL error if it fails. */
- result = E_FAIL;
- goto done;
- }
+ data->viewportDirty = SDL_TRUE;
done:
SAFE_RELEASE(backBuffer);
@@ -1084,35 +987,6 @@ D3D11_UpdateForWindowSizeChange(SDL_Renderer * renderer)
return D3D11_CreateWindowSizeDependentResources(renderer);
}
-HRESULT
-D3D11_HandleDeviceLost(SDL_Renderer * renderer)
-{
- HRESULT result = S_OK;
-
- D3D11_ReleaseAll(renderer);
-
- result = D3D11_CreateDeviceResources(renderer);
- if (FAILED(result)) {
- /* D3D11_CreateDeviceResources will set the SDL error */
- return result;
- }
-
- result = D3D11_UpdateForWindowSizeChange(renderer);
- if (FAILED(result)) {
- /* D3D11_UpdateForWindowSizeChange will set the SDL error */
- return result;
- }
-
- /* Let the application know that the device has been reset */
- {
- SDL_Event event;
- event.type = SDL_RENDER_DEVICE_RESET;
- SDL_PushEvent(&event);
- }
-
- return S_OK;
-}
-
void
D3D11_Trim(SDL_Renderer * renderer)
{
@@ -1671,39 +1545,345 @@ D3D11_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
return 0;
}
-static void
-D3D11_SetModelMatrix(SDL_Renderer *renderer, const Float4X4 *matrix)
+static int
+D3D11_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd)
{
- D3D11_RenderData *data = (D3D11_RenderData *)renderer->driverdata;
+ return 0; /* nothing to do in this backend. */
+}
+
+static int
+D3D11_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
+{
+ VertexPositionColor *verts = (VertexPositionColor *) SDL_AllocateRenderVertices(renderer, count * sizeof (VertexPositionColor), 0, &cmd->data.draw.first);
+ const float r = (float)(cmd->data.draw.r / 255.0f);
+ const float g = (float)(cmd->data.draw.g / 255.0f);
+ const float b = (float)(cmd->data.draw.b / 255.0f);
+ const float a = (float)(cmd->data.draw.a / 255.0f);
+ size_t i;
+
+ if (!verts) {
+ return -1;
+ }
+
+ for (i = 0; i < count; i++) {
+ verts->pos.x = points[i].x + 0.5f;
+ verts->pos.y = points[i].y + 0.5f;
+ verts->pos.z = 0.0f;
+ verts->tex.x = 0.0f;
+ verts->tex.y = 0.0f;
+ verts->color.x = r;
+ verts->color.y = g;
+ verts->color.z = b;
+ verts->color.w = a;
+ verts++;
+ }
+
+ return 0;
+}
+
+static int
+D3D11_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects, int count)
+{
+ VertexPositionColor *verts = (VertexPositionColor *) SDL_AllocateRenderVertices(renderer, count * 4 * sizeof (VertexPositionColor), 0, &cmd->data.draw.first);
+ const float r = (float)(cmd->data.draw.r / 255.0f);
+ const float g = (float)(cmd->data.draw.g / 255.0f);
+ const float b = (float)(cmd->data.draw.b / 255.0f);
+ const float a = (float)(cmd->data.draw.a / 255.0f);
+ size_t i;
+
+ if (!verts) {
+ return -1;
+ }
+
+ for (i = 0; i < count; i++) {
+ verts->pos.x = rects[i].x;
+ verts->pos.y = rects[i].y;
+ verts->pos.z = 0.0f;
+ verts->tex.x = 0.0f;
+ verts->tex.y = 0.0f;
+ verts->color.x = r;
+ verts->color.y = g;
+ verts->color.z = b;
+ verts->color.w = a;
+ verts++;
+
+ verts->pos.x = rects[i].x;
+ verts->pos.y = rects[i].y + rects[i].h;
+ verts->pos.z = 0.0f;
+ verts->tex.x = 0.0f;
+ verts->tex.y = 0.0f;
+ verts->color.x = r;
+ verts->color.y = g;
+ verts->color.z = b;
+ verts->color.w = a;
+ verts++;
+
+ verts->pos.x = rects[i].x + rects[i].w;
+ verts->pos.y = rects[i].y;
+ verts->pos.z = 0.0f;
+ verts->tex.x = 0.0f;
+ verts->tex.y = 0.0f;
+ verts->color.x = r;
+ verts->color.y = g;
+ verts->color.z = b;
+ verts->color.w = a;
+ verts++;
+
+ verts->pos.x = rects[i].x + rects[i].w;
+ verts->pos.y = rects[i].y + rects[i].h;
+ verts->pos.z = 0.0f;
+ verts->tex.x = 0.0f;
+ verts->tex.y = 0.0f;
+ verts->color.x = r;
+ verts->color.y = g;
+ verts->color.z = b;
+ verts->color.w = a;
+ verts++;
+ }
+
+ return 0;
+}
+
+static int
+D3D11_QueueCopy(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
+ const SDL_Rect * srcrect, const SDL_FRect * dstrect)
+{
+ VertexPositionColor *verts = (VertexPositionColor *) SDL_AllocateRenderVertices(renderer, 4 * sizeof (VertexPositionColor), 0, &cmd->data.draw.first);
+ const float r = (float)(cmd->data.draw.r / 255.0f);
+ const float g = (float)(cmd->data.draw.g / 255.0f);
+ const float b = (float)(cmd->data.draw.b / 255.0f);
+ const float a = (float)(cmd->data.draw.a / 255.0f);
+ const float minu = (float) srcrect->x / texture->w;
+ const float maxu = (float) (srcrect->x + srcrect->w) / texture->w;
+ const float minv = (float) srcrect->y / texture->h;
+ const float maxv = (float) (srcrect->y + srcrect->h) / texture->h;
+
+ if (!verts) {
+ return -1;
+ }
+
+ verts->pos.x = dstrect->x;
+ verts->pos.y = dstrect->y;
+ verts->pos.z = 0.0f;
+ verts->tex.x = minu;
+ verts->tex.y = minv;
+ verts->color.x = r;
+ verts->color.y = g;
+ verts->color.z = b;
+ verts->color.w = a;
+ verts++;
+
+ verts->pos.x = dstrect->x;
+ verts->pos.y = dstrect->y + dstrect->h;
+ verts->pos.z = 0.0f;
+ verts->tex.x = minu;
+ verts->tex.y = maxv;
+ verts->color.x = r;
+ verts->color.y = g;
+ verts->color.z = b;
+ verts->color.w = a;
+ verts++;
+
+ verts->pos.x = dstrect->x + dstrect->w;
+ verts->pos.y = dstrect->y;
+ verts->pos.z = 0.0f;
+ verts->tex.x = maxu;
+ verts->tex.y = minv;
+ verts->color.x = r;
+ verts->color.y = g;
+ verts->color.z = b;
+ verts->color.w = a;
+ verts++;
+
+ verts->pos.x = dstrect->x + dstrect->w;
+ verts->pos.y = dstrect->y + dstrect->h;
+ verts->pos.z = 0.0f;
+ verts->tex.x = maxu;
+ verts->tex.y = maxv;
+ verts->color.x = r;
+ verts->color.y = g;
+ verts->color.z = b;
+ verts->color.w = a;
+ verts++;
+
+ return 0;
+}
+
+static int
+D3D11_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
+ const SDL_Rect * srcrect, const SDL_FRect * dstrect,
+ const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
+{
+ VertexPositionColor *verts = (VertexPositionColor *) SDL_AllocateRenderVertices(renderer, 5 * sizeof (VertexPositionColor), 0, &cmd->data.draw.first);
+ const float r = (float)(cmd->data.draw.r / 255.0f);
+ const float g = (float)(cmd->data.draw.g / 255.0f);
+ const float b = (float)(cmd->data.draw.b / 255.0f);
+ const float a = (float)(cmd->data.draw.a / 255.0f);
+ float minx, miny, maxx, maxy;
+ float minu, maxu, minv, maxv;
- if (matrix) {
- data->vertexShaderConstantsData.model = *matrix;
+ if (flip & SDL_FLIP_HORIZONTAL) {
+ minu = (float) srcrect->x / texture->w;
+ maxu = (float) (srcrect->x + srcrect->w) / texture->w;
} else {
- data->vertexShaderConstantsData.model = MatrixIdentity();
+ minu = (float) (srcrect->x + srcrect->w) / texture->w;
+ maxu = (float) srcrect->x / texture->w;
}
- ID3D11DeviceContext_UpdateSubresource(data->d3dContext,
- (ID3D11Resource *)data->vertexShaderConstants,
- 0,
- NULL,
- &data->vertexShaderConstantsData,
- 0,
- 0
- );
+ if (flip & SDL_FLIP_VERTICAL) {
+ minv = (float) srcrect->y / texture->h;
+ maxv = (float) (srcrect->y + srcrect->h) / texture->h;
+ } else {
+ minv = (float) (srcrect->y + srcrect->h) / texture->h;
+ maxv = (float) srcrect->y / texture->h;
+ }
+
+ minx = -center->x;
+ maxx = dstrect->w - center->x;
+ miny = -center->y;
+ maxy = dstrect->h - center->y;
+
+ verts->pos.x = minx;
+ verts->pos.y = miny;
+ verts->pos.z = 0.0f;
+ verts->tex.x = minu;
+ verts->tex.y = minv;
+ verts->color.x = r;
+ verts->color.y = g;
+ verts->color.z = b;
+ verts->color.w = a;
+ verts++;
+
+ verts->pos.x = minx;
+ verts->pos.y = maxy;
+ verts->pos.z = 0.0f;
+ verts->tex.x = minu;
+ verts->tex.y = maxv;
+ verts->color.x = r;
+ verts->color.y = g;
+ verts->color.z = b;
+ verts->color.w = a;
+ verts++;
+
+ verts->pos.x = maxx;
+ verts->pos.y = miny;
+ verts->pos.z = 0.0f;
+ verts->tex.x = maxu;
+ verts->tex.y = minv;
+ verts->color.x = r;
+ verts->color.y = g;
+ verts->color.z = b;
+ verts->color.w = a;
+ verts++;
+
+ verts->pos.x = maxx;
+ verts->pos.y = maxy;
+ verts->pos.z = 0.0f;
+ verts->tex.x = maxu;
+ verts->tex.y = maxv;
+ verts->color.x = r;
+ verts->color.y = g;
+ verts->color.z = b;
+ verts->color.w = a;
+ verts++;
+
+ verts->pos.x = dstrect->x + center->x; /* X translation */
+ verts->pos.y = dstrect->y + center->y; /* Y translation */
+ verts->pos.z = (float)(M_PI * (float) angle / 180.0f); /* rotation */
+ verts->tex.x = 0.0f;
+ verts->tex.y = 0.0f;
+ verts->color.x = 0;
+ verts->color.y = 0;
+ verts->color.z = 0;
+ verts->color.w = 0;
+ verts++;
+
+ return 0;
+}
+
+
+static int
+D3D11_UpdateVertexBuffer(SDL_Renderer *renderer,
+ const void * vertexData, size_t dataSizeInBytes)
+{
+ D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
+ HRESULT result = S_OK;
+ const int vbidx = rendererData->currentVertexBuffer;
+
+ if (rendererData->vertexBuffers[vbidx] && rendererData->vertexBufferSizes[vbidx] >= dataSizeInBytes) {
+ D3D11_MAPPED_SUBRESOURCE mappedResource;
+ result = ID3D11DeviceContext_Map(rendererData->d3dContext,
+ (ID3D11Resource *)rendererData->vertexBuffers[vbidx],
+ 0,
+ D3D11_MAP_WRITE_DISCARD,
+ 0,
+ &mappedResource
+ );
+ if (FAILED(result)) {
+ WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11DeviceContext1::Map [vertex buffer]"), result);
+ return -1;
+ }
+ SDL_memcpy(mappedResource.pData, vertexData, dataSizeInBytes);
+ ID3D11DeviceContext_Unmap(rendererData->d3dContext, (ID3D11Resource *)rendererData->vertexBuffers[vbidx], 0);
+ } else {
+ D3D11_BUFFER_DESC vertexBufferDesc;
+ D3D11_SUBRESOURCE_DATA vertexBufferData;
+ const UINT stride = sizeof(VertexPositionColor);
+ const UINT offset = 0;
+
+ SAFE_RELEASE(rendererData->vertexBuffers[vbidx]);
+
+ SDL_zero(vertexBufferDesc);
+ vertexBufferDesc.ByteWidth = (UINT) dataSizeInBytes;
+ vertexBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
+ vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
+ vertexBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+
+ SDL_zero(vertexBufferData);
+ vertexBufferData.pSysMem = vertexData;
+ vertexBufferData.SysMemPitch = 0;
+ vertexBufferData.SysMemSlicePitch = 0;
+
+ result = ID3D11Device_CreateBuffer(rendererData->d3dDevice,
+ &vertexBufferDesc,
+ &vertexBufferData,
+ &rendererData->vertexBuffers[vbidx]
+ );
+ if (FAILED(result)) {
+ WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateBuffer [vertex buffer]"), result);
+ return -1;
+ }
+
+ ID3D11DeviceContext_IASetVertexBuffers(rendererData->d3dContext,
+ 0,
+ 1,
+ &rendererData->vertexBuffers[vbidx],
+ &stride,
+ &offset
+ );
+ }
+
+ rendererData->currentVertexBuffer++;
+ if (rendererData->currentVertexBuffer >= SDL_arraysize(rendererData->vertexBuffers)) {
+ rendererData->currentVertexBuffer = 0;
+ }
+
+ return 0;
}
static int
D3D11_UpdateViewport(SDL_Renderer * renderer)
{
D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
+ const SDL_Rect *viewport = &data->currentViewport;
Float4X4 projection;
Float4X4 view;
SDL_FRect orientationAlignedViewport;
BOOL swapDimensions;
- D3D11_VIEWPORT viewport;
+ D3D11_VIEWPORT d3dviewport;
const int rotation = D3D11_GetRotationForCurrentRenderTarget(renderer);
- if (renderer->viewport.w == 0 || renderer->viewport.h == 0) {
+ if (viewport->w == 0 || viewport->h == 0) {
/* If the viewport is empty, assume that it is because
* SDL_CreateRenderer is calling it, and will call it again later
* with a non-empty viewport.
@@ -1735,21 +1915,12 @@ D3D11_UpdateViewport(SDL_Renderer * renderer)
}
/* Update the view matrix */
- view.m[0][0] = 2.0f / renderer->viewport.w;
- view.m[0][1] = 0.0f;
- view.m[0][2] = 0.0f;
- view.m[0][3] = 0.0f;
- view.m[1][0] = 0.0f;
- view.m[1][1] = -2.0f / renderer->viewport.h;
- view.m[1][2] = 0.0f;
- view.m[1][3] = 0.0f;
- view.m[2][0] = 0.0f;
- view.m[2][1] = 0.0f;
+ SDL_zero(view);
+ view.m[0][0] = 2.0f / viewport->w;
+ view.m[1][1] = -2.0f / viewport->h;
view.m[2][2] = 1.0f;
- view.m[2][3] = 0.0f;
view.m[3][0] = -1.0f;
view.m[3][1] = 1.0f;
- view.m[3][2] = 0.0f;
view.m[3][3] = 1.0f;
/* Combine the projection + view matrix together now, as both only get
@@ -1760,9 +1931,6 @@ D3D11_UpdateViewport(SDL_Renderer * renderer)
view,
projection);
- /* Reset the model matrix */
- D3D11_SetModelMatrix(renderer, NULL);
-
/* Update the Direct3D viewport, which seems to be aligned to the
* swap buffer's coordinate space, which is always in either
* a landscape mode, for all Windows 8/RT devices, or a portrait mode,
@@ -1770,158 +1938,58 @@ D3D11_UpdateViewport(SDL_Renderer * renderer)
*/
swapDimensions = D3D11_IsDisplayRotated90Degrees(rotation);
if (swapDimensions) {
- orientationAlignedViewport.x = (float) renderer->viewport.y;
- orientationAlignedViewport.y = (float) renderer->viewport.x;
- orientationAlignedViewport.w = (float) renderer->viewport.h;
- orientationAlignedViewport.h = (float) renderer->viewport.w;
+ orientationAlignedViewport.x = (float) viewport->y;
+ orientationAlignedViewport.y = (float) viewport->x;
+ orientationAlignedViewport.w = (float) viewport->h;
+ orientationAlignedViewport.h = (float) viewport->w;
} else {
- orientationAlignedViewport.x = (float) renderer->viewport.x;
- orientationAlignedViewport.y = (float) renderer->viewport.y;
- orientationAlignedViewport.w = (float) renderer->viewport.w;
- orientationAlignedViewport.h = (float) renderer->viewport.h;
+ orientationAlignedViewport.x = (float) viewport->x;
+ orientationAlignedViewport.y = (float) viewport->y;
+ orientationAlignedViewport.w = (float) viewport->w;
+ orientationAlignedViewport.h = (float) viewport->h;
}
/* TODO, WinRT: get custom viewports working with non-Landscape modes (Portrait, PortraitFlipped, and LandscapeFlipped) */
- viewport.TopLeftX = orientationAlignedViewport.x;
- viewport.TopLeftY = orientationAlignedViewport.y;
- viewport.Width = orientationAlignedViewport.w;
- viewport.Height = orientationAlignedViewport.h;
- viewport.MinDepth = 0.0f;
- viewport.MaxDepth = 1.0f;
- /* SDL_Log("%s: D3D viewport = {%f,%f,%f,%f}\n", __FUNCTION__, viewport.TopLeftX, viewport.TopLeftY, viewport.Width, viewport.Height); */
- ID3D11DeviceContext_RSSetViewports(data->d3dContext, 1, &viewport);
+ d3dviewport.TopLeftX = orientationAlignedViewport.x;
+ d3dviewport.TopLeftY = orientationAlignedViewport.y;
+ d3dviewport.Width = orientationAlignedViewport.w;
+ d3dviewport.Height = orientationAlignedViewport.h;
+ d3dviewport.MinDepth = 0.0f;
+ d3dviewport.MaxDepth = 1.0f;
+ /* SDL_Log("%s: D3D viewport = {%f,%f,%f,%f}\n", __FUNCTION__, d3dviewport.TopLeftX, d3dviewport.TopLeftY, d3dviewport.Width, d3dviewport.Height); */
+ ID3D11DeviceContext_RSSetViewports(data->d3dContext, 1, &d3dviewport);
- return 0;
-}
-
-static int
-D3D11_UpdateClipRect(SDL_Renderer * renderer)
-{
- D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
-
- if (!renderer->clipping_enabled) {
- ID3D11DeviceContext_RSSetScissorRects(data->d3dContext, 0, NULL);
- } else {
- D3D11_RECT scissorRect;
- if (D3D11_GetViewportAlignedD3DRect(renderer, &renderer->clip_rect, &scissorRect, TRUE) != 0) {
- /* D3D11_GetViewportAlignedD3DRect will have set the SDL error */
- return -1;
- }
- ID3D11DeviceContext_RSSetScissorRects(data->d3dContext, 1, &scissorRect);
- }
+ data->viewportDirty = SDL_FALSE;
return 0;
}
-static void
-D3D11_ReleaseMainRenderTargetView(SDL_Renderer * renderer)
-{
- D3D11_RenderData *data = (D3D11_RenderData *)renderer->driverdata;
- ID3D11DeviceContext_OMSetRenderTargets(data->d3dContext, 0, NULL, NULL);
- SAFE_RELEASE(data->mainRenderTargetView);
-}
-
static ID3D11RenderTargetView *
D3D11_GetCurrentRenderTargetView(SDL_Renderer * renderer)
{
- D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
+ D3D11_RenderData *data = (D3D11_RenderData *)renderer->driverdata;
if (data->currentOffscreenRenderTargetView) {
return data->currentOffscreenRenderTargetView;
- } else {
+ }
+ else {
return data->mainRenderTargetView;
}
}
static int
-D3D11_RenderClear(SDL_Renderer * renderer)
-{
- D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
- const float colorRGBA[] = {
- (renderer->r / 255.0f),
- (renderer->g / 255.0f),
- (renderer->b / 255.0f),
- (renderer->a / 255.0f)
- };
- ID3D11DeviceContext_ClearRenderTargetView(data->d3dContext,
- D3D11_GetCurrentRenderTargetView(renderer),
- colorRGBA
- );
- return 0;
-}
-
-static int
-D3D11_UpdateVertexBuffer(SDL_Renderer *renderer,
- const void * vertexData, size_t dataSizeInBytes)
-{
- D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
- D3D11_BUFFER_DESC vertexBufferDesc;
- HRESULT result = S_OK;
- D3D11_SUBRESOURCE_DATA vertexBufferData;
- const UINT stride = sizeof(VertexPositionColor);
- const UINT offset = 0;
-
- if (rendererData->vertexBuffer) {
- ID3D11Buffer_GetDesc(rendererData->vertexBuffer, &vertexBufferDesc);
- } else {
- SDL_zero(vertexBufferDesc);
- }
-
- if (rendererData->vertexBuffer && vertexBufferDesc.ByteWidth >= dataSizeInBytes) {
- D3D11_MAPPED_SUBRESOURCE mappedResource;
- result = ID3D11DeviceContext_Map(rendererData->d3dContext,
- (ID3D11Resource *)rendererData->vertexBuffer,
- 0,
- D3D11_MAP_WRITE_DISCARD,
- 0,
- &mappedResource
- );
- if (FAILED(result)) {
- WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11DeviceContext1::Map [vertex buffer]"), result);
- return -1;
- }
- SDL_memcpy(mappedResource.pData, vertexData, dataSizeInBytes);
- ID3D11DeviceContext_Unmap(rendererData->d3dContext, (ID3D11Resource *)rendererData->vertexBuffer, 0);
- } else {
- SAFE_RELEASE(rendererData->vertexBuffer);
-
- vertexBufferDesc.ByteWidth = (UINT) dataSizeInBytes;
- vertexBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
- vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
- vertexBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
-
- SDL_zero(vertexBufferData);
- vertexBufferData.pSysMem = vertexData;
- vertexBufferData.SysMemPitch = 0;
- vertexBufferData.SysMemSlicePitch = 0;
-
- result = ID3D11Device_CreateBuffer(rendererData->d3dDevice,
- &vertexBufferDesc,
- &vertexBufferData,
- &rendererData->vertexBuffer
- );
- if (FAILED(result)) {
- WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateBuffer [vertex buffer]"), result);
- return -1;
- }
-
- ID3D11DeviceContext_IASetVertexBuffers(rendererData->d3dContext,
- 0,
- 1,
- &rendererData->vertexBuffer,
- &stride,
- &offset
- );
- }
+D3D11_SetDrawState(SDL_Renderer * renderer, const SDL_RenderCommand *cmd, ID3D11PixelShader * shader,
+ const int numShaderResources, ID3D11ShaderResourceView ** shaderResources,
+ ID3D11SamplerState * sampler, const Float4X4 *matrix)
- return 0;
-}
-
-static void
-D3D11_RenderStartDrawOp(SDL_Renderer * renderer)
{
D3D11_RenderData *rendererData = (D3D11_RenderData *)renderer->driverdata;
+ const Float4X4 *newmatrix = matrix ? matrix : &rendererData->identity;
ID3D11RasterizerState *rasterizerState;
ID3D11RenderTargetView *renderTargetView = D3D11_GetCurrentRenderTargetView(renderer);
+ ID3D11ShaderResourceView *shaderResource;
+ const SDL_BlendMode blendMode = cmd->data.draw.blend;
+ ID3D11BlendState *blendState = NULL;
+
if (renderTargetView != rendererData->currentRenderTargetView) {
ID3D11DeviceContext_OMSetRenderTargets(rendererData->d3dContext,
1,
@@ -1931,7 +1999,25 @@ D3D11_RenderStartDrawOp(SDL_Renderer * renderer)
rendererData->currentRenderTargetView = renderTargetView;
}
- if (!renderer->clipping_enabled) {
+ if (rendererData->viewportDirty) {
+ D3D11_UpdateViewport(renderer);
+ }
+
+ if (rendererData->cliprectDirty) {
+ if (!rendererData->currentCliprectEnabled) {
+ ID3D11DeviceContext_RSSetScissorRects(rendererData->d3dContext, 0, NULL);
+ } else {
+ D3D11_RECT scissorRect;
+ if (D3D11_GetViewportAlignedD3DRect(renderer, &rendererData->currentCliprect, &scissorRect, TRUE) != 0) {
+ /* D3D11_GetViewportAlignedD3DRect will have set the SDL error */
+ return -1;
+ }
+ ID3D11DeviceContext_RSSetScissorRects(rendererData->d3dContext, 1, &scissorRect);
+ }
+ rendererData->cliprectDirty = SDL_FALSE;
+ }
+
+ if (!rendererData->currentCliprectEnabled) {
rasterizerState = rendererData->mainRasterizer;
} else {
rasterizerState = rendererData->clippedRasterizer;
@@ -1940,13 +2026,7 @@ D3D11_RenderStartDrawOp(SDL_Renderer * renderer)
ID3D11DeviceContext_RSSetState(rendererData->d3dContext, rasterizerState);
rendererData->currentRasterizerState = rasterizerState;
}
-}
-static void
-D3D11_RenderSetBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
-{
- D3D11_RenderData *rendererData = (D3D11_RenderData *)renderer->driverdata;
- ID3D11BlendState *blendState = NULL;
if (blendMode != SDL_BLENDMODE_NONE) {
int i;
for (i = 0; i < rendererData->blendModesCount; ++i) {
@@ -1956,28 +2036,17 @@ D3D11_RenderSetBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
}
}
if (!blendState) {
- if (D3D11_CreateBlendState(renderer, blendMode)) {
- /* Successfully created the blend state, try again */
- D3D11_RenderSetBlendMode(renderer, blendMode);
+ blendState = D3D11_CreateBlendState(renderer, blendMode);
+ if (!blendState) {
+ return -1;
}
- return;
}
}
if (blendState != rendererData->currentBlendState) {
ID3D11DeviceContext_OMSetBlendState(rendererData->d3dContext, blendState, 0, 0xFFFFFFFF);
rendererData->currentBlendState = blendState;
}
-}
-static void
-D3D11_SetPixelShader(SDL_Renderer * renderer,
- ID3D11PixelShader * shader,
- int numShaderResources,
- ID3D11ShaderResourceView ** shaderResources,
- ID3D11SamplerState * sampler)
-{
- D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
- ID3D11ShaderResourceView *shaderResource;
if (shader != rendererData->currentShader) {
ID3D11DeviceContext_PSSetShader(rendererData->d3dContext, shader, NULL, 0);
rendererData->currentShader = shader;
@@ -1995,146 +2064,26 @@ D3D11_SetPixelShader(SDL_Renderer * renderer,
ID3D11DeviceContext_PSSetSamplers(rendererData->d3dContext, 0, 1, &sampler);
rendererData->currentSampler = sampler;
}
-}
-
-static void
-D3D11_RenderFinishDrawOp(SDL_Renderer * renderer,
- D3D11_PRIMITIVE_TOPOLOGY primitiveTopology,
- UINT vertexCount)
-{
- D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
-
- ID3D11DeviceContext_IASetPrimitiveTopology(rendererData->d3dContext, primitiveTopology);
- ID3D11DeviceContext_Draw(rendererData->d3dContext, vertexCount, 0);
-}
-
-static int
-D3D11_RenderDrawPoints(SDL_Renderer * renderer,
- const SDL_FPoint * points, int count)
-{
- D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
- float r, g, b, a;
- VertexPositionColor *vertices;
- int i;
-
- r = (float)(renderer->r / 255.0f);
- g = (float)(renderer->g / 255.0f);
- b = (float)(renderer->b / 255.0f);
- a = (float)(renderer->a / 255.0f);
-
- vertices = SDL_stack_alloc(VertexPositionColor, count);
- for (i = 0; i < count; ++i) {
- const VertexPositionColor v = { { points[i].x + 0.5f, points[i].y + 0.5f, 0.0f }, { 0.0f, 0.0f }, { r, g, b, a } };
- vertices[i] = v;
- }
- D3D11_RenderStartDrawOp(renderer);
- D3D11_RenderSetBlendMode(renderer, renderer->blendMode);
- if (D3D11_UpdateVertexBuffer(renderer, vertices, (unsigned int)count * sizeof(VertexPositionColor)) != 0) {
- SDL_stack_free(vertices);
- return -1;
- }
-
- D3D11_SetPixelShader(
- renderer,
- rendererData->pixelShaders[SHADER_SOLID],
- 0,
- NULL,
- NULL);
-
- D3D11_RenderFinishDrawOp(renderer, D3D11_PRIMITIVE_TOPOLOGY_POINTLIST, count);
- SDL_stack_free(vertices);
- return 0;
-}
-
-static int
-D3D11_RenderDrawLines(SDL_Renderer * renderer,
- const SDL_FPoint * points, int count)
-{
- D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
- float r, g, b, a;
- VertexPositionColor *vertices;
- int i;
-
- r = (float)(renderer->r / 255.0f);
- g = (float)(renderer->g / 255.0f);
- b = (float)(renderer->b / 255.0f);
- a = (float)(renderer->a / 255.0f);
-
- vertices = SDL_stack_alloc(VertexPositionColor, count);
- for (i = 0; i < count; ++i) {
- const VertexPositionColor v = { { points[i].x + 0.5f, points[i].y + 0.5f, 0.0f }, { 0.0f, 0.0f }, { r, g, b, a } };
- vertices[i] = v;
- }
-
- D3D11_RenderStartDrawOp(renderer);
- D3D11_RenderSetBlendMode(renderer, renderer->blendMode);
- if (D3D11_UpdateVertexBuffer(renderer, vertices, (unsigned int)count * sizeof(VertexPositionColor)) != 0) {
- SDL_stack_free(vertices);
- return -1;
- }
-
- D3D11_SetPixelShader(
- renderer,
- rendererData->pixelShaders[SHADER_SOLID],
- 0,
- NULL,
- NULL);
-
- D3D11_RenderFinishDrawOp(renderer, D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP, count);
-
- if (points[0].x != points[count - 1].x || points[0].y != points[count - 1].y) {
- ID3D11DeviceContext_IASetPrimitiveTopology(rendererData->d3dContext, D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
- ID3D11DeviceContext_Draw(rendererData->d3dContext, 1, count - 1);
- }
-
- SDL_stack_free(vertices);
- return 0;
-}
-
-static int
-D3D11_RenderFillRects(SDL_Renderer * renderer,
- const SDL_FRect * rects, int count)
-{
- D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
- float r, g, b, a;
- int i;
-
- r = (float)(renderer->r / 255.0f);
- g = (float)(renderer->g / 255.0f);
- b = (float)(renderer->b / 255.0f);
- a = (float)(renderer->a / 255.0f);
-
- for (i = 0; i < count; ++i) {
- VertexPositionColor vertices[] = {
- { { rects[i].x, rects[i].y, 0.0f }, { 0.0f, 0.0f}, {r, g, b, a} },
- { { rects[i].x, rects[i].y + rects[i].h, 0.0f }, { 0.0f, 0.0f }, { r, g, b, a } },
- { { rects[i].x + rects[i].w, rects[i].y, 0.0f }, { 0.0f, 0.0f }, { r, g, b, a } },
- { { rects[i].x + rects[i].w, rects[i].y + rects[i].h, 0.0f }, { 0.0f, 0.0f }, { r, g, b, a } },
- };
-
- D3D11_RenderStartDrawOp(renderer);
- D3D11_RenderSetBlendMode(renderer, renderer->blendMode);
- if (D3D11_UpdateVertexBuffer(renderer, vertices, sizeof(vertices)) != 0) {
- return -1;
- }
-
- D3D11_SetPixelShader(
- renderer,
- rendererData->pixelShaders[SHADER_SOLID],
+ if (SDL_memcmp(&rendererData->vertexShaderConstantsData.model, newmatrix, sizeof (*newmatrix)) != 0) {
+ SDL_memcpy(&rendererData->vertexShaderConstantsData.model, newmatrix, sizeof (*newmatrix));
+ ID3D11DeviceContext_UpdateSubresource(rendererData->d3dContext,
+ (ID3D11Resource *)rendererData->vertexShaderConstants,
0,
NULL,
- NULL);
-
- D3D11_RenderFinishDrawOp(renderer, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, SDL_arraysize(vertices));
+ &rendererData->vertexShaderConstantsData,
+ 0,
+ 0
+ );
}
return 0;
}
static int
-D3D11_RenderSetupSampler(SDL_Renderer * renderer, SDL_Texture * texture)
+D3D11_SetCopyState(SDL_Renderer * renderer, const SDL_RenderCommand *cmd, const Float4X4 *matrix)
{
+ SDL_Texture *texture = cmd->data.draw.texture;
D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
D3D11_TextureData *textureData = (D3D11_TextureData *) texture->driverdata;
ID3D11SamplerState *textureSampler;
@@ -2172,12 +2121,8 @@ D3D11_RenderSetupSampler(SDL_Renderer * renderer, SDL_Texture * texture)
return SDL_SetError("Unsupported YUV conversion mode");
}
- D3D11_SetPixelShader(
- renderer,
- rendererData->pixelShaders[shader],
- SDL_arraysize(shaderResources),
- shaderResources,
- textureSampler);
+ return D3D11_SetDrawState(renderer, cmd, rendererData->pixelShaders[shader],
+ SDL_arraysize(shaderResources), shaderResources, textureSampler, matrix);
} else if (textureData->nv12) {
ID3D11ShaderResourceView *shaderResources[] = {
@@ -2200,189 +2145,141 @@ D3D11_RenderSetupSampler(SDL_Renderer * renderer, SDL_Texture * texture)
return SDL_SetError("Unsupported YUV conversion mode");
}
- D3D11_SetPixelShader(
- renderer,
- rendererData->pixelShaders[shader],
- SDL_arraysize(shaderResources),
- shaderResources,
- textureSampler);
+ return D3D11_SetDrawState(renderer, cmd, rendererData->pixelShaders[shader],
+ SDL_arraysize(shaderResources), shaderResources, textureSampler, matrix);
- } else {
- D3D11_SetPixelShader(
- renderer,
- rendererData->pixelShaders[SHADER_RGB],
- 1,
- &textureData->mainTextureResourceView,
- textureSampler);
}
- return 0;
+ return D3D11_SetDrawState(renderer, cmd, rendererData->pixelShaders[SHADER_RGB],
+ 1, &textureData->mainTextureResourceView, textureSampler, matrix);
+}
+
+static void
+D3D11_DrawPrimitives(SDL_Renderer * renderer, D3D11_PRIMITIVE_TOPOLOGY primitiveTopology, const size_t vertexStart, const size_t vertexCount)
+{
+ D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
+ ID3D11DeviceContext_IASetPrimitiveTopology(rendererData->d3dContext, primitiveTopology);
+ ID3D11DeviceContext_Draw(rendererData->d3dContext, (UINT) vertexCount, (UINT) vertexStart);
}
static int
-D3D11_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * srcrect, const SDL_FRect * dstrect)
+D3D11_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
{
- float minu, maxu, minv, maxv;
- Float4 color;
- VertexPositionColor vertices[4];
-
- D3D11_RenderStartDrawOp(renderer);
- D3D11_RenderSetBlendMode(renderer, texture->blendMode);
-
- minu = (float) srcrect->x / texture->w;
- maxu = (float) (srcrect->x + srcrect->w) / texture->w;
- minv = (float) srcrect->y / texture->h;
- maxv = (float) (srcrect->y + srcrect->h) / texture->h;
-
- color.x = 1.0f; /* red */
- color.y = 1.0f; /* green */
- color.z = 1.0f; /* blue */
- color.w = 1.0f; /* alpha */
- if (texture->modMode & SDL_TEXTUREMODULATE_COLOR) {
- color.x = (float)(texture->r / 255.0f); /* red */
- color.y = (float)(texture->g / 255.0f); /* green */
- color.z = (float)(texture->b / 255.0f); /* blue */
- }
- if (texture->modMode & SDL_TEXTUREMODULATE_ALPHA) {
- color.w = (float)(texture->a / 255.0f); /* alpha */
- }
-
- vertices[0].pos.x = dstrect->x;
- vertices[0].pos.y = dstrect->y;
- vertices[0].pos.z = 0.0f;
- vertices[0].tex.x = minu;
- vertices[0].tex.y = minv;
- vertices[0].color = color;
-
- vertices[1].pos.x = dstrect->x;
- vertices[1].pos.y = dstrect->y + dstrect->h;
- vertices[1].pos.z = 0.0f;
- vertices[1].tex.x = minu;
- vertices[1].tex.y = maxv;
- vertices[1].color = color;
-
- vertices[2].pos.x = dstrect->x + dstrect->w;
- vertices[2].pos.y = dstrect->y;
- vertices[2].pos.z = 0.0f;
- vertices[2].tex.x = maxu;
- vertices[2].tex.y = minv;
- vertices[2].color = color;
-
- vertices[3].pos.x = dstrect->x + dstrect->w;
- vertices[3].pos.y = dstrect->y + dstrect->h;
- vertices[3].pos.z = 0.0f;
- vertices[3].tex.x = maxu;
- vertices[3].tex.y = maxv;
- vertices[3].color = color;
-
- if (D3D11_UpdateVertexBuffer(renderer, vertices, sizeof(vertices)) != 0) {
- return -1;
+ D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
+ const int viewportRotation = D3D11_GetRotationForCurrentRenderTarget(renderer);
+ size_t i;
+
+ if (rendererData->currentViewportRotation != viewportRotation) {
+ rendererData->currentViewportRotation = viewportRotation;
+ rendererData->viewportDirty = SDL_TRUE;
}
- if (D3D11_RenderSetupSampler(renderer, texture) < 0) {
+ if (D3D11_UpdateVertexBuffer(renderer, vertices, vertsize) < 0) {
return -1;
}
- D3D11_RenderFinishDrawOp(renderer, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, sizeof(vertices) / sizeof(VertexPositionColor));
+ while (cmd) {
+ switch (cmd->command) {
+ case SDL_RENDERCMD_SETDRAWCOLOR: {
+ break; /* this isn't currently used in this render backend. */
+ }
- return 0;
-}
+ case SDL_RENDERCMD_SETVIEWPORT: {
+ SDL_Rect *viewport = &rendererData->currentViewport;
+ if (SDL_memcmp(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect)) != 0) {
+ SDL_memcpy(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect));
+ rendererData->viewportDirty = SDL_TRUE;
+ }
+ break;
+ }
-static int
-D3D11_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * srcrect, const SDL_FRect * dstrect,
- const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip)
-{
- float minu, maxu, minv, maxv;
- Float4 color;
- Float4X4 modelMatrix;
- float minx, maxx, miny, maxy;
- VertexPositionColor vertices[4];
+ case SDL_RENDERCMD_SETCLIPRECT: {
+ const SDL_Rect *rect = &cmd->data.cliprect.rect;
+ if (rendererData->currentCliprectEnabled != cmd->data.cliprect.enabled) {
+ rendererData->currentCliprectEnabled = cmd->data.cliprect.enabled;
+ rendererData->cliprectDirty = SDL_TRUE;
+ }
+ if (SDL_memcmp(&rendererData->currentCliprect, rect, sizeof (SDL_Rect)) != 0) {
+ SDL_memcpy(&rendererData->currentCliprect, rect, sizeof (SDL_Rect));
+ rendererData->cliprectDirty = SDL_TRUE;
+ }
+ break;
+ }
- D3D11_RenderStartDrawOp(renderer);
- D3D11_RenderSetBlendMode(renderer, texture->blendMode);
+ case SDL_RENDERCMD_CLEAR: {
+ const float colorRGBA[] = {
+ (cmd->data.color.r / 255.0f),
+ (cmd->data.color.g / 255.0f),
+ (cmd->data.color.b / 255.0f),
+ (cmd->data.color.a / 255.0f)
+ };
+ ID3D11DeviceContext_ClearRenderTargetView(rendererData->d3dContext, D3D11_GetCurrentRenderTargetView(renderer), colorRGBA);
+ break;
+ }
- minu = (float) srcrect->x / texture->w;
- maxu = (float) (srcrect->x + srcrect->w) / texture->w;
- minv = (float) srcrect->y / texture->h;
- maxv = (float) (srcrect->y + srcrect->h) / texture->h;
+ case SDL_RENDERCMD_DRAW_POINTS: {
+ const size_t count = cmd->data.draw.count;
+ const size_t first = cmd->data.draw.first;
+ const size_t start = first / sizeof (VertexPositionColor);
+ D3D11_SetDrawState(renderer, cmd, rendererData->pixelShaders[SHADER_SOLID], 0, NULL, NULL, NULL);
+ D3D11_DrawPrimitives(renderer, D3D11_PRIMITIVE_TOPOLOGY_POINTLIST, start, count);
+ break;
+ }
- color.x = 1.0f; /* red */
- color.y = 1.0f; /* green */
- color.z = 1.0f; /* blue */
- color.w = 1.0f; /* alpha */
- if (texture->modMode & SDL_TEXTUREMODULATE_COLOR) {
- color.x = (float)(texture->r / 255.0f); /* red */
- color.y = (float)(texture->g / 255.0f); /* green */
- color.z = (float)(texture->b / 255.0f); /* blue */
- }
- if (texture->modMode & SDL_TEXTUREMODULATE_ALPHA) {
- color.w = (float)(texture->a / 255.0f); /* alpha */
- }
+ case SDL_RENDERCMD_DRAW_LINES: {
+ const size_t count = cmd->data.draw.count;
+ const size_t first = cmd->data.draw.first;
+ const size_t start = first / sizeof (VertexPositionColor);
+ const VertexPositionColor *verts = (VertexPositionColor *) (((Uint8 *) vertices) + first);
+ D3D11_SetDrawState(renderer, cmd, rendererData->pixelShaders[SHADER_SOLID], 0, NULL, NULL, NULL);
+ D3D11_DrawPrimitives(renderer, D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP, start, count);
+ if (verts[0].pos.x != verts[count - 1].pos.x || verts[0].pos.y != verts[count - 1].pos.y) {
+ D3D11_DrawPrimitives(renderer, D3D11_PRIMITIVE_TOPOLOGY_POINTLIST, start + (count-1), 1);
+ }
+ break;
+ }
- if (flip & SDL_FLIP_HORIZONTAL) {
- float tmp = maxu;
- maxu = minu;
- minu = tmp;
- }
- if (flip & SDL_FLIP_VERTICAL) {
- float tmp = maxv;
- maxv = minv;
- minv = tmp;
- }
+ case SDL_RENDERCMD_FILL_RECTS: {
+ const size_t count = cmd->data.draw.count;
+ const size_t first = cmd->data.draw.first;
+ const size_t start = first / sizeof (VertexPositionColor);
+ size_t offset = 0;
+ D3D11_SetDrawState(renderer, cmd, rendererData->pixelShaders[SHADER_SOLID], 0, NULL, NULL, NULL);
+ for (i = 0; i < count; i++, offset += 4) {
+ D3D11_DrawPrimitives(renderer, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, start + offset, 4);
+ }
+ break;
+ }
- modelMatrix = MatrixMultiply(
- MatrixRotationZ((float)(M_PI * (float) angle / 180.0f)),
- MatrixTranslation(dstrect->x + center->x, dstrect->y + center->y, 0)
- );
- D3D11_SetModelMatrix(renderer, &modelMatrix);
+ case SDL_RENDERCMD_COPY: {
+ const size_t first = cmd->data.draw.first;
+ const size_t start = first / sizeof (VertexPositionColor);
+ D3D11_SetCopyState(renderer, cmd, NULL);
+ D3D11_DrawPrimitives(renderer, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, start, 4);
+ break;
+ }
- minx = -center->x;
- maxx = dstrect->w - center->x;
- miny = -center->y;
- maxy = dstrect->h - center->y;
+ case SDL_RENDERCMD_COPY_EX: {
+ const size_t first = cmd->data.draw.first;
+ const size_t start = first / sizeof (VertexPositionColor);
+ const VertexPositionColor *verts = (VertexPositionColor *) (((Uint8 *) vertices) + first);
+ const VertexPositionColor *transvert = verts + 4;
+ const float translatex = transvert->pos.x;
+ const float translatey = transvert->pos.y;
+ const float rotation = transvert->pos.z;
+ const Float4X4 matrix = MatrixMultiply(MatrixRotationZ(rotation), MatrixTranslation(translatex, translatey, 0));
+ D3D11_SetCopyState(renderer, cmd, &matrix);
+ D3D11_DrawPrimitives(renderer, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, start, 4);
+ break;
+ }
- vertices[0].pos.x = minx;
- vertices[0].pos.y = miny;
- vertices[0].pos.z = 0.0f;
- vertices[0].tex.x = minu;
- vertices[0].tex.y = minv;
- vertices[0].color = color;
-
- vertices[1].pos.x = minx;
- vertices[1].pos.y = maxy;
- vertices[1].pos.z = 0.0f;
- vertices[1].tex.x = minu;
- vertices[1].tex.y = maxv;
- vertices[1].color = color;
-
- vertices[2].pos.x = maxx;
- vertices[2].pos.y = miny;
- vertices[2].pos.z = 0.0f;
- vertices[2].tex.x = maxu;
- vertices[2].tex.y = minv;
- vertices[2].color = color;
-
- vertices[3].pos.x = maxx;
- vertices[3].pos.y = maxy;
- vertices[3].pos.z = 0.0f;
- vertices[3].tex.x = maxu;
- vertices[3].tex.y = maxv;
- vertices[3].color = color;
-
- if (D3D11_UpdateVertexBuffer(renderer, vertices, sizeof(vertices)) != 0) {
- return -1;
- }
+ case SDL_RENDERCMD_NO_OP:
+ break;
+ }
- if (D3D11_RenderSetupSampler(renderer, texture) < 0) {
- return -1;
+ cmd = cmd->next;
}
- D3D11_RenderFinishDrawOp(renderer, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, sizeof(vertices) / sizeof(VertexPositionColor));
-
- D3D11_SetModelMatrix(renderer, NULL);
-
return 0;
}
@@ -2550,6 +2447,110 @@ D3D11_RenderPresent(SDL_Renderer * renderer)
}
}
+SDL_Renderer *
+D3D11_CreateRenderer(SDL_Window * window, Uint32 flags)
+{
+ SDL_Renderer *renderer;
+ D3D11_RenderData *data;
+
+ renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
+ if (!renderer) {
+ SDL_OutOfMemory();
+ return NULL;
+ }
+
+ data = (D3D11_RenderData *) SDL_calloc(1, sizeof(*data));
+ if (!data) {
+ SDL_OutOfMemory();
+ return NULL;
+ }
+
+ data->identity = MatrixIdentity();
+
+ renderer->WindowEvent = D3D11_WindowEvent;
+ renderer->SupportsBlendMode = D3D11_SupportsBlendMode;
+ renderer->CreateTexture = D3D11_CreateTexture;
+ renderer->UpdateTexture = D3D11_UpdateTexture;
+ renderer->UpdateTextureYUV = D3D11_UpdateTextureYUV;
+ renderer->LockTexture = D3D11_LockTexture;
+ renderer->UnlockTexture = D3D11_UnlockTexture;
+ renderer->SetRenderTarget = D3D11_SetRenderTarget;
+ renderer->QueueSetViewport = D3D11_QueueSetViewport;
+ renderer->QueueSetDrawColor = D3D11_QueueSetViewport; /* SetViewport and SetDrawColor are (currently) no-ops. */
+ renderer->QueueDrawPoints = D3D11_QueueDrawPoints;
+ renderer->QueueDrawLines = D3D11_QueueDrawPoints; /* lines and points queue vertices the same way. */
+ renderer->QueueFillRects = D3D11_QueueFillRects;
+ renderer->QueueCopy = D3D11_QueueCopy;
+ renderer->QueueCopyEx = D3D11_QueueCopyEx;
+ renderer->RunCommandQueue = D3D11_RunCommandQueue;
+ renderer->RenderReadPixels = D3D11_RenderReadPixels;
+ renderer->RenderPresent = D3D11_RenderPresent;
+ renderer->DestroyTexture = D3D11_DestroyTexture;
+ renderer->DestroyRenderer = D3D11_DestroyRenderer;
+ renderer->info = D3D11_RenderDriver.info;
+ renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
+ renderer->driverdata = data;
+
+#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
+ /* VSync is required in Windows Phone, at least for Win Phone 8.0 and 8.1.
+ * Failure to use it seems to either result in:
+ *
+ * - with the D3D11 debug runtime turned OFF, vsync seemingly gets turned
+ * off (framerate doesn't get capped), but nothing appears on-screen
+ *
+ * - with the D3D11 debug runtime turned ON, vsync gets automatically
+ * turned back on, and the following gets output to the debug console:
+ *
+ * DXGI ERROR: IDXGISwapChain::Present: Interval 0 is not supported, changed to Interval 1. [ UNKNOWN ERROR #1024: ]
+ */
+ renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
+#else
+ if ((flags & SDL_RENDERER_PRESENTVSYNC)) {
+ renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
+ }
+#endif
+
+ /* HACK: make sure the SDL_Renderer references the SDL_Window data now, in
+ * order to give init functions access to the underlying window handle:
+ */
+ renderer->window = window;
+
+ /* Initialize Direct3D resources */
+ if (FAILED(D3D11_CreateDeviceResources(renderer))) {
+ D3D11_DestroyRenderer(renderer);
+ return NULL;
+ }
+ if (FAILED(D3D11_CreateWindowSizeDependentResources(renderer))) {
+ D3D11_DestroyRenderer(renderer);
+ return NULL;
+ }
+
+ return renderer;
+}
+
+SDL_RenderDriver D3D11_RenderDriver = {
+ D3D11_CreateRenderer,
+ {
+ "direct3d11",
+ (
+ SDL_RENDERER_ACCELERATED |
+ SDL_RENDERER_PRESENTVSYNC |
+ SDL_RENDERER_TARGETTEXTURE
+ ), /* flags. see SDL_RendererFlags */
+ 6, /* num_texture_formats */
+ { /* texture_formats */
+ SDL_PIXELFORMAT_ARGB8888,
+ SDL_PIXELFORMAT_RGB888,
+ SDL_PIXELFORMAT_YV12,
+ SDL_PIXELFORMAT_IYUV,
+ SDL_PIXELFORMAT_NV12,
+ SDL_PIXELFORMAT_NV21
+ },
+ 0, /* max_texture_width: will be filled in later */
+ 0 /* max_texture_height: will be filled in later */
+ }
+};
+
#endif /* SDL_VIDEO_RENDER_D3D11 && !SDL_RENDER_DISABLED */
/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/render/metal/SDL_render_metal.m b/src/render/metal/SDL_render_metal.m
index 5b4d8ea27c..d8f5b4328f 100644
--- a/src/render/metal/SDL_render_metal.m
+++ b/src/render/metal/SDL_render_metal.m
@@ -46,64 +46,6 @@
/* Apple Metal renderer implementation */
-static SDL_Renderer *METAL_CreateRenderer(SDL_Window * window, Uint32 flags);
-static void METAL_WindowEvent(SDL_Renderer * renderer,
- const SDL_WindowEvent *event);
-static int METAL_GetOutputSize(SDL_Renderer * renderer, int *w, int *h);
-static SDL_bool METAL_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode);
-static int METAL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
-static int METAL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * rect, const void *pixels,
- int pitch);
-static int METAL_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * rect,
- const Uint8 *Yplane, int Ypitch,
- const Uint8 *Uplane, int Upitch,
- const Uint8 *Vplane, int Vpitch);
-static int METAL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * rect, void **pixels, int *pitch);
-static void METAL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
-static int METAL_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture);
-static int METAL_UpdateViewport(SDL_Renderer * renderer);
-static int METAL_UpdateClipRect(SDL_Renderer * renderer);
-static int METAL_RenderClear(SDL_Renderer * renderer);
-static int METAL_RenderDrawPoints(SDL_Renderer * renderer,
- const SDL_FPoint * points, int count);
-static int METAL_RenderDrawLines(SDL_Renderer * renderer,
- const SDL_FPoint * points, int count);
-static int METAL_RenderFillRects(SDL_Renderer * renderer,
- const SDL_FRect * rects, int count);
-static int METAL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * srcrect, const SDL_FRect * dstrect);
-static int METAL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * srcrect, const SDL_FRect * dstrect,
- const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip);
-static int METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
- Uint32 pixel_format, void * pixels, int pitch);
-static void METAL_RenderPresent(SDL_Renderer * renderer);
-static void METAL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture);
-static void METAL_DestroyRenderer(SDL_Renderer * renderer);
-static void *METAL_GetMetalLayer(SDL_Renderer * renderer);
-static void *METAL_GetMetalCommandEncoder(SDL_Renderer * renderer);
-
-SDL_RenderDriver METAL_RenderDriver = {
- METAL_CreateRenderer,
- {
- "metal",
- (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
- 6,
- {
- SDL_PIXELFORMAT_ARGB8888,
- SDL_PIXELFORMAT_ABGR8888,
- SDL_PIXELFORMAT_YV12,
- SDL_PIXELFORMAT_IYUV,
- SDL_PIXELFORMAT_NV12,
- SDL_PIXELFORMAT_NV21
- },
- 0, 0,
- }
-};
-
/* macOS requires constants in a buffer to have a 256 byte alignment. */
#ifdef __MACOSX__
#define CONSTANT_ALIGN 256
@@ -113,6 +55,7 @@ SDL_RenderDriver METAL_RenderDriver = {
#define ALIGN_CONSTANTS(size) ((size + CONSTANT_ALIGN - 1) & (~(CONSTANT_ALIGN - 1)))
+static const size_t CONSTANTS_OFFSET_INVALID = 0xFFFFFFFF;
static const size_t CONSTANTS_OFFSET_IDENTITY = 0;
static const size_t CONSTANTS_OFFSET_HALF_PIXEL_TRANSFORM = ALIGN_CONSTANTS(CONSTANTS_OFFSET_IDENTITY + sizeof(float) * 16);
static const size_t CONSTANTS_OFFSET_DECODE_JPEG = ALIGN_CONSTANTS(CONSTANTS_OFFSET_HALF_PIXEL_TRANSFORM + sizeof(float) * 16);
@@ -457,248 +400,8 @@ ChoosePipelineState(METAL_RenderData *data, METAL_ShaderPipelines *pipelines, SD
return MakePipelineState(data, cache, [NSString stringWithFormat:@" (blend=custom 0x%x)", blendmode], blendmode);
}
-static SDL_Renderer *
-METAL_CreateRenderer(SDL_Window * window, Uint32 flags)
-{ @autoreleasepool {
- SDL_Renderer *renderer = NULL;
- METAL_RenderData *data = NULL;
- id<MTLDevice> mtldevice = nil;
- SDL_SysWMinfo syswm;
-
- SDL_VERSION(&syswm.version);
- if (!SDL_GetWindowWMInfo(window, &syswm)) {
- return NULL;
- }
-
- if (IsMetalAvailable(&syswm) == -1) {
- return NULL;
- }
-
- renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
- if (!renderer) {
- SDL_OutOfMemory();
- return NULL;
- }
-
- // !!! FIXME: MTLCopyAllDevices() can find other GPUs on macOS...
- mtldevice = MTLCreateSystemDefaultDevice();
-
- if (mtldevice == nil) {
- SDL_free(renderer);
- SDL_SetError("Failed to obtain Metal device");
- return NULL;
- }
-
- // !!! FIXME: error checking on all of this.
- data = [[METAL_RenderData alloc] init];
-
- renderer->driverdata = (void*)CFBridgingRetain(data);
- renderer->window = window;
-
-#ifdef __MACOSX__
- NSView *view = Cocoa_Mtl_AddMetalView(window);
- CAMetalLayer *layer = (CAMetalLayer *)[view layer];
-
- layer.device = mtldevice;
-
- //layer.colorspace = nil;
-
-#else
- UIView *view = UIKit_Mtl_AddMetalView(window);
- CAMetalLayer *layer = (CAMetalLayer *)[view layer];
-#endif
-
- // Necessary for RenderReadPixels.
- layer.framebufferOnly = NO;
-
- data.mtldevice = layer.device;
- data.mtllayer = layer;
- id<MTLCommandQueue> mtlcmdqueue = [data.mtldevice newCommandQueue];
- data.mtlcmdqueue = mtlcmdqueue;
- data.mtlcmdqueue.label = @"SDL Metal Renderer";
- data.mtlpassdesc = [MTLRenderPassDescriptor renderPassDescriptor];
-
- NSError *err = nil;
-
- // The compiled .metallib is embedded in a static array in a header file
- // but the original shader source code is in SDL_shaders_metal.metal.
- dispatch_data_t mtllibdata = dispatch_data_create(sdl_metallib, sdl_metallib_len, dispatch_get_global_queue(0, 0), ^{});
- id<MTLLibrary> mtllibrary = [data.mtldevice newLibraryWithData:mtllibdata error:&err];
- data.mtllibrary = mtllibrary;
- SDL_assert(err == nil);
-#if !__has_feature(objc_arc)
- dispatch_release(mtllibdata);
-#endif
- data.mtllibrary.label = @"SDL Metal renderer shader library";
-
- /* Do some shader pipeline state loading up-front rather than on demand. */
- data.pipelinescount = 0;
- data.allpipelines = NULL;
- ChooseShaderPipelines(data, MTLPixelFormatBGRA8Unorm);
-
- MTLSamplerDescriptor *samplerdesc = [[MTLSamplerDescriptor alloc] init];
-
- samplerdesc.minFilter = MTLSamplerMinMagFilterNearest;
- samplerdesc.magFilter = MTLSamplerMinMagFilterNearest;
- id<MTLSamplerState> mtlsamplernearest = [data.mtldevice newSamplerStateWithDescriptor:samplerdesc];
- data.mtlsamplernearest = mtlsamplernearest;
-
- samplerdesc.minFilter = MTLSamplerMinMagFilterLinear;
- samplerdesc.magFilter = MTLSamplerMinMagFilterLinear;
- id<MTLSamplerState> mtlsamplerlinear = [data.mtldevice newSamplerStateWithDescriptor:samplerdesc];
- data.mtlsamplerlinear = mtlsamplerlinear;
-
- /* Note: matrices are column major. */
- float identitytransform[16] = {
- 1.0f, 0.0f, 0.0f, 0.0f,
- 0.0f, 1.0f, 0.0f, 0.0f,
- 0.0f, 0.0f, 1.0f, 0.0f,
- 0.0f, 0.0f, 0.0f, 1.0f,
- };
-
- float halfpixeltransform[16] = {
- 1.0f, 0.0f, 0.0f, 0.0f,
- 0.0f, 1.0f, 0.0f, 0.0f,
- 0.0f, 0.0f, 1.0f, 0.0f,
- 0.5f, 0.5f, 0.0f, 1.0f,
- };
-
- /* Metal pads float3s to 16 bytes. */
- float decodetransformJPEG[4*4] = {
- 0.0, -0.501960814, -0.501960814, 0.0, /* offset */
- 1.0000, 0.0000, 1.4020, 0.0, /* Rcoeff */
- 1.0000, -0.3441, -0.7141, 0.0, /* Gcoeff */
- 1.0000, 1.7720, 0.0000, 0.0, /* Bcoeff */
- };
-
- float decodetransformBT601[4*4] = {
- -0.0627451017, -0.501960814, -0.501960814, 0.0, /* offset */
- 1.1644, 0.0000, 1.5960, 0.0, /* Rcoeff */
- 1.1644, -0.3918, -0.8130, 0.0, /* Gcoeff */
- 1.1644, 2.0172, 0.0000, 0.0, /* Bcoeff */
- };
-
- float decodetransformBT709[4*4] = {
- 0.0, -0.501960814, -0.501960814, 0.0, /* offset */
- 1.0000, 0.0000, 1.4020, 0.0, /* Rcoeff */
- 1.0000, -0.3441, -0.7141, 0.0, /* Gcoeff */
- 1.0000, 1.7720, 0.0000, 0.0, /* Bcoeff */
- };
-
- float clearverts[6] = {0.0f, 0.0f, 0.0f, 2.0f, 2.0f, 0.0f};
-
- id<MTLBuffer> mtlbufconstantstaging = [data.mtldevice newBufferWithLength:CONSTANTS_LENGTH options:MTLResourceStorageModeShared];
- mtlbufconstantstaging.label = @"SDL constant staging data";
-
- id<MTLBuffer> mtlbufconstants = [data.mtldevice newBufferWithLength:CONSTANTS_LENGTH options:MTLResourceStorageModePrivate];
- data.mtlbufconstants = mtlbufconstants;
- data.mtlbufconstants.label = @"SDL constant data";
-
- char *constantdata = [mtlbufconstantstaging contents];
- SDL_memcpy(constantdata + CONSTANTS_OFFSET_IDENTITY, identitytransform, sizeof(identitytransform));
- SDL_memcpy(constantdata + CONSTANTS_OFFSET_HALF_PIXEL_TRANSFORM, halfpixeltransform, sizeof(halfpixeltransform));
- SDL_memcpy(constantdata + CONSTANTS_OFFSET_DECODE_JPEG, decodetransformJPEG, sizeof(decodetransformJPEG));
- SDL_memcpy(constantdata + CONSTANTS_OFFSET_DECODE_BT601, decodetransformBT601, sizeof(decodetransformBT601));
- SDL_memcpy(constantdata + CONSTANTS_OFFSET_DECODE_BT709, decodetransformBT709, sizeof(decodetransformBT709));
- SDL_memcpy(constantdata + CONSTANTS_OFFSET_CLEAR_VERTS, clearverts, sizeof(clearverts));
-
- id<MTLCommandBuffer> cmdbuffer = [data.mtlcmdqueue commandBuffer];
- id<MTLBlitCommandEncoder> blitcmd = [cmdbuffer blitCommandEncoder];
-
- [blitcmd copyFromBuffer:mtlbufconstantstaging sourceOffset:0 toBuffer:data.mtlbufconstants destinationOffset:0 size:CONSTANTS_LENGTH];
-
- [blitcmd endEncoding];
- [cmdbuffer commit];
-
- // !!! FIXME: force more clears here so all the drawables are sane to start, and our static buffers are definitely flushed.
-
- renderer->WindowEvent = METAL_WindowEvent;
- renderer->GetOutputSize = METAL_GetOutputSize;
- renderer->SupportsBlendMode = METAL_SupportsBlendMode;
- renderer->CreateTexture = METAL_CreateTexture;
- renderer->UpdateTexture = METAL_UpdateTexture;
- renderer->UpdateTextureYUV = METAL_UpdateTextureYUV;
- renderer->LockTexture = METAL_LockTexture;
- renderer->UnlockTexture = METAL_UnlockTexture;
- renderer->SetRenderTarget = METAL_SetRenderTarget;
- renderer->UpdateViewport = METAL_UpdateViewport;
- renderer->UpdateClipRect = METAL_UpdateClipRect;
- renderer->RenderClear = METAL_RenderClear;
- renderer->RenderDrawPoints = METAL_RenderDrawPoints;
- renderer->RenderDrawLines = METAL_RenderDrawLines;
- renderer->RenderFillRects = METAL_RenderFillRects;
- renderer->RenderCopy = METAL_RenderCopy;
- renderer->RenderCopyEx = METAL_RenderCopyEx;
- renderer->RenderReadPixels = METAL_RenderReadPixels;
- renderer->RenderPresent = METAL_RenderPresent;
- renderer->DestroyTexture = METAL_DestroyTexture;
- renderer->DestroyRenderer = METAL_DestroyRenderer;
- renderer->GetMetalLayer = METAL_GetMetalLayer;
- renderer->GetMetalCommandEncoder = METAL_GetMetalCommandEncoder;
-
- renderer->info = METAL_RenderDriver.info;
- renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
-
-#if defined(__MACOSX__) && defined(MAC_OS_X_VERSION_10_13)
- if (@available(macOS 10.13, *)) {
- data.mtllayer.displaySyncEnabled = (flags & SDL_RENDERER_PRESENTVSYNC) != 0;
- } else
-#endif
- {
- renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
- }
-
- /* https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf */
- int maxtexsize = 4096;
-#if defined(__MACOSX__)
- maxtexsize = 16384;
-#elif defined(__TVOS__)
- maxtexsize = 8192;
-#ifdef __TVOS_11_0
- if (@available(tvOS 11.0, *)) {
- if ([mtldevice supportsFeatureSet:MTLFeatureSet_tvOS_GPUFamily2_v1]) {
- maxtexsize = 16384;
- }
- }
-#endif
-#else
-#ifdef __IPHONE_11_0
- if ([mtldevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily4_v1]) {
- maxtexsize = 16384;
- } else
-#endif
-#ifdef __IPHONE_10_0
- if ([mtldevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v1]) {
- maxtexsize = 16384;
- } else
-#endif
- if ([mtldevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily2_v2] || [mtldevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily1_v2]) {
- maxtexsize = 8192;
- } else {
- maxtexsize = 4096;
- }
-#endif
-
- renderer->info.max_texture_width = maxtexsize;
- renderer->info.max_texture_height = maxtexsize;
-
-#if !__has_feature(objc_arc)
- [mtlcmdqueue release];
- [mtllibrary release];
- [samplerdesc release];
- [mtlsamplernearest release];
- [mtlsamplerlinear release];
- [mtlbufconstants release];
- [view release];
- [data release];
- [mtldevice release];
-#endif
-
- return renderer;
-}}
-
static void
-METAL_ActivateRenderCommandEncoder(SDL_Renderer * renderer, MTLLoadAction load)
+METAL_ActivateRenderCommandEncoder(SDL_Renderer * renderer, MTLLoadAction load, MTLClearColor *clear_color)
{
METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
@@ -725,8 +428,8 @@ METAL_ActivateRenderCommandEncoder(SDL_Renderer * renderer, MTLLoadAction load)
SDL_assert(mtltexture);
if (load == MTLLoadActionClear) {
- MTLClearColor color = MTLClearColorMake(renderer->r/255.0, renderer->g/255.0, renderer->b/255.0, renderer->a/255.0);
- data.mtlpassdesc.colorAttachments[0].clearColor = color;
+ SDL_assert(clear_color != NULL);
+ data.mtlpassdesc.colorAttachments[0].clearColor = *clear_color;
}
data.mtlpassdesc.colorAttachments[0].loadAction = load;
@@ -743,9 +446,10 @@ METAL_ActivateRenderCommandEncoder(SDL_Renderer * renderer, MTLLoadAction load)
data.activepipelines = ChooseShaderPipelines(data, mtltexture.pixelFormat);
- /* Make sure the viewport and clip rect are set on the new render pass. */
- METAL_UpdateViewport(renderer);
- METAL_UpdateClipRect(renderer);
+ // make sure this has a definite place in the queue. This way it will
+ // execute reliably whether the app tries to make its own command buffers
+ // or whatever. This means we can _always_ batch rendering commands!
+ [data.mtlcmdbuffer enqueue];
}
}
@@ -849,7 +553,7 @@ METAL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
mtltexdesc.height = (texture->h + 1) / 2;
}
- if (yuv || nv12) {
+ if (yuv || nc12) {
mtltexture_uv = [data.mtldevice newTextureWithDescriptor:mtltexdesc];
if (mtltexture_uv == nil) {
#if !__has_feature(objc_arc)
@@ -1027,322 +731,466 @@ METAL_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
return 0;
}}
+
+// normalize a value from 0.0f to len into 0.0f to 1.0f.
+static inline float
+normtex(const float _val, const float len)
+{
+ return _val / len;
+}
+
static int
-METAL_SetOrthographicProjection(SDL_Renderer *renderer, int w, int h)
-{ @autoreleasepool {
- METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
- float projection[4][4];
+METAL_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd)
+{
+ float projection[4][4]; /* Prepare an orthographic projection */
+ const int w = cmd->data.viewport.rect.w;
+ const int h = cmd->data.viewport.rect.h;
+ const size_t matrixlen = sizeof (projection);
+ float *matrix = (float *) SDL_AllocateRenderVertices(renderer, matrixlen, CONSTANT_ALIGN, &cmd->data.viewport.first);
+ if (!matrix) {
+ return -1;
+ }
- if (!w || !h) {
- return 0;
+ SDL_memset(projection, '\0', matrixlen);
+ if (w && h) {
+ projection[0][0] = 2.0f / w;
+ projection[1][1] = -2.0f / h;
+ projection[3][0] = -1.0f;
+ projection[3][1] = 1.0f;
+ projection[3][3] = 1.0f;
}
+ SDL_memcpy(matrix, projection, matrixlen);
- /* Prepare an orthographic projection */
- projection[0][0] = 2.0f / w;
- projection[0][1] = 0.0f;
- projection[0][2] = 0.0f;
- projection[0][3] = 0.0f;
- projection[1][0] = 0.0f;
- projection[1][1] = -2.0f / h;
- projection[1][2] = 0.0f;
- projection[1][3] = 0.0f;
- projection[2][0] = 0.0f;
- projection[2][1] = 0.0f;
- projection[2][2] = 0.0f;
- projection[2][3] = 0.0f;
- projection[3][0] = -1.0f;
- projection[3][1] = 1.0f;
- projection[3][2] = 0.0f;
- projection[3][3] = 1.0f;
-
- // !!! FIXME: This should be in a buffer...
- [data.mtlcmdencoder setVertexBytes:projection length:sizeof(float)*16 atIndex:2];
return 0;
-}}
+}
static int
-METAL_UpdateViewport(SDL_Renderer * renderer)
-{ @autoreleasepool {
- METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
- if (data.mtlcmdencoder) {
- MTLViewport viewport;
- viewport.originX = renderer->viewport.x;
- viewport.originY = renderer->viewport.y;
- viewport.width = renderer->viewport.w;
- viewport.height = renderer->viewport.h;
- viewport.znear = 0.0;
- viewport.zfar = 1.0;
- [data.mtlcmdencoder setViewport:viewport];
- METAL_SetOrthographicProjection(renderer, renderer->viewport.w, renderer->viewport.h);
+METAL_QueueSetDrawColor(SDL_Renderer *renderer, SDL_RenderCommand *cmd)
+{
+ const size_t vertlen = sizeof (float) * 4;
+ float *verts = (float *) SDL_AllocateRenderVertices(renderer, vertlen, CONSTANT_ALIGN, &cmd->data.color.first);
+ if (!verts) {
+ return -1;
}
+ *(verts++) = ((float)cmd->data.color.r) / 255.0f;
+ *(verts++) = ((float)cmd->data.color.g) / 255.0f;
+ *(verts++) = ((float)cmd->data.color.b) / 255.0f;
+ *(verts++) = ((float)cmd->data.color.a) / 255.0f;
return 0;
-}}
+}
static int
-METAL_UpdateClipRect(SDL_Renderer * renderer)
-{ @autoreleasepool {
- METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
- if (data.mtlcmdencoder) {
- MTLScissorRect mtlrect;
- // !!! FIXME: should this care about the viewport?
- if (renderer->clipping_enabled) {
- const SDL_Rect *rect = &renderer->clip_rect;
- mtlrect.x = renderer->viewport.x + rect->x;
- mtlrect.y = renderer->viewport.x + rect->y;
- mtlrect.width = rect->w;
- mtlrect.height = rect->h;
- } else {
- mtlrect.x = renderer->viewport.x;
- mtlrect.y = renderer->viewport.y;
- mtlrect.width = renderer->viewport.w;
- mtlrect.height = renderer->viewport.h;
- }
- if (mtlrect.width > 0 && mtlrect.height > 0) {
- [data.mtlcmdencoder setScissorRect:mtlrect];
- }
+METAL_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
+{
+ const size_t vertlen = (sizeof (float) * 2) * count;
+ float *verts = (float *) SDL_AllocateRenderVertices(renderer, vertlen, 0, &cmd->data.draw.first);
+ if (!verts) {
+ return -1;
}
+ cmd->data.draw.count = count;
+ SDL_memcpy(verts, points, vertlen);
return 0;
-}}
+}
static int
-METAL_RenderClear(SDL_Renderer * renderer)
-{ @autoreleasepool {
- METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
+METAL_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects, int count)
+{
+ // !!! FIXME: use an index buffer
+ const size_t vertlen = (sizeof (float) * 8) * count;
+ float *verts = (float *) SDL_AllocateRenderVertices(renderer, vertlen, 0, &cmd->data.draw.first);
+ if (!verts) {
+ return -1;
+ }
- /* Since we set up the render command encoder lazily when a draw is
- * requested, we can do the fast path hardware clear if no draws have
- * happened since the last SetRenderTarget. */
- if (data.mtlcmdencoder == nil) {
- METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionClear);
- } else {
- // !!! FIXME: render color should live in a dedicated uniform buffer.
- const float color[4] = { ((float)renderer->r) / 255.0f, ((float)renderer->g) / 255.0f, ((float)renderer->b) / 255.0f, ((float)renderer->a) / 255.0f };
+ cmd->data.draw.count = count;
- MTLViewport viewport; // RenderClear ignores the viewport state, though, so reset that.
- viewport.originX = viewport.originY = 0.0;
- viewport.width = data.mtlpassdesc.colorAttachments[0].texture.width;
- viewport.height = data.mtlpassdesc.colorAttachments[0].texture.height;
- viewport.znear = 0.0;
- viewport.zfar = 1.0;
+ for (int i = 0; i < count; i++, rects++) {
+ if ((rects->w <= 0.0f) || (rects->h <= 0.0f)) {
+ cmd->data.draw.count--;
+ } else {
+ *(verts++) = rects->x;
+ *(verts++) = rects->y + rects->h;
+ *(verts++) = rects->x;
+ *(verts++) = rects->y;
+ *(verts++) = rects->x + rects->w;
+ *(verts++) = rects->y + rects->h;
+ *(verts++) = rects->x + rects->w;
+ *(verts++) = rects->y;
+ }
+ }
- // Slow path for clearing: draw a filled fullscreen triangle.
- METAL_SetOrthographicProjection(renderer, 1, 1);
- [data.mtlcmdencoder setViewport:viewport];
- [data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data, data.activepipelines, SDL_METAL_FRAGMENT_SOLID, SDL_BLENDMODE_NONE)];
- [data.mtlcmdencoder setVertexBuffer:data.mtlbufconstants offset:CONSTANTS_OFFSET_CLEAR_VERTS atIndex:0];
- [data.mtlcmdencoder setVertexBuffer:data.mtlbufconstants offset:CONSTANTS_OFFSET_IDENTITY atIndex:3];
- [data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
- [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:3];
-
- // reset the viewport for the rest of our usual drawing work...
- viewport.originX = renderer->viewport.x;
- viewport.originY = renderer->viewport.y;
- viewport.width = renderer->viewport.w;
- viewport.height = renderer->viewport.h;
- viewport.znear = 0.0;
- viewport.zfar = 1.0;
- [data.mtlcmdencoder setViewport:viewport];
- METAL_SetOrthographicProjection(renderer, renderer->viewport.w, renderer->viewport.h);
+ if (cmd->data.draw.count == 0) {
+ cmd->command = SDL_RENDERCMD_NO_OP; // nothing to do, just skip this one later.
}
return 0;
-}}
-
-// normalize a value from 0.0f to len into 0.0f to 1.0f.
-static inline float
-normtex(const float _val, const float len)
-{
- return _val / len;
}
static int
-DrawVerts(SDL_Renderer * renderer, const SDL_FPoint * points, int count,
- const MTLPrimitiveType primtype)
-{ @autoreleasepool {
- METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad);
-
- const size_t vertlen = (sizeof (float) * 2) * count;
- METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
-
- // !!! FIXME: render color should live in a dedicated uniform buffer.
- const float color[4] = { ((float)renderer->r) / 255.0f, ((float)renderer->g) / 255.0f, ((float)renderer->b) / 255.0f, ((float)renderer->a) / 255.0f };
-
- [data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data, data.activepipelines, SDL_METAL_FRAGMENT_SOLID, renderer->blendMode)];
- [data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
+METAL_QueueCopy(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
+ const SDL_Rect * srcrect, const SDL_FRect * dstrect)
+{
+ METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->driverdata;
+ const float texw = (float) texturedata.mtltexture.width;
+ const float texh = (float) texturedata.mtltexture.height;
+ // !!! FIXME: use an index buffer
+ const size_t vertlen = (sizeof (float) * 16);
+ float *verts = (float *) SDL_AllocateRenderVertices(renderer, vertlen, 0, &cmd->data.draw.first);
+ if (!verts) {
+ return -1;
+ }
- [data.mtlcmdencoder setVertexBytes:points length:vertlen atIndex:0];
- [data.mtlcmdencoder setVertexBuffer:data.mtlbufconstants offset:CONSTANTS_OFFSET_HALF_PIXEL_TRANSFORM atIndex:3];
- [data.mtlcmdencoder drawPrimitives:primtype vertexStart:0 vertexCount:count];
+ cmd->data.draw.count = 1;
+
+ *(verts++) = dstrect->x;
+ *(verts++) = dstrect->y + dstrect->h;
+ *(verts++) = dstrect->x;
+ *(verts++) = dstrect->y;
+ *(verts++) = dstrect->x + dstrect->w;
+ *(verts++) = dstrect->y + dstrect->h;
+ *(verts++) = dstrect->x + dstrect->w;
+ *(verts++) = dstrect->y;
+
+ *(verts++) = normtex(srcrect->x, texw);
+ *(verts++) = normtex(srcrect->y + srcrect->h, texh);
+ *(verts++) = normtex(srcrect->x, texw);
+ *(verts++) = normtex(srcrect->y, texh);
+ *(verts++) = normtex(srcrect->x + srcrect->w, texw);
+ *(verts++) = normtex(srcrect->y + srcrect->h, texh);
+ *(verts++) = normtex(srcrect->x + srcrect->w, texw);
+ *(verts++) = normtex(srcrect->y, texh);
return 0;
-}}
-
-static int
-METAL_RenderDrawPoints(SDL_Renderer * renderer, const SDL_FPoint * points, int count)
-{
- return DrawVerts(renderer, points, count, MTLPrimitiveTypePoint);
}
static int
-METAL_RenderDrawLines(SDL_Renderer * renderer, const SDL_FPoint * points, int count)
+METAL_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
+ const SDL_Rect * srcquad, const SDL_FRect * dstrect,
+ const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
{
- return DrawVerts(renderer, points, count, MTLPrimitiveTypeLineStrip);
-}
-
-static int
-METAL_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects, int count)
-{ @autoreleasepool {
- METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad);
- METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
-
- // !!! FIXME: render color should live in a dedicated uniform buffer.
- const float color[4] = { ((float)renderer->r) / 255.0f, ((float)renderer->g) / 255.0f, ((float)renderer->b) / 255.0f, ((float)renderer->a) / 255.0f };
+ METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->driverdata;
+ const float texw = (float) texturedata.mtltexture.width;
+ const float texh = (float) texturedata.mtltexture.height;
+ const float rads = (float)(M_PI * (float) angle / 180.0f);
+ const float c = cosf(rads), s = sinf(rads);
+ float minu, maxu, minv, maxv;
+ const size_t vertlen = (sizeof (float) * 32);
+ float *verts;
- [data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data, data.activepipelines, SDL_METAL_FRAGMENT_SOLID, renderer->blendMode)];
- [data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
- [data.mtlcmdencoder setVertexBuffer:data.mtlbufconstants offset:CONSTANTS_OFFSET_IDENTITY atIndex:3];
+ // 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.
+ verts = (float *) SDL_AllocateRenderVertices(renderer, vertlen, CONSTANT_ALIGN, &cmd->data.draw.count);
+ if (!verts) {
+ return -1;
+ }
- for (int i = 0; i < count; i++, rects++) {
- if ((rects->w <= 0.0f) || (rects->h <= 0.0f)) continue;
+ // transform matrix
+ SDL_memset(verts, '\0', sizeof (*verts) * 16);
+ verts[10] = verts[15] = 1.0f;
+ // rotation
+ verts[0] = c;
+ verts[1] = s;
+ verts[4] = -s;
+ verts[5] = c;
+
+ // translation
+ verts[12] = dstrect->x + center->x;
+ verts[13] = dstrect->y + center->y;
+
+ // rest of the vertices don't need the aggressive alignment. Pack them in.
+ verts = (float *) SDL_AllocateRenderVertices(renderer, vertlen, 0, &cmd->data.draw.first);
+ if (!verts) {
+ return -1;
+ }
- const float verts[] = {
- rects->x, rects->y + rects->h,
- rects->x, rects->y,
- rects->x + rects->w, rects->y + rects->h,
- rects->x + rects->w, rects->y
- };
+ minu = normtex(srcquad->x, texw);
+ maxu = normtex(srcquad->x + srcquad->w, texw);
+ minv = normtex(srcquad->y, texh);
+ maxv = normtex(srcquad->y + srcquad->h, texh);
- [data.mtlcmdencoder setVertexBytes:verts length:sizeof(verts) atIndex:0];
- [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
+ if (flip & SDL_FLIP_HORIZONTAL) {
+ float tmp = maxu;
+ maxu = minu;
+ minu = tmp;
+ }
+ if (flip & SDL_FLIP_VERTICAL) {
+ float tmp = maxv;
+ maxv = minv;
+ minv = tmp;
}
+ // vertices
+ *(verts++) = -center->x;
+ *(verts++) = dstrect->h - center->y;
+ *(verts++) = -center->x;
+ *(verts++) = -center->y;
+ *(verts++) = dstrect->w - center->x;
+ *(verts++) = dstrect->h - center->y;
+ *(verts++) = dstrect->w - center->x;
+ *(verts++) = -center->y;
+
+ // texcoords
+ *(verts++) = minu;
+ *(verts++) = maxv;
+ *(verts++) = minu;
+ *(verts++) = minv;
+ *(verts++) = maxu;
+ *(verts++) = maxv;
+ *(verts++) = maxu;
+ *(verts++) = minv;
+
return 0;
-}}
+}
+
+
+typedef struct
+{
+ #if __has_feature(objc_arc)
+ __unsafe_unretained id<MTLRenderPipelineState> pipeline;
+ #else
+ id<MTLRenderPipelineState> pipeline;
+ #endif
+ size_t constants_offset;
+ SDL_Texture *texture;
+ SDL_bool cliprect_dirty;
+ SDL_bool cliprect_enabled;
+ SDL_Rect cliprect;
+ SDL_bool viewport_dirty;
+ SDL_Rect viewport;
+ size_t projection_offset;
+ SDL_bool color_dirty;
+ size_t color_offset;
+} METAL_DrawStateCache;
static void
-METAL_SetupRenderCopy(METAL_RenderData *data, SDL_Texture *texture, METAL_TextureData *texturedata)
+SetDrawState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, const SDL_MetalFragmentFunction shader,
+ const size_t constants_offset, id<MTLBuffer> mtlbufvertex, METAL_DrawStateCache *statecache)
{
- float color[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
- if (texture->modMode) {
- color[0] = ((float)texture->r) / 255.0f;
- color[1] = ((float)texture->g) / 255.0f;
- color[2] = ((float)texture->b) / 255.0f;
- color[3] = ((float)texture->a) / 255.0f;
+ METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
+ const SDL_BlendMode blend = cmd->data.draw.blend;
+ size_t first = cmd->data.draw.first;
+ id<MTLRenderPipelineState> newpipeline;
+
+ METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad, NULL);
+
+ if (statecache->viewport_dirty) {
+ MTLViewport viewport;
+ viewport.originX = statecache->viewport.x;
+ viewport.originY = statecache->viewport.y;
+ viewport.width = statecache->viewport.w;
+ viewport.height = statecache->viewport.h;
+ viewport.znear = 0.0;
+ viewport.zfar = 1.0;
+ [data.mtlcmdencoder setViewport:viewport];
+ [data.mtlcmdencoder setVertexBuffer:mtlbufvertex offset:statecache->projection_offset atIndex:2]; // projection
+ statecache->viewport_dirty = SDL_FALSE;
+ }
+
+ if (statecache->cliprect_dirty) {
+ MTLScissorRect mtlrect;
+ if (statecache->cliprect_enabled) {
+ const SDL_Rect *rect = &statecache->cliprect;
+ mtlrect.x = statecache->viewport.x + rect->x;
+ mtlrect.y = statecache->viewport.y + rect->y;
+ mtlrect.width = rect->w;
+ mtlrect.height = rect->h;
+ } else {
+ mtlrect.x = statecache->viewport.x;
+ mtlrect.y = statecache->viewport.y;
+ mtlrect.width = statecache->viewport.w;
+ mtlrect.height = statecache->viewport.h;
+ }
+ if (mtlrect.width > 0 && mtlrect.height > 0) {
+ [data.mtlcmdencoder setScissorRect:mtlrect];
+ }
+ statecache->cliprect_dirty = SDL_FALSE;
}
- [data.mtlcmdencoder setRenderPipelineState:ChoosePipelineState(data, data.activepipelines, texturedata.fragmentFunction, texture->blendMode)];
- [data.mtlcmdencoder setFragmentBytes:color length:sizeof(color) atIndex:0];
- [data.mtlcmdencoder setFragmentSamplerState:texturedata.mtlsampler atIndex:0];
+ if (statecache->color_dirty) {
+ [data.mtlcmdencoder setFragmentBuffer:mtlbufvertex offset:statecache->color_offset atIndex:0];
+ statecache->color_dirty = SDL_FALSE;
+ }
- [data.mtlcmdencoder setFragmentTexture:texturedata.mtltexture atIndex:0];
+ newpipeline = ChoosePipelineState(data, data.activepipelines, shader, blend);
+ if (newpipeline != statecache->pipeline) {
+ [data.mtlcmdencoder setRenderPipelineState:newpipeline];
+ statecache->pipeline = newpipeline;
+ }
- if (texturedata.yuv || texturedata.nv12) {
- [data.mtlcmdencoder setFragmentTexture:texturedata.mtltexture_uv atIndex:1];
- [data.mtlcmdencoder setFragmentBuffer:data.mtlbufconstants offset:texturedata.conversionBufferOffset atIndex:1];
+ if (constants_offset != statecache->constants_offset) {
+ if (constants_offset != CONSTANTS_OFFSET_INVALID) {
+ [data.mtlcmdencoder setVertexBuffer:data.mtlbufconstants offset:constants_offset atIndex:3];
+ }
+ statecache->constants_offset = constants_offset;
}
+
+ [data.mtlcmdencoder setVertexBuffer:mtlbufvertex offset:first atIndex:0]; // position
}
-static int
-METAL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * srcrect, const SDL_FRect * dstrect)
-{ @autoreleasepool {
- METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad);
+static void
+SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, const size_t constants_offset,
+ id<MTLBuffer> mtlbufvertex, METAL_DrawStateCache *statecache)
+{
METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
+ SDL_Texture *texture = cmd->data.draw.texture;
METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->driverdata;
- const float texw = (float) texturedata.mtltexture.width;
- const float texh = (float) texturedata.mtltexture.height;
- METAL_SetupRenderCopy(data, texture, texturedata);
+ SetDrawState(renderer, cmd, texturedata.fragmentFunction, constants_offset, mtlbufvertex, statecache);
- const float xy[] = {
- dstrect->x, dstrect->y + dstrect->h,
- dstrect->x, dstrect->y,
- dstrect->x + dstrect->w, dstrect->y + dstrect->h,
- dstrect->x + dstrect->w, dstrect->y
- };
-
- const float uv[] = {
- normtex(srcrect->x, texw), normtex(srcrect->y + srcrect->h, texh),
- normtex(srcrect->x, texw), normtex(srcrect->y, texh),
- normtex(srcrect->x + srcrect->w, texw), normtex(srcrect->y + srcrect->h, texh),
- normtex(srcrect->x + srcrect->w, texw), normtex(srcrect->y, texh)
- };
+ [data.mtlcmdencoder setVertexBuffer:mtlbufvertex offset:cmd->data.draw.first+(8*sizeof (float)) atIndex:1]; // texcoords
- [data.mtlcmdencoder setVertexBytes:xy length:sizeof(xy) atIndex:0];
- [data.mtlcmdencoder setVertexBytes:uv length:sizeof(uv) atIndex:1];
- [data.mtlcmdencoder setVertexBuffer:data.mtlbufconstants offset:CONSTANTS_OFFSET_IDENTITY atIndex:3];
- [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
+ if (texture != statecache->texture) {
+ METAL_TextureData *oldtexturedata = NULL;
+ if (statecache->texture) {
+ oldtexturedata = (__bridge METAL_TextureData *) statecache->texture->driverdata;
+ }
+ if (!oldtexturedata || (texturedata.mtlsampler != oldtexturedata.mtlsampler)) {
+ [data.mtlcmdencoder setFragmentSamplerState:texturedata.mtlsampler atIndex:0];
+ }
- return 0;
-}}
+ [data.mtlcmdencoder setFragmentTexture:texturedata.mtltexture atIndex:0];
+ if (texturedata.yuv || texturedata.nv12) {
+ [data.mtlcmdencoder setFragmentTexture:texturedata.mtltexture_uv atIndex:1];
+ [data.mtlcmdencoder setFragmentBuffer:data.mtlbufconstants offset:texturedata.conversionBufferOffset atIndex:1];
+ }
+ statecache->texture = texture;
+ }
+}
static int
-METAL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * srcrect, const SDL_FRect * dstrect,
- const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
+METAL_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
{ @autoreleasepool {
- METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad);
METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
- METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->driverdata;
- const float texw = (float) texturedata.mtltexture.width;
- const float texh = (float) texturedata.mtltexture.height;
- float transform[16];
- float minu, maxu, minv, maxv;
+ METAL_DrawStateCache statecache;
+ id<MTLBuffer> mtlbufvertex = nil;
+
+ statecache.pipeline = nil;
+ statecache.constants_offset = CONSTANTS_OFFSET_INVALID;
+ statecache.texture = NULL;
+ statecache.color_dirty = SDL_TRUE;
+ statecache.cliprect_dirty = SDL_TRUE;
+ statecache.viewport_dirty = SDL_TRUE;
+ statecache.projection_offset = 0;
+ statecache.color_offset = 0;
+
+ // !!! FIXME: have a ring of pre-made MTLBuffers we cycle through? How expensive is creation?
+ if (vertsize > 0) {
+ id<MTLBuffer> mtlbufvertexstaging = [data.mtldevice newBufferWithLength:vertsize options:MTLResourceStorageModeShared];
+ #if !__has_feature(objc_arc)
+ [mtlbufvertexstaging autorelease];
+ #endif
+ mtlbufvertexstaging.label = @"SDL vertex staging data";
+ SDL_memcpy([mtlbufvertexstaging contents], vertices, vertsize);
+
+ // Move our new vertex buffer from system RAM to GPU memory so any draw calls can use it.
+ mtlbufvertex = [data.mtldevice newBufferWithLength:vertsize options:MTLResourceStorageModePrivate];
+ #if !__has_feature(objc_arc)
+ [mtlbufvertex autorelease];
+ #endif
+ mtlbufvertex.label = @"SDL vertex data";
+ id<MTLCommandBuffer> cmdbuffer = [data.mtlcmdqueue commandBuffer];
+ id<MTLBlitCommandEncoder> blitcmd = [cmdbuffer blitCommandEncoder];
+ [blitcmd copyFromBuffer:mtlbufvertexstaging sourceOffset:0 toBuffer:mtlbufvertex destinationOffset:0 size:vertsize];
+ [blitcmd endEncoding];
+ [cmdbuffer commit];
+ }
- METAL_SetupRenderCopy(data, texture, texturedata);
+ // If there's a command buffer here unexpectedly (app requested one?). Commit it so we can start fresh.
+ [data.mtlcmdencoder endEncoding];
+ [data.mtlcmdbuffer commit];
+ data.mtlcmdencoder = nil;
+ data.mtlcmdbuffer = nil;
- minu = normtex(srcrect->x, texw);
- maxu = normtex(srcrect->x + srcrect->w, texw);
- minv = normtex(srcrect->y, texh);
- maxv = normtex(srcrect->y + srcrect->h, texh);
+ while (cmd) {
+ switch (cmd->command) {
+ case SDL_RENDERCMD_SETVIEWPORT: {
+ SDL_memcpy(&statecache.viewport, &cmd->data.viewport.rect, sizeof (statecache.viewport));
+ statecache.projection_offset = cmd->data.viewport.first;
+ statecache.viewport_dirty = SDL_TRUE;
+ break;
+ }
- if (flip & SDL_FLIP_HORIZONTAL) {
- float tmp = maxu;
- maxu = minu;
- minu = tmp;
- }
- if (flip & SDL_FLIP_VERTICAL) {
- float tmp = maxv;
- maxv = minv;
- minv = tmp;
- }
+ case SDL_RENDERCMD_SETCLIPRECT: {
+ SDL_memcpy(&statecache.cliprect, &cmd->data.cliprect.rect, sizeof (statecache.cliprect));
+ statecache.cliprect_enabled = cmd->data.cliprect.enabled;
+ statecache.cliprect_dirty = SDL_TRUE;
+ break;
+ }
- const float uv[] = {
- minu, maxv,
- minu, minv,
- maxu, maxv,
- maxu, minv
- };
+ case SDL_RENDERCMD_SETDRAWCOLOR: {
+ statecache.color_offset = cmd->data.color.first;
+ statecache.color_dirty = SDL_TRUE;
+ break;
+ }
- const float xy[] = {
- -center->x, dstrect->h - center->y,
- -center->x, -center->y,
- dstrect->w - center->x, dstrect->h - center->y,
- dstrect->w - center->x, -center->y
- };
+ case SDL_RENDERCMD_CLEAR: {
+ /* If we're already encoding a command buffer, dump it without committing it. We'd just
+ clear all its work anyhow, and starting a new encoder will let us use a hardware clear
+ operation via MTLLoadActionClear. */
+ if (data.mtlcmdencoder != nil) {
+ [data.mtlcmdencoder endEncoding];
+
+ // !!! FIXME: have to commit, or an uncommitted but enqueued buffer will prevent the frame from finishing.
+ [data.mtlcmdbuffer commit];
+ data.mtlcmdencoder = nil;
+ data.mtlcmdbuffer = nil;
+ }
- {
- float rads = (float)(M_PI * (float) angle / 180.0f);
- float c = cosf(rads), s = sinf(rads);
- SDL_memset(transform, 0, sizeof(transform));
+ // force all this state to be reconfigured on next command buffer.
+ statecache.pipeline = nil;
+ statecache.constants_offset = CONSTANTS_OFFSET_INVALID;
+ statecache.texture = NULL;
+ statecache.color_dirty = SDL_TRUE;
+ statecache.cliprect_dirty = SDL_TRUE;
+ statecache.viewport_dirty = SDL_TRUE;
+
+ const Uint8 r = cmd->data.color.r;
+ const Uint8 g = cmd->data.color.g;
+ const Uint8 b = cmd->data.color.b;
+ const Uint8 a = cmd->data.color.a;
+ MTLClearColor color = MTLClearColorMake(r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f);
+
+ // get new command encoder, set up with an initial clear operation.
+ METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionClear, &color);
+ break;
+ }
- transform[10] = transform[15] = 1.0f;
+ case SDL_RENDERCMD_DRAW_POINTS:
+ case SDL_RENDERCMD_DRAW_LINES: {
+ const size_t count = cmd->data.draw.count;
+ const MTLPrimitiveType primtype = (cmd->command == SDL_RENDERCMD_DRAW_POINTS) ? MTLPrimitiveTypePoint : MTLPrimitiveTypeLineStrip;
+ SetDrawState(renderer, cmd, SDL_METAL_FRAGMENT_SOLID, CONSTANTS_OFFSET_HALF_PIXEL_TRANSFORM, mtlbufvertex, &statecache);
+ [data.mtlcmdencoder drawPrimitives:primtype vertexStart:0 vertexCount:count];
+ break;
+ }
- /* Rotation */
- transform[0] = c;
- transform[1] = s;
- transform[4] = -s;
- transform[5] = c;
+ case SDL_RENDERCMD_FILL_RECTS: {
+ const size_t count = cmd->data.draw.count;
+ size_t start = 0;
+ SetDrawState(renderer, cmd, SDL_METAL_FRAGMENT_SOLID, CONSTANTS_OFFSET_IDENTITY, mtlbufvertex, &statecache);
+ 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?
+ [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:start vertexCount:4];
+ }
+ break;
+ }
- /* Translation */
- transform[12] = dstrect->x + center->x;
- transform[13] = dstrect->y + center->y;
- }
+ case SDL_RENDERCMD_COPY: {
+ SetCopyState(renderer, cmd, CONSTANTS_OFFSET_IDENTITY, mtlbufvertex, &statecache);
+ [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
+ break;
+ }
- [data.mtlcmdencoder setVertexBytes:xy length:sizeof(xy) atIndex:0];
- [data.mtlcmdencoder setVertexBytes:uv length:sizeof(uv) atIndex:1];
- [data.mtlcmdencoder setVertexBytes:transform length:sizeof(transform) atIndex:3];
- [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
+ case SDL_RENDERCMD_COPY_EX: {
+ SetCopyState(renderer, cmd, CONSTANTS_OFFSET_INVALID, mtlbufvertex, &statecache);
+ [data.mtlcmdencoder setVertexBuffer:mtlbufvertex offset:cmd->data.draw.count atIndex:3]; // transform
+ [data.mtlcmdencoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
+ break;
+ }
+
+ case SDL_RENDERCMD_NO_OP:
+ break;
+ }
+ cmd = cmd->next;
+ }
return 0;
}}
@@ -1352,21 +1200,14 @@ METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
Uint32 pixel_format, void * pixels, int pitch)
{ @autoreleasepool {
METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
+ METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad, NULL);
- /* Make sure we have a valid MTLTexture to read from, and an active command
- * buffer we can wait for. */
- METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad);
-
- /* Wait for the current command buffer to finish, so we don't read from the
- * texture before the GPU finishes rendering to it. */
- if (data.mtlcmdencoder) {
- [data.mtlcmdencoder endEncoding];
- [data.mtlcmdbuffer commit];
- [data.mtlcmdbuffer waitUntilCompleted];
-
- data.mtlcmdencoder = nil;
- data.mtlcmdbuffer = nil;
- }
+ // Commit any current command buffer, and waitUntilCompleted, so any output is ready to be read.
+ [data.mtlcmdencoder endEncoding];
+ [data.mtlcmdbuffer commit];
+ [data.mtlcmdbuffer waitUntilCompleted];
+ data.mtlcmdencoder = nil;
+ data.mtlcmdbuffer = nil;
id<MTLTexture> mtltexture = data.mtlpassdesc.colorAttachments[0].texture;
MTLRegion mtlregion = MTLRegionMake2D(rect->x, rect->y, rect->w, rect->h);
@@ -1383,13 +1224,6 @@ METAL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
const Uint32 temp_format = (mtltexture.pixelFormat == MTLPixelFormatBGRA8Unorm) ? SDL_PIXELFORMAT_ARGB8888 : SDL_PIXELFORMAT_ABGR8888;
const int status = SDL_ConvertPixels(rect->w, rect->h, temp_format, temp_pixels, temp_pitch, pixel_format, pixels, pitch);
SDL_free(temp_pixels);
-
- /* Set up an active command buffer and encoder once we're done. It will use
- * the same texture that was active before (even if it's part of the swap
- * chain), since we didn't clear that when waiting for the command buffer to
- * complete. */
- METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad);
-
return status;
}}
@@ -1445,11 +1279,274 @@ METAL_GetMetalLayer(SDL_Renderer * renderer)
static void *
METAL_GetMetalCommandEncoder(SDL_Renderer * renderer)
{ @autoreleasepool {
- METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad);
+ METAL_ActivateRenderCommandEncoder(renderer, MTLLoadActionLoad, NULL);
METAL_RenderData *data = (__bridge METAL_RenderData *) renderer->driverdata;
return (__bridge void*)data.mtlcmdencoder;
}}
+static SDL_Renderer *
+METAL_CreateRenderer(SDL_Window * window, Uint32 flags)
+{ @autoreleasepool {
+ SDL_Renderer *renderer = NULL;
+ METAL_RenderData *data = NULL;
+ id<MTLDevice> mtldevice = nil;
+ SDL_SysWMinfo syswm;
+
+ SDL_VERSION(&syswm.version);
+ if (!SDL_GetWindowWMInfo(window, &syswm)) {
+ return NULL;
+ }
+
+ if (IsMetalAvailable(&syswm) == -1) {
+ return NULL;
+ }
+
+ renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
+ if (!renderer) {
+ SDL_OutOfMemory();
+ return NULL;
+ }
+
+ // !!! FIXME: MTLCopyAllDevices() can find other GPUs on macOS...
+ mtldevice = MTLCreateSystemDefaultDevice();
+
+ if (mtldevice == nil) {
+ SDL_free(renderer);
+ SDL_SetError("Failed to obtain Metal device");
+ return NULL;
+ }
+
+ // !!! FIXME: error checking on all of this.
+ data = [[METAL_RenderData alloc] init];
+
+ renderer->driverdata = (void*)CFBridgingRetain(data);
+ renderer->window = window;
+
+#ifdef __MACOSX__
+ NSView *view = Cocoa_Mtl_AddMetalView(window);
+ CAMetalLayer *layer = (CAMetalLayer *)[view layer];
+
+ layer.device = mtldevice;
+
+ //layer.colorspace = nil;
+
+#else
+ UIView *view = UIKit_Mtl_AddMetalView(window);
+ CAMetalLayer *layer = (CAMetalLayer *)[view layer];
+#endif
+
+ // Necessary for RenderReadPixels.
+ layer.framebufferOnly = NO;
+
+ data.mtldevice = layer.device;
+ data.mtllayer = layer;
+ id<MTLCommandQueue> mtlcmdqueue = [data.mtldevice newCommandQueue];
+ data.mtlcmdqueue = mtlcmdqueue;
+ data.mtlcmdqueue.label = @"SDL Metal Renderer";
+ data.mtlpassdesc = [MTLRenderPassDescriptor renderPassDescriptor];
+
+ NSError *err = nil;
+
+ // The compiled .metallib is embedded in a static array in a header file
+ // but the original shader source code is in SDL_shaders_metal.metal.
+ dispatch_data_t mtllibdata = dispatch_data_create(sdl_metallib, sdl_metallib_len, dispatch_get_global_queue(0, 0), ^{});
+ id<MTLLibrary> mtllibrary = [data.mtldevice newLibraryWithData:mtllibdata error:&err];
+ data.mtllibrary = mtllibrary;
+ SDL_assert(err == nil);
+#if !__has_feature(objc_arc)
+ dispatch_release(mtllibdata);
+#endif
+ data.mtllibrary.label = @"SDL Metal renderer shader library";
+
+ /* Do some shader pipeline state loading up-front rather than on demand. */
+ data.pipelinescount = 0;
+ data.allpipelines = NULL;
+ ChooseShaderPipelines(data, MTLPixelFormatBGRA8Unorm);
+
+ MTLSamplerDescriptor *samplerdesc = [[MTLSamplerDescriptor alloc] init];
+
+ samplerdesc.minFilter = MTLSamplerMinMagFilterNearest;
+ samplerdesc.magFilter = MTLSamplerMinMagFilterNearest;
+ id<MTLSamplerState> mtlsamplernearest = [data.mtldevice newSamplerStateWithDescriptor:samplerdesc];
+ data.mtlsamplernearest = mtlsamplernearest;
+
+ samplerdesc.minFilter = MTLSamplerMinMagFilterLinear;
+ samplerdesc.magFilter = MTLSamplerMinMagFilterLinear;
+ id<MTLSamplerState> mtlsamplerlinear = [data.mtldevice newSamplerStateWithDescriptor:samplerdesc];
+ data.mtlsamplerlinear = mtlsamplerlinear;
+
+ /* Note: matrices are column major. */
+ float identitytransform[16] = {
+ 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f,
+ };
+
+ float halfpixeltransform[16] = {
+ 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.5f, 0.5f, 0.0f, 1.0f,
+ };
+
+ /* Metal pads float3s to 16 bytes. */
+ float decodetransformJPEG[4*4] = {
+ 0.0, -0.501960814, -0.501960814, 0.0, /* offset */
+ 1.0000, 0.0000, 1.4020, 0.0, /* Rcoeff */
+ 1.0000, -0.3441, -0.7141, 0.0, /* Gcoeff */
+ 1.0000, 1.7720, 0.0000, 0.0, /* Bcoeff */
+ };
+
+ float decodetransformBT601[4*4] = {
+ -0.0627451017, -0.501960814, -0.501960814, 0.0, /* offset */
+ 1.1644, 0.0000, 1.5960, 0.0, /* Rcoeff */
+ 1.1644, -0.3918, -0.8130, 0.0, /* Gcoeff */
+ 1.1644, 2.0172, 0.0000, 0.0, /* Bcoeff */
+ };
+
+ float decodetransformBT709[4*4] = {
+ 0.0, -0.501960814, -0.501960814, 0.0, /* offset */
+ 1.0000, 0.0000, 1.4020, 0.0, /* Rcoeff */
+ 1.0000, -0.3441, -0.7141, 0.0, /* Gcoeff */
+ 1.0000, 1.7720, 0.0000, 0.0, /* Bcoeff */
+ };
+
+ float clearverts[6] = {0.0f, 0.0f, 0.0f, 2.0f, 2.0f, 0.0f};
+
+ id<MTLBuffer> mtlbufconstantstaging = [data.mtldevice newBufferWithLength:CONSTANTS_LENGTH options:MTLResourceStorageModeShared];
+ #if !__has_feature(objc_arc)
+ [mtlbufconstantstaging autorelease];
+ #endif
+ mtlbufconstantstaging.label = @"SDL constant staging data";
+
+ id<MTLBuffer> mtlbufconstants = [data.mtldevice newBufferWithLength:CONSTANTS_LENGTH options:MTLResourceStorageModePrivate];
+ data.mtlbufconstants = mtlbufconstants;
+ data.mtlbufconstants.label = @"SDL constant data";
+
+ char *constantdata = [mtlbufconstantstaging contents];
+ SDL_memcpy(constantdata + CONSTANTS_OFFSET_IDENTITY, identitytransform, sizeof(identitytransform));
+ SDL_memcpy(constantdata + CONSTANTS_OFFSET_HALF_PIXEL_TRANSFORM, halfpixeltransform, sizeof(halfpixeltransform));
+ SDL_memcpy(constantdata + CONSTANTS_OFFSET_DECODE_JPEG, decodetransformJPEG, sizeof(decodetransformJPEG));
+ SDL_memcpy(constantdata + CONSTANTS_OFFSET_DECODE_BT601, decodetransformBT601, sizeof(decodetransformBT601));
+ SDL_memcpy(constantdata + CONSTANTS_OFFSET_DECODE_BT709, decodetransformBT709, sizeof(decodetransformBT709));
+ SDL_memcpy(constantdata + CONSTANTS_OFFSET_CLEAR_VERTS, clearverts, sizeof(clearverts));
+
+ id<MTLCommandBuffer> cmdbuffer = [data.mtlcmdqueue commandBuffer];
+ id<MTLBlitCommandEncoder> blitcmd = [cmdbuffer blitCommandEncoder];
+
+ [blitcmd copyFromBuffer:mtlbufconstantstaging sourceOffset:0 toBuffer:data.mtlbufconstants destinationOffset:0 size:CONSTANTS_LENGTH];
+
+ [blitcmd endEncoding];
+ [cmdbuffer commit];
+
+ // !!! FIXME: force more clears here so all the drawables are sane to start, and our static buffers are definitely flushed.
+
+ renderer->WindowEvent = METAL_WindowEvent;
+ renderer->GetOutputSize = METAL_GetOutputSize;
+ renderer->SupportsBlendMode = METAL_SupportsBlendMode;
+ renderer->CreateTexture = METAL_CreateTexture;
+ renderer->UpdateTexture = METAL_UpdateTexture;
+ renderer->UpdateTextureYUV = METAL_UpdateTextureYUV;
+ renderer->LockTexture = METAL_LockTexture;
+ renderer->UnlockTexture = METAL_UnlockTexture;
+ renderer->SetRenderTarget = METAL_SetRenderTarget;
+ renderer->QueueSetViewport = METAL_QueueSetViewport;
+ renderer->QueueSetDrawColor = METAL_QueueSetDrawColor;
+ renderer->QueueDrawPoints = METAL_QueueDrawPoints;
+ renderer->QueueDrawLines = METAL_QueueDrawPoints; // lines and points queue the same way.
+ renderer->QueueFillRects = METAL_QueueFillRects;
+ renderer->QueueCopy = METAL_QueueCopy;
+ renderer->QueueCopyEx = METAL_QueueCopyEx;
+ renderer->RunCommandQueue = METAL_RunCommandQueue;
+ renderer->RenderReadPixels = METAL_RenderReadPixels;
+ renderer->RenderPresent = METAL_RenderPresent;
+ renderer->DestroyTexture = METAL_DestroyTexture;
+ renderer->DestroyRenderer = METAL_DestroyRenderer;
+ renderer->GetMetalLayer = METAL_GetMetalLayer;
+ renderer->GetMetalCommandEncoder = METAL_GetMetalCommandEncoder;
+
+ renderer->info = METAL_RenderDriver.info;
+ renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
+
+ renderer->always_batch = SDL_TRUE;
+
+#if defined(__MACOSX__) && defined(MAC_OS_X_VERSION_10_13)
+ if (@available(macOS 10.13, *)) {
+ data.mtllayer.displaySyncEnabled = (flags & SDL_RENDERER_PRESENTVSYNC) != 0;
+ } else
+#endif
+ {
+ renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
+ }
+
+ /* https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf */
+ int maxtexsize = 4096;
+#if defined(__MACOSX__)
+ maxtexsize = 16384;
+#elif defined(__TVOS__)
+ maxtexsize = 8192;
+#ifdef __TVOS_11_0
+ if (@available(tvOS 11.0, *)) {
+ if ([mtldevice supportsFeatureSet:MTLFeatureSet_tvOS_GPUFamily2_v1]) {
+ maxtexsize = 16384;
+ }
+ }
+#endif
+#else
+#ifdef __IPHONE_11_0
+ if ([mtldevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily4_v1]) {
+ maxtexsize = 16384;
+ } else
+#endif
+#ifdef __IPHONE_10_0
+ if ([mtldevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v1]) {
+ maxtexsize = 16384;
+ } else
+#endif
+ if ([mtldevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily2_v2] || [mtldevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily1_v2]) {
+ maxtexsize = 8192;
+ } else {
+ maxtexsize = 4096;
+ }
+#endif
+
+ renderer->info.max_texture_width = maxtexsize;
+ renderer->info.max_texture_height = maxtexsize;
+
+#if !__has_feature(objc_arc)
+ [mtlcmdqueue release];
+ [mtllibrary release];
+ [samplerdesc release];
+ [mtlsamplernearest release];
+ [mtlsamplerlinear release];
+ [mtlbufconstants release];
+ [view release];
+ [data release];
+ [mtldevice release];
+#endif
+
+ return renderer;
+}}
+
+SDL_RenderDriver METAL_RenderDriver = {
+ METAL_CreateRenderer,
+ {
+ "metal",
+ (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
+ 6,
+ {
+ SDL_PIXELFORMAT_ARGB8888,
+ SDL_PIXELFORMAT_ABGR8888,
+ SDL_PIXELFORMAT_YV12,
+ SDL_PIXELFORMAT_IYUV,
+ SDL_PIXELFORMAT_NV12,
+ SDL_PIXELFORMAT_NV21
+ },
+ 0, 0,
+ }
+};
+
#endif /* SDL_VIDEO_RENDER_METAL && !SDL_RENDER_DISABLED */
/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/render/opengl/SDL_render_gl.c b/src/render/opengl/SDL_render_gl.c
index 09db12de80..01d6dadf01 100644
--- a/src/render/opengl/SDL_render_gl.c
+++ b/src/render/opengl/SDL_render_gl.c
@@ -51,57 +51,6 @@ extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags);
static const float inv255f = 1.0f / 255.0f;
-static SDL_Renderer *GL_CreateRenderer(SDL_Window * window, Uint32 flags);
-static void GL_WindowEvent(SDL_Renderer * renderer,
- const SDL_WindowEvent *event);
-static int GL_GetOutputSize(SDL_Renderer * renderer, int *w, int *h);
-static SDL_bool GL_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode);
-static int GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
-static int GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * rect, const void *pixels,
- int pitch);
-static int GL_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * rect,
- const Uint8 *Yplane, int Ypitch,
- const Uint8 *Uplane, int Upitch,
- const Uint8 *Vplane, int Vpitch);
-static int GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * rect, void **pixels, int *pitch);
-static void GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
-static int GL_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture);
-static int GL_UpdateViewport(SDL_Renderer * renderer);
-static int GL_UpdateClipRect(SDL_Renderer * renderer);
-static int GL_RenderClear(SDL_Renderer * renderer);
-static int GL_RenderDrawPoints(SDL_Renderer * renderer,
- const SDL_FPoint * points, int count);
-static int GL_RenderDrawLines(SDL_Renderer * renderer,
- const SDL_FPoint * points, int count);
-static int GL_RenderFillRects(SDL_Renderer * renderer,
- const SDL_FRect * rects, int count);
-static int GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * srcrect, const SDL_FRect * dstrect);
-static int GL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * srcrect, const SDL_FRect * dstrect,
- const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip);
-static int GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
- Uint32 pixel_format, void * pixels, int pitch);
-static void GL_RenderPresent(SDL_Renderer * renderer);
-static void GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture);
-static void GL_DestroyRenderer(SDL_Renderer * renderer);
-static int GL_BindTexture (SDL_Renderer * renderer, SDL_Texture *texture, float *texw, float *texh);
-static int GL_UnbindTexture (SDL_Renderer * renderer, SDL_Texture *texture);
-
-SDL_RenderDriver GL_RenderDriver = {
- GL_CreateRenderer,
- {
- "opengl",
- (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
- 1,
- {SDL_PIXELFORMAT_ARGB8888},
- 0,
- 0}
-};
-
typedef struct GL_FBOList GL_FBOList;
struct GL_FBOList
@@ -113,6 +62,25 @@ struct GL_FBOList
typedef struct
{
+ SDL_bool viewport_dirty;
+ SDL_Rect viewport;
+ SDL_Texture *texture;
+ SDL_Texture *target;
+ int drawablew;
+ int drawableh;
+ SDL_BlendMode blend;
+ GL_Shader shader;
+ SDL_bool cliprect_enabled_dirty;
+ SDL_bool cliprect_enabled;
+ SDL_bool cliprect_dirty;
+ SDL_Rect cliprect;
+ SDL_bool texturing;
+ Uint32 color;
+ Uint32 clear_color;
+} GL_DrawStateCache;
+
+typedef struct
+{
SDL_GLContext context;
SDL_bool debug_enabled;
@@ -122,14 +90,10 @@ typedef struct
GLDEBUGPROCARB next_error_callback;
GLvoid *next_error_userparam;
+ GLenum textype;
+
SDL_bool GL_ARB_texture_non_power_of_two_supported;
SDL_bool GL_ARB_texture_rectangle_supported;
- struct {
- GL_Shader shader;
- Uint32 color;
- SDL_BlendMode blendMode;
- } current;
-
SDL_bool GL_EXT_framebuffer_object_supported;
GL_FBOList *framebuffers;
@@ -152,12 +116,12 @@ typedef struct
/* Shader support */
GL_ShaderContext *shaders;
+ GL_DrawStateCache drawstate;
} GL_RenderData;
typedef struct
{
GLuint texture;
- GLenum type;
GLfloat texw;
GLfloat texh;
GLenum format;
@@ -284,21 +248,15 @@ GL_LoadFunctions(GL_RenderData * data)
return 0;
}
-static SDL_GLContext SDL_CurrentContext = NULL;
-
static int
GL_ActivateRenderer(SDL_Renderer * renderer)
{
GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
- if (SDL_CurrentContext != data->context ||
- SDL_GL_GetCurrentContext() != data->context) {
+ if (SDL_GL_GetCurrentContext() != data->context) {
if (SDL_GL_MakeCurrent(renderer->window, data->context) < 0) {
return -1;
}
- SDL_CurrentContext = data->context;
-
- GL_UpdateViewport(renderer);
}
GL_ClearErrors(renderer);
@@ -306,33 +264,6 @@ GL_ActivateRenderer(SDL_Renderer * renderer)
return 0;
}
-/* This is called if we need to invalidate all of the SDL OpenGL state */
-static void
-GL_ResetState(SDL_Renderer *renderer)
-{
- GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
-
- if (SDL_GL_GetCurrentContext() == data->context) {
- GL_UpdateViewport(renderer);
- } else {
- GL_ActivateRenderer(renderer);
- }
-
- data->current.shader = SHADER_NONE;
- data->current.color = 0xffffffff;
- data->current.blendMode = SDL_BLENDMODE_INVALID;
-
- data->glDisable(GL_DEPTH_TEST);
- data->glDisable(GL_CULL_FACE);
- /* This ended up causing video discrepancies between OpenGL and Direct3D */
- /* data->glEnable(GL_LINE_SMOOTH); */
-
- data->glMatrixMode(GL_MODELVIEW);
- data->glLoadIdentity();
-
- GL_CheckError("", renderer);
-}
-
static void APIENTRY
GL_HandleDebugMessage(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char *message, const void *userParam)
{
@@ -384,215 +315,6 @@ GL_GetFBO(GL_RenderData *data, Uint32 w, Uint32 h)
return result;
}
-SDL_Renderer *
-GL_CreateRenderer(SDL_Window * window, Uint32 flags)
-{
- SDL_Renderer *renderer;
- GL_RenderData *data;
- GLint value;
- Uint32 window_flags;
- int profile_mask = 0, major = 0, minor = 0;
- SDL_bool changed_window = SDL_FALSE;
-
- SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profile_mask);
- SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major);
- SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor);
-
- window_flags = SDL_GetWindowFlags(window);
- if (!(window_flags & SDL_WINDOW_OPENGL) ||
- profile_mask == SDL_GL_CONTEXT_PROFILE_ES || major != RENDERER_CONTEXT_MAJOR || minor != RENDERER_CONTEXT_MINOR) {
-
- changed_window = SDL_TRUE;
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0);
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, RENDERER_CONTEXT_MAJOR);
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, RENDERER_CONTEXT_MINOR);
-
- if (SDL_RecreateWindow(window, window_flags | SDL_WINDOW_OPENGL) < 0) {
- goto error;
- }
- }
-
- renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
- if (!renderer) {
- SDL_OutOfMemory();
- goto error;
- }
-
- data = (GL_RenderData *) SDL_calloc(1, sizeof(*data));
- if (!data) {
- SDL_free(renderer);
- SDL_OutOfMemory();
- goto error;
- }
-
- renderer->WindowEvent = GL_WindowEvent;
- renderer->GetOutputSize = GL_GetOutputSize;
- renderer->SupportsBlendMode = GL_SupportsBlendMode;
- renderer->CreateTexture = GL_CreateTexture;
- renderer->UpdateTexture = GL_UpdateTexture;
- renderer->UpdateTextureYUV = GL_UpdateTextureYUV;
- renderer->LockTexture = GL_LockTexture;
- renderer->UnlockTexture = GL_UnlockTexture;
- renderer->SetRenderTarget = GL_SetRenderTarget;
- renderer->UpdateViewport = GL_UpdateViewport;
- renderer->UpdateClipRect = GL_UpdateClipRect;
- renderer->RenderClear = GL_RenderClear;
- renderer->RenderDrawPoints = GL_RenderDrawPoints;
- renderer->RenderDrawLines = GL_RenderDrawLines;
- renderer->RenderFillRects = GL_RenderFillRects;
- renderer->RenderCopy = GL_RenderCopy;
- renderer->RenderCopyEx = GL_RenderCopyEx;
- renderer->RenderReadPixels = GL_RenderReadPixels;
- renderer->RenderPresent = GL_RenderPresent;
- renderer->DestroyTexture = GL_DestroyTexture;
- renderer->DestroyRenderer = GL_DestroyRenderer;
- renderer->GL_BindTexture = GL_BindTexture;
- renderer->GL_UnbindTexture = GL_UnbindTexture;
- renderer->info = GL_RenderDriver.info;
- renderer->info.flags = SDL_RENDERER_ACCELERATED;
- renderer->driverdata = data;
- renderer->window = window;
-
- data->context = SDL_GL_CreateContext(window);
- if (!data->context) {
- SDL_free(renderer);
- SDL_free(data);
- goto error;
- }
- if (SDL_GL_MakeCurrent(window, data->context) < 0) {
- SDL_GL_DeleteContext(data->context);
- SDL_free(renderer);
- SDL_free(data);
- goto error;
- }
-
- if (GL_LoadFunctions(data) < 0) {
- SDL_GL_DeleteContext(data->context);
- SDL_free(renderer);
- SDL_free(data);
- goto error;
- }
-
-#ifdef __MACOSX__
- /* Enable multi-threaded rendering */
- /* Disabled until Ryan finishes his VBO/PBO code...
- CGLEnable(CGLGetCurrentContext(), kCGLCEMPEngine);
- */
-#endif
-
- if (flags & SDL_RENDERER_PRESENTVSYNC) {
- SDL_GL_SetSwapInterval(1);
- } else {
- SDL_GL_SetSwapInterval(0);
- }
- if (SDL_GL_GetSwapInterval() > 0) {
- renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
- }
-
- /* Check for debug output support */
- if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_FLAGS, &value) == 0 &&
- (value & SDL_GL_CONTEXT_DEBUG_FLAG)) {
- data->debug_enabled = SDL_TRUE;
- }
- if (data->debug_enabled && SDL_GL_ExtensionSupported("GL_ARB_debug_output")) {
- PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARBFunc = (PFNGLDEBUGMESSAGECALLBACKARBPROC) SDL_GL_GetProcAddress("glDebugMessageCallbackARB");
-
- data->GL_ARB_debug_output_supported = SDL_TRUE;
- data->glGetPointerv(GL_DEBUG_CALLBACK_FUNCTION_ARB, (GLvoid **)(char *)&data->next_error_callback);
- data->glGetPointerv(GL_DEBUG_CALLBACK_USER_PARAM_ARB, &data->next_error_userparam);
- glDebugMessageCallbackARBFunc(GL_HandleDebugMessage, renderer);
-
- /* Make sure our callback is called when errors actually happen */
- data->glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
- }
-
- if (SDL_GL_ExtensionSupported("GL_ARB_texture_non_power_of_two")) {
- data->GL_ARB_texture_non_power_of_two_supported = SDL_TRUE;
- } else if (SDL_GL_ExtensionSupported("GL_ARB_texture_rectangle") ||
- SDL_GL_ExtensionSupported("GL_EXT_texture_rectangle")) {
- data->GL_ARB_texture_rectangle_supported = SDL_TRUE;
- }
- if (data->GL_ARB_texture_rectangle_supported) {
- data->glGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB, &value);
- renderer->info.max_texture_width = value;
- renderer->info.max_texture_height = value;
- } else {
- data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
- renderer->info.max_texture_width = value;
- renderer->info.max_texture_height = value;
- }
-
- /* Check for multitexture support */
- if (SDL_GL_ExtensionSupported("GL_ARB_multitexture")) {
- data->glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC) SDL_GL_GetProcAddress("glActiveTextureARB");
- if (data->glActiveTextureARB) {
- data->GL_ARB_multitexture_supported = SDL_TRUE;
- data->glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &data->num_texture_units);
- }
- }
-
- /* Check for shader support */
- if (SDL_GetHintBoolean(SDL_HINT_RENDER_OPENGL_SHADERS, SDL_TRUE)) {
- data->shaders = GL_CreateShaderContext();
- }
- SDL_LogInfo(SDL_LOG_CATEGORY_RENDER, "OpenGL shaders: %s",
- data->shaders ? "ENABLED" : "DISABLED");
-
- /* We support YV12 textures using 3 textures and a shader */
- if (data->shaders && data->num_texture_units >= 3) {
- renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;
- renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
- renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_NV12;
- renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_NV21;
- }
-
-#ifdef __MACOSX__
- renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_UYVY;
-#endif
-
- if (SDL_GL_ExtensionSupported("GL_EXT_framebuffer_object")) {
- data->GL_EXT_framebuffer_object_supported = SDL_TRUE;
- data->glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC)
- SDL_GL_GetProcAddress("glGenFramebuffersEXT");
- data->glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC)
- SDL_GL_GetProcAddress("glDeleteFramebuffersEXT");
- data->glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)
- SDL_GL_GetProcAddress("glFramebufferTexture2DEXT");
- data->glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)
- SDL_GL_GetProcAddress("glBindFramebufferEXT");
- data->glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)
- SDL_GL_GetProcAddress("glCheckFramebufferStatusEXT");
- renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE;
- }
- data->framebuffers = NULL;
-
- /* Set up parameters for rendering */
- GL_ResetState(renderer);
-
- return renderer;
-
-error:
- if (changed_window) {
- /* Uh oh, better try to put it back... */
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profile_mask);
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major);
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minor);
- SDL_RecreateWindow(window, window_flags);
- }
- return NULL;
-}
-
-static void
-GL_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
-{
- if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED ||
- event->event == SDL_WINDOWEVENT_SHOWN ||
- event->event == SDL_WINDOWEVENT_HIDDEN) {
- /* Rebind the context to the window area and update matrices */
- SDL_CurrentContext = NULL;
- }
-}
-
static int
GL_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
{
@@ -712,6 +434,7 @@ static int
GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
{
GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
+ const GLenum textype = renderdata->textype;
GL_TextureData *data;
GLint internalFormat;
GLenum format, type;
@@ -775,19 +498,16 @@ GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
texture->driverdata = data;
if (renderdata->GL_ARB_texture_non_power_of_two_supported) {
- data->type = GL_TEXTURE_2D;
texture_w = texture->w;
texture_h = texture->h;
data->texw = 1.0f;
data->texh = 1.0f;
} else if (renderdata->GL_ARB_texture_rectangle_supported) {
- data->type = GL_TEXTURE_RECTANGLE_ARB;
texture_w = texture->w;
texture_h = texture->h;
data->texw = (GLfloat) texture_w;
data->texh = (GLfloat) texture_h;
} else {
- data->type = GL_TEXTURE_2D;
texture_w = power_of_2(texture->w);
texture_h = power_of_2(texture->h);
data->texw = (GLfloat) (texture->w) / texture_w;
@@ -797,17 +517,17 @@ GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
data->format = format;
data->formattype = type;
scaleMode = (texture->scaleMode == SDL_ScaleModeNearest) ? GL_NEAREST : GL_LINEAR;
- renderdata->glEnable(data->type);
- renderdata->glBindTexture(data->type, data->texture);
- renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER, scaleMode);
- renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER, scaleMode);
+ renderdata->glEnable(textype);
+ renderdata->glBindTexture(textype, data->texture);
+ renderdata->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, scaleMode);
+ renderdata->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, scaleMode);
/* According to the spec, CLAMP_TO_EDGE is the default for TEXTURE_RECTANGLE
and setting it causes an INVALID_ENUM error in the latest NVidia drivers.
*/
- if (data->type != GL_TEXTURE_RECTANGLE_ARB) {
- renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
+ if (textype != GL_TEXTURE_RECTANGLE_ARB) {
+ renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_S,
GL_CLAMP_TO_EDGE);
- renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
+ renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_T,
GL_CLAMP_TO_EDGE);
}
#ifdef __MACOSX__
@@ -821,10 +541,10 @@ GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
#define STORAGE_SHARED_APPLE 0x85BF
#endif
if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
- renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
+ renderdata->glTexParameteri(textype, GL_TEXTURE_STORAGE_HINT_APPLE,
GL_STORAGE_SHARED_APPLE);
} else {
- renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
+ renderdata->glTexParameteri(textype, GL_TEXTURE_STORAGE_HINT_APPLE,
GL_STORAGE_CACHED_APPLE);
}
if (texture->access == SDL_TEXTUREACCESS_STREAMING
@@ -834,17 +554,17 @@ GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH,
(data->pitch / SDL_BYTESPERPIXEL(texture->format)));
- renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
+ renderdata->glTexImage2D(textype, 0, internalFormat, texture_w,
texture_h, 0, format, type, data->pixels);
renderdata->glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
}
else
#endif
{
- renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
+ renderdata->glTexImage2D(textype, 0, internalFormat, texture_w,
texture_h, 0, format, type, NULL);
}
- renderdata->glDisable(data->type);
+ renderdata->glDisable(textype);
if (GL_CheckError("glTexImage2D()", renderer) < 0) {
return -1;
}
@@ -855,33 +575,33 @@ GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
renderdata->glGenTextures(1, &data->utexture);
renderdata->glGenTextures(1, &data->vtexture);
- renderdata->glEnable(data->type);
+ renderdata->glEnable(textype);
- renderdata->glBindTexture(data->type, data->utexture);
- renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
+ renderdata->glBindTexture(textype, data->utexture);
+ renderdata->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER,
scaleMode);
- renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
+ renderdata->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER,
scaleMode);
- renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
+ renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_S,
GL_CLAMP_TO_EDGE);
- renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
+ renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_T,
GL_CLAMP_TO_EDGE);
- renderdata->glTexImage2D(data->type, 0, internalFormat, (texture_w+1)/2,
+ renderdata->glTexImage2D(textype, 0, internalFormat, (texture_w+1)/2,
(texture_h+1)/2, 0, format, type, NULL);
- renderdata->glBindTexture(data->type, data->vtexture);
- renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
+ renderdata->glBindTexture(textype, data->vtexture);
+ renderdata->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER,
scaleMode);
- renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
+ renderdata->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER,
scaleMode);
- renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
+ renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_S,
GL_CLAMP_TO_EDGE);
- renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
+ renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_T,
GL_CLAMP_TO_EDGE);
- renderdata->glTexImage2D(data->type, 0, internalFormat, (texture_w+1)/2,
+ renderdata->glTexImage2D(textype, 0, internalFormat, (texture_w+1)/2,
(texture_h+1)/2, 0, format, type, NULL);
- renderdata->glDisable(data->type);
+ renderdata->glDisable(textype);
}
if (texture->format == SDL_PIXELFORMAT_NV12 ||
@@ -889,20 +609,20 @@ GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
data->nv12 = SDL_TRUE;
renderdata->glGenTextures(1, &data->utexture);
- renderdata->glEnable(data->type);
+ renderdata->glEnable(textype);
- renderdata->glBindTexture(data->type, data->utexture);
- renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
+ renderdata->glBindTexture(textype, data->utexture);
+ renderdata->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER,
scaleMode);
- renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
+ renderdata->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER,
scaleMode);
- renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
+ renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_S,
GL_CLAMP_TO_EDGE);
- renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
+ renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_T,
GL_CLAMP_TO_EDGE);
- renderdata->glTexImage2D(data->type, 0, GL_LUMINANCE_ALPHA, (texture_w+1)/2,
+ renderdata->glTexImage2D(textype, 0, GL_LUMINANCE_ALPHA, (texture_w+1)/2,
(texture_h+1)/2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL);
- renderdata->glDisable(data->type);
+ renderdata->glDisable(textype);
}
return GL_CheckError("", renderer);
@@ -913,6 +633,7 @@ GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
const SDL_Rect * rect, const void *pixels, int pitch)
{
GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
+ const GLenum textype = renderdata->textype;
GL_TextureData *data = (GL_TextureData *) texture->driverdata;
const int texturebpp = SDL_BYTESPERPIXEL(texture->format);
@@ -920,11 +641,11 @@ GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
GL_ActivateRenderer(renderer);
- renderdata->glEnable(data->type);
- renderdata->glBindTexture(data->type, data->texture);
+ renderdata->glEnable(textype);
+ renderdata->glBindTexture(textype, data->texture);
renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, (pitch / texturebpp));
- renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w,
+ renderdata->glTexSubImage2D(textype, 0, rect->x, rect->y, rect->w,
rect->h, data->format, data->formattype,
pixels);
if (data->yuv) {
@@ -933,22 +654,22 @@ GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
/* Skip to the correct offset into the next texture */
pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
if (texture->format == SDL_PIXELFORMAT_YV12) {
- renderdata->glBindTexture(data->type, data->vtexture);
+ renderdata->glBindTexture(textype, data->vtexture);
} else {
- renderdata->glBindTexture(data->type, data->utexture);
+ renderdata->glBindTexture(textype, data->utexture);
}
- renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
+ renderdata->glTexSubImage2D(textype, 0, rect->x/2, rect->y/2,
(rect->w+1)/2, (rect->h+1)/2,
data->format, data->formattype, pixels);
/* Skip to the correct offset into the next texture */
pixels = (const void*)((const Uint8*)pixels + ((rect->h + 1) / 2) * ((pitch + 1) / 2));
if (texture->format == SDL_PIXELFORMAT_YV12) {
- renderdata->glBindTexture(data->type, data->utexture);
+ renderdata->glBindTexture(textype, data->utexture);
} else {
- renderdata->glBindTexture(data->type, data->vtexture);
+ renderdata->glBindTexture(textype, data->vtexture);
}
- renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
+ renderdata->glTexSubImage2D(textype, 0, rect->x/2, rect->y/2,
(rect->w+1)/2, (rect->h+1)/2,
data->format, data->formattype, pixels);
}
@@ -958,12 +679,12 @@ GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
/* Skip to the correct offset into the next texture */
pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
- renderdata->glBindTexture(data->type, data->utexture);
- renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
+ renderdata->glBindTexture(textype, data->utexture);
+ renderdata->glTexSubImage2D(textype, 0, rect->x/2, rect->y/2,
(rect->w + 1)/2, (rect->h + 1)/2,
GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, pixels);
}
- renderdata->glDisable(data->type);
+ renderdata->glDisable(textype);
return GL_CheckError("glTexSubImage2D()", renderer);
}
@@ -976,30 +697,31 @@ GL_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
const Uint8 *Vplane, int Vpitch)
{
GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
+ const GLenum textype = renderdata->textype;
GL_TextureData *data = (GL_TextureData *) texture->driverdata;
GL_ActivateRenderer(renderer);
- renderdata->glEnable(data->type);
- renderdata->glBindTexture(data->type, data->texture);
+ renderdata->glEnable(textype);
+ renderdata->glBindTexture(textype, data->texture);
renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, Ypitch);
- renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w,
+ renderdata->glTexSubImage2D(textype, 0, rect->x, rect->y, rect->w,
rect->h, data->format, data->formattype,
Yplane);
renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, Upitch);
- renderdata->glBindTexture(data->type, data->utexture);
- renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
+ renderdata->glBindTexture(textype, data->utexture);
+ renderdata->glTexSubImage2D(textype, 0, rect->x/2, rect->y/2,
(rect->w + 1)/2, (rect->h + 1)/2,
data->format, data->formattype, Uplane);
renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, Vpitch);
- renderdata->glBindTexture(data->type, data->vtexture);
- renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
+ renderdata->glBindTexture(textype, data->vtexture);
+ renderdata->glTexSubImage2D(textype, 0, rect->x/2, rect->y/2,
(rect->w + 1)/2, (rect->h + 1)/2,
data->format, data->formattype, Vplane);
- renderdata->glDisable(data->type);
+ renderdata->glDisable(textype);
return GL_CheckError("glTexSubImage2D()", renderer);
}
@@ -1053,7 +775,7 @@ GL_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
texturedata = (GL_TextureData *) texture->driverdata;
data->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, texturedata->fbo->FBO);
/* TODO: check if texture pixel format allows this operation */
- data->glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, texturedata->type, texturedata->texture, 0);
+ data->glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, data->textype, texturedata->texture, 0);
/* Check FBO status */
status = data->glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
@@ -1062,337 +784,71 @@ GL_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
return 0;
}
+/* !!! FIXME: all these Queue* calls set up the vertex buffer the way the immediate mode
+ !!! FIXME: renderer wants it, but this might want to operate differently if we move to
+ !!! FIXME: VBOs at some point. */
static int
-GL_UpdateViewport(SDL_Renderer * renderer)
+GL_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd)
{
- GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
-
- if (SDL_CurrentContext != data->context) {
- /* We'll update the viewport after we rebind the context */
- return 0;
- }
-
- if (renderer->target) {
- data->glViewport(renderer->viewport.x, renderer->viewport.y,
- renderer->viewport.w, renderer->viewport.h);
- } else {
- int w, h;
-
- SDL_GL_GetDrawableSize(renderer->window, &w, &h);
- data->glViewport(renderer->viewport.x, (h - renderer->viewport.y - renderer->viewport.h),
- renderer->viewport.w, renderer->viewport.h);
- }
-
- data->glMatrixMode(GL_PROJECTION);
- data->glLoadIdentity();
- if (renderer->viewport.w && renderer->viewport.h) {
- if (renderer->target) {
- data->glOrtho((GLdouble) 0,
- (GLdouble) renderer->viewport.w,
- (GLdouble) 0,
- (GLdouble) renderer->viewport.h,
- 0.0, 1.0);
- } else {
- data->glOrtho((GLdouble) 0,
- (GLdouble) renderer->viewport.w,
- (GLdouble) renderer->viewport.h,
- (GLdouble) 0,
- 0.0, 1.0);
- }
- }
- data->glMatrixMode(GL_MODELVIEW);
-
- return GL_CheckError("", renderer);
+ return 0; /* nothing to do in this backend. */
}
static int
-GL_UpdateClipRect(SDL_Renderer * renderer)
+GL_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
{
- GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
-
- if (renderer->clipping_enabled) {
- const SDL_Rect *rect = &renderer->clip_rect;
- data->glEnable(GL_SCISSOR_TEST);
- if (renderer->target) {
- data->glScissor(renderer->viewport.x + rect->x, renderer->viewport.y + rect->y, rect->w, rect->h);
- } else {
- int w, h;
+ GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, count * 2 * sizeof (GLfloat), 0, &cmd->data.draw.first);
+ size_t i;
- SDL_GL_GetDrawableSize(renderer->window, &w, &h);
- data->glScissor(renderer->viewport.x + rect->x, h - renderer->viewport.y - rect->y - rect->h, rect->w, rect->h);
- }
- } else {
- data->glDisable(GL_SCISSOR_TEST);
- }
- return 0;
-}
-
-static void
-GL_SetShader(GL_RenderData * data, GL_Shader shader)
-{
- if (data->shaders && shader != data->current.shader) {
- GL_SelectShader(data->shaders, shader);
- data->current.shader = shader;
- }
-}
-
-static void
-GL_SetColor(GL_RenderData * data, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
-{
- Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b);
-
- if (color != data->current.color) {
- data->glColor4f((GLfloat) r * inv255f,
- (GLfloat) g * inv255f,
- (GLfloat) b * inv255f,
- (GLfloat) a * inv255f);
- data->current.color = color;
- }
-}
-
-static void
-GL_SetBlendMode(GL_RenderData * data, SDL_BlendMode blendMode)
-{
- if (blendMode != data->current.blendMode) {
- if (blendMode == SDL_BLENDMODE_NONE) {
- data->glDisable(GL_BLEND);
- } else {
- data->glEnable(GL_BLEND);
- data->glBlendFuncSeparate(GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blendMode)),
- GetBlendFunc(SDL_GetBlendModeDstColorFactor(blendMode)),
- GetBlendFunc(SDL_GetBlendModeSrcAlphaFactor(blendMode)),
- GetBlendFunc(SDL_GetBlendModeDstAlphaFactor(blendMode)));
- data->glBlendEquation(GetBlendEquation(SDL_GetBlendModeColorOperation(blendMode)));
- }
- data->current.blendMode = blendMode;
- }
-}
-
-static void
-GL_SetDrawingState(SDL_Renderer * renderer)
-{
- GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
-
- GL_ActivateRenderer(renderer);
-
- GL_SetColor(data, renderer->r,
- renderer->g,
- renderer->b,
- renderer->a);
-
- GL_SetBlendMode(data, renderer->blendMode);
-
- GL_SetShader(data, SHADER_SOLID);
-}
-
-static int
-GL_RenderClear(SDL_Renderer * renderer)
-{
- GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
-
- GL_ActivateRenderer(renderer);
-
- data->glClearColor((GLfloat) renderer->r * inv255f,
- (GLfloat) renderer->g * inv255f,
- (GLfloat) renderer->b * inv255f,
- (GLfloat) renderer->a * inv255f);
-
- if (renderer->clipping_enabled) {
- data->glDisable(GL_SCISSOR_TEST);
- }
-
- data->glClear(GL_COLOR_BUFFER_BIT);
-
- if (renderer->clipping_enabled) {
- data->glEnable(GL_SCISSOR_TEST);
+ if (!verts) {
+ return -1;
}
- return 0;
-}
-
-static int
-GL_RenderDrawPoints(SDL_Renderer * renderer, const SDL_FPoint * points,
- int count)
-{
- GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
- int i;
-
- GL_SetDrawingState(renderer);
-
- data->glBegin(GL_POINTS);
- for (i = 0; i < count; ++i) {
- data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
+ cmd->data.draw.count = count;
+ for (i = 0; i < count; i++) {
+ *(verts++) = 0.5f + points[i].x;
+ *(verts++) = 0.5f + points[i].y;
}
- data->glEnd();
return 0;
}
static int
-GL_RenderDrawLines(SDL_Renderer * renderer, const SDL_FPoint * points,
- int count)
+GL_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects, int count)
{
- GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
- int i;
-
- GL_SetDrawingState(renderer);
+ GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, count * 4 * sizeof (GLfloat), 0, &cmd->data.draw.first);
+ size_t i;
- if (count > 2 &&
- points[0].x == points[count-1].x && points[0].y == points[count-1].y) {
- data->glBegin(GL_LINE_LOOP);
- /* GL_LINE_LOOP takes care of the final segment */
- --count;
- for (i = 0; i < count; ++i) {
- data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
- }
- data->glEnd();
- } else {
-#if defined(__MACOSX__) || defined(__WIN32__)
-#else
- int x1, y1, x2, y2;
-#endif
-
- data->glBegin(GL_LINE_STRIP);
- for (i = 0; i < count; ++i) {
- data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
- }
- data->glEnd();
-
- /* The line is half open, so we need one more point to complete it.
- * http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node47.html
- * If we have to, we can use vertical line and horizontal line textures
- * for vertical and horizontal lines, and then create custom textures
- * for diagonal lines and software render those. It's terrible, but at
- * least it would be pixel perfect.
- */
- data->glBegin(GL_POINTS);
-#if defined(__MACOSX__) || defined(__WIN32__)
- /* Mac OS X and Windows seem to always leave the last point open */
- data->glVertex2f(0.5f + points[count-1].x, 0.5f + points[count-1].y);
-#else
- /* Linux seems to leave the right-most or bottom-most point open */
- x1 = points[0].x;
- y1 = points[0].y;
- x2 = points[count-1].x;
- y2 = points[count-1].y;
-
- if (x1 > x2) {
- data->glVertex2f(0.5f + x1, 0.5f + y1);
- } else if (x2 > x1) {
- data->glVertex2f(0.5f + x2, 0.5f + y2);
- }
- if (y1 > y2) {
- data->glVertex2f(0.5f + x1, 0.5f + y1);
- } else if (y2 > y1) {
- data->glVertex2f(0.5f + x2, 0.5f + y2);
- }
-#endif
- data->glEnd();
+ if (!verts) {
+ return -1;
}
- return GL_CheckError("", renderer);
-}
-static int
-GL_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects, int count)
-{
- GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
- int i;
-
- GL_SetDrawingState(renderer);
-
- for (i = 0; i < count; ++i) {
+ cmd->data.draw.count = count;
+ for (i = 0; i < count; i++) {
const SDL_FRect *rect = &rects[i];
-
- data->glRectf(rect->x, rect->y, rect->x + rect->w, rect->y + rect->h);
+ *(verts++) = rect->x;
+ *(verts++) = rect->y;
+ *(verts++) = rect->x + rect->w;
+ *(verts++) = rect->y + rect->h;
}
- return GL_CheckError("", renderer);
-}
-
-static int
-GL_SetupCopy(SDL_Renderer * renderer, SDL_Texture * texture)
-{
- GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
- GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
-
- data->glEnable(texturedata->type);
- if (texturedata->yuv) {
- data->glActiveTextureARB(GL_TEXTURE2_ARB);
- data->glBindTexture(texturedata->type, texturedata->vtexture);
-
- data->glActiveTextureARB(GL_TEXTURE1_ARB);
- data->glBindTexture(texturedata->type, texturedata->utexture);
- data->glActiveTextureARB(GL_TEXTURE0_ARB);
- }
- if (texturedata->nv12) {
- data->glActiveTextureARB(GL_TEXTURE1_ARB);
- data->glBindTexture(texturedata->type, texturedata->utexture);
-
- data->glActiveTextureARB(GL_TEXTURE0_ARB);
- }
- data->glBindTexture(texturedata->type, texturedata->texture);
-
- if (texture->modMode) {
- GL_SetColor(data, texture->r, texture->g, texture->b, texture->a);
- } else {
- GL_SetColor(data, 255, 255, 255, 255);
- }
-
- GL_SetBlendMode(data, texture->blendMode);
-
- if (texturedata->yuv || texturedata->nv12) {
- switch (SDL_GetYUVConversionModeForResolution(texture->w, texture->h)) {
- case SDL_YUV_CONVERSION_JPEG:
- if (texturedata->yuv) {
- GL_SetShader(data, SHADER_YUV_JPEG);
- } else if (texture->format == SDL_PIXELFORMAT_NV12) {
- GL_SetShader(data, SHADER_NV12_JPEG);
- } else {
- GL_SetShader(data, SHADER_NV21_JPEG);
- }
- break;
- case SDL_YUV_CONVERSION_BT601:
- if (texturedata->yuv) {
- GL_SetShader(data, SHADER_YUV_BT601);
- } else if (texture->format == SDL_PIXELFORMAT_NV12) {
- GL_SetShader(data, SHADER_NV12_BT601);
- } else {
- GL_SetShader(data, SHADER_NV21_BT601);
- }
- break;
- case SDL_YUV_CONVERSION_BT709:
- if (texturedata->yuv) {
- GL_SetShader(data, SHADER_YUV_BT709);
- } else if (texture->format == SDL_PIXELFORMAT_NV12) {
- GL_SetShader(data, SHADER_NV12_BT709);
- } else {
- GL_SetShader(data, SHADER_NV21_BT709);
- }
- break;
- default:
- return SDL_SetError("Unsupported YUV conversion mode");
- }
- } else {
- GL_SetShader(data, SHADER_RGB);
- }
return 0;
}
static int
-GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * srcrect, const SDL_FRect * dstrect)
+GL_QueueCopy(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
+ const SDL_Rect * srcrect, const SDL_FRect * dstrect)
{
- GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
GLfloat minx, miny, maxx, maxy;
GLfloat minu, maxu, minv, maxv;
+ GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, 8 * sizeof (GLfloat), 0, &cmd->data.draw.first);
- GL_ActivateRenderer(renderer);
-
- if (GL_SetupCopy(renderer, texture) < 0) {
+ if (!verts) {
return -1;
}
+ cmd->data.draw.count = 1;
+
minx = dstrect->x;
miny = dstrect->y;
maxx = dstrect->x + dstrect->w;
@@ -1407,36 +863,30 @@ GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
maxv *= texturedata->texh;
- data->glBegin(GL_TRIANGLE_STRIP);
- data->glTexCoord2f(minu, minv);
- data->glVertex2f(minx, miny);
- data->glTexCoord2f(maxu, minv);
- data->glVertex2f(maxx, miny);
- data->glTexCoord2f(minu, maxv);
- data->glVertex2f(minx, maxy);
- data->glTexCoord2f(maxu, maxv);
- data->glVertex2f(maxx, maxy);
- data->glEnd();
-
- data->glDisable(texturedata->type);
-
- return GL_CheckError("", renderer);
+ cmd->data.draw.count = 1;
+ *(verts++) = minx;
+ *(verts++) = miny;
+ *(verts++) = maxx;
+ *(verts++) = maxy;
+ *(verts++) = minu;
+ *(verts++) = maxu;
+ *(verts++) = minv;
+ *(verts++) = maxv;
+ return 0;
}
static int
-GL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * srcrect, const SDL_FRect * dstrect,
- const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
+GL_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
+ const SDL_Rect * srcrect, const SDL_FRect * dstrect,
+ const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
{
- GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
GLfloat minx, miny, maxx, maxy;
GLfloat centerx, centery;
GLfloat minu, maxu, minv, maxv;
+ GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, 11 * sizeof (GLfloat), 0, &cmd->data.draw.first);
- GL_ActivateRenderer(renderer);
-
- if (GL_SetupCopy(renderer, texture) < 0) {
+ if (!verts) {
return -1;
}
@@ -1470,24 +920,383 @@ GL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
maxv *= texturedata->texh;
- /* Translate to flip, rotate, translate to position */
- data->glPushMatrix();
- data->glTranslatef((GLfloat)dstrect->x + centerx, (GLfloat)dstrect->y + centery, (GLfloat)0.0);
- data->glRotated(angle, (GLdouble)0.0, (GLdouble)0.0, (GLdouble)1.0);
-
- data->glBegin(GL_TRIANGLE_STRIP);
- data->glTexCoord2f(minu, minv);
- data->glVertex2f(minx, miny);
- data->glTexCoord2f(maxu, minv);
- data->glVertex2f(maxx, miny);
- data->glTexCoord2f(minu, maxv);
- data->glVertex2f(minx, maxy);
- data->glTexCoord2f(maxu, maxv);
- data->glVertex2f(maxx, maxy);
- data->glEnd();
- data->glPopMatrix();
-
- data->glDisable(texturedata->type);
+ cmd->data.draw.count = 1;
+ *(verts++) = minx;
+ *(verts++) = miny;
+ *(verts++) = maxx;
+ *(verts++) = maxy;
+ *(verts++) = minu;
+ *(verts++) = maxu;
+ *(verts++) = minv;
+ *(verts++) = maxv;
+ *(verts++) = (GLfloat) dstrect->x + centerx;
+ *(verts++) = (GLfloat) dstrect->y + centery;
+ *(verts++) = (GLfloat) angle;
+ return 0;
+}
+
+static void
+SetDrawState(GL_RenderData *data, const SDL_RenderCommand *cmd, const GL_Shader shader)
+{
+ const SDL_BlendMode blend = cmd->data.draw.blend;
+
+ if (data->drawstate.viewport_dirty) {
+ const SDL_bool istarget = data->drawstate.target != NULL;
+ const SDL_Rect *viewport = &data->drawstate.viewport;
+ data->glMatrixMode(GL_PROJECTION);
+ data->glLoadIdentity();
+ data->glViewport(viewport->x,
+ istarget ? viewport->y : (data->drawstate.drawableh - viewport->y - viewport->h),
+ viewport->w, viewport->h);
+ if (viewport->w && viewport->h) {
+ data->glOrtho((GLdouble) 0, (GLdouble) viewport->w,
+ (GLdouble) istarget ? 0 : viewport->h,
+ (GLdouble) istarget ? viewport->h : 0,
+ 0.0, 1.0);
+ }
+ data->glMatrixMode(GL_MODELVIEW);
+ data->drawstate.viewport_dirty = SDL_FALSE;
+ }
+
+ if (data->drawstate.cliprect_enabled_dirty) {
+ if (!data->drawstate.cliprect_enabled) {
+ data->glDisable(GL_SCISSOR_TEST);
+ } else {
+ data->glEnable(GL_SCISSOR_TEST);
+ }
+ data->drawstate.cliprect_enabled_dirty = SDL_FALSE;
+ }
+
+ if (data->drawstate.cliprect_enabled && data->drawstate.cliprect_dirty) {
+ const SDL_Rect *viewport = &data->drawstate.viewport;
+ const SDL_Rect *rect = &data->drawstate.cliprect;
+ data->glScissor(viewport->x + rect->x,
+ data->drawstate.target ? viewport->y + rect->y : data->drawstate.drawableh - viewport->y - rect->y - rect->h,
+ rect->w, rect->h);
+ data->drawstate.cliprect_dirty = SDL_FALSE;
+ }
+
+ if (blend != data->drawstate.blend) {
+ if (blend == SDL_BLENDMODE_NONE) {
+ data->glDisable(GL_BLEND);
+ } else {
+ data->glEnable(GL_BLEND);
+ data->glBlendFuncSeparate(GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blend)),
+ GetBlendFunc(SDL_GetBlendModeDstColorFactor(blend)),
+ GetBlendFunc(SDL_GetBlendModeSrcAlphaFactor(blend)),
+ GetBlendFunc(SDL_GetBlendModeDstAlphaFactor(blend)));
+ data->glBlendEquation(GetBlendEquation(SDL_GetBlendModeColorOperation(blend)));
+ }
+ data->drawstate.blend = blend;
+ }
+
+ if (data->shaders && (shader != data->drawstate.shader)) {
+ GL_SelectShader(data->shaders, shader);
+ data->drawstate.shader = shader;
+ }
+
+ if ((cmd->data.draw.texture != NULL) != data->drawstate.texturing) {
+ if (cmd->data.draw.texture == NULL) {
+ data->glDisable(data->textype);
+ data->drawstate.texturing = SDL_FALSE;
+ } else {
+ data->glEnable(data->textype);
+ data->drawstate.texturing = SDL_TRUE;
+ }
+ }
+}
+
+static void
+SetCopyState(GL_RenderData *data, const SDL_RenderCommand *cmd)
+{
+ SDL_Texture *texture = cmd->data.draw.texture;
+ const GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
+ GL_Shader shader = SHADER_RGB;
+
+ if (data->shaders) {
+ if (texturedata->yuv || texturedata->nv12) {
+ switch (SDL_GetYUVConversionModeForResolution(texture->w, texture->h)) {
+ case SDL_YUV_CONVERSION_JPEG:
+ if (texturedata->yuv) {
+ shader = SHADER_YUV_JPEG;
+ } else if (texture->format == SDL_PIXELFORMAT_NV12) {
+ shader = SHADER_NV12_JPEG;
+ } else {
+ shader = SHADER_NV21_JPEG;
+ }
+ break;
+ case SDL_YUV_CONVERSION_BT601:
+ if (texturedata->yuv) {
+ shader = SHADER_YUV_BT601;
+ } else if (texture->format == SDL_PIXELFORMAT_NV12) {
+ shader = SHADER_NV12_BT601;
+ } else {
+ shader = SHADER_NV21_BT601;
+ }
+ break;
+ case SDL_YUV_CONVERSION_BT709:
+ if (texturedata->yuv) {
+ shader = SHADER_YUV_BT709;
+ } else if (texture->format == SDL_PIXELFORMAT_NV12) {
+ shader = SHADER_NV12_BT709;
+ } else {
+ shader = SHADER_NV21_BT709;
+ }
+ break;
+ default:
+ SDL_assert(!"unsupported YUV conversion mode");
+ break;
+ }
+ }
+ }
+
+ SetDrawState(data, cmd, shader);
+
+ if (texture != data->drawstate.texture) {
+ const GLenum textype = data->textype;
+ if (texturedata->yuv) {
+ data->glActiveTextureARB(GL_TEXTURE2_ARB);
+ data->glBindTexture(textype, texturedata->vtexture);
+
+ data->glActiveTextureARB(GL_TEXTURE1_ARB);
+ data->glBindTexture(textype, texturedata->utexture);
+ }
+ if (texturedata->nv12) {
+ data->glActiveTextureARB(GL_TEXTURE1_ARB);
+ data->glBindTexture(textype, texturedata->utexture);
+ }
+ data->glActiveTextureARB(GL_TEXTURE0_ARB);
+ data->glBindTexture(textype, texturedata->texture);
+
+ data->drawstate.texture = texture;
+ }
+}
+
+static int
+GL_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
+{
+ /* !!! FIXME: it'd be nice to use a vertex buffer instead of immediate mode... */
+ GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
+ size_t i;
+
+ if (GL_ActivateRenderer(renderer) < 0) {
+ return -1;
+ }
+
+ data->drawstate.target = renderer->target;
+ if (!data->drawstate.target) {
+ SDL_GL_GetDrawableSize(renderer->window, &data->drawstate.drawablew, &data->drawstate.drawableh);
+ }
+
+
+ while (cmd) {
+ switch (cmd->command) {
+ case SDL_RENDERCMD_SETDRAWCOLOR: {
+ const Uint8 r = cmd->data.color.r;
+ const Uint8 g = cmd->data.color.g;
+ const Uint8 b = cmd->data.color.b;
+ const Uint8 a = cmd->data.color.a;
+ const Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b);
+ if (color != data->drawstate.color) {
+ data->glColor4f((GLfloat) r * inv255f,
+ (GLfloat) g * inv255f,
+ (GLfloat) b * inv255f,
+ (GLfloat) a * inv255f);
+ data->drawstate.color = color;
+ }
+ break;
+ }
+
+ case SDL_RENDERCMD_SETVIEWPORT: {
+ SDL_Rect *viewport = &data->drawstate.viewport;
+ if (SDL_memcmp(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect)) != 0) {
+ SDL_memcpy(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect));
+ data->drawstate.viewport_dirty = SDL_TRUE;
+ }
+ break;
+ }
+
+ case SDL_RENDERCMD_SETCLIPRECT: {
+ const SDL_Rect *rect = &cmd->data.cliprect.rect;
+ if (data->drawstate.cliprect_enabled != cmd->data.cliprect.enabled) {
+ data->drawstate.cliprect_enabled = cmd->data.cliprect.enabled;
+ data->drawstate.cliprect_enabled_dirty = SDL_TRUE;
+ }
+ if (SDL_memcmp(&data->drawstate.cliprect, rect, sizeof (SDL_Rect)) != 0) {
+ SDL_memcpy(&data->drawstate.cliprect, rect, sizeof (SDL_Rect));
+ data->drawstate.cliprect_dirty = SDL_TRUE;
+ }
+ break;
+ }
+
+ case SDL_RENDERCMD_CLEAR: {
+ const Uint8 r = cmd->data.color.r;
+ const Uint8 g = cmd->data.color.g;
+ const Uint8 b = cmd->data.color.b;
+ const Uint8 a = cmd->data.color.a;
+ const Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b);
+ if (color != data->drawstate.clear_color) {
+ const GLfloat fr = ((GLfloat) r) * inv255f;
+ const GLfloat fg = ((GLfloat) g) * inv255f;
+ const GLfloat fb = ((GLfloat) b) * inv255f;
+ const GLfloat fa = ((GLfloat) a) * inv255f;
+ data->glClearColor(fr, fg, fb, fa);
+ data->drawstate.clear_color = color;
+ }
+
+ if (data->drawstate.cliprect_enabled) {
+ data->glDisable(GL_SCISSOR_TEST);
+ data->drawstate.cliprect_enabled_dirty = SDL_TRUE;
+ }
+
+ data->glClear(GL_COLOR_BUFFER_BIT);
+
+ break;
+ }
+
+ case SDL_RENDERCMD_DRAW_POINTS: {
+ const size_t count = cmd->data.draw.count;
+ const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
+ SetDrawState(data, cmd, SHADER_SOLID);
+ data->glBegin(GL_POINTS);
+ for (i = 0; i < count; i++, verts += 2) {
+ data->glVertex2f(verts[0], verts[1]);
+ }
+ data->glEnd();
+ break;
+ }
+
+ case SDL_RENDERCMD_DRAW_LINES: {
+ const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
+ const size_t count = cmd->data.draw.count;
+ SetDrawState(data, cmd, SHADER_SOLID);
+ if (count > 2 && (verts[0] == verts[(count-1)*2]) && (verts[1] == verts[(count*2)-1])) {
+ data->glBegin(GL_LINE_LOOP);
+ /* GL_LINE_LOOP takes care of the final segment */
+ for (i = 1; i < count; ++i, verts += 2) {
+ data->glVertex2f(verts[0], verts[1]);
+ }
+ data->glEnd();
+ } else {
+ #if defined(__MACOSX__) || defined(__WIN32__)
+ #else
+ int x1, y1, x2, y2;
+ #endif
+
+ data->glBegin(GL_LINE_STRIP);
+ for (i = 0; i < count; ++i, verts += 2) {
+ data->glVertex2f(verts[0], verts[1]);
+ }
+ data->glEnd();
+
+ /* The line is half open, so we need one more point to complete it.
+ * http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node47.html
+ * If we have to, we can use vertical line and horizontal line textures
+ * for vertical and horizontal lines, and then create custom textures
+ * for diagonal lines and software render those. It's terrible, but at
+ * least it would be pixel perfect.
+ */
+
+ data->glBegin(GL_POINTS);
+ #if defined(__MACOSX__) || defined(__WIN32__)
+ /* Mac OS X and Windows seem to always leave the last point open */
+ data->glVertex2f(verts[(count-1)*2], verts[(count*2)-1]);
+ #else
+ /* Linux seems to leave the right-most or bottom-most point open */
+ x1 = verts[0];
+ y1 = verts[1];
+ x2 = verts[(count-1)*2];
+ y2 = verts[(count*2)-1];
+
+ if (x1 > x2) {
+ data->glVertex2f(x1, y1);
+ } else if (x2 > x1) {
+ data->glVertex2f(x2, y2);
+ }
+ if (y1 > y2) {
+ data->glVertex2f(x1, y1);
+ } else if (y2 > y1) {
+ data->glVertex2f(x2, y2);
+ }
+ #endif
+ data->glEnd();
+ }
+ break;
+ }
+
+ case SDL_RENDERCMD_FILL_RECTS: {
+ const size_t count = cmd->data.draw.count;
+ const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
+ SetDrawState(data, cmd, SHADER_SOLID);
+ for (i = 0; i < count; ++i, verts += 4) {
+ data->glRectf(verts[0], verts[1], verts[2], verts[3]);
+ }
+ break;
+ }
+
+ case SDL_RENDERCMD_COPY: {
+ const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
+ const GLfloat minx = verts[0];
+ const GLfloat miny = verts[1];
+ const GLfloat maxx = verts[2];
+ const GLfloat maxy = verts[3];
+ const GLfloat minu = verts[4];
+ const GLfloat maxu = verts[5];
+ const GLfloat minv = verts[6];
+ const GLfloat maxv = verts[7];
+ SetCopyState(data, cmd);
+ data->glBegin(GL_TRIANGLE_STRIP);
+ data->glTexCoord2f(minu, minv);
+ data->glVertex2f(minx, miny);
+ data->glTexCoord2f(maxu, minv);
+ data->glVertex2f(maxx, miny);
+ data->glTexCoord2f(minu, maxv);
+ data->glVertex2f(minx, maxy);
+ data->glTexCoord2f(maxu, maxv);
+ data->glVertex2f(maxx, maxy);
+ data->glEnd();
+ break;
+ }
+
+ case SDL_RENDERCMD_COPY_EX: {
+ const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
+ const GLfloat minx = verts[0];
+ const GLfloat miny = verts[1];
+ const GLfloat maxx = verts[2];
+ const GLfloat maxy = verts[3];
+ const GLfloat minu = verts[4];
+ const GLfloat maxu = verts[5];
+ const GLfloat minv = verts[6];
+ const GLfloat maxv = verts[7];
+ const GLfloat translatex = verts[8];
+ const GLfloat translatey = verts[9];
+ const GLdouble angle = verts[10];
+ SetCopyState(data, cmd);
+
+ /* Translate to flip, rotate, translate to position */
+ data->glPushMatrix();
+ data->glTranslatef(translatex, translatey, 0.0f);
+ data->glRotated(angle, 0.0, 0.0, 1.0);
+ data->glBegin(GL_TRIANGLE_STRIP);
+ data->glTexCoord2f(minu, minv);
+ data->glVertex2f(minx, miny);
+ data->glTexCoord2f(maxu, minv);
+ data->glVertex2f(maxx, miny);
+ data->glTexCoord2f(minu, maxv);
+ data->glVertex2f(minx, maxy);
+ data->glTexCoord2f(maxu, maxv);
+ data->glVertex2f(maxx, maxy);
+ data->glEnd();
+ data->glPopMatrix();
+ break;
+ }
+
+ case SDL_RENDERCMD_NO_OP:
+ break;
+ }
+
+ cmd = cmd->next;
+ }
return GL_CheckError("", renderer);
}
@@ -1539,10 +1348,11 @@ GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
/* Flip the rows to be top-down if necessary */
if (!renderer->target) {
+ SDL_bool isstack;
length = rect->w * SDL_BYTESPERPIXEL(temp_format);
src = (Uint8*)temp_pixels + (rect->h-1)*temp_pitch;
dst = (Uint8*)temp_pixels;
- tmp = SDL_stack_alloc(Uint8, length);
+ tmp = SDL_small_alloc(Uint8, length, &isstack);
rows = rect->h / 2;
while (rows--) {
SDL_memcpy(tmp, dst, length);
@@ -1551,7 +1361,7 @@ GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
dst += temp_pitch;
src -= temp_pitch;
}
- SDL_stack_free(tmp);
+ SDL_small_free(tmp, isstack);
}
status = SDL_ConvertPixels(rect->w, rect->h,
@@ -1636,19 +1446,21 @@ GL_BindTexture (SDL_Renderer * renderer, SDL_Texture *texture, float *texw, floa
{
GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
+ const GLenum textype = data->textype;
+
GL_ActivateRenderer(renderer);
- data->glEnable(texturedata->type);
+ data->glEnable(textype);
if (texturedata->yuv) {
data->glActiveTextureARB(GL_TEXTURE2_ARB);
- data->glBindTexture(texturedata->type, texturedata->vtexture);
+ data->glBindTexture(textype, texturedata->vtexture);
data->glActiveTextureARB(GL_TEXTURE1_ARB);
- data->glBindTexture(texturedata->type, texturedata->utexture);
+ data->glBindTexture(textype, texturedata->utexture);
data->glActiveTextureARB(GL_TEXTURE0_ARB);
}
- data->glBindTexture(texturedata->type, texturedata->texture);
+ data->glBindTexture(textype, texturedata->texture);
if(texw) *texw = (float)texturedata->texw;
if(texh) *texh = (float)texturedata->texh;
@@ -1661,23 +1473,252 @@ GL_UnbindTexture (SDL_Renderer * renderer, SDL_Texture *texture)
{
GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
+ const GLenum textype = data->textype;
+
GL_ActivateRenderer(renderer);
if (texturedata->yuv) {
data->glActiveTextureARB(GL_TEXTURE2_ARB);
- data->glDisable(texturedata->type);
+ data->glDisable(textype);
data->glActiveTextureARB(GL_TEXTURE1_ARB);
- data->glDisable(texturedata->type);
+ data->glDisable(textype);
data->glActiveTextureARB(GL_TEXTURE0_ARB);
}
- data->glDisable(texturedata->type);
+ data->glDisable(textype);
return 0;
}
+
+SDL_Renderer *
+GL_CreateRenderer(SDL_Window * window, Uint32 flags)
+{
+ SDL_Renderer *renderer;
+ GL_RenderData *data;
+ GLint value;
+ Uint32 window_flags;
+ int profile_mask = 0, major = 0, minor = 0;
+ SDL_bool changed_window = SDL_FALSE;
+
+ SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profile_mask);
+ SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major);
+ SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor);
+
+ window_flags = SDL_GetWindowFlags(window);
+ if (!(window_flags & SDL_WINDOW_OPENGL) ||
+ profile_mask == SDL_GL_CONTEXT_PROFILE_ES || major != RENDERER_CONTEXT_MAJOR || minor != RENDERER_CONTEXT_MINOR) {
+
+ changed_window = SDL_TRUE;
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, RENDERER_CONTEXT_MAJOR);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, RENDERER_CONTEXT_MINOR);
+
+ if (SDL_RecreateWindow(window, window_flags | SDL_WINDOW_OPENGL) < 0) {
+ goto error;
+ }
+ }
+
+ renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
+ if (!renderer) {
+ SDL_OutOfMemory();
+ goto error;
+ }
+
+ data = (GL_RenderData *) SDL_calloc(1, sizeof(*data));
+ if (!data) {
+ SDL_free(renderer);
+ SDL_OutOfMemory();
+ goto error;
+ }
+
+ renderer->GetOutputSize = GL_GetOutputSize;
+ renderer->SupportsBlendMode = GL_SupportsBlendMode;
+ renderer->CreateTexture = GL_CreateTexture;
+ renderer->UpdateTexture = GL_UpdateTexture;
+ renderer->UpdateTextureYUV = GL_UpdateTextureYUV;
+ renderer->LockTexture = GL_LockTexture;
+ renderer->UnlockTexture = GL_UnlockTexture;
+ renderer->SetRenderTarget = GL_SetRenderTarget;
+ renderer->QueueSetViewport = GL_QueueSetViewport;
+ renderer->QueueSetDrawColor = GL_QueueSetViewport; /* SetViewport and SetDrawColor are (currently) no-ops. */
+ renderer->QueueDrawPoints = GL_QueueDrawPoints;
+ renderer->QueueDrawLines = GL_QueueDrawPoints; /* lines and points queue vertices the same way. */
+ renderer->QueueFillRects = GL_QueueFillRects;
+ renderer->QueueCopy = GL_QueueCopy;
+ renderer->QueueCopyEx = GL_QueueCopyEx;
+ renderer->RunCommandQueue = GL_RunCommandQueue;
+ renderer->RenderReadPixels = GL_RenderReadPixels;
+ renderer->RenderPresent = GL_RenderPresent;
+ renderer->DestroyTexture = GL_DestroyTexture;
+ renderer->DestroyRenderer = GL_DestroyRenderer;
+ renderer->GL_BindTexture = GL_BindTexture;
+ renderer->GL_UnbindTexture = GL_UnbindTexture;
+ renderer->info = GL_RenderDriver.info;
+ renderer->info.flags = SDL_RENDERER_ACCELERATED;
+ renderer->driverdata = data;
+ renderer->window = window;
+
+ data->context = SDL_GL_CreateContext(window);
+ if (!data->context) {
+ SDL_free(renderer);
+ SDL_free(data);
+ goto error;
+ }
+ if (SDL_GL_MakeCurrent(window, data->context) < 0) {
+ SDL_GL_DeleteContext(data->context);
+ SDL_free(renderer);
+ SDL_free(data);
+ goto error;
+ }
+
+ if (GL_LoadFunctions(data) < 0) {
+ SDL_GL_DeleteContext(data->context);
+ SDL_free(renderer);
+ SDL_free(data);
+ goto error;
+ }
+
+#ifdef __MACOSX__
+ /* Enable multi-threaded rendering */
+ /* Disabled until Ryan finishes his VBO/PBO code...
+ CGLEnable(CGLGetCurrentContext(), kCGLCEMPEngine);
+ */
+#endif
+
+ if (flags & SDL_RENDERER_PRESENTVSYNC) {
+ SDL_GL_SetSwapInterval(1);
+ } else {
+ SDL_GL_SetSwapInterval(0);
+ }
+ if (SDL_GL_GetSwapInterval() > 0) {
+ renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
+ }
+
+ /* Check for debug output support */
+ if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_FLAGS, &value) == 0 &&
+ (value & SDL_GL_CONTEXT_DEBUG_FLAG)) {
+ data->debug_enabled = SDL_TRUE;
+ }
+ if (data->debug_enabled && SDL_GL_ExtensionSupported("GL_ARB_debug_output")) {
+ PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARBFunc = (PFNGLDEBUGMESSAGECALLBACKARBPROC) SDL_GL_GetProcAddress("glDebugMessageCallbackARB");
+
+ data->GL_ARB_debug_output_supported = SDL_TRUE;
+ data->glGetPointerv(GL_DEBUG_CALLBACK_FUNCTION_ARB, (GLvoid **)(char *)&data->next_error_callback);
+ data->glGetPointerv(GL_DEBUG_CALLBACK_USER_PARAM_ARB, &data->next_error_userparam);
+ glDebugMessageCallbackARBFunc(GL_HandleDebugMessage, renderer);
+
+ /* Make sure our callback is called when errors actually happen */
+ data->glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
+ }
+
+ data->textype = GL_TEXTURE_2D;
+ if (SDL_GL_ExtensionSupported("GL_ARB_texture_non_power_of_two")) {
+ data->GL_ARB_texture_non_power_of_two_supported = SDL_TRUE;
+ } else if (SDL_GL_ExtensionSupported("GL_ARB_texture_rectangle") ||
+ SDL_GL_ExtensionSupported("GL_EXT_texture_rectangle")) {
+ data->GL_ARB_texture_rectangle_supported = SDL_TRUE;
+ data->textype = GL_TEXTURE_RECTANGLE_ARB;
+ }
+ if (data->GL_ARB_texture_rectangle_supported) {
+ data->glGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB, &value);
+ renderer->info.max_texture_width = value;
+ renderer->info.max_texture_height = value;
+ } else {
+ data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
+ renderer->info.max_texture_width = value;
+ renderer->info.max_texture_height = value;
+ }
+
+ /* Check for multitexture support */
+ if (SDL_GL_ExtensionSupported("GL_ARB_multitexture")) {
+ data->glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC) SDL_GL_GetProcAddress("glActiveTextureARB");
+ if (data->glActiveTextureARB) {
+ data->GL_ARB_multitexture_supported = SDL_TRUE;
+ data->glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &data->num_texture_units);
+ }
+ }
+
+ /* Check for shader support */
+ if (SDL_GetHintBoolean(SDL_HINT_RENDER_OPENGL_SHADERS, SDL_TRUE)) {
+ data->shaders = GL_CreateShaderContext();
+ }
+ SDL_LogInfo(SDL_LOG_CATEGORY_RENDER, "OpenGL shaders: %s",
+ data->shaders ? "ENABLED" : "DISABLED");
+
+ /* We support YV12 textures using 3 textures and a shader */
+ if (data->shaders && data->num_texture_units >= 3) {
+ renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;
+ renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
+ renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_NV12;
+ renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_NV21;
+ }
+
+#ifdef __MACOSX__
+ renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_UYVY;
+#endif
+
+ if (SDL_GL_ExtensionSupported("GL_EXT_framebuffer_object")) {
+ data->GL_EXT_framebuffer_object_supported = SDL_TRUE;
+ data->glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC)
+ SDL_GL_GetProcAddress("glGenFramebuffersEXT");
+ data->glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC)
+ SDL_GL_GetProcAddress("glDeleteFramebuffersEXT");
+ data->glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)
+ SDL_GL_GetProcAddress("glFramebufferTexture2DEXT");
+ data->glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)
+ SDL_GL_GetProcAddress("glBindFramebufferEXT");
+ data->glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)
+ SDL_GL_GetProcAddress("glCheckFramebufferStatusEXT");
+ renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE;
+ }
+ data->framebuffers = NULL;
+
+ /* Set up parameters for rendering */
+ data->glMatrixMode(GL_MODELVIEW);
+ data->glLoadIdentity();
+ data->glDisable(GL_DEPTH_TEST);
+ data->glDisable(GL_CULL_FACE);
+ data->glDisable(GL_SCISSOR_TEST);
+ data->glDisable(data->textype);
+ data->glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+ data->glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+ /* This ended up causing video discrepancies between OpenGL and Direct3D */
+ /* data->glEnable(GL_LINE_SMOOTH); */
+
+ data->drawstate.blend = SDL_BLENDMODE_INVALID;
+ data->drawstate.shader = SHADER_INVALID;
+ data->drawstate.color = 0xFFFFFFFF;
+ data->drawstate.clear_color = 0xFFFFFFFF;
+
+ return renderer;
+
+error:
+ if (changed_window) {
+ /* Uh oh, better try to put it back... */
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profile_mask);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minor);
+ SDL_RecreateWindow(window, window_flags);
+ }
+ return NULL;
+}
+
+
+SDL_RenderDriver GL_RenderDriver = {
+ GL_CreateRenderer,
+ {
+ "opengl",
+ (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
+ 1,
+ {SDL_PIXELFORMAT_ARGB8888},
+ 0,
+ 0}
+};
+
+
#endif /* SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED */
/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/render/opengl/SDL_shaders_gl.c b/src/render/opengl/SDL_shaders_gl.c
index 251b54d130..650b244639 100644
--- a/src/render/opengl/SDL_shaders_gl.c
+++ b/src/render/opengl/SDL_shaders_gl.c
@@ -340,11 +340,12 @@ CompileShader(GL_ShaderContext *ctx, GLhandleARB shader, const char *defines, co
ctx->glCompileShaderARB(shader);
ctx->glGetObjectParameterivARB(shader, GL_OBJECT_COMPILE_STATUS_ARB, &status);
if (status == 0) {
+ SDL_bool isstack;
GLint length;
char *info;
ctx->glGetObjectParameterivARB(shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length);
- info = SDL_stack_alloc(char, length+1);
+ info = SDL_small_alloc(char, length+1, &isstack);
ctx->glGetInfoLogARB(shader, length, NULL, info);
SDL_LogError(SDL_LOG_CATEGORY_RENDER,
"Failed to compile shader:\n%s%s\n%s", defines, source, info);
@@ -352,7 +353,7 @@ CompileShader(GL_ShaderContext *ctx, GLhandleARB shader, const char *defines, co
fprintf(stderr,
"Failed to compile shader:\n%s%s\n%s", defines, source, info);
#endif
- SDL_stack_free(info);
+ SDL_small_free(info, isstack);
return SDL_FALSE;
} else {
diff --git a/src/render/opengl/SDL_shaders_gl.h b/src/render/opengl/SDL_shaders_gl.h
index 36975214d9..6f3c8672e6 100644
--- a/src/render/opengl/SDL_shaders_gl.h
+++ b/src/render/opengl/SDL_shaders_gl.h
@@ -27,6 +27,7 @@
/* OpenGL shader implementation */
typedef enum {
+ SHADER_INVALID = -1,
SHADER_NONE,
SHADER_SOLID,
SHADER_RGB,
diff --git a/src/render/opengles/SDL_render_gles.c b/src/render/opengles/SDL_render_gles.c
index 4007dff585..a410152e7b 100644
--- a/src/render/opengles/SDL_render_gles.c
+++ b/src/render/opengles/SDL_render_gles.c
@@ -52,45 +52,6 @@ extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags);
static const float inv255f = 1.0f / 255.0f;
-static SDL_Renderer *GLES_CreateRenderer(SDL_Window * window, Uint32 flags);
-static void GLES_WindowEvent(SDL_Renderer * renderer,
- const SDL_WindowEvent *event);
-static int GLES_GetOutputSize(SDL_Renderer * renderer, int *w, int *h);
-static SDL_bool GLES_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode);
-static int GLES_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
-static int GLES_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * rect, const void *pixels,
- int pitch);
-static int GLES_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * rect, void **pixels, int *pitch);
-static void GLES_UnlockTexture(SDL_Renderer * renderer,
- SDL_Texture * texture);
-static int GLES_SetRenderTarget(SDL_Renderer * renderer,
- SDL_Texture * texture);
-static int GLES_UpdateViewport(SDL_Renderer * renderer);
-static int GLES_UpdateClipRect(SDL_Renderer * renderer);
-static int GLES_RenderClear(SDL_Renderer * renderer);
-static int GLES_RenderDrawPoints(SDL_Renderer * renderer,
- const SDL_FPoint * points, int count);
-static int GLES_RenderDrawLines(SDL_Renderer * renderer,
- const SDL_FPoint * points, int count);
-static int GLES_RenderFillRects(SDL_Renderer * renderer,
- const SDL_FRect * rects, int count);
-static int GLES_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * srcrect,
- const SDL_FRect * dstrect);
-static int GLES_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * srcrect, const SDL_FRect * dstrect,
- const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip);
-static int GLES_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
- Uint32 pixel_format, void * pixels, int pitch);
-static void GLES_RenderPresent(SDL_Renderer * renderer);
-static void GLES_DestroyTexture(SDL_Renderer * renderer,
- SDL_Texture * texture);
-static void GLES_DestroyRenderer(SDL_Renderer * renderer);
-static int GLES_BindTexture (SDL_Renderer * renderer, SDL_Texture *texture, float *texw, float *texh);
-static int GLES_UnbindTexture (SDL_Renderer * renderer, SDL_Texture *texture);
-
typedef struct GLES_FBOList GLES_FBOList;
struct GLES_FBOList
@@ -100,26 +61,27 @@ struct GLES_FBOList
GLES_FBOList *next;
};
-
-SDL_RenderDriver GLES_RenderDriver = {
- GLES_CreateRenderer,
- {
- "opengles",
- (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC),
- 1,
- {SDL_PIXELFORMAT_ABGR8888},
- 0,
- 0}
-};
+typedef struct
+{
+ SDL_Rect viewport;
+ SDL_bool viewport_dirty;
+ SDL_Texture *texture;
+ SDL_Texture *target;
+ int drawablew;
+ int drawableh;
+ SDL_BlendMode blend;
+ SDL_bool cliprect_enabled_dirty;
+ SDL_bool cliprect_enabled;
+ SDL_bool cliprect_dirty;
+ SDL_Rect cliprect;
+ SDL_bool texturing;
+ Uint32 color;
+ Uint32 clear_color;
+} GLES_DrawStateCache;
typedef struct
{
SDL_GLContext context;
- struct {
- Uint32 color;
- SDL_BlendMode blendMode;
- SDL_bool tex_coords;
- } current;
#define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
#define SDL_PROC_OES SDL_PROC
@@ -133,6 +95,8 @@ typedef struct
SDL_bool GL_OES_blend_func_separate_supported;
SDL_bool GL_OES_blend_equation_separate_supported;
SDL_bool GL_OES_blend_subtract_supported;
+
+ GLES_DrawStateCache drawstate;
} GLES_RenderData;
typedef struct
@@ -215,8 +179,6 @@ static int GLES_LoadFunctions(GLES_RenderData * data)
return 0;
}
-static SDL_GLContext SDL_CurrentContext = NULL;
-
static GLES_FBOList *
GLES_GetFBO(GLES_RenderData *data, Uint32 w, Uint32 h)
{
@@ -241,178 +203,13 @@ GLES_ActivateRenderer(SDL_Renderer * renderer)
{
GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
- if (SDL_CurrentContext != data->context) {
+ if (SDL_GL_GetCurrentContext() != data->context) {
if (SDL_GL_MakeCurrent(renderer->window, data->context) < 0) {
return -1;
}
- SDL_CurrentContext = data->context;
-
- GLES_UpdateViewport(renderer);
- }
- return 0;
-}
-
-/* This is called if we need to invalidate all of the SDL OpenGL state */
-static void
-GLES_ResetState(SDL_Renderer *renderer)
-{
- GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
-
- if (SDL_CurrentContext == data->context) {
- GLES_UpdateViewport(renderer);
- } else {
- GLES_ActivateRenderer(renderer);
- }
-
- data->current.color = 0xffffffff;
- data->current.blendMode = SDL_BLENDMODE_INVALID;
- data->current.tex_coords = SDL_FALSE;
-
- data->glDisable(GL_DEPTH_TEST);
- data->glDisable(GL_CULL_FACE);
-
- data->glMatrixMode(GL_MODELVIEW);
- data->glLoadIdentity();
-
- data->glEnableClientState(GL_VERTEX_ARRAY);
- data->glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-}
-
-SDL_Renderer *
-GLES_CreateRenderer(SDL_Window * window, Uint32 flags)
-{
-
- SDL_Renderer *renderer;
- GLES_RenderData *data;
- GLint value;
- Uint32 window_flags;
- int profile_mask = 0, major = 0, minor = 0;
- SDL_bool changed_window = SDL_FALSE;
-
- SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profile_mask);
- SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major);
- SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor);
-
- window_flags = SDL_GetWindowFlags(window);
- if (!(window_flags & SDL_WINDOW_OPENGL) ||
- profile_mask != SDL_GL_CONTEXT_PROFILE_ES || major != RENDERER_CONTEXT_MAJOR || minor != RENDERER_CONTEXT_MINOR) {
-
- changed_window = SDL_TRUE;
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, RENDERER_CONTEXT_MAJOR);
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, RENDERER_CONTEXT_MINOR);
-
- if (SDL_RecreateWindow(window, window_flags | SDL_WINDOW_OPENGL) < 0) {
- goto error;
- }
- }
-
- renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
- if (!renderer) {
- SDL_OutOfMemory();
- goto error;
- }
-
- data = (GLES_RenderData *) SDL_calloc(1, sizeof(*data));
- if (!data) {
- GLES_DestroyRenderer(renderer);
- SDL_OutOfMemory();
- goto error;
- }
-
- renderer->WindowEvent = GLES_WindowEvent;
- renderer->GetOutputSize = GLES_GetOutputSize;
- renderer->SupportsBlendMode = GLES_SupportsBlendMode;
- renderer->CreateTexture = GLES_CreateTexture;
- renderer->UpdateTexture = GLES_UpdateTexture;
- renderer->LockTexture = GLES_LockTexture;
- renderer->UnlockTexture = GLES_UnlockTexture;
- renderer->SetRenderTarget = GLES_SetRenderTarget;
- renderer->UpdateViewport = GLES_UpdateViewport;
- renderer->UpdateClipRect = GLES_UpdateClipRect;
- renderer->RenderClear = GLES_RenderClear;
- renderer->RenderDrawPoints = GLES_RenderDrawPoints;
- renderer->RenderDrawLines = GLES_RenderDrawLines;
- renderer->RenderFillRects = GLES_RenderFillRects;
- renderer->RenderCopy = GLES_RenderCopy;
- renderer->RenderCopyEx = GLES_RenderCopyEx;
- renderer->RenderReadPixels = GLES_RenderReadPixels;
- renderer->RenderPresent = GLES_RenderPresent;
- renderer->DestroyTexture = GLES_DestroyTexture;
- renderer->DestroyRenderer = GLES_DestroyRenderer;
- renderer->GL_BindTexture = GLES_BindTexture;
- renderer->GL_UnbindTexture = GLES_UnbindTexture;
- renderer->info = GLES_RenderDriver.info;
- renderer->info.flags = SDL_RENDERER_ACCELERATED;
- renderer->driverdata = data;
- renderer->window = window;
-
- data->context = SDL_GL_CreateContext(window);
- if (!data->context) {
- GLES_DestroyRenderer(renderer);
- goto error;
- }
- if (SDL_GL_MakeCurrent(window, data->context) < 0) {
- GLES_DestroyRenderer(renderer);
- goto error;
- }
-
- if (GLES_LoadFunctions(data) < 0) {
- GLES_DestroyRenderer(renderer);
- goto error;
- }
-
- if (flags & SDL_RENDERER_PRESENTVSYNC) {
- SDL_GL_SetSwapInterval(1);
- } else {
- SDL_GL_SetSwapInterval(0);
- }
- if (SDL_GL_GetSwapInterval() > 0) {
- renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
- }
-
- value = 0;
- data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
- renderer->info.max_texture_width = value;
- value = 0;
- data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
- renderer->info.max_texture_height = value;
-
- /* Android does not report GL_OES_framebuffer_object but the functionality seems to be there anyway */
- if (SDL_GL_ExtensionSupported("GL_OES_framebuffer_object") || data->glGenFramebuffersOES) {
- data->GL_OES_framebuffer_object_supported = SDL_TRUE;
- renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE;
-
- value = 0;
- data->glGetIntegerv(GL_FRAMEBUFFER_BINDING_OES, &value);
- data->window_framebuffer = (GLuint)value;
}
- data->framebuffers = NULL;
- if (SDL_GL_ExtensionSupported("GL_OES_blend_func_separate")) {
- data->GL_OES_blend_func_separate_supported = SDL_TRUE;
- }
- if (SDL_GL_ExtensionSupported("GL_OES_blend_equation_separate")) {
- data->GL_OES_blend_equation_separate_supported = SDL_TRUE;
- }
- if (SDL_GL_ExtensionSupported("GL_OES_blend_subtract")) {
- data->GL_OES_blend_subtract_supported = SDL_TRUE;
- }
-
- /* Set up parameters for rendering */
- GLES_ResetState(renderer);
-
- return renderer;
-
-error:
- if (changed_window) {
- /* Uh oh, better try to put it back... */
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profile_mask);
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major);
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minor);
- SDL_RecreateWindow(window, window_flags);
- }
- return NULL;
+ return 0;
}
static void
@@ -420,13 +217,6 @@ GLES_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
{
GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
- if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED ||
- event->event == SDL_WINDOWEVENT_SHOWN ||
- event->event == SDL_WINDOWEVENT_HIDDEN) {
- /* Rebind the context to the window area and update matrices */
- SDL_CurrentContext = NULL;
- }
-
if (event->event == SDL_WINDOWEVENT_MINIMIZED) {
/* According to Apple documentation, we need to finish drawing NOW! */
data->glFinish();
@@ -725,293 +515,77 @@ GLES_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
return 0;
}
-static int
-GLES_UpdateViewport(SDL_Renderer * renderer)
-{
- GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
-
- if (SDL_CurrentContext != data->context) {
- /* We'll update the viewport after we rebind the context */
- return 0;
- }
-
- if (renderer->target) {
- data->glViewport(renderer->viewport.x, renderer->viewport.y,
- renderer->viewport.w, renderer->viewport.h);
- } else {
- int w, h;
-
- SDL_GL_GetDrawableSize(renderer->window, &w, &h);
- data->glViewport(renderer->viewport.x, (h - renderer->viewport.y - renderer->viewport.h),
- renderer->viewport.w, renderer->viewport.h);
- }
-
- data->glMatrixMode(GL_PROJECTION);
- data->glLoadIdentity();
- if (renderer->viewport.w && renderer->viewport.h) {
- if (renderer->target) {
- data->glOrthof((GLfloat) 0,
- (GLfloat) renderer->viewport.w,
- (GLfloat) 0,
- (GLfloat) renderer->viewport.h,
- 0.0, 1.0);
- } else {
- data->glOrthof((GLfloat) 0,
- (GLfloat) renderer->viewport.w,
- (GLfloat) renderer->viewport.h,
- (GLfloat) 0,
- 0.0, 1.0);
- }
- }
- data->glMatrixMode(GL_MODELVIEW);
-
- return 0;
-}
static int
-GLES_UpdateClipRect(SDL_Renderer * renderer)
-{
- GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
-
- if (SDL_CurrentContext != data->context) {
- /* We'll update the clip rect after we rebind the context */
- return 0;
- }
-
- if (renderer->clipping_enabled) {
- const SDL_Rect *rect = &renderer->clip_rect;
- data->glEnable(GL_SCISSOR_TEST);
- if (renderer->target) {
- data->glScissor(renderer->viewport.x + rect->x, renderer->viewport.y + rect->y, rect->w, rect->h);
- } else {
- int w, h;
-
- SDL_GL_GetDrawableSize(renderer->window, &w, &h);
- data->glScissor(renderer->viewport.x + rect->x, h - renderer->viewport.y - rect->y - rect->h, rect->w, rect->h);
- }
- } else {
- data->glDisable(GL_SCISSOR_TEST);
- }
- return 0;
-}
-
-static void
-GLES_SetColor(GLES_RenderData * data, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
+GLES_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd)
{
- Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b);
-
- if (color != data->current.color) {
- data->glColor4f((GLfloat) r * inv255f,
- (GLfloat) g * inv255f,
- (GLfloat) b * inv255f,
- (GLfloat) a * inv255f);
- data->current.color = color;
- }
-}
-
-static void
-GLES_SetBlendMode(GLES_RenderData * data, SDL_BlendMode blendMode)
-{
- if (blendMode != data->current.blendMode) {
- if (blendMode == SDL_BLENDMODE_NONE) {
- data->glDisable(GL_BLEND);
- } else {
- data->glEnable(GL_BLEND);
- if (data->GL_OES_blend_func_separate_supported) {
- data->glBlendFuncSeparateOES(GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blendMode)),
- GetBlendFunc(SDL_GetBlendModeDstColorFactor(blendMode)),
- GetBlendFunc(SDL_GetBlendModeSrcAlphaFactor(blendMode)),
- GetBlendFunc(SDL_GetBlendModeDstAlphaFactor(blendMode)));
- } else {
- data->glBlendFunc(GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blendMode)),
- GetBlendFunc(SDL_GetBlendModeDstColorFactor(blendMode)));
- }
- if (data->GL_OES_blend_equation_separate_supported) {
- data->glBlendEquationSeparateOES(GetBlendEquation(SDL_GetBlendModeColorOperation(blendMode)),
- GetBlendEquation(SDL_GetBlendModeAlphaOperation(blendMode)));
- } else if (data->GL_OES_blend_subtract_supported) {
- data->glBlendEquationOES(GetBlendEquation(SDL_GetBlendModeColorOperation(blendMode)));
- }
- }
- data->current.blendMode = blendMode;
- }
-}
-
-static void
-GLES_SetTexCoords(GLES_RenderData * data, SDL_bool enabled)
-{
- if (enabled != data->current.tex_coords) {
- if (enabled) {
- data->glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- } else {
- data->glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- }
- data->current.tex_coords = enabled;
- }
-}
-
-static void
-GLES_SetDrawingState(SDL_Renderer * renderer)
-{
- GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
-
- GLES_ActivateRenderer(renderer);
-
- GLES_SetColor(data, (GLfloat) renderer->r,
- (GLfloat) renderer->g,
- (GLfloat) renderer->b,
- (GLfloat) renderer->a);
-
- GLES_SetBlendMode(data, renderer->blendMode);
-
- GLES_SetTexCoords(data, SDL_FALSE);
+ return 0; /* nothing to do in this backend. */
}
static int
-GLES_RenderClear(SDL_Renderer * renderer)
+GLES_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
{
- GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
-
- GLES_ActivateRenderer(renderer);
-
- data->glClearColor((GLfloat) renderer->r * inv255f,
- (GLfloat) renderer->g * inv255f,
- (GLfloat) renderer->b * inv255f,
- (GLfloat) renderer->a * inv255f);
-
- if (renderer->clipping_enabled) {
- data->glDisable(GL_SCISSOR_TEST);
- }
-
- data->glClear(GL_COLOR_BUFFER_BIT);
+ GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, count * 2 * sizeof (GLfloat), 0, &cmd->data.draw.first);
+ size_t i;
- if (renderer->clipping_enabled) {
- data->glEnable(GL_SCISSOR_TEST);
+ if (!verts) {
+ return -1;
}
- return 0;
-}
-
-static int
-GLES_RenderDrawPoints(SDL_Renderer * renderer, const SDL_FPoint * points,
- int count)
-{
- GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
- GLfloat *vertices;
- int idx;
-
- GLES_SetDrawingState(renderer);
-
- /* Emit the specified vertices as points */
- vertices = SDL_stack_alloc(GLfloat, count * 2);
- for (idx = 0; idx < count; ++idx) {
- GLfloat x = points[idx].x + 0.5f;
- GLfloat y = points[idx].y + 0.5f;
-
- vertices[idx * 2] = x;
- vertices[(idx * 2) + 1] = y;
+ cmd->data.draw.count = count;
+ for (i = 0; i < count; i++) {
+ *(verts++) = 0.5f + points[i].x;
+ *(verts++) = 0.5f + points[i].y;
}
- data->glVertexPointer(2, GL_FLOAT, 0, vertices);
- data->glDrawArrays(GL_POINTS, 0, count);
- SDL_stack_free(vertices);
return 0;
}
static int
-GLES_RenderDrawLines(SDL_Renderer * renderer, const SDL_FPoint * points,
- int count)
+GLES_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects, int count)
{
- GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
- GLfloat *vertices;
- int idx;
-
- GLES_SetDrawingState(renderer);
-
- /* Emit a line strip including the specified vertices */
- vertices = SDL_stack_alloc(GLfloat, count * 2);
- for (idx = 0; idx < count; ++idx) {
- GLfloat x = points[idx].x + 0.5f;
- GLfloat y = points[idx].y + 0.5f;
+ GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, count * 8 * sizeof (GLfloat), 0, &cmd->data.draw.first);
+ size_t i;
- vertices[idx * 2] = x;
- vertices[(idx * 2) + 1] = y;
+ if (!verts) {
+ return -1;
}
- data->glVertexPointer(2, GL_FLOAT, 0, vertices);
- if (count > 2 &&
- points[0].x == points[count-1].x && points[0].y == points[count-1].y) {
- /* GL_LINE_LOOP takes care of the final segment */
- --count;
- data->glDrawArrays(GL_LINE_LOOP, 0, count);
- } else {
- data->glDrawArrays(GL_LINE_STRIP, 0, count);
- /* We need to close the endpoint of the line */
- data->glDrawArrays(GL_POINTS, count-1, 1);
- }
- SDL_stack_free(vertices);
+ cmd->data.draw.count = count;
- return 0;
-}
-
-static int
-GLES_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects,
- int count)
-{
- GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
- int i;
-
- GLES_SetDrawingState(renderer);
-
- for (i = 0; i < count; ++i) {
+ for (i = 0; i < count; i++) {
const SDL_FRect *rect = &rects[i];
- GLfloat minx = rect->x;
- GLfloat maxx = rect->x + rect->w;
- GLfloat miny = rect->y;
- GLfloat maxy = rect->y + rect->h;
- GLfloat vertices[8];
- vertices[0] = minx;
- vertices[1] = miny;
- vertices[2] = maxx;
- vertices[3] = miny;
- vertices[4] = minx;
- vertices[5] = maxy;
- vertices[6] = maxx;
- vertices[7] = maxy;
-
- data->glVertexPointer(2, GL_FLOAT, 0, vertices);
- data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ const GLfloat minx = rect->x;
+ const GLfloat maxx = rect->x + rect->w;
+ const GLfloat miny = rect->y;
+ const GLfloat maxy = rect->y + rect->h;
+ *(verts++) = minx;
+ *(verts++) = miny;
+ *(verts++) = maxx;
+ *(verts++) = miny;
+ *(verts++) = minx;
+ *(verts++) = maxy;
+ *(verts++) = maxx;
+ *(verts++) = maxy;
}
return 0;
}
static int
-GLES_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * srcrect, const SDL_FRect * dstrect)
+GLES_QueueCopy(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
+ const SDL_Rect * srcrect, const SDL_FRect * dstrect)
{
- GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
GLES_TextureData *texturedata = (GLES_TextureData *) texture->driverdata;
GLfloat minx, miny, maxx, maxy;
GLfloat minu, maxu, minv, maxv;
- GLfloat vertices[8];
- GLfloat texCoords[8];
-
- GLES_ActivateRenderer(renderer);
+ GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, 16 * sizeof (GLfloat), 0, &cmd->data.draw.first);
- data->glEnable(GL_TEXTURE_2D);
-
- data->glBindTexture(texturedata->type, texturedata->texture);
-
- if (texture->modMode) {
- GLES_SetColor(data, texture->r, texture->g, texture->b, texture->a);
- } else {
- GLES_SetColor(data, 255, 255, 255, 255);
+ if (!verts) {
+ return -1;
}
- GLES_SetBlendMode(data, texture->blendMode);
-
- GLES_SetTexCoords(data, SDL_TRUE);
+ cmd->data.draw.count = 1;
minx = dstrect->x;
miny = dstrect->y;
@@ -1027,126 +601,351 @@ GLES_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
maxv *= texturedata->texh;
- vertices[0] = minx;
- vertices[1] = miny;
- vertices[2] = maxx;
- vertices[3] = miny;
- vertices[4] = minx;
- vertices[5] = maxy;
- vertices[6] = maxx;
- vertices[7] = maxy;
-
- texCoords[0] = minu;
- texCoords[1] = minv;
- texCoords[2] = maxu;
- texCoords[3] = minv;
- texCoords[4] = minu;
- texCoords[5] = maxv;
- texCoords[6] = maxu;
- texCoords[7] = maxv;
-
- data->glVertexPointer(2, GL_FLOAT, 0, vertices);
- data->glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
- data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-
- data->glDisable(GL_TEXTURE_2D);
+ *(verts++) = minx;
+ *(verts++) = miny;
+ *(verts++) = maxx;
+ *(verts++) = miny;
+ *(verts++) = minx;
+ *(verts++) = maxy;
+ *(verts++) = maxx;
+ *(verts++) = maxy;
+
+ *(verts++) = minu;
+ *(verts++) = minv;
+ *(verts++) = maxu;
+ *(verts++) = minv;
+ *(verts++) = minu;
+ *(verts++) = maxv;
+ *(verts++) = maxu;
+ *(verts++) = maxv;
return 0;
}
static int
-GLES_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * srcrect, const SDL_FRect * dstrect,
- const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
+GLES_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
+ const SDL_Rect * srcquad, const SDL_FRect * dstrect,
+ const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
{
-
- GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
GLES_TextureData *texturedata = (GLES_TextureData *) texture->driverdata;
GLfloat minx, miny, maxx, maxy;
- GLfloat minu, maxu, minv, maxv;
GLfloat centerx, centery;
- GLfloat vertices[8];
- GLfloat texCoords[8];
-
-
- GLES_ActivateRenderer(renderer);
-
- data->glEnable(GL_TEXTURE_2D);
-
- data->glBindTexture(texturedata->type, texturedata->texture);
+ GLfloat minu, maxu, minv, maxv;
+ GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, 19 * sizeof (GLfloat), 0, &cmd->data.draw.first);
- if (texture->modMode) {
- GLES_SetColor(data, texture->r, texture->g, texture->b, texture->a);
- } else {
- GLES_SetColor(data, 255, 255, 255, 255);
+ if (!verts) {
+ return -1;
}
- GLES_SetBlendMode(data, texture->blendMode);
-
- GLES_SetTexCoords(data, SDL_TRUE);
-
centerx = center->x;
centery = center->y;
- /* Rotate and translate */
- data->glPushMatrix();
- data->glTranslatef(dstrect->x + centerx, dstrect->y + centery, 0.0f);
- data->glRotatef((GLfloat)angle, 0.0f, 0.0f, 1.0f);
-
if (flip & SDL_FLIP_HORIZONTAL) {
minx = dstrect->w - centerx;
maxx = -centerx;
- } else {
+ }
+ else {
minx = -centerx;
- maxx = dstrect->w - centerx;
+ maxx = dstrect->w - centerx;
}
if (flip & SDL_FLIP_VERTICAL) {
- miny = dstrect->h - centery;
+ miny = dstrect->h - centery;
maxy = -centery;
- } else {
+ }
+ else {
miny = -centery;
- maxy = dstrect->h - centery;
+ maxy = dstrect->h - centery;
}
- minu = (GLfloat) srcrect->x / texture->w;
+ minu = (GLfloat) srcquad->x / texture->w;
minu *= texturedata->texw;
- maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
+ maxu = (GLfloat) (srcquad->x + srcquad->w) / texture->w;
maxu *= texturedata->texw;
- minv = (GLfloat) srcrect->y / texture->h;
+ minv = (GLfloat) srcquad->y / texture->h;
minv *= texturedata->texh;
- maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
+ maxv = (GLfloat) (srcquad->y + srcquad->h) / texture->h;
maxv *= texturedata->texh;
- vertices[0] = minx;
- vertices[1] = miny;
- vertices[2] = maxx;
- vertices[3] = miny;
- vertices[4] = minx;
- vertices[5] = maxy;
- vertices[6] = maxx;
- vertices[7] = maxy;
-
- texCoords[0] = minu;
- texCoords[1] = minv;
- texCoords[2] = maxu;
- texCoords[3] = minv;
- texCoords[4] = minu;
- texCoords[5] = maxv;
- texCoords[6] = maxu;
- texCoords[7] = maxv;
- data->glVertexPointer(2, GL_FLOAT, 0, vertices);
- data->glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
- data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- data->glPopMatrix();
- data->glDisable(GL_TEXTURE_2D);
+ cmd->data.draw.count = 1;
+
+ *(verts++) = minx;
+ *(verts++) = miny;
+ *(verts++) = maxx;
+ *(verts++) = miny;
+ *(verts++) = minx;
+ *(verts++) = maxy;
+ *(verts++) = maxx;
+ *(verts++) = maxy;
+
+ *(verts++) = minu;
+ *(verts++) = minv;
+ *(verts++) = maxu;
+ *(verts++) = minv;
+ *(verts++) = minu;
+ *(verts++) = maxv;
+ *(verts++) = maxu;
+ *(verts++) = maxv;
+
+ *(verts++) = (GLfloat) dstrect->x + centerx;
+ *(verts++) = (GLfloat) dstrect->y + centery;
+ *(verts++) = (GLfloat) angle;
+
+ return 0;
+}
+
+static void
+SetDrawState(GLES_RenderData *data, const SDL_RenderCommand *cmd)
+{
+ const SDL_BlendMode blend = cmd->data.draw.blend;
+ const Uint8 r = cmd->data.color.r;
+ const Uint8 g = cmd->data.color.g;
+ const Uint8 b = cmd->data.color.b;
+ const Uint8 a = cmd->data.color.a;
+ const Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b);
+
+ if (color != data->drawstate.color) {
+ const GLfloat fr = ((GLfloat) r) * inv255f;
+ const GLfloat fg = ((GLfloat) g) * inv255f;
+ const GLfloat fb = ((GLfloat) b) * inv255f;
+ const GLfloat fa = ((GLfloat) a) * inv255f;
+ data->glColor4f(fr, fg, fb, fa);
+ data->drawstate.color = color;
+ }
+
+ if (data->drawstate.viewport_dirty) {
+ const SDL_Rect *viewport = &data->drawstate.viewport;
+ const SDL_bool istarget = (data->drawstate.target != NULL);
+ data->glMatrixMode(GL_PROJECTION);
+ data->glLoadIdentity();
+ data->glViewport(viewport->x,
+ istarget ? viewport->y : (data->drawstate.drawableh - viewport->y - viewport->h),
+ viewport->w, viewport->h);
+ if (viewport->w && viewport->h) {
+ data->glOrthof((GLfloat) 0, (GLfloat) viewport->w,
+ (GLfloat) istarget ? 0 : viewport->h,
+ (GLfloat) istarget ? viewport->h : 0,
+ 0.0, 1.0);
+ }
+ data->glMatrixMode(GL_MODELVIEW);
+ data->drawstate.viewport_dirty = SDL_FALSE;
+ }
+
+ if (data->drawstate.cliprect_enabled_dirty) {
+ if (data->drawstate.cliprect_enabled) {
+ data->glEnable(GL_SCISSOR_TEST);
+ } else {
+ data->glDisable(GL_SCISSOR_TEST);
+ }
+ data->drawstate.cliprect_enabled_dirty = SDL_FALSE;
+ }
+
+ if (data->drawstate.cliprect_enabled && data->drawstate.cliprect_dirty) {
+ const SDL_Rect *viewport = &data->drawstate.viewport;
+ const SDL_Rect *rect = &data->drawstate.cliprect;
+ const SDL_bool istarget = (data->drawstate.target != NULL);
+ data->glScissor(viewport->x + rect->x,
+ istarget ? viewport->y + rect->y : data->drawstate.drawableh - viewport->y - rect->y - rect->h,
+ rect->w, rect->h);
+ data->drawstate.cliprect_dirty = SDL_FALSE;
+ }
+
+ if (blend != data->drawstate.blend) {
+ if (blend == SDL_BLENDMODE_NONE) {
+ data->glDisable(GL_BLEND);
+ } else {
+ data->glEnable(GL_BLEND);
+ if (data->GL_OES_blend_func_separate_supported) {
+ data->glBlendFuncSeparateOES(GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blend)),
+ GetBlendFunc(SDL_GetBlendModeDstColorFactor(blend)),
+ GetBlendFunc(SDL_GetBlendModeSrcAlphaFactor(blend)),
+ GetBlendFunc(SDL_GetBlendModeDstAlphaFactor(blend)));
+ } else {
+ data->glBlendFunc(GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blend)),
+ GetBlendFunc(SDL_GetBlendModeDstColorFactor(blend)));
+ }
+ if (data->GL_OES_blend_equation_separate_supported) {
+ data->glBlendEquationSeparateOES(GetBlendEquation(SDL_GetBlendModeColorOperation(blend)),
+ GetBlendEquation(SDL_GetBlendModeAlphaOperation(blend)));
+ } else if (data->GL_OES_blend_subtract_supported) {
+ data->glBlendEquationOES(GetBlendEquation(SDL_GetBlendModeColorOperation(blend)));
+ }
+ }
+ data->drawstate.blend = blend;
+ }
+
+ if ((cmd->data.draw.texture != NULL) != data->drawstate.texturing) {
+ if (cmd->data.draw.texture == NULL) {
+ data->glDisable(GL_TEXTURE_2D);
+ data->glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ data->drawstate.texturing = SDL_FALSE;
+ } else {
+ data->glEnable(GL_TEXTURE_2D);
+ data->glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ data->drawstate.texturing = SDL_TRUE;
+ }
+ }
+}
+
+static void
+SetCopyState(GLES_RenderData *data, const SDL_RenderCommand *cmd)
+{
+ SDL_Texture *texture = cmd->data.draw.texture;
+ SetDrawState(data, cmd);
+
+ if (texture != data->drawstate.texture) {
+ GLES_TextureData *texturedata = (GLES_TextureData *) texture->driverdata;
+ data->glBindTexture(GL_TEXTURE_2D, texturedata->texture);
+ data->drawstate.texture = texture;
+ }
+}
+
+static int
+GLES_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
+{
+ GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
+ size_t i;
+
+ if (GLES_ActivateRenderer(renderer) < 0) {
+ return -1;
+ }
+
+ data->drawstate.target = renderer->target;
+
+ if (!renderer->target) {
+ SDL_GL_GetDrawableSize(renderer->window, &data->drawstate.drawablew, &data->drawstate.drawableh);
+ }
+
+ while (cmd) {
+ switch (cmd->command) {
+ case SDL_RENDERCMD_SETDRAWCOLOR: {
+ break; /* not used in this render backend. */
+ }
+
+ case SDL_RENDERCMD_SETVIEWPORT: {
+ SDL_Rect *viewport = &data->drawstate.viewport;
+ if (SDL_memcmp(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect)) != 0) {
+ SDL_memcpy(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect));
+ data->drawstate.viewport_dirty = SDL_TRUE;
+ }
+ break;
+ }
+
+ case SDL_RENDERCMD_SETCLIPRECT: {
+ const SDL_Rect *rect = &cmd->data.cliprect.rect;
+ if (data->drawstate.cliprect_enabled != cmd->data.cliprect.enabled) {
+ data->drawstate.cliprect_enabled = cmd->data.cliprect.enabled;
+ data->drawstate.cliprect_enabled_dirty = SDL_TRUE;
+ }
+ if (SDL_memcmp(&data->drawstate.cliprect, rect, sizeof (SDL_Rect)) != 0) {
+ SDL_memcpy(&data->drawstate.cliprect, rect, sizeof (SDL_Rect));
+ data->drawstate.cliprect_dirty = SDL_TRUE;
+ }
+ break;
+ }
+
+ case SDL_RENDERCMD_CLEAR: {
+ const Uint8 r = cmd->data.color.r;
+ const Uint8 g = cmd->data.color.g;
+ const Uint8 b = cmd->data.color.b;
+ const Uint8 a = cmd->data.color.a;
+ const Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b);
+ if (color != data->drawstate.clear_color) {
+ const GLfloat fr = ((GLfloat) r) * inv255f;
+ const GLfloat fg = ((GLfloat) g) * inv255f;
+ const GLfloat fb = ((GLfloat) b) * inv255f;
+ const GLfloat fa = ((GLfloat) a) * inv255f;
+ data->glClearColor(fr, fg, fb, fa);
+ data->drawstate.clear_color = color;
+ }
+
+ if (data->drawstate.cliprect_enabled) {
+ data->glDisable(GL_SCISSOR_TEST);
+ data->drawstate.cliprect_enabled_dirty = SDL_TRUE;
+ }
+
+ data->glClear(GL_COLOR_BUFFER_BIT);
+
+ break;
+ }
+
+ case SDL_RENDERCMD_DRAW_POINTS: {
+ const size_t count = cmd->data.draw.count;
+ const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
+ SetDrawState(data, cmd);
+ data->glVertexPointer(2, GL_FLOAT, 0, verts);
+ data->glDrawArrays(GL_POINTS, 0, count);
+ break;
+ }
+
+ case SDL_RENDERCMD_DRAW_LINES: {
+ const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
+ const size_t count = cmd->data.draw.count;
+ SetDrawState(data, cmd);
+ data->glVertexPointer(2, GL_FLOAT, 0, verts);
+ if (count > 2 && (verts[0] == verts[(count-1)*2]) && (verts[1] == verts[(count*2)-1])) {
+ /* GL_LINE_LOOP takes care of the final segment */
+ data->glDrawArrays(GL_LINE_LOOP, 0, count - 1);
+ } else {
+ data->glDrawArrays(GL_LINE_STRIP, 0, count);
+ /* We need to close the endpoint of the line */
+ data->glDrawArrays(GL_POINTS, count - 1, 1);
+ }
+ break;
+ }
+
+ case SDL_RENDERCMD_FILL_RECTS: {
+ const size_t count = cmd->data.draw.count;
+ const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
+ size_t offset = 0;
+ SetDrawState(data, cmd);
+ data->glVertexPointer(2, GL_FLOAT, 0, verts);
+ for (i = 0; i < count; ++i, offset += 4) {
+ data->glDrawArrays(GL_TRIANGLE_STRIP, offset, 4);
+ }
+ break;
+ }
+
+ case SDL_RENDERCMD_COPY: {
+ const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
+ SetCopyState(data, cmd);
+ data->glVertexPointer(2, GL_FLOAT, 0, verts);
+ data->glTexCoordPointer(2, GL_FLOAT, 0, verts + 8);
+ data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ break;
+ }
+
+ case SDL_RENDERCMD_COPY_EX: {
+ const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
+ const GLfloat translatex = verts[16];
+ const GLfloat translatey = verts[17];
+ const GLfloat angle = verts[18];
+ SetCopyState(data, cmd);
+ data->glVertexPointer(2, GL_FLOAT, 0, verts);
+ data->glTexCoordPointer(2, GL_FLOAT, 0, verts + 8);
+
+ /* Translate to flip, rotate, translate to position */
+ data->glPushMatrix();
+ data->glTranslatef(translatex, translatey, 0.0f);
+ data->glRotatef(angle, 0.0, 0.0, 1.0);
+ data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ data->glPopMatrix();
+ break;
+ }
+
+ case SDL_RENDERCMD_NO_OP:
+ break;
+ }
+
+ cmd = cmd->next;
+ }
return 0;
}
static int
GLES_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
- Uint32 pixel_format, void * pixels, int pitch)
+ Uint32 pixel_format, void * pixels, int pitch)
{
GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
Uint32 temp_format = renderer->target ? renderer->target->format : SDL_PIXELFORMAT_ABGR8888;
@@ -1173,10 +972,11 @@ GLES_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
/* Flip the rows to be top-down if necessary */
if (!renderer->target) {
+ SDL_bool isstack;
length = rect->w * SDL_BYTESPERPIXEL(temp_format);
src = (Uint8*)temp_pixels + (rect->h-1)*temp_pitch;
dst = (Uint8*)temp_pixels;
- tmp = SDL_stack_alloc(Uint8, length);
+ tmp = SDL_small_alloc(Uint8, length, &isstack);
rows = rect->h / 2;
while (rows--) {
SDL_memcpy(tmp, dst, length);
@@ -1185,7 +985,7 @@ GLES_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
dst += temp_pitch;
src -= temp_pitch;
}
- SDL_stack_free(tmp);
+ SDL_small_free(tmp, isstack);
}
status = SDL_ConvertPixels(rect->w, rect->h,
@@ -1273,6 +1073,164 @@ static int GLES_UnbindTexture (SDL_Renderer * renderer, SDL_Texture *texture)
return 0;
}
+SDL_Renderer *
+GLES_CreateRenderer(SDL_Window * window, Uint32 flags)
+{
+ SDL_Renderer *renderer;
+ GLES_RenderData *data;
+ GLint value;
+ Uint32 window_flags;
+ int profile_mask = 0, major = 0, minor = 0;
+ SDL_bool changed_window = SDL_FALSE;
+
+ SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profile_mask);
+ SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major);
+ SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor);
+
+ window_flags = SDL_GetWindowFlags(window);
+ if (!(window_flags & SDL_WINDOW_OPENGL) ||
+ profile_mask != SDL_GL_CONTEXT_PROFILE_ES || major != RENDERER_CONTEXT_MAJOR || minor != RENDERER_CONTEXT_MINOR) {
+
+ changed_window = SDL_TRUE;
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, RENDERER_CONTEXT_MAJOR);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, RENDERER_CONTEXT_MINOR);
+
+ if (SDL_RecreateWindow(window, window_flags | SDL_WINDOW_OPENGL) < 0) {
+ goto error;
+ }
+ }
+
+ renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
+ if (!renderer) {
+ SDL_OutOfMemory();
+ goto error;
+ }
+
+ data = (GLES_RenderData *) SDL_calloc(1, sizeof(*data));
+ if (!data) {
+ GLES_DestroyRenderer(renderer);
+ SDL_OutOfMemory();
+ goto error;
+ }
+
+ renderer->WindowEvent = GLES_WindowEvent;
+ renderer->GetOutputSize = GLES_GetOutputSize;
+ renderer->SupportsBlendMode = GLES_SupportsBlendMode;
+ renderer->CreateTexture = GLES_CreateTexture;
+ renderer->UpdateTexture = GLES_UpdateTexture;
+ renderer->LockTexture = GLES_LockTexture;
+ renderer->UnlockTexture = GLES_UnlockTexture;
+ renderer->SetRenderTarget = GLES_SetRenderTarget;
+ renderer->QueueSetViewport = GLES_QueueSetViewport;
+ renderer->QueueSetDrawColor = GLES_QueueSetViewport; /* SetViewport and SetDrawColor are (currently) no-ops. */
+ renderer->QueueDrawPoints = GLES_QueueDrawPoints;
+ renderer->QueueDrawLines = GLES_QueueDrawPoints; /* lines and points queue vertices the same way. */
+ renderer->QueueFillRects = GLES_QueueFillRects;
+ renderer->QueueCopy = GLES_QueueCopy;
+ renderer->QueueCopyEx = GLES_QueueCopyEx;
+ renderer->RunCommandQueue = GLES_RunCommandQueue;
+ renderer->RenderReadPixels = GLES_RenderReadPixels;
+ renderer->RenderPresent = GLES_RenderPresent;
+ renderer->DestroyTexture = GLES_DestroyTexture;
+ renderer->DestroyRenderer = GLES_DestroyRenderer;
+ renderer->GL_BindTexture = GLES_BindTexture;
+ renderer->GL_UnbindTexture = GLES_UnbindTexture;
+ renderer->info = GLES_RenderDriver.info;
+ renderer->info.flags = SDL_RENDERER_ACCELERATED;
+ renderer->driverdata = data;
+ renderer->window = window;
+
+ data->context = SDL_GL_CreateContext(window);
+ if (!data->context) {
+ GLES_DestroyRenderer(renderer);
+ goto error;
+ }
+ if (SDL_GL_MakeCurrent(window, data->context) < 0) {
+ GLES_DestroyRenderer(renderer);
+ goto error;
+ }
+
+ if (GLES_LoadFunctions(data) < 0) {
+ GLES_DestroyRenderer(renderer);
+ goto error;
+ }
+
+ if (flags & SDL_RENDERER_PRESENTVSYNC) {
+ SDL_GL_SetSwapInterval(1);
+ } else {
+ SDL_GL_SetSwapInterval(0);
+ }
+ if (SDL_GL_GetSwapInterval() > 0) {
+ renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
+ }
+
+ value = 0;
+ data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
+ renderer->info.max_texture_width = value;
+ value = 0;
+ data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
+ renderer->info.max_texture_height = value;
+
+ /* Android does not report GL_OES_framebuffer_object but the functionality seems to be there anyway */
+ if (SDL_GL_ExtensionSupported("GL_OES_framebuffer_object") || data->glGenFramebuffersOES) {
+ data->GL_OES_framebuffer_object_supported = SDL_TRUE;
+ renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE;
+
+ value = 0;
+ data->glGetIntegerv(GL_FRAMEBUFFER_BINDING_OES, &value);
+ data->window_framebuffer = (GLuint)value;
+ }
+ data->framebuffers = NULL;
+
+ if (SDL_GL_ExtensionSupported("GL_OES_blend_func_separate")) {
+ data->GL_OES_blend_func_separate_supported = SDL_TRUE;
+ }
+ if (SDL_GL_ExtensionSupported("GL_OES_blend_equation_separate")) {
+ data->GL_OES_blend_equation_separate_supported = SDL_TRUE;
+ }
+ if (SDL_GL_ExtensionSupported("GL_OES_blend_subtract")) {
+ data->GL_OES_blend_subtract_supported = SDL_TRUE;
+ }
+
+ /* Set up parameters for rendering */
+ data->glDisable(GL_DEPTH_TEST);
+ data->glDisable(GL_CULL_FACE);
+
+ data->glMatrixMode(GL_MODELVIEW);
+ data->glLoadIdentity();
+
+ data->glEnableClientState(GL_VERTEX_ARRAY);
+ data->glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+
+ data->drawstate.blend = SDL_BLENDMODE_INVALID;
+ data->drawstate.color = 0xFFFFFFFF;
+ data->drawstate.clear_color = 0xFFFFFFFF;
+
+ return renderer;
+
+error:
+ if (changed_window) {
+ /* Uh oh, better try to put it back... */
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profile_mask);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minor);
+ SDL_RecreateWindow(window, window_flags);
+ }
+ return NULL;
+}
+
+SDL_RenderDriver GLES_RenderDriver = {
+ GLES_CreateRenderer,
+ {
+ "opengles",
+ (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC),
+ 1,
+ {SDL_PIXELFORMAT_ABGR8888},
+ 0,
+ 0}
+};
+
#endif /* SDL_VIDEO_RENDER_OGL_ES && !SDL_RENDER_DISABLED */
/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/render/opengles2/SDL_gles2funcs.h b/src/render/opengles2/SDL_gles2funcs.h
index b6a1436186..68096aaaf0 100644
--- a/src/render/opengles2/SDL_gles2funcs.h
+++ b/src/render/opengles2/SDL_gles2funcs.h
@@ -75,6 +75,7 @@ SDL_PROC(void, glDeleteFramebuffers, (GLsizei, const GLuint *))
SDL_PROC(GLint, glGetAttribLocation, (GLuint, const GLchar *))
SDL_PROC(void, glGetProgramInfoLog, (GLuint, GLsizei, GLsizei*, GLchar*))
SDL_PROC(void, glGenBuffers, (GLsizei, GLuint *))
+SDL_PROC(void, glDeleteBuffers, (GLsizei, GLuint *))
SDL_PROC(void, glBindBuffer, (GLenum, GLuint))
SDL_PROC(void, glBufferData, (GLenum, GLsizeiptr, const GLvoid *, GLenum))
SDL_PROC(void, glBufferSubData, (GLenum, GLintptr, GLsizeiptr, const GLvoid *))
diff --git a/src/render/opengles2/SDL_render_gles2.c b/src/render/opengles2/SDL_render_gles2.c
index f21a957625..fe2ce1ab8a 100644
--- a/src/render/opengles2/SDL_render_gles2.c
+++ b/src/render/opengles2/SDL_render_gles2.c
@@ -29,19 +29,6 @@
#include "../../video/SDL_blit.h"
#include "SDL_shaders_gles2.h"
-/* !!! FIXME: Emscripten makes these into WebGL calls, and WebGL doesn't offer
- !!! FIXME: client-side arrays (without an Emscripten compatibility hack,
- !!! FIXME: at least), but the current VBO code here is dramatically
- !!! FIXME: slower on actual iOS devices, even though the iOS Simulator
- !!! FIXME: is okay. Some time after 2.0.4 ships, we should revisit this,
- !!! FIXME: fix the performance bottleneck, and make everything use VBOs.
-*/
-#ifdef __EMSCRIPTEN__
-#define SDL_GLES2_USE_VBOS 1
-#else
-#define SDL_GLES2_USE_VBOS 0
-#endif
-
/* To prevent unnecessary window recreation,
* these should match the defaults selected in SDL_GL_ResetAttributes
*/
@@ -52,29 +39,6 @@
extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags);
/*************************************************************************************************
- * Bootstrap data *
- *************************************************************************************************/
-
-static SDL_Renderer *GLES2_CreateRenderer(SDL_Window *window, Uint32 flags);
-
-SDL_RenderDriver GLES2_RenderDriver = {
- GLES2_CreateRenderer,
- {
- "opengles2",
- (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
- 4,
- {
- SDL_PIXELFORMAT_ARGB8888,
- SDL_PIXELFORMAT_ABGR8888,
- SDL_PIXELFORMAT_RGB888,
- SDL_PIXELFORMAT_BGR888
- },
- 0,
- 0
- }
-};
-
-/*************************************************************************************************
* Context structures *
*************************************************************************************************/
@@ -109,7 +73,6 @@ typedef struct GLES2_ShaderCacheEntry
GLES2_ShaderType type;
const GLES2_ShaderInstance *instance;
int references;
- Uint8 modulation_r, modulation_g, modulation_b, modulation_a;
struct GLES2_ShaderCacheEntry *prev;
struct GLES2_ShaderCacheEntry *next;
} GLES2_ShaderCacheEntry;
@@ -126,8 +89,7 @@ typedef struct GLES2_ProgramCacheEntry
GLES2_ShaderCacheEntry *vertex_shader;
GLES2_ShaderCacheEntry *fragment_shader;
GLuint uniform_locations[16];
- Uint8 color_r, color_g, color_b, color_a;
- Uint8 modulation_r, modulation_g, modulation_b, modulation_a;
+ Uint32 color;
GLfloat projection[4][4];
struct GLES2_ProgramCacheEntry *prev;
struct GLES2_ProgramCacheEntry *next;
@@ -152,7 +114,6 @@ typedef enum
{
GLES2_UNIFORM_PROJECTION,
GLES2_UNIFORM_TEXTURE,
- GLES2_UNIFORM_MODULATION,
GLES2_UNIFORM_COLOR,
GLES2_UNIFORM_TEXTURE_U,
GLES2_UNIFORM_TEXTURE_V
@@ -160,6 +121,7 @@ typedef enum
typedef enum
{
+ GLES2_IMAGESOURCE_INVALID,
GLES2_IMAGESOURCE_SOLID,
GLES2_IMAGESOURCE_TEXTURE_ABGR,
GLES2_IMAGESOURCE_TEXTURE_ARGB,
@@ -171,17 +133,33 @@ typedef enum
GLES2_IMAGESOURCE_TEXTURE_EXTERNAL_OES
} GLES2_ImageSource;
-typedef struct GLES2_DriverContext
+typedef struct
+{
+ SDL_Rect viewport;
+ SDL_bool viewport_dirty;
+ SDL_Texture *texture;
+ SDL_Texture *target;
+ SDL_BlendMode blend;
+ SDL_bool cliprect_enabled_dirty;
+ SDL_bool cliprect_enabled;
+ SDL_bool cliprect_dirty;
+ SDL_Rect cliprect;
+ SDL_bool texturing;
+ SDL_bool is_copy_ex;
+ Uint32 color;
+ Uint32 clear_color;
+ int drawablew;
+ int drawableh;
+ GLES2_ProgramCacheEntry *program;
+ GLfloat projection[4][4];
+} GLES2_DrawStateCache;
+
+typedef struct GLES2_RenderData
{
SDL_GLContext *context;
SDL_bool debug_enabled;
- struct {
- SDL_BlendMode blendMode;
- SDL_bool tex_coords;
- } current;
-
#define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
#include "SDL_gles2funcs.h"
#undef SDL_PROC
@@ -192,17 +170,18 @@ typedef struct GLES2_DriverContext
GLenum *shader_formats;
GLES2_ShaderCache shader_cache;
GLES2_ProgramCache program_cache;
- GLES2_ProgramCacheEntry *current_program;
Uint8 clear_r, clear_g, clear_b, clear_a;
-#if SDL_GLES2_USE_VBOS
- GLuint vertex_buffers[4];
- GLsizeiptr vertex_buffer_size[4];
-#endif
-} GLES2_DriverContext;
+ GLuint vertex_buffers[8];
+ GLsizeiptr vertex_buffer_size[8];
+ int current_vertex_buffer;
+ GLES2_DrawStateCache drawstate;
+} GLES2_RenderData;
#define GLES2_MAX_CACHED_PROGRAMS 8
+static const float inv255f = 1.0f / 255.0f;
+
SDL_FORCE_INLINE const char*
GL_TranslateError (GLenum error)
@@ -223,7 +202,7 @@ GL_TranslateError (GLenum error)
SDL_FORCE_INLINE void
GL_ClearErrors(SDL_Renderer *renderer)
{
- GLES2_DriverContext *data = (GLES2_DriverContext *) renderer->driverdata;
+ GLES2_RenderData *data = (GLES2_RenderData *) renderer->driverdata;
if (!data->debug_enabled) {
return;
@@ -236,7 +215,7 @@ GL_ClearErrors(SDL_Renderer *renderer)
SDL_FORCE_INLINE int
GL_CheckAllErrors (const char *prefix, SDL_Renderer *renderer, const char *file, int line, const char *function)
{
- GLES2_DriverContext *data = (GLES2_DriverContext *) renderer->driverdata;
+ GLES2_RenderData *data = (GLES2_RenderData *) renderer->driverdata;
int ret = 0;
if (!data->debug_enabled) {
@@ -269,17 +248,7 @@ GL_CheckAllErrors (const char *prefix, SDL_Renderer *renderer, const char *file,
* Renderer state APIs *
*************************************************************************************************/
-static int GLES2_ActivateRenderer(SDL_Renderer *renderer);
-static void GLES2_WindowEvent(SDL_Renderer * renderer,
- const SDL_WindowEvent *event);
-static int GLES2_UpdateViewport(SDL_Renderer * renderer);
-static void GLES2_DestroyRenderer(SDL_Renderer *renderer);
-static int GLES2_SetOrthographicProjection(SDL_Renderer *renderer);
-
-
-static SDL_GLContext SDL_CurrentContext = NULL;
-
-static int GLES2_LoadFunctions(GLES2_DriverContext * data)
+static int GLES2_LoadFunctions(GLES2_RenderData * data)
{
#if SDL_VIDEO_DRIVER_UIKIT
#define __SDL_NOGETPROCADDR__
@@ -307,7 +276,7 @@ static int GLES2_LoadFunctions(GLES2_DriverContext * data)
}
static GLES2_FBOList *
-GLES2_GetFBO(GLES2_DriverContext *data, Uint32 w, Uint32 h)
+GLES2_GetFBO(GLES2_RenderData *data, Uint32 w, Uint32 h)
{
GLES2_FBOList *result = data->framebuffers;
while ((result) && ((result->w != w) || (result->h != h)) ) {
@@ -327,18 +296,15 @@ GLES2_GetFBO(GLES2_DriverContext *data, Uint32 w, Uint32 h)
static int
GLES2_ActivateRenderer(SDL_Renderer * renderer)
{
- GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
+ GLES2_RenderData *data = (GLES2_RenderData *)renderer->driverdata;
- if (SDL_CurrentContext != data->context) {
+ if (SDL_GL_GetCurrentContext() != data->context) {
/* Null out the current program to ensure we set it again */
- data->current_program = NULL;
+ data->drawstate.program = NULL;
if (SDL_GL_MakeCurrent(renderer->window, data->context) < 0) {
return -1;
}
- SDL_CurrentContext = data->context;
-
- GLES2_UpdateViewport(renderer);
}
GL_ClearErrors(renderer);
@@ -349,14 +315,7 @@ GLES2_ActivateRenderer(SDL_Renderer * renderer)
static void
GLES2_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
{
- GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
-
- if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED ||
- event->event == SDL_WINDOWEVENT_SHOWN ||
- event->event == SDL_WINDOWEVENT_HIDDEN) {
- /* Rebind the context to the window area */
- SDL_CurrentContext = NULL;
- }
+ GLES2_RenderData *data = (GLES2_RenderData *)renderer->driverdata;
if (event->event == SDL_WINDOWEVENT_MINIMIZED) {
/* According to Apple documentation, we need to finish drawing NOW! */
@@ -434,538 +393,31 @@ GLES2_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
return SDL_TRUE;
}
-static int
-GLES2_UpdateViewport(SDL_Renderer * renderer)
-{
- GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
-
- if (SDL_CurrentContext != data->context) {
- /* We'll update the viewport after we rebind the context */
- return 0;
- }
-
- if (renderer->target) {
- data->glViewport(renderer->viewport.x, renderer->viewport.y,
- renderer->viewport.w, renderer->viewport.h);
- } else {
- int w, h;
-
- SDL_GL_GetDrawableSize(renderer->window, &w, &h);
- data->glViewport(renderer->viewport.x, (h - renderer->viewport.y - renderer->viewport.h),
- renderer->viewport.w, renderer->viewport.h);
- }
-
- if (data->current_program) {
- GLES2_SetOrthographicProjection(renderer);
- }
- return GL_CheckError("", renderer);
-}
-
-static int
-GLES2_UpdateClipRect(SDL_Renderer * renderer)
-{
- GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
-
- if (SDL_CurrentContext != data->context) {
- /* We'll update the clip rect after we rebind the context */
- return 0;
- }
-
- if (renderer->clipping_enabled) {
- const SDL_Rect *rect = &renderer->clip_rect;
- data->glEnable(GL_SCISSOR_TEST);
- if (renderer->target) {
- data->glScissor(renderer->viewport.x + rect->x, renderer->viewport.y + rect->y, rect->w, rect->h);
- } else {
- int w, h;
-
- SDL_GL_GetDrawableSize(renderer->window, &w, &h);
- data->glScissor(renderer->viewport.x + rect->x, h - renderer->viewport.y - rect->y - rect->h, rect->w, rect->h);
- }
- } else {
- data->glDisable(GL_SCISSOR_TEST);
- }
- return 0;
-}
static void
-GLES2_DestroyRenderer(SDL_Renderer *renderer)
+GLES2_EvictShader(GLES2_RenderData *data, GLES2_ShaderCacheEntry *entry)
{
- GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
-
- /* Deallocate everything */
- if (data) {
- GLES2_ActivateRenderer(renderer);
-
- {
- GLES2_ShaderCacheEntry *entry;
- GLES2_ShaderCacheEntry *next;
- entry = data->shader_cache.head;
- while (entry) {
- data->glDeleteShader(entry->id);
- next = entry->next;
- SDL_free(entry);
- entry = next;
- }
- }
- {
- GLES2_ProgramCacheEntry *entry;
- GLES2_ProgramCacheEntry *next;
- entry = data->program_cache.head;
- while (entry) {
- data->glDeleteProgram(entry->id);
- next = entry->next;
- SDL_free(entry);
- entry = next;
- }
- }
- if (data->context) {
- while (data->framebuffers) {
- GLES2_FBOList *nextnode = data->framebuffers->next;
- data->glDeleteFramebuffers(1, &data->framebuffers->FBO);
- GL_CheckError("", renderer);
- SDL_free(data->framebuffers);
- data->framebuffers = nextnode;
- }
- SDL_GL_DeleteContext(data->context);
- }
- SDL_free(data->shader_formats);
- SDL_free(data);
- }
- SDL_free(renderer);
-}
-
-/*************************************************************************************************
- * Texture APIs *
- *************************************************************************************************/
-
-static int GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture);
-static int GLES2_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect,
- const void *pixels, int pitch);
-static int GLES2_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * rect,
- const Uint8 *Yplane, int Ypitch,
- const Uint8 *Uplane, int Upitch,
- const Uint8 *Vplane, int Vpitch);
-static int GLES2_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect,
- void **pixels, int *pitch);
-static void GLES2_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture);
-static int GLES2_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture);
-static void GLES2_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture);
-
-static int
-GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture)
-{
- GLES2_DriverContext *renderdata = (GLES2_DriverContext *)renderer->driverdata;
- GLES2_TextureData *data;
- GLenum format;
- GLenum type;
- GLenum scaleMode;
-
- GLES2_ActivateRenderer(renderer);
-
- /* Determine the corresponding GLES texture format params */
- switch (texture->format)
- {
- case SDL_PIXELFORMAT_ARGB8888:
- case SDL_PIXELFORMAT_ABGR8888:
- case SDL_PIXELFORMAT_RGB888:
- case SDL_PIXELFORMAT_BGR888:
- format = GL_RGBA;
- type = GL_UNSIGNED_BYTE;
- break;
- case SDL_PIXELFORMAT_IYUV:
- case SDL_PIXELFORMAT_YV12:
- case SDL_PIXELFORMAT_NV12:
- case SDL_PIXELFORMAT_NV21:
- format = GL_LUMINANCE;
- type = GL_UNSIGNED_BYTE;
- break;
-#ifdef GL_TEXTURE_EXTERNAL_OES
- case SDL_PIXELFORMAT_EXTERNAL_OES:
- format = GL_NONE;
- type = GL_NONE;
- break;
-#endif
- default:
- return SDL_SetError("Texture format not supported");
- }
-
- if (texture->format == SDL_PIXELFORMAT_EXTERNAL_OES &&
- texture->access != SDL_TEXTUREACCESS_STATIC) {
- return SDL_SetError("Unsupported texture access for SDL_PIXELFORMAT_EXTERNAL_OES");
- }
-
- /* Allocate a texture struct */
- data = (GLES2_TextureData *)SDL_calloc(1, sizeof(GLES2_TextureData));
- if (!data) {
- return SDL_OutOfMemory();
- }
- data->texture = 0;
-#ifdef GL_TEXTURE_EXTERNAL_OES
- data->texture_type = (texture->format == SDL_PIXELFORMAT_EXTERNAL_OES) ? GL_TEXTURE_EXTERNAL_OES : GL_TEXTURE_2D;
-#else
- data->texture_type = GL_TEXTURE_2D;
-#endif
- data->pixel_format = format;
- data->pixel_type = type;
- data->yuv = ((texture->format == SDL_PIXELFORMAT_IYUV) || (texture->format == SDL_PIXELFORMAT_YV12));
- data->nv12 = ((texture->format == SDL_PIXELFORMAT_NV12) || (texture->format == SDL_PIXELFORMAT_NV21));
- data->texture_u = 0;
- data->texture_v = 0;
- scaleMode = (texture->scaleMode == SDL_ScaleModeNearest) ? GL_NEAREST : GL_LINEAR;
-
- /* Allocate a blob for image renderdata */
- if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
- size_t size;
- data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);
- size = texture->h * data->pitch;
- if (data->yuv) {
- /* Need to add size for the U and V planes */
- size += 2 * ((texture->h + 1) / 2) * ((data->pitch + 1) / 2);
- }
- if (data->nv12) {
- /* Need to add size for the U/V plane */
- size += 2 * ((texture->h + 1) / 2) * ((data->pitch + 1) / 2);
- }
- data->pixel_data = SDL_calloc(1, size);
- if (!data->pixel_data) {
- SDL_free(data);
- return SDL_OutOfMemory();
- }
- }
-
- /* Allocate the texture */
- GL_CheckError("", renderer);
-
- if (data->yuv) {
- renderdata->glGenTextures(1, &data->texture_v);
- if (GL_CheckError("glGenTexures()", renderer) < 0) {
- return -1;
- }
- renderdata->glActiveTexture(GL_TEXTURE2);
- renderdata->glBindTexture(data->texture_type, data->texture_v);
- renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode);
- renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode);
- renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- renderdata->glTexImage2D(data->texture_type, 0, format, (texture->w + 1) / 2, (texture->h + 1) / 2, 0, format, type, NULL);
-
- renderdata->glGenTextures(1, &data->texture_u);
- if (GL_CheckError("glGenTexures()", renderer) < 0) {
- return -1;
- }
- renderdata->glActiveTexture(GL_TEXTURE1);
- renderdata->glBindTexture(data->texture_type, data->texture_u);
- renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode);
- renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode);
- renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- renderdata->glTexImage2D(data->texture_type, 0, format, (texture->w + 1) / 2, (texture->h + 1) / 2, 0, format, type, NULL);
- if (GL_CheckError("glTexImage2D()", renderer) < 0) {
- return -1;
- }
- }
-
- if (data->nv12) {
- renderdata->glGenTextures(1, &data->texture_u);
- if (GL_CheckError("glGenTexures()", renderer) < 0) {
- return -1;
- }
- renderdata->glActiveTexture(GL_TEXTURE1);
- renderdata->glBindTexture(data->texture_type, data->texture_u);
- renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode);
- renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode);
- renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- renderdata->glTexImage2D(data->texture_type, 0, GL_LUMINANCE_ALPHA, (texture->w + 1) / 2, (texture->h + 1) / 2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL);
- if (GL_CheckError("glTexImage2D()", renderer) < 0) {
- return -1;
- }
- }
-
- renderdata->glGenTextures(1, &data->texture);
- if (GL_CheckError("glGenTexures()", renderer) < 0) {
- return -1;
- }
- texture->driverdata = data;
- renderdata->glActiveTexture(GL_TEXTURE0);
- renderdata->glBindTexture(data->texture_type, data->texture);
- renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode);
- renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode);
- renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- if (texture->format != SDL_PIXELFORMAT_EXTERNAL_OES) {
- renderdata->glTexImage2D(data->texture_type, 0, format, texture->w, texture->h, 0, format, type, NULL);
- if (GL_CheckError("glTexImage2D()", renderer) < 0) {
- return -1;
- }
- }
-
- if (texture->access == SDL_TEXTUREACCESS_TARGET) {
- data->fbo = GLES2_GetFBO(renderer->driverdata, texture->w, texture->h);
- } else {
- data->fbo = NULL;
- }
-
- return GL_CheckError("", renderer);
-}
-
-static int
-GLES2_TexSubImage2D(GLES2_DriverContext *data, GLenum target, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels, GLint pitch, GLint bpp)
-{
- Uint8 *blob = NULL;
- Uint8 *src;
- int src_pitch;
- int y;
-
- if ((width == 0) || (height == 0) || (bpp == 0)) {
- return 0; /* nothing to do */
- }
-
- /* Reformat the texture data into a tightly packed array */
- src_pitch = width * bpp;
- src = (Uint8 *)pixels;
- if (pitch != src_pitch) {
- blob = (Uint8 *)SDL_malloc(src_pitch * height);
- if (!blob) {
- return SDL_OutOfMemory();
- }
- src = blob;
- for (y = 0; y < height; ++y)
- {
- SDL_memcpy(src, pixels, src_pitch);
- src += src_pitch;
- pixels = (Uint8 *)pixels + pitch;
- }
- src = blob;
- }
-
- data->glTexSubImage2D(target, 0, xoffset, yoffset, width, height, format, type, src);
- if (blob) {
- SDL_free(blob);
- }
- return 0;
-}
-
-static int
-GLES2_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect,
- const void *pixels, int pitch)
-{
- GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
- GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
-
- GLES2_ActivateRenderer(renderer);
-
- /* Bail out if we're supposed to update an empty rectangle */
- if (rect->w <= 0 || rect->h <= 0) {
- return 0;
- }
-
- /* Create a texture subimage with the supplied data */
- data->glBindTexture(tdata->texture_type, tdata->texture);
- GLES2_TexSubImage2D(data, tdata->texture_type,
- rect->x,
- rect->y,
- rect->w,
- rect->h,
- tdata->pixel_format,
- tdata->pixel_type,
- pixels, pitch, SDL_BYTESPERPIXEL(texture->format));
-
- if (tdata->yuv) {
- /* Skip to the correct offset into the next texture */
- pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
- if (texture->format == SDL_PIXELFORMAT_YV12) {
- data->glBindTexture(tdata->texture_type, tdata->texture_v);
- } else {
- data->glBindTexture(tdata->texture_type, tdata->texture_u);
- }
- GLES2_TexSubImage2D(data, tdata->texture_type,
- rect->x / 2,
- rect->y / 2,
- (rect->w + 1) / 2,
- (rect->h + 1) / 2,
- tdata->pixel_format,
- tdata->pixel_type,
- pixels, (pitch + 1) / 2, 1);
-
-
- /* Skip to the correct offset into the next texture */
- pixels = (const void*)((const Uint8*)pixels + ((rect->h + 1) / 2) * ((pitch + 1)/2));
- if (texture->format == SDL_PIXELFORMAT_YV12) {
- data->glBindTexture(tdata->texture_type, tdata->texture_u);
- } else {
- data->glBindTexture(tdata->texture_type, tdata->texture_v);
- }
- GLES2_TexSubImage2D(data, tdata->texture_type,
- rect->x / 2,
- rect->y / 2,
- (rect->w + 1) / 2,
- (rect->h + 1) / 2,
- tdata->pixel_format,
- tdata->pixel_type,
- pixels, (pitch + 1) / 2, 1);
- }
-
- if (tdata->nv12) {
- /* Skip to the correct offset into the next texture */
- pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
- data->glBindTexture(tdata->texture_type, tdata->texture_u);
- GLES2_TexSubImage2D(data, tdata->texture_type,
- rect->x / 2,
- rect->y / 2,
- (rect->w + 1) / 2,
- (rect->h + 1) / 2,
- GL_LUMINANCE_ALPHA,
- GL_UNSIGNED_BYTE,
- pixels, 2 * ((pitch + 1) / 2), 2);
+ /* Unlink the shader from the cache */
+ if (entry->next) {
+ entry->next->prev = entry->prev;
}
-
- return GL_CheckError("glTexSubImage2D()", renderer);
-}
-
-static int
-GLES2_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * rect,
- const Uint8 *Yplane, int Ypitch,
- const Uint8 *Uplane, int Upitch,
- const Uint8 *Vplane, int Vpitch)
-{
- GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
- GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
-
- GLES2_ActivateRenderer(renderer);
-
- /* Bail out if we're supposed to update an empty rectangle */
- if (rect->w <= 0 || rect->h <= 0) {
- return 0;
+ if (entry->prev) {
+ entry->prev->next = entry->next;
}
-
- data->glBindTexture(tdata->texture_type, tdata->texture_v);
- GLES2_TexSubImage2D(data, tdata->texture_type,
- rect->x / 2,
- rect->y / 2,
- (rect->w + 1) / 2,
- (rect->h + 1) / 2,
- tdata->pixel_format,
- tdata->pixel_type,
- Vplane, Vpitch, 1);
-
- data->glBindTexture(tdata->texture_type, tdata->texture_u);
- GLES2_TexSubImage2D(data, tdata->texture_type,
- rect->x / 2,
- rect->y / 2,
- (rect->w + 1) / 2,
- (rect->h + 1) / 2,
- tdata->pixel_format,
- tdata->pixel_type,
- Uplane, Upitch, 1);
-
- data->glBindTexture(tdata->texture_type, tdata->texture);
- GLES2_TexSubImage2D(data, tdata->texture_type,
- rect->x,
- rect->y,
- rect->w,
- rect->h,
- tdata->pixel_format,
- tdata->pixel_type,
- Yplane, Ypitch, 1);
-
- return GL_CheckError("glTexSubImage2D()", renderer);
-}
-
-static int
-GLES2_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect,
- void **pixels, int *pitch)
-{
- GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
-
- /* Retrieve the buffer/pitch for the specified region */
- *pixels = (Uint8 *)tdata->pixel_data +
- (tdata->pitch * rect->y) +
- (rect->x * SDL_BYTESPERPIXEL(texture->format));
- *pitch = tdata->pitch;
-
- return 0;
-}
-
-static void
-GLES2_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
-{
- GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
- SDL_Rect rect;
-
- /* We do whole texture updates, at least for now */
- rect.x = 0;
- rect.y = 0;
- rect.w = texture->w;
- rect.h = texture->h;
- GLES2_UpdateTexture(renderer, texture, &rect, tdata->pixel_data, tdata->pitch);
-}
-
-static int
-GLES2_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
-{
- GLES2_DriverContext *data = (GLES2_DriverContext *) renderer->driverdata;
- GLES2_TextureData *texturedata = NULL;
- GLenum status;
-
- if (texture == NULL) {
- data->glBindFramebuffer(GL_FRAMEBUFFER, data->window_framebuffer);
- } else {
- texturedata = (GLES2_TextureData *) texture->driverdata;
- data->glBindFramebuffer(GL_FRAMEBUFFER, texturedata->fbo->FBO);
- /* TODO: check if texture pixel format allows this operation */
- data->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texturedata->texture_type, texturedata->texture, 0);
- /* Check FBO status */
- status = data->glCheckFramebufferStatus(GL_FRAMEBUFFER);
- if (status != GL_FRAMEBUFFER_COMPLETE) {
- return SDL_SetError("glFramebufferTexture2D() failed");
- }
+ if (data->shader_cache.head == entry) {
+ data->shader_cache.head = entry->next;
}
- return 0;
-}
-
-static void
-GLES2_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture)
-{
- GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
- GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
-
- GLES2_ActivateRenderer(renderer);
+ --data->shader_cache.count;
- /* Destroy the texture */
- if (tdata) {
- data->glDeleteTextures(1, &tdata->texture);
- if (tdata->texture_v) {
- data->glDeleteTextures(1, &tdata->texture_v);
- }
- if (tdata->texture_u) {
- data->glDeleteTextures(1, &tdata->texture_u);
- }
- SDL_free(tdata->pixel_data);
- SDL_free(tdata);
- texture->driverdata = NULL;
- }
+ /* Deallocate the shader */
+ data->glDeleteShader(entry->id);
+ SDL_free(entry);
}
-/*************************************************************************************************
- * Shader management functions *
- *************************************************************************************************/
-
-static GLES2_ShaderCacheEntry *GLES2_CacheShader(SDL_Renderer *renderer, GLES2_ShaderType type);
-static void GLES2_EvictShader(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *entry);
-static GLES2_ProgramCacheEntry *GLES2_CacheProgram(SDL_Renderer *renderer,
- GLES2_ShaderCacheEntry *vertex,
- GLES2_ShaderCacheEntry *fragment);
-static int GLES2_SelectProgram(SDL_Renderer *renderer, GLES2_ImageSource source, int w, int h);
-
static GLES2_ProgramCacheEntry *
-GLES2_CacheProgram(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *vertex,
+GLES2_CacheProgram(GLES2_RenderData *data, GLES2_ShaderCacheEntry *vertex,
GLES2_ShaderCacheEntry *fragment)
{
- GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
GLES2_ProgramCacheEntry *entry;
GLES2_ShaderCacheEntry *shaderEntry;
GLint linkSuccessful;
@@ -1029,21 +481,27 @@ GLES2_CacheProgram(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *vertex,
data->glGetUniformLocation(entry->id, "u_texture_u");
entry->uniform_locations[GLES2_UNIFORM_TEXTURE] =
data->glGetUniformLocation(entry->id, "u_texture");
- entry->uniform_locations[GLES2_UNIFORM_MODULATION] =
- data->glGetUniformLocation(entry->id, "u_modulation");
entry->uniform_locations[GLES2_UNIFORM_COLOR] =
data->glGetUniformLocation(entry->id, "u_color");
- entry->modulation_r = entry->modulation_g = entry->modulation_b = entry->modulation_a = 255;
- entry->color_r = entry->color_g = entry->color_b = entry->color_a = 255;
+ entry->color = 0;
data->glUseProgram(entry->id);
- data->glUniform1i(entry->uniform_locations[GLES2_UNIFORM_TEXTURE_V], 2); /* always texture unit 2. */
- data->glUniform1i(entry->uniform_locations[GLES2_UNIFORM_TEXTURE_U], 1); /* always texture unit 1. */
- data->glUniform1i(entry->uniform_locations[GLES2_UNIFORM_TEXTURE], 0); /* always texture unit 0. */
- data->glUniformMatrix4fv(entry->uniform_locations[GLES2_UNIFORM_PROJECTION], 1, GL_FALSE, (GLfloat *)entry->projection);
- data->glUniform4f(entry->uniform_locations[GLES2_UNIFORM_MODULATION], 1.0f, 1.0f, 1.0f, 1.0f);
- data->glUniform4f(entry->uniform_locations[GLES2_UNIFORM_COLOR], 1.0f, 1.0f, 1.0f, 1.0f);
+ if (entry->uniform_locations[GLES2_UNIFORM_TEXTURE_V] != -1) {
+ data->glUniform1i(entry->uniform_locations[GLES2_UNIFORM_TEXTURE_V], 2); /* always texture unit 2. */
+ }
+ if (entry->uniform_locations[GLES2_UNIFORM_TEXTURE_U] != -1) {
+ data->glUniform1i(entry->uniform_locations[GLES2_UNIFORM_TEXTURE_U], 1); /* always texture unit 1. */
+ }
+ if (entry->uniform_locations[GLES2_UNIFORM_TEXTURE] != -1) {
+ data->glUniform1i(entry->uniform_locations[GLES2_UNIFORM_TEXTURE], 0); /* always texture unit 0. */
+ }
+ if (entry->uniform_locations[GLES2_UNIFORM_PROJECTION] != -1) {
+ data->glUniformMatrix4fv(entry->uniform_locations[GLES2_UNIFORM_PROJECTION], 1, GL_FALSE, (GLfloat *)entry->projection);
+ }
+ if (entry->uniform_locations[GLES2_UNIFORM_COLOR] != -1) {
+ data->glUniform4f(entry->uniform_locations[GLES2_UNIFORM_COLOR], 0.0f, 0.0f, 0.0f, 0.0f);
+ }
/* Cache the linked program */
if (data->program_cache.head) {
@@ -1063,11 +521,11 @@ GLES2_CacheProgram(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *vertex,
if (data->program_cache.count > GLES2_MAX_CACHED_PROGRAMS) {
shaderEntry = data->program_cache.tail->vertex_shader;
if (--shaderEntry->references <= 0) {
- GLES2_EvictShader(renderer, shaderEntry);
+ GLES2_EvictShader(data, shaderEntry);
}
shaderEntry = data->program_cache.tail->fragment_shader;
if (--shaderEntry->references <= 0) {
- GLES2_EvictShader(renderer, shaderEntry);
+ GLES2_EvictShader(data, shaderEntry);
}
data->glDeleteProgram(data->program_cache.tail->id);
data->program_cache.tail = data->program_cache.tail->prev;
@@ -1079,9 +537,8 @@ GLES2_CacheProgram(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *vertex,
}
static GLES2_ShaderCacheEntry *
-GLES2_CacheShader(SDL_Renderer *renderer, GLES2_ShaderType type)
+GLES2_CacheShader(GLES2_RenderData *data, GLES2_ShaderType type)
{
- GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
const GLES2_Shader *shader;
const GLES2_ShaderInstance *instance = NULL;
GLES2_ShaderCacheEntry *entry = NULL;
@@ -1144,19 +601,20 @@ GLES2_CacheShader(SDL_Renderer *renderer, GLES2_ShaderType type)
compileSuccessful = GL_TRUE;
}
if (!compileSuccessful) {
+ SDL_bool isstack = SDL_FALSE;
char *info = NULL;
int length = 0;
data->glGetShaderiv(entry->id, GL_INFO_LOG_LENGTH, &length);
if (length > 0) {
- info = SDL_stack_alloc(char, length);
+ info = SDL_small_alloc(char, length, &isstack);
if (info) {
data->glGetShaderInfoLog(entry->id, length, &length, info);
}
}
if (info) {
SDL_SetError("Failed to load the shader: %s", info);
- SDL_stack_free(info);
+ SDL_small_free(info, isstack);
} else {
SDL_SetError("Failed to load the shader");
}
@@ -1175,32 +633,9 @@ GLES2_CacheShader(SDL_Renderer *renderer, GLES2_ShaderType type)
return entry;
}
-static void
-GLES2_EvictShader(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *entry)
-{
- GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
-
- /* Unlink the shader from the cache */
- if (entry->next) {
- entry->next->prev = entry->prev;
- }
- if (entry->prev) {
- entry->prev->next = entry->next;
- }
- if (data->shader_cache.head == entry) {
- data->shader_cache.head = entry->next;
- }
- --data->shader_cache.count;
-
- /* Deallocate the shader */
- data->glDeleteShader(entry->id);
- SDL_free(entry);
-}
-
static int
-GLES2_SelectProgram(SDL_Renderer *renderer, GLES2_ImageSource source, int w, int h)
+GLES2_SelectProgram(GLES2_RenderData *data, GLES2_ImageSource source, int w, int h)
{
- GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
GLES2_ShaderCacheEntry *vertex = NULL;
GLES2_ShaderCacheEntry *fragment = NULL;
GLES2_ShaderType vtype, ftype;
@@ -1280,24 +715,24 @@ GLES2_SelectProgram(SDL_Renderer *renderer, GLES2_ImageSource source, int w, int
}
/* Load the requested shaders */
- vertex = GLES2_CacheShader(renderer, vtype);
+ vertex = GLES2_CacheShader(data, vtype);
if (!vertex) {
goto fault;
}
- fragment = GLES2_CacheShader(renderer, ftype);
+ fragment = GLES2_CacheShader(data, ftype);
if (!fragment) {
goto fault;
}
/* Check if we need to change programs at all */
- if (data->current_program &&
- data->current_program->vertex_shader == vertex &&
- data->current_program->fragment_shader == fragment) {
+ if (data->drawstate.program &&
+ data->drawstate.program->vertex_shader == vertex &&
+ data->drawstate.program->fragment_shader == fragment) {
return 0;
}
/* Generate a matching program */
- program = GLES2_CacheProgram(renderer, vertex, fragment);
+ program = GLES2_CacheProgram(data, vertex, fragment);
if (!program) {
goto fault;
}
@@ -1306,361 +741,352 @@ GLES2_SelectProgram(SDL_Renderer *renderer, GLES2_ImageSource source, int w, int
data->glUseProgram(program->id);
/* Set the current program */
- data->current_program = program;
-
- /* Activate an orthographic projection */
- if (GLES2_SetOrthographicProjection(renderer) < 0) {
- goto fault;
- }
+ data->drawstate.program = program;
/* Clean up and return */
return 0;
fault:
if (vertex && vertex->references <= 0) {
- GLES2_EvictShader(renderer, vertex);
+ GLES2_EvictShader(data, vertex);
}
if (fragment && fragment->references <= 0) {
- GLES2_EvictShader(renderer, fragment);
+ GLES2_EvictShader(data, fragment);
}
- data->current_program = NULL;
+ data->drawstate.program = NULL;
return -1;
}
static int
-GLES2_SetOrthographicProjection(SDL_Renderer *renderer)
+GLES2_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd)
{
- GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
- GLfloat projection[4][4];
+ return 0; /* nothing to do in this backend. */
+}
- if (!renderer->viewport.w || !renderer->viewport.h) {
- return 0;
- }
+static int
+GLES2_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
+{
+ GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, count * 2 * sizeof (GLfloat), 0, &cmd->data.draw.first);
+ size_t i;
- /* Prepare an orthographic projection */
- projection[0][0] = 2.0f / renderer->viewport.w;
- projection[0][1] = 0.0f;
- projection[0][2] = 0.0f;
- projection[0][3] = 0.0f;
- projection[1][0] = 0.0f;
- if (renderer->target) {
- projection[1][1] = 2.0f / renderer->viewport.h;
- } else {
- projection[1][1] = -2.0f / renderer->viewport.h;
- }
- projection[1][2] = 0.0f;
- projection[1][3] = 0.0f;
- projection[2][0] = 0.0f;
- projection[2][1] = 0.0f;
- projection[2][2] = 0.0f;
- projection[2][3] = 0.0f;
- projection[3][0] = -1.0f;
- if (renderer->target) {
- projection[3][1] = -1.0f;
- } else {
- projection[3][1] = 1.0f;
+ if (!verts) {
+ return -1;
}
- projection[3][2] = 0.0f;
- projection[3][3] = 1.0f;
- /* Set the projection matrix */
- if (SDL_memcmp(data->current_program->projection, projection, sizeof (projection)) != 0) {
- const GLuint locProjection = data->current_program->uniform_locations[GLES2_UNIFORM_PROJECTION];
- data->glUniformMatrix4fv(locProjection, 1, GL_FALSE, (GLfloat *)projection);
- SDL_memcpy(data->current_program->projection, projection, sizeof (projection));
+ cmd->data.draw.count = count;
+ for (i = 0; i < count; i++) {
+ *(verts++) = 0.5f + points[i].x;
+ *(verts++) = 0.5f + points[i].y;
}
return 0;
}
-/*************************************************************************************************
- * Rendering functions *
- *************************************************************************************************/
-
-static const float inv255f = 1.0f / 255.0f;
-
-static int GLES2_RenderClear(SDL_Renderer *renderer);
-static int GLES2_RenderDrawPoints(SDL_Renderer *renderer, const SDL_FPoint *points, int count);
-static int GLES2_RenderDrawLines(SDL_Renderer *renderer, const SDL_FPoint *points, int count);
-static int GLES2_RenderFillRects(SDL_Renderer *renderer, const SDL_FRect *rects, int count);
-static int GLES2_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *srcrect,
- const SDL_FRect *dstrect);
-static int GLES2_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * srcrect, const SDL_FRect * dstrect,
- const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip);
-static int GLES2_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
- Uint32 pixel_format, void * pixels, int pitch);
-static void GLES2_RenderPresent(SDL_Renderer *renderer);
-
-static SDL_bool
-CompareColors(Uint8 r1, Uint8 g1, Uint8 b1, Uint8 a1,
- Uint8 r2, Uint8 g2, Uint8 b2, Uint8 a2)
-{
- Uint32 Pixel1, Pixel2;
- RGBA8888_FROM_RGBA(Pixel1, r1, g1, b1, a1);
- RGBA8888_FROM_RGBA(Pixel2, r2, g2, b2, a2);
- return (Pixel1 == Pixel2);
-}
-
static int
-GLES2_RenderClear(SDL_Renderer * renderer)
+GLES2_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects, int count)
{
- Uint8 r, g, b, a;
-
- GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
-
- GLES2_ActivateRenderer(renderer);
-
- if (!CompareColors(data->clear_r, data->clear_g, data->clear_b, data->clear_a,
- renderer->r, renderer->g, renderer->b, renderer->a)) {
-
- /* Select the color to clear with */
- g = renderer->g;
- a = renderer->a;
-
- if (renderer->target &&
- (renderer->target->format == SDL_PIXELFORMAT_ARGB8888 ||
- renderer->target->format == SDL_PIXELFORMAT_RGB888)) {
- r = renderer->b;
- b = renderer->r;
- } else {
- r = renderer->r;
- b = renderer->b;
- }
-
- data->glClearColor((GLfloat) r * inv255f,
- (GLfloat) g * inv255f,
- (GLfloat) b * inv255f,
- (GLfloat) a * inv255f);
- data->clear_r = renderer->r;
- data->clear_g = renderer->g;
- data->clear_b = renderer->b;
- data->clear_a = renderer->a;
- }
+ GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, count * 8 * sizeof (GLfloat), 0, &cmd->data.draw.first);
+ size_t i;
- if (renderer->clipping_enabled) {
- data->glDisable(GL_SCISSOR_TEST);
+ if (!verts) {
+ return -1;
}
- data->glClear(GL_COLOR_BUFFER_BIT);
+ cmd->data.draw.count = count;
- if (renderer->clipping_enabled) {
- data->glEnable(GL_SCISSOR_TEST);
+ for (i = 0; i < count; i++) {
+ const SDL_FRect *rect = &rects[i];
+ const GLfloat minx = rect->x;
+ const GLfloat maxx = rect->x + rect->w;
+ const GLfloat miny = rect->y;
+ const GLfloat maxy = rect->y + rect->h;
+ *(verts++) = minx;
+ *(verts++) = miny;
+ *(verts++) = maxx;
+ *(verts++) = miny;
+ *(verts++) = minx;
+ *(verts++) = maxy;
+ *(verts++) = maxx;
+ *(verts++) = maxy;
}
return 0;
}
-static void
-GLES2_SetBlendMode(GLES2_DriverContext *data, SDL_BlendMode blendMode)
-{
- if (blendMode != data->current.blendMode) {
- if (blendMode == SDL_BLENDMODE_NONE) {
- data->glDisable(GL_BLEND);
- } else {
- data->glEnable(GL_BLEND);
- data->glBlendFuncSeparate(GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blendMode)),
- GetBlendFunc(SDL_GetBlendModeDstColorFactor(blendMode)),
- GetBlendFunc(SDL_GetBlendModeSrcAlphaFactor(blendMode)),
- GetBlendFunc(SDL_GetBlendModeDstAlphaFactor(blendMode)));
- data->glBlendEquationSeparate(GetBlendEquation(SDL_GetBlendModeColorOperation(blendMode)),
- GetBlendEquation(SDL_GetBlendModeAlphaOperation(blendMode)));
- }
- data->current.blendMode = blendMode;
- }
-}
-
-static void
-GLES2_SetTexCoords(GLES2_DriverContext * data, SDL_bool enabled)
-{
- if (enabled != data->current.tex_coords) {
- if (enabled) {
- data->glEnableVertexAttribArray(GLES2_ATTRIBUTE_TEXCOORD);
- } else {
- data->glDisableVertexAttribArray(GLES2_ATTRIBUTE_TEXCOORD);
- }
- data->current.tex_coords = enabled;
- }
-}
-
static int
-GLES2_SetDrawingState(SDL_Renderer * renderer)
+GLES2_QueueCopy(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
+ const SDL_Rect * srcrect, const SDL_FRect * dstrect)
{
- GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
- GLES2_ProgramCacheEntry *program;
- Uint8 r, g, b, a;
-
- GLES2_ActivateRenderer(renderer);
-
- GLES2_SetBlendMode(data, renderer->blendMode);
-
- GLES2_SetTexCoords(data, SDL_FALSE);
+ GLfloat minx, miny, maxx, maxy;
+ GLfloat minu, maxu, minv, maxv;
+ GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, 16 * sizeof (GLfloat), 0, &cmd->data.draw.first);
- /* Activate an appropriate shader and set the projection matrix */
- if (GLES2_SelectProgram(renderer, GLES2_IMAGESOURCE_SOLID, 0, 0) < 0) {
+ if (!verts) {
return -1;
}
- /* Select the color to draw with */
- g = renderer->g;
- a = renderer->a;
-
- if (renderer->target &&
- (renderer->target->format == SDL_PIXELFORMAT_ARGB8888 ||
- renderer->target->format == SDL_PIXELFORMAT_RGB888)) {
- r = renderer->b;
- b = renderer->r;
- } else {
- r = renderer->r;
- b = renderer->b;
- }
-
- program = data->current_program;
- if (!CompareColors(program->color_r, program->color_g, program->color_b, program->color_a, r, g, b, a)) {
- /* Select the color to draw with */
- data->glUniform4f(program->uniform_locations[GLES2_UNIFORM_COLOR], r * inv255f, g * inv255f, b * inv255f, a * inv255f);
- program->color_r = r;
- program->color_g = g;
- program->color_b = b;
- program->color_a = a;
- }
+ cmd->data.draw.count = 1;
+
+ minx = dstrect->x;
+ miny = dstrect->y;
+ maxx = dstrect->x + dstrect->w;
+ maxy = dstrect->y + dstrect->h;
+
+ minu = (GLfloat) srcrect->x / texture->w;
+ maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
+ minv = (GLfloat) srcrect->y / texture->h;
+ maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
+
+ *(verts++) = minx;
+ *(verts++) = miny;
+ *(verts++) = maxx;
+ *(verts++) = miny;
+ *(verts++) = minx;
+ *(verts++) = maxy;
+ *(verts++) = maxx;
+ *(verts++) = maxy;
+
+ *(verts++) = minu;
+ *(verts++) = minv;
+ *(verts++) = maxu;
+ *(verts++) = minv;
+ *(verts++) = minu;
+ *(verts++) = maxv;
+ *(verts++) = maxu;
+ *(verts++) = maxv;
return 0;
}
static int
-GLES2_UpdateVertexBuffer(SDL_Renderer *renderer, GLES2_Attribute attr,
- const void *vertexData, size_t dataSizeInBytes)
+GLES2_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
+ const SDL_Rect * srcquad, const SDL_FRect * dstrect,
+ const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
{
- GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
-
-#if !SDL_GLES2_USE_VBOS
- data->glVertexAttribPointer(attr, 2, GL_FLOAT, GL_FALSE, 0, vertexData);
-#else
- if (!data->vertex_buffers[attr]) {
- data->glGenBuffers(1, &data->vertex_buffers[attr]);
+ /* render expects cos value - 1 (see GLES2_VertexSrc_Default_) */
+ const float radian_angle = (float)(M_PI * (360.0 - angle) / 180.0);
+ const GLfloat s = (GLfloat) SDL_sin(radian_angle);
+ const GLfloat c = (GLfloat) SDL_cos(radian_angle) - 1.0f;
+ const GLfloat centerx = center->x + dstrect->x;
+ const GLfloat centery = center->y + dstrect->y;
+ GLfloat minx, miny, maxx, maxy;
+ GLfloat minu, maxu, minv, maxv;
+ GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, 32 * sizeof (GLfloat), 0, &cmd->data.draw.first);
+
+ if (!verts) {
+ return -1;
}
- data->glBindBuffer(GL_ARRAY_BUFFER, data->vertex_buffers[attr]);
-
- if (data->vertex_buffer_size[attr] < dataSizeInBytes) {
- data->glBufferData(GL_ARRAY_BUFFER, dataSizeInBytes, vertexData, GL_STREAM_DRAW);
- data->vertex_buffer_size[attr] = dataSizeInBytes;
+ if (flip & SDL_FLIP_HORIZONTAL) {
+ minx = dstrect->x + dstrect->w;
+ maxx = dstrect->x;
} else {
- data->glBufferSubData(GL_ARRAY_BUFFER, 0, dataSizeInBytes, vertexData);
+ minx = dstrect->x;
+ maxx = dstrect->x + dstrect->w;
}
- data->glVertexAttribPointer(attr, 2, GL_FLOAT, GL_FALSE, 0, 0);
-#endif
+ if (flip & SDL_FLIP_VERTICAL) {
+ miny = dstrect->y + dstrect->h;
+ maxy = dstrect->y;
+ } else {
+ miny = dstrect->y;
+ maxy = dstrect->y + dstrect->h;
+ }
+
+ minu = ((GLfloat) srcquad->x) / ((GLfloat) texture->w);
+ maxu = ((GLfloat) (srcquad->x + srcquad->w)) / ((GLfloat) texture->w);
+ minv = ((GLfloat) srcquad->y) / ((GLfloat) texture->h);
+ maxv = ((GLfloat) (srcquad->y + srcquad->h)) / ((GLfloat) texture->h);
+
+
+ cmd->data.draw.count = 1;
+
+ *(verts++) = minx;
+ *(verts++) = miny;
+ *(verts++) = maxx;
+ *(verts++) = miny;
+ *(verts++) = minx;
+ *(verts++) = maxy;
+ *(verts++) = maxx;
+ *(verts++) = maxy;
+
+ *(verts++) = minu;
+ *(verts++) = minv;
+ *(verts++) = maxu;
+ *(verts++) = minv;
+ *(verts++) = minu;
+ *(verts++) = maxv;
+ *(verts++) = maxu;
+ *(verts++) = maxv;
+
+ *(verts++) = s;
+ *(verts++) = c;
+ *(verts++) = s;
+ *(verts++) = c;
+ *(verts++) = s;
+ *(verts++) = c;
+ *(verts++) = s;
+ *(verts++) = c;
+
+ *(verts++) = centerx;
+ *(verts++) = centery;
+ *(verts++) = centerx;
+ *(verts++) = centery;
+ *(verts++) = centerx;
+ *(verts++) = centery;
+ *(verts++) = centerx;
+ *(verts++) = centery;
return 0;
}
static int
-GLES2_RenderDrawPoints(SDL_Renderer *renderer, const SDL_FPoint *points, int count)
+SetDrawState(GLES2_RenderData *data, const SDL_RenderCommand *cmd, const GLES2_ImageSource imgsrc)
{
- GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
- GLfloat *vertices;
- int idx;
+ const SDL_bool was_copy_ex = data->drawstate.is_copy_ex;
+ const SDL_bool is_copy_ex = (cmd->command == SDL_RENDERCMD_COPY_EX);
+ SDL_Texture *texture = cmd->data.draw.texture;
+ const SDL_BlendMode blend = cmd->data.draw.blend;
+ GLES2_ProgramCacheEntry *program;
- if (GLES2_SetDrawingState(renderer) < 0) {
- return -1;
+ SDL_assert((texture != NULL) == (imgsrc != GLES2_IMAGESOURCE_SOLID));
+
+ if (data->drawstate.viewport_dirty) {
+ const SDL_Rect *viewport = &data->drawstate.viewport;
+ data->glViewport(viewport->x,
+ data->drawstate.target ? viewport->y : (data->drawstate.drawableh - viewport->y - viewport->h),
+ viewport->w, viewport->h);
+ if (viewport->w && viewport->h) {
+ data->drawstate.projection[0][0] = 2.0f / viewport->w;
+ data->drawstate.projection[1][1] = (data->drawstate.target ? 2.0f : -2.0f) / viewport->h;
+ data->drawstate.projection[3][1] = data->drawstate.target ? -1.0f : 1.0f;
+ }
+ data->drawstate.viewport_dirty = SDL_FALSE;
}
- /* Emit the specified vertices as points */
- vertices = SDL_stack_alloc(GLfloat, count * 2);
- for (idx = 0; idx < count; ++idx) {
- GLfloat x = points[idx].x + 0.5f;
- GLfloat y = points[idx].y + 0.5f;
+ if (data->drawstate.cliprect_enabled_dirty) {
+ if (!data->drawstate.cliprect_enabled) {
+ data->glDisable(GL_SCISSOR_TEST);
+ } else {
+ data->glEnable(GL_SCISSOR_TEST);
+ }
+ data->drawstate.cliprect_enabled_dirty = SDL_FALSE;
+ }
+
+ if (data->drawstate.cliprect_enabled && data->drawstate.cliprect_dirty) {
+ const SDL_Rect *viewport = &data->drawstate.viewport;
+ const SDL_Rect *rect = &data->drawstate.cliprect;
+ data->glScissor(viewport->x + rect->x,
+ data->drawstate.target ? viewport->y + rect->y : data->drawstate.drawableh - viewport->y - rect->y - rect->h,
+ rect->w, rect->h);
+ data->drawstate.cliprect_dirty = SDL_FALSE;
+ }
+
+ if (texture != data->drawstate.texture) {
+ if ((texture != NULL) != data->drawstate.texturing) {
+ if (texture == NULL) {
+ data->glDisableVertexAttribArray((GLenum) GLES2_ATTRIBUTE_TEXCOORD);
+ data->drawstate.texturing = SDL_FALSE;
+ } else {
+ data->glEnableVertexAttribArray((GLenum) GLES2_ATTRIBUTE_TEXCOORD);
+ data->drawstate.texturing = SDL_TRUE;
+ }
+ }
+
+ if (texture) {
+ GLES2_TextureData *tdata = (GLES2_TextureData *) texture->driverdata;
+ if (tdata->yuv) {
+ data->glActiveTexture(GL_TEXTURE2);
+ data->glBindTexture(tdata->texture_type, tdata->texture_v);
+
+ data->glActiveTexture(GL_TEXTURE1);
+ data->glBindTexture(tdata->texture_type, tdata->texture_u);
+
+ data->glActiveTexture(GL_TEXTURE0);
+ } else if (tdata->nv12) {
+ data->glActiveTexture(GL_TEXTURE1);
+ data->glBindTexture(tdata->texture_type, tdata->texture_u);
- vertices[idx * 2] = x;
- vertices[(idx * 2) + 1] = y;
+ data->glActiveTexture(GL_TEXTURE0);
+ }
+ data->glBindTexture(tdata->texture_type, tdata->texture);
+ }
+
+ data->drawstate.texture = texture;
}
- /*data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);*/
- GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_POSITION, vertices, count * 2 * sizeof(GLfloat));
- data->glDrawArrays(GL_POINTS, 0, count);
- SDL_stack_free(vertices);
- return 0;
-}
-static int
-GLES2_RenderDrawLines(SDL_Renderer *renderer, const SDL_FPoint *points, int count)
-{
- GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
- GLfloat *vertices;
- int idx;
+ if (texture) {
+ data->glVertexAttribPointer(GLES2_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid *) (cmd->data.draw.first + (sizeof (GLfloat) * 8)));
+ }
- if (GLES2_SetDrawingState(renderer) < 0) {
+ if (GLES2_SelectProgram(data, imgsrc, texture ? texture->w : 0, texture ? texture->h : 0) < 0) {
return -1;
}
- /* Emit a line strip including the specified vertices */
- vertices = SDL_stack_alloc(GLfloat, count * 2);
- for (idx = 0; idx < count; ++idx) {
- GLfloat x = points[idx].x + 0.5f;
- GLfloat y = points[idx].y + 0.5f;
+ program = data->drawstate.program;
- vertices[idx * 2] = x;
- vertices[(idx * 2) + 1] = y;
+ if (program->uniform_locations[GLES2_UNIFORM_PROJECTION] != -1) {
+ if (SDL_memcmp(program->projection, data->drawstate.projection, sizeof (data->drawstate.projection)) != 0) {
+ data->glUniformMatrix4fv(program->uniform_locations[GLES2_UNIFORM_PROJECTION], 1, GL_FALSE, (GLfloat *)data->drawstate.projection);
+ SDL_memcpy(program->projection, data->drawstate.projection, sizeof (data->drawstate.projection));
+ }
}
- /*data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);*/
- GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_POSITION, vertices, count * 2 * sizeof(GLfloat));
- data->glDrawArrays(GL_LINE_STRIP, 0, count);
- /* We need to close the endpoint of the line */
- if (count == 2 ||
- points[0].x != points[count-1].x || points[0].y != points[count-1].y) {
- data->glDrawArrays(GL_POINTS, count-1, 1);
+ if (program->uniform_locations[GLES2_UNIFORM_COLOR] != -1) {
+ if (data->drawstate.color != program->color) {
+ const Uint8 r = (data->drawstate.color >> 16) & 0xFF;
+ const Uint8 g = (data->drawstate.color >> 8) & 0xFF;
+ const Uint8 b = (data->drawstate.color >> 0) & 0xFF;
+ const Uint8 a = (data->drawstate.color >> 24) & 0xFF;
+ data->glUniform4f(program->uniform_locations[GLES2_UNIFORM_COLOR], r * inv255f, g * inv255f, b * inv255f, a * inv255f);
+ program->color = data->drawstate.color;
+ }
}
- SDL_stack_free(vertices);
- return GL_CheckError("", renderer);
-}
-
-static int
-GLES2_RenderFillRects(SDL_Renderer *renderer, const SDL_FRect *rects, int count)
-{
- GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
- GLfloat vertices[8];
- int idx;
-
- if (GLES2_SetDrawingState(renderer) < 0) {
- return -1;
+ if (blend != data->drawstate.blend) {
+ if (blend == SDL_BLENDMODE_NONE) {
+ data->glDisable(GL_BLEND);
+ } else {
+ data->glEnable(GL_BLEND);
+ data->glBlendFuncSeparate(GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blend)),
+ GetBlendFunc(SDL_GetBlendModeDstColorFactor(blend)),
+ GetBlendFunc(SDL_GetBlendModeSrcAlphaFactor(blend)),
+ GetBlendFunc(SDL_GetBlendModeDstAlphaFactor(blend)));
+ data->glBlendEquationSeparate(GetBlendEquation(SDL_GetBlendModeColorOperation(blend)),
+ GetBlendEquation(SDL_GetBlendModeAlphaOperation(blend)));
+ }
+ data->drawstate.blend = blend;
}
- /* Emit a line loop for each rectangle */
- for (idx = 0; idx < count; ++idx) {
- const SDL_FRect *rect = &rects[idx];
+ /* all drawing commands use this */
+ data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid *) cmd->data.draw.first);
- GLfloat xMin = rect->x;
- GLfloat xMax = (rect->x + rect->w);
- GLfloat yMin = rect->y;
- GLfloat yMax = (rect->y + rect->h);
+ if (is_copy_ex != was_copy_ex) {
+ if (is_copy_ex) {
+ data->glEnableVertexAttribArray((GLenum) GLES2_ATTRIBUTE_ANGLE);
+ data->glEnableVertexAttribArray((GLenum) GLES2_ATTRIBUTE_CENTER);
+ } else {
+ data->glDisableVertexAttribArray((GLenum) GLES2_ATTRIBUTE_ANGLE);
+ data->glDisableVertexAttribArray((GLenum) GLES2_ATTRIBUTE_CENTER);
+ }
+ data->drawstate.is_copy_ex = is_copy_ex;
+ }
- vertices[0] = xMin;
- vertices[1] = yMin;
- vertices[2] = xMax;
- vertices[3] = yMin;
- vertices[4] = xMin;
- vertices[5] = yMax;
- vertices[6] = xMax;
- vertices[7] = yMax;
- /*data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);*/
- GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_POSITION, vertices, 8 * sizeof(GLfloat));
- data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ if (is_copy_ex) {
+ data->glVertexAttribPointer(GLES2_ATTRIBUTE_ANGLE, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid *) (cmd->data.draw.first + (sizeof (GLfloat) * 16)));
+ data->glVertexAttribPointer(GLES2_ATTRIBUTE_CENTER, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid *) (cmd->data.draw.first + (sizeof (GLfloat) * 24)));
}
- return GL_CheckError("", renderer);
+
+ return 0;
}
static int
-GLES2_SetupCopy(SDL_Renderer *renderer, SDL_Texture *texture)
+SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd)
{
- GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
- GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
+ GLES2_RenderData *data = (GLES2_RenderData *) renderer->driverdata;
GLES2_ImageSource sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
- GLES2_ProgramCacheEntry *program;
- Uint8 r, g, b, a;
+ SDL_Texture *texture = cmd->data.draw.texture;
- /* Activate an appropriate shader and set the projection matrix */
+ /* Pick an appropriate shader */
if (renderer->target) {
/* Check if we need to do color mapping between the source and render target textures */
if (renderer->target->format != texture->format) {
@@ -1764,178 +1190,602 @@ GLES2_SetupCopy(SDL_Renderer *renderer, SDL_Texture *texture)
}
}
- if (GLES2_SelectProgram(renderer, sourceType, texture->w, texture->h) < 0) {
+ return SetDrawState(data, cmd, sourceType);
+}
+
+static int
+GLES2_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
+{
+ GLES2_RenderData *data = (GLES2_RenderData *) renderer->driverdata;
+ const SDL_bool colorswap = (renderer->target && (renderer->target->format == SDL_PIXELFORMAT_ARGB8888 || renderer->target->format == SDL_PIXELFORMAT_RGB888));
+ const int vboidx = data->current_vertex_buffer;
+ const GLuint vbo = data->vertex_buffers[vboidx];
+ size_t i;
+
+ if (GLES2_ActivateRenderer(renderer) < 0) {
return -1;
}
- /* Select the target texture */
- if (tdata->yuv) {
- data->glActiveTexture(GL_TEXTURE2);
- data->glBindTexture(tdata->texture_type, tdata->texture_v);
+ data->drawstate.target = renderer->target;
+ if (!data->drawstate.target) {
+ SDL_GL_GetDrawableSize(renderer->window, &data->drawstate.drawablew, &data->drawstate.drawableh);
+ }
- data->glActiveTexture(GL_TEXTURE1);
- data->glBindTexture(tdata->texture_type, tdata->texture_u);
+ /* upload the new VBO data for this set of commands. */
+ data->glBindBuffer(GL_ARRAY_BUFFER, vbo);
+ if (data->vertex_buffer_size[vboidx] < vertsize) {
+ data->glBufferData(GL_ARRAY_BUFFER, vertsize, vertices, GL_STREAM_DRAW);
+ data->vertex_buffer_size[vboidx] = vertsize;
+ } else {
+ data->glBufferSubData(GL_ARRAY_BUFFER, 0, vertsize, vertices);
+ }
- data->glActiveTexture(GL_TEXTURE0);
+ /* cycle through a few VBOs so the GL has some time with the data before we replace it. */
+ data->current_vertex_buffer++;
+ if (data->current_vertex_buffer >= SDL_arraysize(data->vertex_buffers)) {
+ data->current_vertex_buffer = 0;
}
- if (tdata->nv12) {
- data->glActiveTexture(GL_TEXTURE1);
- data->glBindTexture(tdata->texture_type, tdata->texture_u);
- data->glActiveTexture(GL_TEXTURE0);
+ while (cmd) {
+ switch (cmd->command) {
+ case SDL_RENDERCMD_SETDRAWCOLOR: {
+ const Uint8 r = colorswap ? cmd->data.color.b : cmd->data.color.r;
+ const Uint8 g = cmd->data.color.g;
+ const Uint8 b = colorswap ? cmd->data.color.r : cmd->data.color.b;
+ const Uint8 a = cmd->data.color.a;
+ data->drawstate.color = ((a << 24) | (r << 16) | (g << 8) | b);
+ break;
+ }
+
+ case SDL_RENDERCMD_SETVIEWPORT: {
+ SDL_Rect *viewport = &data->drawstate.viewport;
+ if (SDL_memcmp(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect)) != 0) {
+ SDL_memcpy(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect));
+ data->drawstate.viewport_dirty = SDL_TRUE;
+ }
+ break;
+ }
+
+ case SDL_RENDERCMD_SETCLIPRECT: {
+ const SDL_Rect *rect = &cmd->data.cliprect.rect;
+ if (data->drawstate.cliprect_enabled != cmd->data.cliprect.enabled) {
+ data->drawstate.cliprect_enabled = cmd->data.cliprect.enabled;
+ data->drawstate.cliprect_enabled_dirty = SDL_TRUE;
+ }
+
+ if (SDL_memcmp(&data->drawstate.cliprect, rect, sizeof (SDL_Rect)) != 0) {
+ SDL_memcpy(&data->drawstate.cliprect, rect, sizeof (SDL_Rect));
+ data->drawstate.cliprect_dirty = SDL_TRUE;
+ }
+ break;
+ }
+
+ case SDL_RENDERCMD_CLEAR: {
+ const Uint8 r = colorswap ? cmd->data.color.b : cmd->data.color.r;
+ const Uint8 g = cmd->data.color.g;
+ const Uint8 b = colorswap ? cmd->data.color.r : cmd->data.color.b;
+ const Uint8 a = cmd->data.color.a;
+ const Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b);
+ if (color != data->drawstate.clear_color) {
+ const GLfloat fr = ((GLfloat) r) * inv255f;
+ const GLfloat fg = ((GLfloat) g) * inv255f;
+ const GLfloat fb = ((GLfloat) b) * inv255f;
+ const GLfloat fa = ((GLfloat) a) * inv255f;
+ data->glClearColor(fr, fg, fb, fa);
+ data->drawstate.clear_color = color;
+ }
+
+ if (data->drawstate.cliprect_enabled) {
+ data->glDisable(GL_SCISSOR_TEST);
+ data->drawstate.cliprect_enabled_dirty = SDL_TRUE;
+ }
+
+ data->glClear(GL_COLOR_BUFFER_BIT);
+ break;
+ }
+
+ case SDL_RENDERCMD_DRAW_POINTS: {
+ if (SetDrawState(data, cmd, GLES2_IMAGESOURCE_SOLID) == 0) {
+ data->glDrawArrays(GL_POINTS, 0, cmd->data.draw.count);
+ }
+ break;
+ }
+
+ case SDL_RENDERCMD_DRAW_LINES: {
+ const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
+ const size_t count = cmd->data.draw.count;
+ if (SetDrawState(data, cmd, GLES2_IMAGESOURCE_SOLID) == 0) {
+ if (count > 2 && (verts[0] == verts[(count-1)*2]) && (verts[1] == verts[(count*2)-1])) {
+ /* GL_LINE_LOOP takes care of the final segment */
+ data->glDrawArrays(GL_LINE_LOOP, 0, count - 1);
+ } else {
+ data->glDrawArrays(GL_LINE_STRIP, 0, count);
+ /* We need to close the endpoint of the line */
+ data->glDrawArrays(GL_POINTS, count - 1, 1);
+ }
+ }
+ break;
+ }
+
+ case SDL_RENDERCMD_FILL_RECTS: {
+ const size_t count = cmd->data.draw.count;
+ size_t offset = 0;
+ if (SetDrawState(data, cmd, GLES2_IMAGESOURCE_SOLID) == 0) {
+ for (i = 0; i < count; ++i, offset += 4) {
+ data->glDrawArrays(GL_TRIANGLE_STRIP, offset, 4);
+ }
+ }
+ break;
+ }
+
+ case SDL_RENDERCMD_COPY:
+ case SDL_RENDERCMD_COPY_EX: {
+ if (SetCopyState(renderer, cmd) == 0) {
+ data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ }
+ break;
+ }
+
+ case SDL_RENDERCMD_NO_OP:
+ break;
+ }
+
+ cmd = cmd->next;
+ }
+
+ return GL_CheckError("", renderer);
+}
+
+static void
+GLES2_DestroyRenderer(SDL_Renderer *renderer)
+{
+ GLES2_RenderData *data = (GLES2_RenderData *)renderer->driverdata;
+
+ /* Deallocate everything */
+ if (data) {
+ GLES2_ActivateRenderer(renderer);
+
+ {
+ GLES2_ShaderCacheEntry *entry;
+ GLES2_ShaderCacheEntry *next;
+ entry = data->shader_cache.head;
+ while (entry) {
+ data->glDeleteShader(entry->id);
+ next = entry->next;
+ SDL_free(entry);
+ entry = next;
+ }
+ }
+ {
+ GLES2_ProgramCacheEntry *entry;
+ GLES2_ProgramCacheEntry *next;
+ entry = data->program_cache.head;
+ while (entry) {
+ data->glDeleteProgram(entry->id);
+ next = entry->next;
+ SDL_free(entry);
+ entry = next;
+ }
+ }
+
+ if (data->context) {
+ while (data->framebuffers) {
+ GLES2_FBOList *nextnode = data->framebuffers->next;
+ data->glDeleteFramebuffers(1, &data->framebuffers->FBO);
+ GL_CheckError("", renderer);
+ SDL_free(data->framebuffers);
+ data->framebuffers = nextnode;
+ }
+
+ data->glDeleteBuffers(SDL_arraysize(data->vertex_buffers), data->vertex_buffers);
+ GL_CheckError("", renderer);
+
+ SDL_GL_DeleteContext(data->context);
+ }
+
+ SDL_free(data->shader_formats);
+ SDL_free(data);
+ }
+ SDL_free(renderer);
+}
+
+static int
+GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture)
+{
+ GLES2_RenderData *renderdata = (GLES2_RenderData *)renderer->driverdata;
+ GLES2_TextureData *data;
+ GLenum format;
+ GLenum type;
+ GLenum scaleMode;
+
+ GLES2_ActivateRenderer(renderer);
+
+ /* Determine the corresponding GLES texture format params */
+ switch (texture->format)
+ {
+ case SDL_PIXELFORMAT_ARGB8888:
+ case SDL_PIXELFORMAT_ABGR8888:
+ case SDL_PIXELFORMAT_RGB888:
+ case SDL_PIXELFORMAT_BGR888:
+ format = GL_RGBA;
+ type = GL_UNSIGNED_BYTE;
+ break;
+ case SDL_PIXELFORMAT_IYUV:
+ case SDL_PIXELFORMAT_YV12:
+ case SDL_PIXELFORMAT_NV12:
+ case SDL_PIXELFORMAT_NV21:
+ format = GL_LUMINANCE;
+ type = GL_UNSIGNED_BYTE;
+ break;
+#ifdef GL_TEXTURE_EXTERNAL_OES
+ case SDL_PIXELFORMAT_EXTERNAL_OES:
+ format = GL_NONE;
+ type = GL_NONE;
+ break;
+#endif
+ default:
+ return SDL_SetError("Texture format not supported");
+ }
+
+ if (texture->format == SDL_PIXELFORMAT_EXTERNAL_OES &&
+ texture->access != SDL_TEXTUREACCESS_STATIC) {
+ return SDL_SetError("Unsupported texture access for SDL_PIXELFORMAT_EXTERNAL_OES");
+ }
+
+ /* Allocate a texture struct */
+ data = (GLES2_TextureData *)SDL_calloc(1, sizeof(GLES2_TextureData));
+ if (!data) {
+ return SDL_OutOfMemory();
+ }
+ data->texture = 0;
+#ifdef GL_TEXTURE_EXTERNAL_OES
+ data->texture_type = (texture->format == SDL_PIXELFORMAT_EXTERNAL_OES) ? GL_TEXTURE_EXTERNAL_OES : GL_TEXTURE_2D;
+#else
+ data->texture_type = GL_TEXTURE_2D;
+#endif
+ data->pixel_format = format;
+ data->pixel_type = type;
+ data->yuv = ((texture->format == SDL_PIXELFORMAT_IYUV) || (texture->format == SDL_PIXELFORMAT_YV12));
+ data->nv12 = ((texture->format == SDL_PIXELFORMAT_NV12) || (texture->format == SDL_PIXELFORMAT_NV21));
+ data->texture_u = 0;
+ data->texture_v = 0;
+ scaleMode = (texture->scaleMode == SDL_ScaleModeNearest) ? GL_NEAREST : GL_LINEAR;
+
+ /* Allocate a blob for image renderdata */
+ if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
+ size_t size;
+ data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);
+ size = texture->h * data->pitch;
+ if (data->yuv) {
+ /* Need to add size for the U and V planes */
+ size += 2 * ((texture->h + 1) / 2) * ((data->pitch + 1) / 2);
+ } else if (data->nv12) {
+ /* Need to add size for the U/V plane */
+ size += 2 * ((texture->h + 1) / 2) * ((data->pitch + 1) / 2);
+ }
+ data->pixel_data = SDL_calloc(1, size);
+ if (!data->pixel_data) {
+ SDL_free(data);
+ return SDL_OutOfMemory();
+ }
+ }
+
+ /* Allocate the texture */
+ GL_CheckError("", renderer);
+
+ if (data->yuv) {
+ renderdata->glGenTextures(1, &data->texture_v);
+ if (GL_CheckError("glGenTexures()", renderer) < 0) {
+ return -1;
+ }
+ renderdata->glActiveTexture(GL_TEXTURE2);
+ renderdata->glBindTexture(data->texture_type, data->texture_v);
+ renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode);
+ renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode);
+ renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ renderdata->glTexImage2D(data->texture_type, 0, format, (texture->w + 1) / 2, (texture->h + 1) / 2, 0, format, type, NULL);
+
+ renderdata->glGenTextures(1, &data->texture_u);
+ if (GL_CheckError("glGenTexures()", renderer) < 0) {
+ return -1;
+ }
+ renderdata->glActiveTexture(GL_TEXTURE1);
+ renderdata->glBindTexture(data->texture_type, data->texture_u);
+ renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode);
+ renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode);
+ renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ renderdata->glTexImage2D(data->texture_type, 0, format, (texture->w + 1) / 2, (texture->h + 1) / 2, 0, format, type, NULL);
+ if (GL_CheckError("glTexImage2D()", renderer) < 0) {
+ return -1;
+ }
+ } else if (data->nv12) {
+ renderdata->glGenTextures(1, &data->texture_u);
+ if (GL_CheckError("glGenTexures()", renderer) < 0) {
+ return -1;
+ }
+ renderdata->glActiveTexture(GL_TEXTURE1);
+ renderdata->glBindTexture(data->texture_type, data->texture_u);
+ renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode);
+ renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode);
+ renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ renderdata->glTexImage2D(data->texture_type, 0, GL_LUMINANCE_ALPHA, (texture->w + 1) / 2, (texture->h + 1) / 2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL);
+ if (GL_CheckError("glTexImage2D()", renderer) < 0) {
+ return -1;
+ }
}
- data->glBindTexture(tdata->texture_type, tdata->texture);
- /* Configure color modulation */
- g = texture->g;
- a = texture->a;
+ renderdata->glGenTextures(1, &data->texture);
+ if (GL_CheckError("glGenTexures()", renderer) < 0) {
+ return -1;
+ }
+ texture->driverdata = data;
+ renderdata->glActiveTexture(GL_TEXTURE0);
+ renderdata->glBindTexture(data->texture_type, data->texture);
+ renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode);
+ renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode);
+ renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ if (texture->format != SDL_PIXELFORMAT_EXTERNAL_OES) {
+ renderdata->glTexImage2D(data->texture_type, 0, format, texture->w, texture->h, 0, format, type, NULL);
+ if (GL_CheckError("glTexImage2D()", renderer) < 0) {
+ return -1;
+ }
+ }
- if (renderer->target &&
- (renderer->target->format == SDL_PIXELFORMAT_ARGB8888 ||
- renderer->target->format == SDL_PIXELFORMAT_RGB888)) {
- r = texture->b;
- b = texture->r;
+ if (texture->access == SDL_TEXTUREACCESS_TARGET) {
+ data->fbo = GLES2_GetFBO(renderer->driverdata, texture->w, texture->h);
} else {
- r = texture->r;
- b = texture->b;
+ data->fbo = NULL;
}
- program = data->current_program;
+ return GL_CheckError("", renderer);
+}
+
+static int
+GLES2_TexSubImage2D(GLES2_RenderData *data, GLenum target, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels, GLint pitch, GLint bpp)
+{
+ Uint8 *blob = NULL;
+ Uint8 *src;
+ int src_pitch;
+ int y;
- if (!CompareColors(program->modulation_r, program->modulation_g, program->modulation_b, program->modulation_a, r, g, b, a)) {
- data->glUniform4f(program->uniform_locations[GLES2_UNIFORM_MODULATION], r * inv255f, g * inv255f, b * inv255f, a * inv255f);
- program->modulation_r = r;
- program->modulation_g = g;
- program->modulation_b = b;
- program->modulation_a = a;
+ if ((width == 0) || (height == 0) || (bpp == 0)) {
+ return 0; /* nothing to do */
}
- /* Configure texture blending */
- GLES2_SetBlendMode(data, texture->blendMode);
+ /* Reformat the texture data into a tightly packed array */
+ src_pitch = width * bpp;
+ src = (Uint8 *)pixels;
+ if (pitch != src_pitch) {
+ blob = (Uint8 *)SDL_malloc(src_pitch * height);
+ if (!blob) {
+ return SDL_OutOfMemory();
+ }
+ src = blob;
+ for (y = 0; y < height; ++y)
+ {
+ SDL_memcpy(src, pixels, src_pitch);
+ src += src_pitch;
+ pixels = (Uint8 *)pixels + pitch;
+ }
+ src = blob;
+ }
- GLES2_SetTexCoords(data, SDL_TRUE);
+ data->glTexSubImage2D(target, 0, xoffset, yoffset, width, height, format, type, src);
+ if (blob) {
+ SDL_free(blob);
+ }
return 0;
}
static int
-GLES2_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *srcrect,
- const SDL_FRect *dstrect)
+GLES2_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect,
+ const void *pixels, int pitch)
{
- GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
- GLfloat vertices[8];
- GLfloat texCoords[8];
+ GLES2_RenderData *data = (GLES2_RenderData *)renderer->driverdata;
+ GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
GLES2_ActivateRenderer(renderer);
- if (GLES2_SetupCopy(renderer, texture) < 0) {
- return -1;
+ /* Bail out if we're supposed to update an empty rectangle */
+ if (rect->w <= 0 || rect->h <= 0) {
+ return 0;
}
- /* Emit the textured quad */
- vertices[0] = dstrect->x;
- vertices[1] = dstrect->y;
- vertices[2] = (dstrect->x + dstrect->w);
- vertices[3] = dstrect->y;
- vertices[4] = dstrect->x;
- vertices[5] = (dstrect->y + dstrect->h);
- vertices[6] = (dstrect->x + dstrect->w);
- vertices[7] = (dstrect->y + dstrect->h);
- /*data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);*/
- GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_POSITION, vertices, 8 * sizeof(GLfloat));
- texCoords[0] = srcrect->x / (GLfloat)texture->w;
- texCoords[1] = srcrect->y / (GLfloat)texture->h;
- texCoords[2] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
- texCoords[3] = srcrect->y / (GLfloat)texture->h;
- texCoords[4] = srcrect->x / (GLfloat)texture->w;
- texCoords[5] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
- texCoords[6] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
- texCoords[7] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
- /*data->glVertexAttribPointer(GLES2_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, texCoords);*/
- GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_TEXCOORD, texCoords, 8 * sizeof(GLfloat));
- data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ /* Create a texture subimage with the supplied data */
+ data->glBindTexture(tdata->texture_type, tdata->texture);
+ GLES2_TexSubImage2D(data, tdata->texture_type,
+ rect->x,
+ rect->y,
+ rect->w,
+ rect->h,
+ tdata->pixel_format,
+ tdata->pixel_type,
+ pixels, pitch, SDL_BYTESPERPIXEL(texture->format));
+
+ if (tdata->yuv) {
+ /* Skip to the correct offset into the next texture */
+ pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
+ if (texture->format == SDL_PIXELFORMAT_YV12) {
+ data->glBindTexture(tdata->texture_type, tdata->texture_v);
+ } else {
+ data->glBindTexture(tdata->texture_type, tdata->texture_u);
+ }
+ GLES2_TexSubImage2D(data, tdata->texture_type,
+ rect->x / 2,
+ rect->y / 2,
+ (rect->w + 1) / 2,
+ (rect->h + 1) / 2,
+ tdata->pixel_format,
+ tdata->pixel_type,
+ pixels, (pitch + 1) / 2, 1);
+
- return GL_CheckError("", renderer);
+ /* Skip to the correct offset into the next texture */
+ pixels = (const void*)((const Uint8*)pixels + ((rect->h + 1) / 2) * ((pitch + 1)/2));
+ if (texture->format == SDL_PIXELFORMAT_YV12) {
+ data->glBindTexture(tdata->texture_type, tdata->texture_u);
+ } else {
+ data->glBindTexture(tdata->texture_type, tdata->texture_v);
+ }
+ GLES2_TexSubImage2D(data, tdata->texture_type,
+ rect->x / 2,
+ rect->y / 2,
+ (rect->w + 1) / 2,
+ (rect->h + 1) / 2,
+ tdata->pixel_format,
+ tdata->pixel_type,
+ pixels, (pitch + 1) / 2, 1);
+ } else if (tdata->nv12) {
+ /* Skip to the correct offset into the next texture */
+ pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
+ data->glBindTexture(tdata->texture_type, tdata->texture_u);
+ GLES2_TexSubImage2D(data, tdata->texture_type,
+ rect->x / 2,
+ rect->y / 2,
+ (rect->w + 1) / 2,
+ (rect->h + 1) / 2,
+ GL_LUMINANCE_ALPHA,
+ GL_UNSIGNED_BYTE,
+ pixels, 2 * ((pitch + 1) / 2), 2);
+ }
+
+ return GL_CheckError("glTexSubImage2D()", renderer);
}
static int
-GLES2_RenderCopyEx(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *srcrect,
- const SDL_FRect *dstrect, const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
+GLES2_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
+ const SDL_Rect * rect,
+ const Uint8 *Yplane, int Ypitch,
+ const Uint8 *Uplane, int Upitch,
+ const Uint8 *Vplane, int Vpitch)
{
- GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
- GLfloat vertices[8];
- GLfloat texCoords[8];
- GLfloat translate[8];
- GLfloat fAngle[8];
- GLfloat tmp;
- float radian_angle;
+ GLES2_RenderData *data = (GLES2_RenderData *)renderer->driverdata;
+ GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
GLES2_ActivateRenderer(renderer);
- if (GLES2_SetupCopy(renderer, texture) < 0) {
- return -1;
+ /* Bail out if we're supposed to update an empty rectangle */
+ if (rect->w <= 0 || rect->h <= 0) {
+ return 0;
}
- data->glEnableVertexAttribArray(GLES2_ATTRIBUTE_CENTER);
- data->glEnableVertexAttribArray(GLES2_ATTRIBUTE_ANGLE);
+ data->glBindTexture(tdata->texture_type, tdata->texture_v);
+ GLES2_TexSubImage2D(data, tdata->texture_type,
+ rect->x / 2,
+ rect->y / 2,
+ (rect->w + 1) / 2,
+ (rect->h + 1) / 2,
+ tdata->pixel_format,
+ tdata->pixel_type,
+ Vplane, Vpitch, 1);
- radian_angle = (float)(M_PI * (360.0 - angle) / 180.0);
- fAngle[0] = fAngle[2] = fAngle[4] = fAngle[6] = (GLfloat)SDL_sin(radian_angle);
- /* render expects cos value - 1 (see GLES2_VertexSrc_Default_) */
- fAngle[1] = fAngle[3] = fAngle[5] = fAngle[7] = (GLfloat)SDL_cos(radian_angle) - 1.0f;
- /* Calculate the center of rotation */
- translate[0] = translate[2] = translate[4] = translate[6] = (center->x + dstrect->x);
- translate[1] = translate[3] = translate[5] = translate[7] = (center->y + dstrect->y);
-
- /* Emit the textured quad */
- vertices[0] = dstrect->x;
- vertices[1] = dstrect->y;
- vertices[2] = (dstrect->x + dstrect->w);
- vertices[3] = dstrect->y;
- vertices[4] = dstrect->x;
- vertices[5] = (dstrect->y + dstrect->h);
- vertices[6] = (dstrect->x + dstrect->w);
- vertices[7] = (dstrect->y + dstrect->h);
- if (flip & SDL_FLIP_HORIZONTAL) {
- tmp = vertices[0];
- vertices[0] = vertices[4] = vertices[2];
- vertices[2] = vertices[6] = tmp;
+ data->glBindTexture(tdata->texture_type, tdata->texture_u);
+ GLES2_TexSubImage2D(data, tdata->texture_type,
+ rect->x / 2,
+ rect->y / 2,
+ (rect->w + 1) / 2,
+ (rect->h + 1) / 2,
+ tdata->pixel_format,
+ tdata->pixel_type,
+ Uplane, Upitch, 1);
+
+ data->glBindTexture(tdata->texture_type, tdata->texture);
+ GLES2_TexSubImage2D(data, tdata->texture_type,
+ rect->x,
+ rect->y,
+ rect->w,
+ rect->h,
+ tdata->pixel_format,
+ tdata->pixel_type,
+ Yplane, Ypitch, 1);
+
+ return GL_CheckError("glTexSubImage2D()", renderer);
+}
+
+static int
+GLES2_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect,
+ void **pixels, int *pitch)
+{
+ GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
+
+ /* Retrieve the buffer/pitch for the specified region */
+ *pixels = (Uint8 *)tdata->pixel_data +
+ (tdata->pitch * rect->y) +
+ (rect->x * SDL_BYTESPERPIXEL(texture->format));
+ *pitch = tdata->pitch;
+
+ return 0;
+}
+
+static void
+GLES2_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
+{
+ GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
+ SDL_Rect rect;
+
+ /* We do whole texture updates, at least for now */
+ rect.x = 0;
+ rect.y = 0;
+ rect.w = texture->w;
+ rect.h = texture->h;
+ GLES2_UpdateTexture(renderer, texture, &rect, tdata->pixel_data, tdata->pitch);
+}
+
+static int
+GLES2_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
+{
+ GLES2_RenderData *data = (GLES2_RenderData *) renderer->driverdata;
+ GLES2_TextureData *texturedata = NULL;
+ GLenum status;
+
+ if (texture == NULL) {
+ data->glBindFramebuffer(GL_FRAMEBUFFER, data->window_framebuffer);
+ } else {
+ texturedata = (GLES2_TextureData *) texture->driverdata;
+ data->glBindFramebuffer(GL_FRAMEBUFFER, texturedata->fbo->FBO);
+ /* TODO: check if texture pixel format allows this operation */
+ data->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texturedata->texture_type, texturedata->texture, 0);
+ /* Check FBO status */
+ status = data->glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ return SDL_SetError("glFramebufferTexture2D() failed");
+ }
}
- if (flip & SDL_FLIP_VERTICAL) {
- tmp = vertices[1];
- vertices[1] = vertices[3] = vertices[5];
- vertices[5] = vertices[7] = tmp;
- }
-
- /*data->glVertexAttribPointer(GLES2_ATTRIBUTE_ANGLE, 1, GL_FLOAT, GL_FALSE, 0, &fAngle);
- data->glVertexAttribPointer(GLES2_ATTRIBUTE_CENTER, 2, GL_FLOAT, GL_FALSE, 0, translate);
- data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);*/
-
- GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_ANGLE, fAngle, 8 * sizeof(GLfloat));
- GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_CENTER, translate, 8 * sizeof(GLfloat));
- GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_POSITION, vertices, 8 * sizeof(GLfloat));
-
- texCoords[0] = srcrect->x / (GLfloat)texture->w;
- texCoords[1] = srcrect->y / (GLfloat)texture->h;
- texCoords[2] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
- texCoords[3] = srcrect->y / (GLfloat)texture->h;
- texCoords[4] = srcrect->x / (GLfloat)texture->w;
- texCoords[5] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
- texCoords[6] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
- texCoords[7] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
- /*data->glVertexAttribPointer(GLES2_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, texCoords);*/
- GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_TEXCOORD, texCoords, 8 * sizeof(GLfloat));
- data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- data->glDisableVertexAttribArray(GLES2_ATTRIBUTE_CENTER);
- data->glDisableVertexAttribArray(GLES2_ATTRIBUTE_ANGLE);
+ return 0;
+}
- return GL_CheckError("", renderer);
+static void
+GLES2_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture)
+{
+ GLES2_RenderData *data = (GLES2_RenderData *)renderer->driverdata;
+ GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
+
+ GLES2_ActivateRenderer(renderer);
+
+ /* Destroy the texture */
+ if (tdata) {
+ data->glDeleteTextures(1, &tdata->texture);
+ if (tdata->texture_v) {
+ data->glDeleteTextures(1, &tdata->texture_v);
+ }
+ if (tdata->texture_u) {
+ data->glDeleteTextures(1, &tdata->texture_u);
+ }
+ SDL_free(tdata->pixel_data);
+ SDL_free(tdata);
+ texture->driverdata = NULL;
+ }
}
static int
GLES2_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
Uint32 pixel_format, void * pixels, int pitch)
{
- GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
+ GLES2_RenderData *data = (GLES2_RenderData *)renderer->driverdata;
Uint32 temp_format = renderer->target ? renderer->target->format : SDL_PIXELFORMAT_ABGR8888;
size_t buflen;
void *temp_pixels;
@@ -1944,8 +1794,6 @@ GLES2_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
int w, h, length, rows;
int status;
- GLES2_ActivateRenderer(renderer);
-
temp_pitch = rect->w * SDL_BYTESPERPIXEL(temp_format);
buflen = (size_t) (rect->h * temp_pitch);
if (buflen == 0) {
@@ -1967,10 +1815,11 @@ GLES2_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
/* Flip the rows to be top-down if necessary */
if (!renderer->target) {
+ SDL_bool isstack;
length = rect->w * SDL_BYTESPERPIXEL(temp_format);
src = (Uint8*)temp_pixels + (rect->h-1)*temp_pitch;
dst = (Uint8*)temp_pixels;
- tmp = SDL_stack_alloc(Uint8, length);
+ tmp = SDL_small_alloc(Uint8, length, &isstack);
rows = rect->h / 2;
while (rows--) {
SDL_memcpy(tmp, dst, length);
@@ -1979,7 +1828,7 @@ GLES2_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
dst += temp_pitch;
src -= temp_pitch;
}
- SDL_stack_free(tmp);
+ SDL_small_free(tmp, isstack);
}
status = SDL_ConvertPixels(rect->w, rect->h,
@@ -1993,8 +1842,6 @@ GLES2_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
static void
GLES2_RenderPresent(SDL_Renderer *renderer)
{
- GLES2_ActivateRenderer(renderer);
-
/* Tell the video driver to swap buffers */
SDL_GL_SwapWindow(renderer->window);
}
@@ -2008,7 +1855,7 @@ static int GLES2_UnbindTexture (SDL_Renderer * renderer, SDL_Texture *texture);
static int GLES2_BindTexture (SDL_Renderer * renderer, SDL_Texture *texture, float *texw, float *texh)
{
- GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
+ GLES2_RenderData *data = (GLES2_RenderData *)renderer->driverdata;
GLES2_TextureData *texturedata = (GLES2_TextureData *)texture->driverdata;
GLES2_ActivateRenderer(renderer);
@@ -2026,7 +1873,7 @@ static int GLES2_BindTexture (SDL_Renderer * renderer, SDL_Texture *texture, flo
static int GLES2_UnbindTexture (SDL_Renderer * renderer, SDL_Texture *texture)
{
- GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
+ GLES2_RenderData *data = (GLES2_RenderData *)renderer->driverdata;
GLES2_TextureData *texturedata = (GLES2_TextureData *)texture->driverdata;
GLES2_ActivateRenderer(renderer);
@@ -2044,40 +1891,12 @@ static int GLES2_UnbindTexture (SDL_Renderer * renderer, SDL_Texture *texture)
#define GL_NVIDIA_PLATFORM_BINARY_NV 0x890B
#endif
-static void
-GLES2_ResetState(SDL_Renderer *renderer)
-{
- GLES2_DriverContext *data = (GLES2_DriverContext *) renderer->driverdata;
-
- if (SDL_CurrentContext == data->context) {
- GLES2_UpdateViewport(renderer);
- } else {
- GLES2_ActivateRenderer(renderer);
- }
-
- data->current.blendMode = SDL_BLENDMODE_INVALID;
- data->current.tex_coords = SDL_FALSE;
-
- data->glActiveTexture(GL_TEXTURE0);
- data->glPixelStorei(GL_PACK_ALIGNMENT, 1);
- data->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-
- data->glClearColor((GLfloat) data->clear_r * inv255f,
- (GLfloat) data->clear_g * inv255f,
- (GLfloat) data->clear_b * inv255f,
- (GLfloat) data->clear_a * inv255f);
-
- data->glEnableVertexAttribArray(GLES2_ATTRIBUTE_POSITION);
- data->glDisableVertexAttribArray(GLES2_ATTRIBUTE_TEXCOORD);
-
- GL_CheckError("", renderer);
-}
static SDL_Renderer *
GLES2_CreateRenderer(SDL_Window *window, Uint32 flags)
{
SDL_Renderer *renderer;
- GLES2_DriverContext *data;
+ GLES2_RenderData *data;
GLint nFormats;
#ifndef ZUNE_HD
GLboolean hasCompiler;
@@ -2099,6 +1918,7 @@ GLES2_CreateRenderer(SDL_Window *window, Uint32 flags)
}
window_flags = SDL_GetWindowFlags(window);
+
/* OpenGL ES 3.0 is a superset of OpenGL ES 2.0 */
if (!(window_flags & SDL_WINDOW_OPENGL) ||
profile_mask != SDL_GL_CONTEXT_PROFILE_ES || major < RENDERER_CONTEXT_MAJOR) {
@@ -2120,7 +1940,7 @@ GLES2_CreateRenderer(SDL_Window *window, Uint32 flags)
goto error;
}
- data = (GLES2_DriverContext *)SDL_calloc(1, sizeof(GLES2_DriverContext));
+ data = (GLES2_RenderData *)SDL_calloc(1, sizeof(GLES2_RenderData));
if (!data) {
SDL_free(renderer);
SDL_OutOfMemory();
@@ -2209,6 +2029,9 @@ GLES2_CreateRenderer(SDL_Window *window, Uint32 flags)
}
#endif /* ZUNE_HD */
+ /* we keep a few of these and cycle through them, so data can live for a few frames. */
+ data->glGenBuffers(SDL_arraysize(data->vertex_buffers), data->vertex_buffers);
+
data->framebuffers = NULL;
data->glGetIntegerv(GL_FRAMEBUFFER_BINDING, &window_framebuffer);
data->window_framebuffer = (GLuint)window_framebuffer;
@@ -2223,14 +2046,14 @@ GLES2_CreateRenderer(SDL_Window *window, Uint32 flags)
renderer->LockTexture = GLES2_LockTexture;
renderer->UnlockTexture = GLES2_UnlockTexture;
renderer->SetRenderTarget = GLES2_SetRenderTarget;
- renderer->UpdateViewport = GLES2_UpdateViewport;
- renderer->UpdateClipRect = GLES2_UpdateClipRect;
- renderer->RenderClear = GLES2_RenderClear;
- renderer->RenderDrawPoints = GLES2_RenderDrawPoints;
- renderer->RenderDrawLines = GLES2_RenderDrawLines;
- renderer->RenderFillRects = GLES2_RenderFillRects;
- renderer->RenderCopy = GLES2_RenderCopy;
- renderer->RenderCopyEx = GLES2_RenderCopyEx;
+ renderer->QueueSetViewport = GLES2_QueueSetViewport;
+ renderer->QueueSetDrawColor = GLES2_QueueSetViewport; /* SetViewport and SetDrawColor are (currently) no-ops. */
+ renderer->QueueDrawPoints = GLES2_QueueDrawPoints;
+ renderer->QueueDrawLines = GLES2_QueueDrawPoints; /* lines and points queue vertices the same way. */
+ renderer->QueueFillRects = GLES2_QueueFillRects;
+ renderer->QueueCopy = GLES2_QueueCopy;
+ renderer->QueueCopyEx = GLES2_QueueCopyEx;
+ renderer->RunCommandQueue = GLES2_RunCommandQueue;
renderer->RenderReadPixels = GLES2_RenderReadPixels;
renderer->RenderPresent = GLES2_RenderPresent;
renderer->DestroyTexture = GLES2_DestroyTexture;
@@ -2246,7 +2069,20 @@ GLES2_CreateRenderer(SDL_Window *window, Uint32 flags)
renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_EXTERNAL_OES;
#endif
- GLES2_ResetState(renderer);
+ data->glActiveTexture(GL_TEXTURE0);
+ data->glPixelStorei(GL_PACK_ALIGNMENT, 1);
+ data->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ data->glEnableVertexAttribArray(GLES2_ATTRIBUTE_POSITION);
+ data->glDisableVertexAttribArray(GLES2_ATTRIBUTE_TEXCOORD);
+
+ data->drawstate.blend = SDL_BLENDMODE_INVALID;
+ data->drawstate.color = 0xFFFFFFFF;
+ data->drawstate.clear_color = 0xFFFFFFFF;
+ data->drawstate.projection[3][0] = -1.0f;
+ data->drawstate.projection[3][3] = 1.0f;
+
+ GL_CheckError("", renderer);
return renderer;
@@ -2261,6 +2097,23 @@ error:
return NULL;
}
+SDL_RenderDriver GLES2_RenderDriver = {
+ GLES2_CreateRenderer,
+ {
+ "opengles2",
+ (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
+ 4,
+ {
+ SDL_PIXELFORMAT_ARGB8888,
+ SDL_PIXELFORMAT_ABGR8888,
+ SDL_PIXELFORMAT_RGB888,
+ SDL_PIXELFORMAT_BGR888
+ },
+ 0,
+ 0
+ }
+};
+
#endif /* SDL_VIDEO_RENDER_OGL_ES2 && !SDL_RENDER_DISABLED */
/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/render/opengles2/SDL_shaders_gles2.c b/src/render/opengles2/SDL_shaders_gles2.c
index f428a49456..7c3e6c17cf 100644
--- a/src/render/opengles2/SDL_shaders_gles2.c
+++ b/src/render/opengles2/SDL_shaders_gles2.c
@@ -69,13 +69,13 @@ static const Uint8 GLES2_FragmentSrc_SolidSrc_[] = " \
static const Uint8 GLES2_FragmentSrc_TextureABGRSrc_[] = " \
precision mediump float; \
uniform sampler2D u_texture; \
- uniform vec4 u_modulation; \
+ uniform vec4 u_color; \
varying vec2 v_texCoord; \
\
void main() \
{ \
gl_FragColor = texture2D(u_texture, v_texCoord); \
- gl_FragColor *= u_modulation; \
+ gl_FragColor *= u_color; \
} \
";
@@ -83,7 +83,7 @@ static const Uint8 GLES2_FragmentSrc_TextureABGRSrc_[] = " \
static const Uint8 GLES2_FragmentSrc_TextureARGBSrc_[] = " \
precision mediump float; \
uniform sampler2D u_texture; \
- uniform vec4 u_modulation; \
+ uniform vec4 u_color; \
varying vec2 v_texCoord; \
\
void main() \
@@ -92,7 +92,7 @@ static const Uint8 GLES2_FragmentSrc_TextureARGBSrc_[] = " \
gl_FragColor = abgr; \
gl_FragColor.r = abgr.b; \
gl_FragColor.b = abgr.r; \
- gl_FragColor *= u_modulation; \
+ gl_FragColor *= u_color; \
} \
";
@@ -100,7 +100,7 @@ static const Uint8 GLES2_FragmentSrc_TextureARGBSrc_[] = " \
static const Uint8 GLES2_FragmentSrc_TextureRGBSrc_[] = " \
precision mediump float; \
uniform sampler2D u_texture; \
- uniform vec4 u_modulation; \
+ uniform vec4 u_color; \
varying vec2 v_texCoord; \
\
void main() \
@@ -110,7 +110,7 @@ static const Uint8 GLES2_FragmentSrc_TextureRGBSrc_[] = " \
gl_FragColor.r = abgr.b; \
gl_FragColor.b = abgr.r; \
gl_FragColor.a = 1.0; \
- gl_FragColor *= u_modulation; \
+ gl_FragColor *= u_color; \
} \
";
@@ -118,7 +118,7 @@ static const Uint8 GLES2_FragmentSrc_TextureRGBSrc_[] = " \
static const Uint8 GLES2_FragmentSrc_TextureBGRSrc_[] = " \
precision mediump float; \
uniform sampler2D u_texture; \
- uniform vec4 u_modulation; \
+ uniform vec4 u_color; \
varying vec2 v_texCoord; \
\
void main() \
@@ -126,7 +126,7 @@ static const Uint8 GLES2_FragmentSrc_TextureBGRSrc_[] = " \
vec4 abgr = texture2D(u_texture, v_texCoord); \
gl_FragColor = abgr; \
gl_FragColor.a = 1.0; \
- gl_FragColor *= u_modulation; \
+ gl_FragColor *= u_color; \
} \
";
@@ -163,7 +163,7 @@ static const Uint8 GLES2_FragmentSrc_TextureBGRSrc_[] = " \
"uniform sampler2D u_texture;\n" \
"uniform sampler2D u_texture_u;\n" \
"uniform sampler2D u_texture_v;\n" \
-"uniform vec4 u_modulation;\n" \
+"uniform vec4 u_color;\n" \
"varying vec2 v_texCoord;\n" \
"\n" \
@@ -185,7 +185,7 @@ static const Uint8 GLES2_FragmentSrc_TextureBGRSrc_[] = " \
"\n" \
" // That was easy. :) \n" \
" gl_FragColor = vec4(rgb, 1);\n" \
-" gl_FragColor *= u_modulation;\n" \
+" gl_FragColor *= u_color;\n" \
"}" \
#define NV12_SHADER_BODY \
@@ -205,7 +205,7 @@ static const Uint8 GLES2_FragmentSrc_TextureBGRSrc_[] = " \
"\n" \
" // That was easy. :) \n" \
" gl_FragColor = vec4(rgb, 1);\n" \
-" gl_FragColor *= u_modulation;\n" \
+" gl_FragColor *= u_color;\n" \
"}" \
#define NV21_SHADER_BODY \
@@ -225,7 +225,7 @@ static const Uint8 GLES2_FragmentSrc_TextureBGRSrc_[] = " \
"\n" \
" // That was easy. :) \n" \
" gl_FragColor = vec4(rgb, 1);\n" \
-" gl_FragColor *= u_modulation;\n" \
+" gl_FragColor *= u_color;\n" \
"}" \
/* YUV to ABGR conversion */
@@ -284,13 +284,13 @@ static const Uint8 GLES2_FragmentSrc_TextureExternalOESSrc_[] = " \
#extension GL_OES_EGL_image_external : require\n\
precision mediump float; \
uniform samplerExternalOES u_texture; \
- uniform vec4 u_modulation; \
+ uniform vec4 u_color; \
varying vec2 v_texCoord; \
\
void main() \
{ \
gl_FragColor = texture2D(u_texture, v_texCoord); \
- gl_FragColor *= u_modulation; \
+ gl_FragColor *= u_color; \
} \
";
diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c
index babc2526a0..eaf2ac7054 100644
--- a/src/render/psp/SDL_render_psp.c
+++ b/src/render/psp/SDL_render_psp.c
@@ -23,6 +23,7 @@
#if SDL_VIDEO_RENDER_PSP
#include "SDL_hints.h"
+#include "SDL_assert.h"
#include "../SDL_sysrender.h"
#include <pspkernel.h>
@@ -42,74 +43,6 @@
/* PSP renderer implementation, based on the PGE */
-
-extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags);
-
-
-static SDL_Renderer *PSP_CreateRenderer(SDL_Window * window, Uint32 flags);
-static void PSP_WindowEvent(SDL_Renderer * renderer,
- const SDL_WindowEvent *event);
-static int PSP_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
-static int PSP_SetTextureColorMod(SDL_Renderer * renderer,
- SDL_Texture * texture);
-static int PSP_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * rect, const void *pixels,
- int pitch);
-static int PSP_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * rect, void **pixels, int *pitch);
-static void PSP_UnlockTexture(SDL_Renderer * renderer,
- SDL_Texture * texture);
-static int PSP_SetRenderTarget(SDL_Renderer * renderer,
- SDL_Texture * texture);
-static int PSP_UpdateViewport(SDL_Renderer * renderer);
-static int PSP_RenderClear(SDL_Renderer * renderer);
-static int PSP_RenderDrawPoints(SDL_Renderer * renderer,
- const SDL_FPoint * points, int count);
-static int PSP_RenderDrawLines(SDL_Renderer * renderer,
- const SDL_FPoint * points, int count);
-static int PSP_RenderFillRects(SDL_Renderer * renderer,
- const SDL_FRect * rects, int count);
-static int PSP_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * srcrect,
- const SDL_FRect * dstrect);
-static int PSP_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
- Uint32 pixel_format, void * pixels, int pitch);
-static int PSP_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * srcrect, const SDL_FRect * dstrect,
- const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip);
-static void PSP_RenderPresent(SDL_Renderer * renderer);
-static void PSP_DestroyTexture(SDL_Renderer * renderer,
- SDL_Texture * texture);
-static void PSP_DestroyRenderer(SDL_Renderer * renderer);
-
-/*
-SDL_RenderDriver PSP_RenderDriver = {
- PSP_CreateRenderer,
- {
- "PSP",
- (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
- 1,
- {SDL_PIXELFORMAT_ABGR8888},
- 0,
- 0}
-};
-*/
-SDL_RenderDriver PSP_RenderDriver = {
- .CreateRenderer = PSP_CreateRenderer,
- .info = {
- .name = "PSP",
- .flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE,
- .num_texture_formats = 4,
- .texture_formats = { [0] = SDL_PIXELFORMAT_BGR565,
- [1] = SDL_PIXELFORMAT_ABGR1555,
- [2] = SDL_PIXELFORMAT_ABGR4444,
- [3] = SDL_PIXELFORMAT_ABGR8888,
- },
- .max_texture_width = 512,
- .max_texture_height = 512,
- }
-};
-
#define PSP_SCREEN_WIDTH 480
#define PSP_SCREEN_HEIGHT 272
@@ -169,6 +102,42 @@ typedef struct
} VertTV;
+#define PI 3.14159265358979f
+
+#define radToDeg(x) ((x)*180.f/PI)
+#define degToRad(x) ((x)*PI/180.f)
+
+float MathAbs(float x)
+{
+ float result;
+
+ __asm__ volatile (
+ "mtv %1, S000\n"
+ "vabs.s S000, S000\n"
+ "mfv %0, S000\n"
+ : "=r"(result) : "r"(x));
+
+ return result;
+}
+
+void MathSincos(float r, float *s, float *c)
+{
+ __asm__ volatile (
+ "mtv %2, S002\n"
+ "vcst.s S003, VFPU_2_PI\n"
+ "vmul.s S002, S002, S003\n"
+ "vrot.p C000, S002, [s, c]\n"
+ "mfv %0, S000\n"
+ "mfv %1, S001\n"
+ : "=r"(*s), "=r"(*c): "r"(r));
+}
+
+void Swap(float *a, float *b)
+{
+ float n=*a;
+ *a = *b;
+ *b = n;
+}
/* Return next power of 2 */
static int
@@ -326,123 +295,9 @@ int TextureUnswizzle(PSP_TextureData *psp_texture)
return 1;
}
-SDL_Renderer *
-PSP_CreateRenderer(SDL_Window * window, Uint32 flags)
-{
-
- SDL_Renderer *renderer;
- PSP_RenderData *data;
- int pixelformat;
- renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
- if (!renderer) {
- SDL_OutOfMemory();
- return NULL;
- }
-
- data = (PSP_RenderData *) SDL_calloc(1, sizeof(*data));
- if (!data) {
- PSP_DestroyRenderer(renderer);
- SDL_OutOfMemory();
- return NULL;
- }
-
-
- renderer->WindowEvent = PSP_WindowEvent;
- renderer->CreateTexture = PSP_CreateTexture;
- renderer->SetTextureColorMod = PSP_SetTextureColorMod;
- renderer->UpdateTexture = PSP_UpdateTexture;
- renderer->LockTexture = PSP_LockTexture;
- renderer->UnlockTexture = PSP_UnlockTexture;
- renderer->SetRenderTarget = PSP_SetRenderTarget;
- renderer->UpdateViewport = PSP_UpdateViewport;
- renderer->RenderClear = PSP_RenderClear;
- renderer->RenderDrawPoints = PSP_RenderDrawPoints;
- renderer->RenderDrawLines = PSP_RenderDrawLines;
- renderer->RenderFillRects = PSP_RenderFillRects;
- renderer->RenderCopy = PSP_RenderCopy;
- renderer->RenderReadPixels = PSP_RenderReadPixels;
- renderer->RenderCopyEx = PSP_RenderCopyEx;
- renderer->RenderPresent = PSP_RenderPresent;
- renderer->DestroyTexture = PSP_DestroyTexture;
- renderer->DestroyRenderer = PSP_DestroyRenderer;
- renderer->info = PSP_RenderDriver.info;
- renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
- renderer->driverdata = data;
- renderer->window = window;
-
- if (data->initialized != SDL_FALSE)
- return 0;
- data->initialized = SDL_TRUE;
-
- if (flags & SDL_RENDERER_PRESENTVSYNC) {
- data->vsync = SDL_TRUE;
- } else {
- data->vsync = SDL_FALSE;
- }
-
- pixelformat=PixelFormatToPSPFMT(SDL_GetWindowPixelFormat(window));
- switch(pixelformat)
- {
- case GU_PSM_4444:
- case GU_PSM_5650:
- case GU_PSM_5551:
- data->frontbuffer = (unsigned int *)(PSP_FRAME_BUFFER_SIZE<<1);
- data->backbuffer = (unsigned int *)(0);
- data->bpp = 2;
- data->psm = pixelformat;
- break;
- default:
- data->frontbuffer = (unsigned int *)(PSP_FRAME_BUFFER_SIZE<<2);
- data->backbuffer = (unsigned int *)(0);
- data->bpp = 4;
- data->psm = GU_PSM_8888;
- break;
- }
-
- sceGuInit();
- /* setup GU */
- sceGuStart(GU_DIRECT, DisplayList);
- sceGuDrawBuffer(data->psm, data->frontbuffer, PSP_FRAME_BUFFER_WIDTH);
- sceGuDispBuffer(PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT, data->backbuffer, PSP_FRAME_BUFFER_WIDTH);
-
-
- sceGuOffset(2048 - (PSP_SCREEN_WIDTH>>1), 2048 - (PSP_SCREEN_HEIGHT>>1));
- sceGuViewport(2048, 2048, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT);
-
- data->frontbuffer = vabsptr(data->frontbuffer);
- data->backbuffer = vabsptr(data->backbuffer);
-
- /* Scissoring */
- sceGuScissor(0, 0, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT);
- sceGuEnable(GU_SCISSOR_TEST);
-
- /* Backface culling */
- sceGuFrontFace(GU_CCW);
- sceGuEnable(GU_CULL_FACE);
-
- /* Texturing */
- sceGuEnable(GU_TEXTURE_2D);
- sceGuShadeModel(GU_SMOOTH);
- sceGuTexWrap(GU_REPEAT, GU_REPEAT);
-
- /* Blending */
- sceGuEnable(GU_BLEND);
- sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0);
-
- sceGuTexFilter(GU_LINEAR,GU_LINEAR);
-
- sceGuFinish();
- sceGuSync(0,0);
- sceDisplayWaitVblankStartCB();
- sceGuDisplay(GU_TRUE);
-
- return renderer;
-}
-
static void
PSP_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
{
-
}
@@ -576,383 +431,429 @@ PSP_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
static int
PSP_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
{
-
return 0;
}
static int
-PSP_UpdateViewport(SDL_Renderer * renderer)
+PSP_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd)
{
-
- return 0;
+ return 0; /* nothing to do in this backend. */
}
-
-static void
-PSP_SetBlendMode(SDL_Renderer * renderer, int blendMode)
-{
- PSP_RenderData *data = (PSP_RenderData *) renderer->driverdata;
- if (blendMode != data-> currentBlendMode) {
- switch (blendMode) {
- case SDL_BLENDMODE_NONE:
- sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA);
- sceGuDisable(GU_BLEND);
- break;
- case SDL_BLENDMODE_BLEND:
- sceGuTexFunc(GU_TFX_MODULATE , GU_TCC_RGBA);
- sceGuEnable(GU_BLEND);
- sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0 );
- break;
- case SDL_BLENDMODE_ADD:
- sceGuTexFunc(GU_TFX_MODULATE , GU_TCC_RGBA);
- sceGuEnable(GU_BLEND);
- sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_FIX, 0, 0x00FFFFFF );
- break;
- case SDL_BLENDMODE_MOD:
- sceGuTexFunc(GU_TFX_MODULATE , GU_TCC_RGBA);
- sceGuEnable(GU_BLEND);
- sceGuBlendFunc( GU_ADD, GU_FIX, GU_SRC_COLOR, 0, 0);
- break;
- }
- data->currentBlendMode = blendMode;
- }
-}
-
-
-
static int
-PSP_RenderClear(SDL_Renderer * renderer)
+PSP_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
{
- /* start list */
- StartDrawing(renderer);
- int color = renderer->a << 24 | renderer->b << 16 | renderer->g << 8 | renderer->r;
- sceGuClearColor(color);
- sceGuClearDepth(0);
- sceGuClear(GU_COLOR_BUFFER_BIT|GU_DEPTH_BUFFER_BIT|GU_FAST_CLEAR_BIT);
+ VertV *verts = (VertV *) SDL_AllocateRenderVertices(renderer, count * sizeof (VertV), 4, &cmd->data.draw.first);
+ size_t i;
- return 0;
-}
+ if (!verts) {
+ return -1;
+ }
-static int
-PSP_RenderDrawPoints(SDL_Renderer * renderer, const SDL_FPoint * points,
- int count)
-{
- int color = renderer->a << 24 | renderer->b << 16 | renderer->g << 8 | renderer->r;
- int i;
- StartDrawing(renderer);
- VertV* vertices = (VertV*)sceGuGetMemory(count*sizeof(VertV));
+ cmd->data.draw.count = count;
- for (i = 0; i < count; ++i) {
- vertices[i].x = points[i].x;
- vertices[i].y = points[i].y;
- vertices[i].z = 0.0f;
+ for (i = 0; i < count; i++, verts++, points++) {
+ verts->x = points->x;
+ verts->y = points->y;
+ verts->z = 0.0f;
}
- sceGuDisable(GU_TEXTURE_2D);
- sceGuColor(color);
- sceGuShadeModel(GU_FLAT);
- sceGuDrawArray(GU_POINTS, GU_VERTEX_32BITF|GU_TRANSFORM_2D, count, 0, vertices);
- sceGuShadeModel(GU_SMOOTH);
- sceGuEnable(GU_TEXTURE_2D);
return 0;
}
static int
-PSP_RenderDrawLines(SDL_Renderer * renderer, const SDL_FPoint * points,
- int count)
+PSP_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects, int count)
{
- int color = renderer->a << 24 | renderer->b << 16 | renderer->g << 8 | renderer->r;
- int i;
- StartDrawing(renderer);
- VertV* vertices = (VertV*)sceGuGetMemory(count*sizeof(VertV));
+ VertV *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, count * 2 * sizeof (VertV), 4, &cmd->data.draw.first);
+ size_t i;
- for (i = 0; i < count; ++i) {
- vertices[i].x = points[i].x;
- vertices[i].y = points[i].y;
- vertices[i].z = 0.0f;
+ if (!verts) {
+ return -1;
}
- sceGuDisable(GU_TEXTURE_2D);
- sceGuColor(color);
- sceGuShadeModel(GU_FLAT);
- sceGuDrawArray(GU_LINE_STRIP, GU_VERTEX_32BITF|GU_TRANSFORM_2D, count, 0, vertices);
- sceGuShadeModel(GU_SMOOTH);
- sceGuEnable(GU_TEXTURE_2D);
-
- return 0;
-}
-
-static int
-PSP_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects,
- int count)
-{
- int color = renderer->a << 24 | renderer->b << 16 | renderer->g << 8 | renderer->r;
- int i;
- StartDrawing(renderer);
-
- for (i = 0; i < count; ++i) {
+ cmd->data.draw.count = count;
+ for (i = 0; i < count; i++, rects++) {
const SDL_FRect *rect = &rects[i];
- VertV* vertices = (VertV*)sceGuGetMemory((sizeof(VertV)<<1));
- vertices[0].x = rect->x;
- vertices[0].y = rect->y;
- vertices[0].z = 0.0f;
-
- vertices[1].x = rect->x + rect->w;
- vertices[1].y = rect->y + rect->h;
- vertices[1].z = 0.0f;
-
- sceGuDisable(GU_TEXTURE_2D);
- sceGuColor(color);
- sceGuShadeModel(GU_FLAT);
- sceGuDrawArray(GU_SPRITES, GU_VERTEX_32BITF|GU_TRANSFORM_2D, 2, 0, vertices);
- sceGuShadeModel(GU_SMOOTH);
- sceGuEnable(GU_TEXTURE_2D);
+ verts->x = rect->x;
+ verts->y = rect->y;
+ verts->z = 0.0f;
+ verts++;
+
+ verts->x = rect->x + rect->w;
+ verts->y = rect->y + rect->h;
+ verts->z = 0.0f;
+ verts++;
}
return 0;
}
-
-#define PI 3.14159265358979f
-
-#define radToDeg(x) ((x)*180.f/PI)
-#define degToRad(x) ((x)*PI/180.f)
-
-float MathAbs(float x)
-{
- float result;
-
- __asm__ volatile (
- "mtv %1, S000\n"
- "vabs.s S000, S000\n"
- "mfv %0, S000\n"
- : "=r"(result) : "r"(x));
-
- return result;
-}
-
-void MathSincos(float r, float *s, float *c)
-{
- __asm__ volatile (
- "mtv %2, S002\n"
- "vcst.s S003, VFPU_2_PI\n"
- "vmul.s S002, S002, S003\n"
- "vrot.p C000, S002, [s, c]\n"
- "mfv %0, S000\n"
- "mfv %1, S001\n"
- : "=r"(*s), "=r"(*c): "r"(r));
-}
-
-void Swap(float *a, float *b)
-{
- float n=*a;
- *a = *b;
- *b = n;
-}
-
static int
-PSP_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * srcrect, const SDL_FRect * dstrect)
+PSP_QueueCopy(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
+ const SDL_Rect * srcrect, const SDL_FRect * dstrect)
{
- float x, y, width, height;
- float u0, v0, u1, v1;
- unsigned char alpha;
-
- x = dstrect->x;
- y = dstrect->y;
- width = dstrect->w;
- height = dstrect->h;
-
- u0 = srcrect->x;
- v0 = srcrect->y;
- u1 = srcrect->x + srcrect->w;
- v1 = srcrect->y + srcrect->h;
-
- alpha = texture->a;
+ VertTV *verts;
+ const float x = dstrect->x;
+ const float y = dstrect->y;
+ const float width = dstrect->w;
+ const float height = dstrect->h;
- StartDrawing(renderer);
- TextureActivate(texture);
- PSP_SetBlendMode(renderer, renderer->blendMode);
-
- if(alpha != 255)
- {
- sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA);
- sceGuColor(GU_RGBA(255, 255, 255, alpha));
- }else{
- sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA);
- sceGuColor(0xFFFFFFFF);
- }
+ const float u0 = srcrect->x;
+ const float v0 = srcrect->y;
+ const float u1 = srcrect->x + srcrect->w;
+ const float v1 = srcrect->y + srcrect->h;
if((MathAbs(u1) - MathAbs(u0)) < 64.0f)
{
- VertTV* vertices = (VertTV*)sceGuGetMemory((sizeof(VertTV))<<1);
-
- vertices[0].u = u0;
- vertices[0].v = v0;
- vertices[0].x = x;
- vertices[0].y = y;
- vertices[0].z = 0;
-
- vertices[1].u = u1;
- vertices[1].v = v1;
- vertices[1].x = x + width;
- vertices[1].y = y + height;
- vertices[1].z = 0;
+ verts = (VertTV *) SDL_AllocateRenderVertices(renderer, 2 * sizeof (VertTV), 4, &cmd->data.draw.first);
+ if (!verts) {
+ return -1;
+ }
- sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF|GU_VERTEX_32BITF|GU_TRANSFORM_2D, 2, 0, vertices);
+ cmd->data.draw.count = 1;
+
+ verts->u = u0;
+ verts->v = v0;
+ verts->x = x;
+ verts->y = y;
+ verts->z = 0;
+ verts++;
+
+ verts->u = u1;
+ verts->v = v1;
+ verts->x = x + width;
+ verts->y = y + height;
+ verts->z = 0;
+ verts++;
}
else
{
float start, end;
float curU = u0;
float curX = x;
- float endX = x + width;
- float slice = 64.0f;
+ const float endX = x + width;
+ const float slice = 64.0f;
+ const size_t count = SDL_ceilf(width / slice);
+ size_t i;
float ustep = (u1 - u0)/width * slice;
if(ustep < 0.0f)
ustep = -ustep;
- for(start = 0, end = width; start < end; start += slice)
+ cmd->data.draw.count = count;
+
+ verts = (VertTV *) SDL_AllocateRenderVertices(renderer, count * sizeof (VertTV), 4, &cmd->data.draw.first);
+ if (!verts) {
+ return -1;
+ }
+
+
+ for(i = 0, start = 0, end = width; i < count; i++, start += slice)
{
- VertTV* vertices = (VertTV*)sceGuGetMemory((sizeof(VertTV))<<1);
+ const float polyWidth = ((curX + slice) > endX) ? (endX - curX) : slice;
+ const float sourceWidth = ((curU + ustep) > u1) ? (u1 - curU) : ustep;
- float polyWidth = ((curX + slice) > endX) ? (endX - curX) : slice;
- float sourceWidth = ((curU + ustep) > u1) ? (u1 - curU) : ustep;
+ SDL_assert(start < end);
- vertices[0].u = curU;
- vertices[0].v = v0;
- vertices[0].x = curX;
- vertices[0].y = y;
- vertices[0].z = 0;
+ verts->u = curU;
+ verts->v = v0;
+ verts->x = curX;
+ verts->y = y;
+ verts->z = 0;
curU += sourceWidth;
curX += polyWidth;
- vertices[1].u = curU;
- vertices[1].v = v1;
- vertices[1].x = curX;
- vertices[1].y = (y + height);
- vertices[1].z = 0;
-
- sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF|GU_VERTEX_32BITF|GU_TRANSFORM_2D, 2, 0, vertices);
+ verts->u = curU;
+ verts->v = v1;
+ verts->x = curX;
+ verts->y = (y + height);
+ verts->z = 0;
}
}
- if(alpha != 255)
- sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA);
return 0;
}
static int
-PSP_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
- Uint32 pixel_format, void * pixels, int pitch)
-
+PSP_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
+ const SDL_Rect * srcrect, const SDL_FRect * dstrect,
+ const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
{
- return SDL_Unsupported();
-}
+ VertTV *verts = (VertTV *) SDL_AllocateRenderVertices(renderer, 4 * sizeof (VertTV), 4, &cmd->data.draw.first);
+ const float centerx = center->x;
+ const float centery = center->y;
+ const float x = dstrect->x + centerx;
+ const float y = dstrect->y + centery;
+ const float width = dstrect->w - centerx;
+ const float height = dstrect->h - centery;
+ float s, c;
+
+ float u0 = srcrect->x;
+ float v0 = srcrect->y;
+ float u1 = srcrect->x + srcrect->w;
+ float v1 = srcrect->y + srcrect->h;
+
+
+ if (!verts) {
+ return -1;
+ }
+ cmd->data.draw.count = 1;
-static int
-PSP_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * srcrect, const SDL_FRect * dstrect,
- const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
-{
- float x, y, width, height;
- float u0, v0, u1, v1;
- unsigned char alpha;
- float centerx, centery;
+ MathSincos(degToRad(angle), &s, &c);
- x = dstrect->x;
- y = dstrect->y;
- width = dstrect->w;
- height = dstrect->h;
+ const float cw = c * width;
+ const float sw = s * width;
+ const float ch = c * height;
+ const float sh = s * height;
- u0 = srcrect->x;
- v0 = srcrect->y;
- u1 = srcrect->x + srcrect->w;
- v1 = srcrect->y + srcrect->h;
+ if (flip & SDL_FLIP_VERTICAL) {
+ Swap(&v0, &v1);
+ }
- centerx = center->x;
- centery = center->y;
+ if (flip & SDL_FLIP_HORIZONTAL) {
+ Swap(&u0, &u1);
+ }
- alpha = texture->a;
+ verts->u = u0;
+ verts->v = v0;
+ verts->x = x - cw + sh;
+ verts->y = y - sw - ch;
+ verts->z = 0;
+ verts++;
+
+ verts->u = u0;
+ verts->v = v1;
+ verts->x = x - cw - sh;
+ verts->y = y - sw + ch;
+ verts->z = 0;
+ verts++;
+
+ verts->u = u1;
+ verts->v = v1;
+ verts->x = x + cw - sh;
+ verts->y = y + sw + ch;
+ verts->z = 0;
+ verts++;
+
+ verts->u = u1;
+ verts->v = v0;
+ verts->x = x + cw + sh;
+ verts->y = y + sw - ch;
+ verts->z = 0;
+ verts++;
- StartDrawing(renderer);
- TextureActivate(texture);
- PSP_SetBlendMode(renderer, renderer->blendMode);
+ return 0;
+}
- if(alpha != 255)
- {
- sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA);
- sceGuColor(GU_RGBA(255, 255, 255, alpha));
- }else{
- sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA);
- sceGuColor(0xFFFFFFFF);
+static void
+PSP_SetBlendMode(SDL_Renderer * renderer, int blendMode)
+{
+ PSP_RenderData *data = (PSP_RenderData *) renderer->driverdata;
+ if (blendMode != data-> currentBlendMode) {
+ switch (blendMode) {
+ case SDL_BLENDMODE_NONE:
+ sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA);
+ sceGuDisable(GU_BLEND);
+ break;
+ case SDL_BLENDMODE_BLEND:
+ sceGuTexFunc(GU_TFX_MODULATE , GU_TCC_RGBA);
+ sceGuEnable(GU_BLEND);
+ sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0 );
+ break;
+ case SDL_BLENDMODE_ADD:
+ sceGuTexFunc(GU_TFX_MODULATE , GU_TCC_RGBA);
+ sceGuEnable(GU_BLEND);
+ sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_FIX, 0, 0x00FFFFFF );
+ break;
+ case SDL_BLENDMODE_MOD:
+ sceGuTexFunc(GU_TFX_MODULATE , GU_TCC_RGBA);
+ sceGuEnable(GU_BLEND);
+ sceGuBlendFunc( GU_ADD, GU_FIX, GU_SRC_COLOR, 0, 0);
+ break;
+ }
+ data->currentBlendMode = blendMode;
}
+}
-/* x += width * 0.5f; */
-/* y += height * 0.5f; */
- x += centerx;
- y += centery;
+static int
+PSP_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
+{
+ PSP_RenderData *data = (PSP_RenderData *) renderer->driverdata;
+ size_t i;
- float c, s;
+ StartDrawing(renderer);
- MathSincos(degToRad(angle), &s, &c);
+ /* note that before the renderer interface change, this would do extrememly small
+ batches with sceGuGetMemory()--a few vertices at a time--and it's not clear that
+ this won't fail if you try to push 100,000 draw calls in a single batch.
+ I don't know what the limits on PSP hardware are. It might be useful to have
+ rendering backends report a reasonable maximum, so the higher level can flush
+ if we appear to be exceeding that. */
+ Uint8 *gpumem = (Uint8 *) sceGuGetMemory(vertsize);
+ if (!gpumem) {
+ return SDL_SetError("Couldn't obtain a %d-byte vertex buffer!", (int) vertsize);
+ }
+ SDL_memcpy(gpumem, vertices, vertsize);
-/* width *= 0.5f; */
-/* height *= 0.5f; */
- width -= centerx;
- height -= centery;
+ while (cmd) {
+ switch (cmd->command) {
+ case SDL_RENDERCMD_SETDRAWCOLOR: {
+ break; /* !!! FIXME: we could cache drawstate like color */
+ }
+ case SDL_RENDERCMD_SETVIEWPORT: {
+ SDL_Rect *viewport = &data->drawstate.viewport;
+ if (SDL_memcmp(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect)) != 0) {
+ SDL_memcpy(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect));
+ data->drawstate.viewport_dirty = SDL_TRUE;
+ }
+ break;
+ }
- float cw = c*width;
- float sw = s*width;
- float ch = c*height;
- float sh = s*height;
+ case SDL_RENDERCMD_SETCLIPRECT: {
+ const SDL_Rect *rect = &cmd->data.cliprect.rect;
+ if (data->drawstate.cliprect_enabled != cmd->data.cliprect.enabled) {
+ data->drawstate.cliprect_enabled = cmd->data.cliprect.enabled;
+ data->drawstate.cliprect_enabled_dirty = SDL_TRUE;
+ }
+ if (SDL_memcmp(&data->drawstate.cliprect, rect, sizeof (SDL_Rect)) != 0) {
+ SDL_memcpy(&data->drawstate.cliprect, rect, sizeof (SDL_Rect));
+ data->drawstate.cliprect_dirty = SDL_TRUE;
+ }
+ break;
+ }
- VertTV* vertices = (VertTV*)sceGuGetMemory(sizeof(VertTV)<<2);
+ case SDL_RENDERCMD_CLEAR: {
+ const Uint8 r = cmd->data.color.r;
+ const Uint8 g = cmd->data.color.g;
+ const Uint8 b = cmd->data.color.b;
+ const Uint8 a = cmd->data.color.a;
+ const Uint32 color = ((a << 24) | (b << 16) | (g << 8) | r);
+ /* !!! FIXME: we could cache drawstate like clear color */
+ sceGuClearColor(color);
+ sceGuClearDepth(0);
+ sceGuClear(GU_COLOR_BUFFER_BIT|GU_DEPTH_BUFFER_BIT|GU_FAST_CLEAR_BIT);
+ break;
+ }
- vertices[0].u = u0;
- vertices[0].v = v0;
- vertices[0].x = x - cw + sh;
- vertices[0].y = y - sw - ch;
- vertices[0].z = 0;
+ case SDL_RENDERCMD_DRAW_POINTS: {
+ const size_t count = cmd->data.draw.count;
+ const VertV *verts = (VertV *) (gpumem + cmd->data.draw.first);
+ const Uint8 r = cmd->data.color.r;
+ const Uint8 g = cmd->data.color.g;
+ const Uint8 b = cmd->data.color.b;
+ const Uint8 a = cmd->data.color.a;
+ const Uint32 color = ((a << 24) | (b << 16) | (g << 8) | r);
+ /* !!! FIXME: we could cache draw state like color, texturing, etc */
+ sceGuColor(color);
+ sceGuDisable(GU_TEXTURE_2D);
+ sceGuShadeModel(GU_FLAT);
+ sceGuDrawArray(GU_POINTS, GU_VERTEX_32BITF|GU_TRANSFORM_2D, count, 0, verts);
+ sceGuShadeModel(GU_SMOOTH);
+ sceGuEnable(GU_TEXTURE_2D);
+ break;
+ }
- vertices[1].u = u0;
- vertices[1].v = v1;
- vertices[1].x = x - cw - sh;
- vertices[1].y = y - sw + ch;
- vertices[1].z = 0;
+ case SDL_RENDERCMD_DRAW_LINES: {
+ const size_t count = cmd->data.draw.count;
+ const VertV *verts = (VertV *) (gpumem + cmd->data.draw.first);
+ const Uint8 r = cmd->data.color.r;
+ const Uint8 g = cmd->data.color.g;
+ const Uint8 b = cmd->data.color.b;
+ const Uint8 a = cmd->data.color.a;
+ const Uint32 color = ((a << 24) | (b << 16) | (g << 8) | r);
+ /* !!! FIXME: we could cache draw state like color, texturing, etc */
+ sceGuColor(color);
+ sceGuDisable(GU_TEXTURE_2D);
+ sceGuShadeModel(GU_FLAT);
+ sceGuDrawArray(GU_LINE_STRIP, GU_VERTEX_32BITF|GU_TRANSFORM_2D, count, 0, verts);
+ sceGuShadeModel(GU_SMOOTH);
+ sceGuEnable(GU_TEXTURE_2D);
+ break;
+ }
- vertices[2].u = u1;
- vertices[2].v = v1;
- vertices[2].x = x + cw - sh;
- vertices[2].y = y + sw + ch;
- vertices[2].z = 0;
+ case SDL_RENDERCMD_FILL_RECTS: {
+ const size_t count = cmd->data.draw.count;
+ const VertV *verts = (VertV *) (gpumem + cmd->data.draw.first);
+ const Uint8 r = cmd->data.color.r;
+ const Uint8 g = cmd->data.color.g;
+ const Uint8 b = cmd->data.color.b;
+ const Uint8 a = cmd->data.color.a;
+ const Uint32 color = ((a << 24) | (b << 16) | (g << 8) | r);
+ /* !!! FIXME: we could cache draw state like color, texturing, etc */
+ sceGuColor(color);
+ sceGuDisable(GU_TEXTURE_2D);
+ sceGuShadeModel(GU_FLAT);
+ sceGuDrawArray(GU_SPRITES, GU_VERTEX_32BITF|GU_TRANSFORM_2D, 2 * count, 0, verts);
+ sceGuShadeModel(GU_SMOOTH);
+ sceGuEnable(GU_TEXTURE_2D);
+ break;
+ }
- vertices[3].u = u1;
- vertices[3].v = v0;
- vertices[3].x = x + cw + sh;
- vertices[3].y = y + sw - ch;
- vertices[3].z = 0;
+ case SDL_RENDERCMD_COPY: {
+ const size_t count = cmd->data.draw.count;
+ const VertTV *verts = (VertTV *) (gpumem + cmd->data.draw.first);
+ const Uint8 alpha = cmd->data.draw.a;
+ TextureActivate(cmd->data.draw.texture);
+ PSP_SetBlendMode(renderer, cmd->data.draw.blend);
+
+ if(alpha != 255) { /* !!! FIXME: is this right? */
+ sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA);
+ sceGuColor(GU_RGBA(255, 255, 255, alpha));
+ } else {
+ sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA);
+ sceGuColor(0xFFFFFFFF);
+ }
+
+ sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF|GU_VERTEX_32BITF|GU_TRANSFORM_2D, 2 * count, 0, verts);
+
+ if(alpha != 255) {
+ sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA);
+ }
+ break;
+ }
- if (flip & SDL_FLIP_VERTICAL) {
- Swap(&vertices[0].v, &vertices[2].v);
- Swap(&vertices[1].v, &vertices[3].v);
- }
- if (flip & SDL_FLIP_HORIZONTAL) {
- Swap(&vertices[0].u, &vertices[2].u);
- Swap(&vertices[1].u, &vertices[3].u);
- }
+ case SDL_RENDERCMD_COPY_EX: {
+ const VertTV *verts = (VertTV *) (gpumem + cmd->data.draw.first);
+ const Uint8 alpha = cmd->data.draw.a;
+ TextureActivate(cmd->data.draw.texture);
+ PSP_SetBlendMode(renderer, cmd->data.draw.blend);
+
+ if(alpha != 255) { /* !!! FIXME: is this right? */
+ sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA);
+ sceGuColor(GU_RGBA(255, 255, 255, alpha));
+ } else {
+ sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA);
+ sceGuColor(0xFFFFFFFF);
+ }
+
+ sceGuDrawArray(GU_TRIANGLE_FAN, GU_TEXTURE_32BITF|GU_VERTEX_32BITF|GU_TRANSFORM_2D, 4, 0, verts);
+
+ if(alpha != 255) {
+ sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA);
+ }
+ break;
+ }
+
+ case SDL_RENDERCMD_NO_OP:
+ break;
+ }
- sceGuDrawArray(GU_TRIANGLE_FAN, GU_TEXTURE_32BITF|GU_VERTEX_32BITF|GU_TRANSFORM_2D, 4, 0, vertices);
+ cmd = cmd->next;
+ }
- if(alpha != 255)
- sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA);
return 0;
}
+static int
+PSP_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
+ Uint32 pixel_format, void * pixels, int pitch)
+{
+ return SDL_Unsupported();
+}
+
static void
PSP_RenderPresent(SDL_Renderer * renderer)
{
@@ -1010,6 +911,136 @@ PSP_DestroyRenderer(SDL_Renderer * renderer)
SDL_free(renderer);
}
+SDL_Renderer *
+PSP_CreateRenderer(SDL_Window * window, Uint32 flags)
+{
+
+ SDL_Renderer *renderer;
+ PSP_RenderData *data;
+ int pixelformat;
+ renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
+ if (!renderer) {
+ SDL_OutOfMemory();
+ return NULL;
+ }
+
+ data = (PSP_RenderData *) SDL_calloc(1, sizeof(*data));
+ if (!data) {
+ PSP_DestroyRenderer(renderer);
+ SDL_OutOfMemory();
+ return NULL;
+ }
+
+
+ renderer->WindowEvent = PSP_WindowEvent;
+ renderer->CreateTexture = PSP_CreateTexture;
+ renderer->SetTextureColorMod = PSP_SetTextureColorMod;
+ renderer->UpdateTexture = PSP_UpdateTexture;
+ renderer->LockTexture = PSP_LockTexture;
+ renderer->UnlockTexture = PSP_UnlockTexture;
+ renderer->SetRenderTarget = PSP_SetRenderTarget;
+ renderer->QueueSetViewport = PSP_QueueSetViewport;
+ renderer->QueueSetDrawColor = PSP_QueueSetViewport; /* SetViewport and SetDrawColor are (currently) no-ops. */
+ renderer->QueueDrawPoints = PSP_QueueDrawPoints;
+ renderer->QueueDrawLines = PSP_QueueDrawPoints; /* lines and points queue vertices the same way. */
+ renderer->QueueFillRects = PSP_QueueFillRects;
+ renderer->QueueCopy = PSP_QueueCopy;
+ renderer->QueueCopyEx = PSP_QueueCopyEx;
+ renderer->RunCommandQueue = PSP_RunCommandQueue;
+ renderer->RenderReadPixels = PSP_RenderReadPixels;
+ renderer->RenderPresent = PSP_RenderPresent;
+ renderer->DestroyTexture = PSP_DestroyTexture;
+ renderer->DestroyRenderer = PSP_DestroyRenderer;
+ renderer->info = PSP_RenderDriver.info;
+ renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
+ renderer->driverdata = data;
+ renderer->window = window;
+
+ if (data->initialized != SDL_FALSE)
+ return 0;
+ data->initialized = SDL_TRUE;
+
+ if (flags & SDL_RENDERER_PRESENTVSYNC) {
+ data->vsync = SDL_TRUE;
+ } else {
+ data->vsync = SDL_FALSE;
+ }
+
+ pixelformat=PixelFormatToPSPFMT(SDL_GetWindowPixelFormat(window));
+ switch(pixelformat)
+ {
+ case GU_PSM_4444:
+ case GU_PSM_5650:
+ case GU_PSM_5551:
+ data->frontbuffer = (unsigned int *)(PSP_FRAME_BUFFER_SIZE<<1);
+ data->backbuffer = (unsigned int *)(0);
+ data->bpp = 2;
+ data->psm = pixelformat;
+ break;
+ default:
+ data->frontbuffer = (unsigned int *)(PSP_FRAME_BUFFER_SIZE<<2);
+ data->backbuffer = (unsigned int *)(0);
+ data->bpp = 4;
+ data->psm = GU_PSM_8888;
+ break;
+ }
+
+ sceGuInit();
+ /* setup GU */
+ sceGuStart(GU_DIRECT, DisplayList);
+ sceGuDrawBuffer(data->psm, data->frontbuffer, PSP_FRAME_BUFFER_WIDTH);
+ sceGuDispBuffer(PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT, data->backbuffer, PSP_FRAME_BUFFER_WIDTH);
+
+
+ sceGuOffset(2048 - (PSP_SCREEN_WIDTH>>1), 2048 - (PSP_SCREEN_HEIGHT>>1));
+ sceGuViewport(2048, 2048, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT);
+
+ data->frontbuffer = vabsptr(data->frontbuffer);
+ data->backbuffer = vabsptr(data->backbuffer);
+
+ /* Scissoring */
+ sceGuScissor(0, 0, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT);
+ sceGuEnable(GU_SCISSOR_TEST);
+
+ /* Backface culling */
+ sceGuFrontFace(GU_CCW);
+ sceGuEnable(GU_CULL_FACE);
+
+ /* Texturing */
+ sceGuEnable(GU_TEXTURE_2D);
+ sceGuShadeModel(GU_SMOOTH);
+ sceGuTexWrap(GU_REPEAT, GU_REPEAT);
+
+ /* Blending */
+ sceGuEnable(GU_BLEND);
+ sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0);
+
+ sceGuTexFilter(GU_LINEAR,GU_LINEAR);
+
+ sceGuFinish();
+ sceGuSync(0,0);
+ sceDisplayWaitVblankStartCB();
+ sceGuDisplay(GU_TRUE);
+
+ return renderer;
+}
+
+SDL_RenderDriver PSP_RenderDriver = {
+ .CreateRenderer = PSP_CreateRenderer,
+ .info = {
+ .name = "PSP",
+ .flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE,
+ .num_texture_formats = 4,
+ .texture_formats = { [0] = SDL_PIXELFORMAT_BGR565,
+ [1] = SDL_PIXELFORMAT_ABGR1555,
+ [2] = SDL_PIXELFORMAT_ABGR4444,
+ [3] = SDL_PIXELFORMAT_ABGR8888,
+ },
+ .max_texture_width = 512,
+ .max_texture_height = 512,
+ }
+};
+
#endif /* SDL_VIDEO_RENDER_PSP */
/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/render/software/SDL_render_sw.c b/src/render/software/SDL_render_sw.c
index 709dfe8e48..4748873e88 100644
--- a/src/render/software/SDL_render_sw.c
+++ b/src/render/software/SDL_render_sw.c
@@ -25,6 +25,7 @@
#include "../SDL_sysrender.h"
#include "SDL_render_sw_c.h"
#include "SDL_hints.h"
+#include "SDL_assert.h"
#include "SDL_draw.h"
#include "SDL_blendfillrect.h"
@@ -36,65 +37,6 @@
/* SDL surface based renderer implementation */
-static SDL_Renderer *SW_CreateRenderer(SDL_Window * window, Uint32 flags);
-static void SW_WindowEvent(SDL_Renderer * renderer,
- const SDL_WindowEvent *event);
-static int SW_GetOutputSize(SDL_Renderer * renderer, int *w, int *h);
-static int SW_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
-static int SW_SetTextureColorMod(SDL_Renderer * renderer,
- SDL_Texture * texture);
-static int SW_SetTextureAlphaMod(SDL_Renderer * renderer,
- SDL_Texture * texture);
-static int SW_SetTextureBlendMode(SDL_Renderer * renderer,
- SDL_Texture * texture);
-static int SW_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * rect, const void *pixels,
- int pitch);
-static int SW_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * rect, void **pixels, int *pitch);
-static void SW_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
-static int SW_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture);
-static int SW_UpdateViewport(SDL_Renderer * renderer);
-static int SW_UpdateClipRect(SDL_Renderer * renderer);
-static int SW_RenderClear(SDL_Renderer * renderer);
-static int SW_RenderDrawPoints(SDL_Renderer * renderer,
- const SDL_FPoint * points, int count);
-static int SW_RenderDrawLines(SDL_Renderer * renderer,
- const SDL_FPoint * points, int count);
-static int SW_RenderFillRects(SDL_Renderer * renderer,
- const SDL_FRect * rects, int count);
-static int SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * srcrect, const SDL_FRect * dstrect);
-static int SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * srcrect, const SDL_FRect * dstrect,
- const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip);
-static int SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
- Uint32 format, void * pixels, int pitch);
-static void SW_RenderPresent(SDL_Renderer * renderer);
-static void SW_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture);
-static void SW_DestroyRenderer(SDL_Renderer * renderer);
-
-
-SDL_RenderDriver SW_RenderDriver = {
- SW_CreateRenderer,
- {
- "software",
- SDL_RENDERER_SOFTWARE | SDL_RENDERER_TARGETTEXTURE,
- 8,
- {
- SDL_PIXELFORMAT_ARGB8888,
- SDL_PIXELFORMAT_ABGR8888,
- SDL_PIXELFORMAT_RGBA8888,
- SDL_PIXELFORMAT_BGRA8888,
- SDL_PIXELFORMAT_RGB888,
- SDL_PIXELFORMAT_BGR888,
- SDL_PIXELFORMAT_RGB565,
- SDL_PIXELFORMAT_RGB555
- },
- 0,
- 0}
-};
-
typedef struct
{
SDL_Surface *surface;
@@ -114,82 +56,11 @@ SW_ActivateRenderer(SDL_Renderer * renderer)
SDL_Surface *surface = SDL_GetWindowSurface(renderer->window);
if (surface) {
data->surface = data->window = surface;
-
- SW_UpdateViewport(renderer);
- SW_UpdateClipRect(renderer);
}
}
return data->surface;
}
-SDL_Renderer *
-SW_CreateRendererForSurface(SDL_Surface * surface)
-{
- SDL_Renderer *renderer;
- SW_RenderData *data;
-
- if (!surface) {
- SDL_SetError("Can't create renderer for NULL surface");
- return NULL;
- }
-
- renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
- if (!renderer) {
- SDL_OutOfMemory();
- return NULL;
- }
-
- data = (SW_RenderData *) SDL_calloc(1, sizeof(*data));
- if (!data) {
- SW_DestroyRenderer(renderer);
- SDL_OutOfMemory();
- return NULL;
- }
- data->surface = surface;
- data->window = surface;
-
- renderer->WindowEvent = SW_WindowEvent;
- renderer->GetOutputSize = SW_GetOutputSize;
- renderer->CreateTexture = SW_CreateTexture;
- renderer->SetTextureColorMod = SW_SetTextureColorMod;
- renderer->SetTextureAlphaMod = SW_SetTextureAlphaMod;
- renderer->SetTextureBlendMode = SW_SetTextureBlendMode;
- renderer->UpdateTexture = SW_UpdateTexture;
- renderer->LockTexture = SW_LockTexture;
- renderer->UnlockTexture = SW_UnlockTexture;
- renderer->SetRenderTarget = SW_SetRenderTarget;
- renderer->UpdateViewport = SW_UpdateViewport;
- renderer->UpdateClipRect = SW_UpdateClipRect;
- renderer->RenderClear = SW_RenderClear;
- renderer->RenderDrawPoints = SW_RenderDrawPoints;
- renderer->RenderDrawLines = SW_RenderDrawLines;
- renderer->RenderFillRects = SW_RenderFillRects;
- renderer->RenderCopy = SW_RenderCopy;
- renderer->RenderCopyEx = SW_RenderCopyEx;
- renderer->RenderReadPixels = SW_RenderReadPixels;
- renderer->RenderPresent = SW_RenderPresent;
- renderer->DestroyTexture = SW_DestroyTexture;
- renderer->DestroyRenderer = SW_DestroyRenderer;
- renderer->info = SW_RenderDriver.info;
- renderer->driverdata = data;
-
- SW_ActivateRenderer(renderer);
-
- return renderer;
-}
-
-SDL_Renderer *
-SW_CreateRenderer(SDL_Window * window, Uint32 flags)
-{
- SDL_Surface *surface;
-
- surface = SDL_GetWindowSurface(window);
- if (!surface) {
- return NULL;
- }
- return SW_CreateRendererForSurface(surface);
-}
-
static void
SW_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
{
@@ -253,46 +124,6 @@ SW_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
}
static int
-SW_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture)
-{
- SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
- /* If the color mod is ever enabled (non-white), permanently disable RLE (which doesn't support
- * color mod) to avoid potentially frequent RLE encoding/decoding.
- */
- if ((texture->r & texture->g & texture->b) != 255) {
- SDL_SetSurfaceRLE(surface, 0);
- }
- return SDL_SetSurfaceColorMod(surface, texture->r, texture->g,
- texture->b);
-}
-
-static int
-SW_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture)
-{
- SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
- /* If the texture ever has multiple alpha values (surface alpha plus alpha channel), permanently
- * disable RLE (which doesn't support this) to avoid potentially frequent RLE encoding/decoding.
- */
- if (texture->a != 255 && surface->format->Amask) {
- SDL_SetSurfaceRLE(surface, 0);
- }
- return SDL_SetSurfaceAlphaMod(surface, texture->a);
-}
-
-static int
-SW_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture)
-{
- SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
- /* If add or mod blending are ever enabled, permanently disable RLE (which doesn't support
- * them) to avoid potentially frequent RLE encoding/decoding.
- */
- if ((texture->blendMode == SDL_BLENDMODE_ADD || texture->blendMode == SDL_BLENDMODE_MOD)) {
- SDL_SetSurfaceRLE(surface, 0);
- }
- return SDL_SetSurfaceBlendMode(surface, texture->blendMode);
-}
-
-static int
SW_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
const SDL_Rect * rect, const void *pixels, int pitch)
{
@@ -350,251 +181,149 @@ SW_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
}
static int
-SW_UpdateViewport(SDL_Renderer * renderer)
+SW_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd)
{
- SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
- SDL_Surface *surface = data->surface;
-
- if (!surface) {
- /* We'll update the viewport after we recreate the surface */
- return 0;
- }
-
- SDL_SetClipRect(data->surface, &renderer->viewport);
- return 0;
-}
-
-static int
-SW_UpdateClipRect(SDL_Renderer * renderer)
-{
- SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
- SDL_Surface *surface = data->surface;
- if (surface) {
- if (renderer->clipping_enabled) {
- SDL_Rect clip_rect;
- clip_rect = renderer->clip_rect;
- clip_rect.x += renderer->viewport.x;
- clip_rect.y += renderer->viewport.y;
- SDL_IntersectRect(&renderer->viewport, &clip_rect, &clip_rect);
- SDL_SetClipRect(surface, &clip_rect);
- } else {
- SDL_SetClipRect(surface, &renderer->viewport);
- }
- }
- return 0;
+ return 0; /* nothing to do in this backend. */
}
static int
-SW_RenderClear(SDL_Renderer * renderer)
+SW_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
{
- SDL_Surface *surface = SW_ActivateRenderer(renderer);
- Uint32 color;
- SDL_Rect clip_rect;
+ SDL_Point *verts = (SDL_Point *) SDL_AllocateRenderVertices(renderer, count * sizeof (SDL_Point), 0, &cmd->data.draw.first);
+ size_t i;
- if (!surface) {
+ if (!verts) {
return -1;
}
- color = SDL_MapRGBA(surface->format,
- renderer->r, renderer->g, renderer->b, renderer->a);
-
- /* By definition the clear ignores the clip rect */
- clip_rect = surface->clip_rect;
- SDL_SetClipRect(surface, NULL);
- SDL_FillRect(surface, NULL, color);
- SDL_SetClipRect(surface, &clip_rect);
- return 0;
-}
-
-static int
-SW_RenderDrawPoints(SDL_Renderer * renderer, const SDL_FPoint * points,
- int count)
-{
- SDL_Surface *surface = SW_ActivateRenderer(renderer);
- SDL_Point *final_points;
- int i, status;
-
- if (!surface) {
- return -1;
- }
+ cmd->data.draw.count = count;
- final_points = SDL_stack_alloc(SDL_Point, count);
- if (!final_points) {
- return SDL_OutOfMemory();
- }
if (renderer->viewport.x || renderer->viewport.y) {
- int x = renderer->viewport.x;
- int y = renderer->viewport.y;
-
- for (i = 0; i < count; ++i) {
- final_points[i].x = (int)(x + points[i].x);
- final_points[i].y = (int)(y + points[i].y);
+ const int x = renderer->viewport.x;
+ const int y = renderer->viewport.y;
+ for (i = 0; i < count; i++, verts++, points++) {
+ verts->x = (int)(x + points->x);
+ verts->y = (int)(y + points->y);
}
} else {
- for (i = 0; i < count; ++i) {
- final_points[i].x = (int)points[i].x;
- final_points[i].y = (int)points[i].y;
+ for (i = 0; i < count; i++, verts++, points++) {
+ verts->x = (int)points->x;
+ verts->y = (int)points->y;
}
}
- /* Draw the points! */
- if (renderer->blendMode == SDL_BLENDMODE_NONE) {
- Uint32 color = SDL_MapRGBA(surface->format,
- renderer->r, renderer->g, renderer->b,
- renderer->a);
-
- status = SDL_DrawPoints(surface, final_points, count, color);
- } else {
- status = SDL_BlendPoints(surface, final_points, count,
- renderer->blendMode,
- renderer->r, renderer->g, renderer->b,
- renderer->a);
- }
- SDL_stack_free(final_points);
-
- return status;
+ return 0;
}
static int
-SW_RenderDrawLines(SDL_Renderer * renderer, const SDL_FPoint * points,
- int count)
+SW_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects, int count)
{
- SDL_Surface *surface = SW_ActivateRenderer(renderer);
- SDL_Point *final_points;
- int i, status;
+ SDL_Rect *verts = (SDL_Rect *) SDL_AllocateRenderVertices(renderer, count * sizeof (SDL_Rect), 0, &cmd->data.draw.first);
+ size_t i;
- if (!surface) {
+ if (!verts) {
return -1;
}
- final_points = SDL_stack_alloc(SDL_Point, count);
- if (!final_points) {
- return SDL_OutOfMemory();
- }
- if (renderer->viewport.x || renderer->viewport.y) {
- int x = renderer->viewport.x;
- int y = renderer->viewport.y;
+ cmd->data.draw.count = count;
- for (i = 0; i < count; ++i) {
- final_points[i].x = (int)(x + points[i].x);
- final_points[i].y = (int)(y + points[i].y);
+ if (renderer->viewport.x || renderer->viewport.y) {
+ const int x = renderer->viewport.x;
+ const int y = renderer->viewport.y;
+
+ for (i = 0; i < count; i++, verts++, rects++) {
+ verts->x = (int)(x + rects->x);
+ verts->y = (int)(y + rects->y);
+ verts->w = SDL_max((int)rects->w, 1);
+ verts->h = SDL_max((int)rects->h, 1);
}
} else {
- for (i = 0; i < count; ++i) {
- final_points[i].x = (int)points[i].x;
- final_points[i].y = (int)points[i].y;
+ for (i = 0; i < count; i++, verts++, rects++) {
+ verts->x = (int)rects->x;
+ verts->y = (int)rects->y;
+ verts->w = SDL_max((int)rects->w, 1);
+ verts->h = SDL_max((int)rects->h, 1);
}
}
- /* Draw the lines! */
- if (renderer->blendMode == SDL_BLENDMODE_NONE) {
- Uint32 color = SDL_MapRGBA(surface->format,
- renderer->r, renderer->g, renderer->b,
- renderer->a);
-
- status = SDL_DrawLines(surface, final_points, count, color);
- } else {
- status = SDL_BlendLines(surface, final_points, count,
- renderer->blendMode,
- renderer->r, renderer->g, renderer->b,
- renderer->a);
- }
- SDL_stack_free(final_points);
-
- return status;
+ return 0;
}
static int
-SW_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects, int count)
+SW_QueueCopy(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
+ const SDL_Rect * srcrect, const SDL_FRect * dstrect)
{
- SDL_Surface *surface = SW_ActivateRenderer(renderer);
- SDL_Rect *final_rects;
- int i, status;
+ SDL_Rect *verts = (SDL_Rect *) SDL_AllocateRenderVertices(renderer, 2 * sizeof (SDL_Rect), 0, &cmd->data.draw.first);
- if (!surface) {
+ if (!verts) {
return -1;
}
- final_rects = SDL_stack_alloc(SDL_Rect, count);
- if (!final_rects) {
- return SDL_OutOfMemory();
- }
- if (renderer->viewport.x || renderer->viewport.y) {
- int x = renderer->viewport.x;
- int y = renderer->viewport.y;
-
- for (i = 0; i < count; ++i) {
- final_rects[i].x = (int)(x + rects[i].x);
- final_rects[i].y = (int)(y + rects[i].y);
- final_rects[i].w = SDL_max((int)rects[i].w, 1);
- final_rects[i].h = SDL_max((int)rects[i].h, 1);
- }
- } else {
- for (i = 0; i < count; ++i) {
- final_rects[i].x = (int)rects[i].x;
- final_rects[i].y = (int)rects[i].y;
- final_rects[i].w = SDL_max((int)rects[i].w, 1);
- final_rects[i].h = SDL_max((int)rects[i].h, 1);
- }
- }
+ cmd->data.draw.count = 1;
- if (renderer->blendMode == SDL_BLENDMODE_NONE) {
- Uint32 color = SDL_MapRGBA(surface->format,
- renderer->r, renderer->g, renderer->b,
- renderer->a);
- status = SDL_FillRects(surface, final_rects, count, color);
+ SDL_memcpy(verts, srcrect, sizeof (SDL_Rect));
+ verts++;
+
+ if (renderer->viewport.x || renderer->viewport.y) {
+ verts->x = (int)(renderer->viewport.x + dstrect->x);
+ verts->y = (int)(renderer->viewport.y + dstrect->y);
} else {
- status = SDL_BlendFillRects(surface, final_rects, count,
- renderer->blendMode,
- renderer->r, renderer->g, renderer->b,
- renderer->a);
+ verts->x = (int)dstrect->x;
+ verts->y = (int)dstrect->y;
}
- SDL_stack_free(final_rects);
+ verts->w = (int)dstrect->w;
+ verts->h = (int)dstrect->h;
- return status;
+ return 0;
}
+typedef struct CopyExData
+{
+ SDL_Rect srcrect;
+ SDL_Rect dstrect;
+ double angle;
+ SDL_FPoint center;
+ SDL_RendererFlip flip;
+} CopyExData;
+
static int
-SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * srcrect, const SDL_FRect * dstrect)
+SW_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
+ const SDL_Rect * srcrect, const SDL_FRect * dstrect,
+ const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
{
- SDL_Surface *surface = SW_ActivateRenderer(renderer);
- SDL_Surface *src = (SDL_Surface *) texture->driverdata;
- SDL_Rect final_rect;
+ CopyExData *verts = (CopyExData *) SDL_AllocateRenderVertices(renderer, sizeof (CopyExData), 0, &cmd->data.draw.first);
- if (!surface) {
+ if (!verts) {
return -1;
}
+ cmd->data.draw.count = 1;
+
+ SDL_memcpy(&verts->srcrect, srcrect, sizeof (SDL_Rect));
+
if (renderer->viewport.x || renderer->viewport.y) {
- final_rect.x = (int)(renderer->viewport.x + dstrect->x);
- final_rect.y = (int)(renderer->viewport.y + dstrect->y);
+ verts->dstrect.x = (int)(renderer->viewport.x + dstrect->x);
+ verts->dstrect.y = (int)(renderer->viewport.y + dstrect->y);
} else {
- final_rect.x = (int)dstrect->x;
- final_rect.y = (int)dstrect->y;
+ verts->dstrect.x = (int)dstrect->x;
+ verts->dstrect.y = (int)dstrect->y;
}
- final_rect.w = (int)dstrect->w;
- final_rect.h = (int)dstrect->h;
+ verts->dstrect.w = (int)dstrect->w;
+ verts->dstrect.h = (int)dstrect->h;
+ verts->angle = angle;
+ SDL_memcpy(&verts->center, center, sizeof (SDL_FPoint));
+ verts->flip = flip;
- if ( srcrect->w == final_rect.w && srcrect->h == final_rect.h ) {
- return SDL_BlitSurface(src, srcrect, surface, &final_rect);
- } else {
- /* If scaling is ever done, permanently disable RLE (which doesn't support scaling)
- * to avoid potentially frequent RLE encoding/decoding.
- */
- SDL_SetSurfaceRLE(surface, 0);
- return SDL_BlitScaled(src, srcrect, surface, &final_rect);
- }
+ return 0;
}
static int
-SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
- const SDL_Rect * srcrect, const SDL_FRect * dstrect,
+SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Surface *surface, SDL_Texture * texture,
+ const SDL_Rect * srcrect, const SDL_Rect * final_rect,
const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip)
{
- SDL_Surface *surface = SW_ActivateRenderer(renderer);
SDL_Surface *src = (SDL_Surface *) texture->driverdata;
- SDL_Rect final_rect, tmp_rect;
+ SDL_Rect tmp_rect;
SDL_Surface *src_clone, *src_rotated, *src_scaled;
SDL_Surface *mask = NULL, *mask_rotated = NULL;
int retval = 0, dstwidth, dstheight, abscenterx, abscentery;
@@ -609,19 +338,10 @@ SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
return -1;
}
- if (renderer->viewport.x || renderer->viewport.y) {
- final_rect.x = (int)(renderer->viewport.x + dstrect->x);
- final_rect.y = (int)(renderer->viewport.y + dstrect->y);
- } else {
- final_rect.x = (int)dstrect->x;
- final_rect.y = (int)dstrect->y;
- }
- final_rect.w = (int)dstrect->w;
- final_rect.h = (int)dstrect->h;
-
- tmp_rect = final_rect;
tmp_rect.x = 0;
tmp_rect.y = 0;
+ tmp_rect.w = final_rect->w;
+ tmp_rect.h = final_rect->h;
/* It is possible to encounter an RLE encoded surface here and locking it is
* necessary because this code is going to access the pixel buffer directly.
@@ -653,7 +373,7 @@ SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
}
/* If scaling and cropping is necessary, it has to be taken care of before the rotation. */
- if (!(srcrect->w == final_rect.w && srcrect->h == final_rect.h && srcrect->x == 0 && srcrect->y == 0)) {
+ if (!(srcrect->w == final_rect->w && srcrect->h == final_rect->h && srcrect->x == 0 && srcrect->y == 0)) {
blitRequired = SDL_TRUE;
}
@@ -678,7 +398,7 @@ SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
* to clear the pixels in the destination surface. The other steps are explained below.
*/
if (blendmode == SDL_BLENDMODE_NONE && !isOpaque) {
- mask = SDL_CreateRGBSurface(0, final_rect.w, final_rect.h, 32,
+ mask = SDL_CreateRGBSurface(0, final_rect->w, final_rect->h, 32,
0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);
if (mask == NULL) {
retval = -1;
@@ -692,7 +412,7 @@ SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
*/
if (!retval && (blitRequired || applyModulation)) {
SDL_Rect scale_rect = tmp_rect;
- src_scaled = SDL_CreateRGBSurface(0, final_rect.w, final_rect.h, 32,
+ src_scaled = SDL_CreateRGBSurface(0, final_rect->w, final_rect->h, 32,
0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);
if (src_scaled == NULL) {
retval = -1;
@@ -723,32 +443,32 @@ SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
}
if (!retval) {
/* Find out where the new origin is by rotating the four final_rect points around the center and then taking the extremes */
- abscenterx = final_rect.x + (int)center->x;
- abscentery = final_rect.y + (int)center->y;
+ abscenterx = final_rect->x + (int)center->x;
+ abscentery = final_rect->y + (int)center->y;
/* Compensate the angle inversion to match the behaviour of the other backends */
sangle = -sangle;
/* Top Left */
- px = final_rect.x - abscenterx;
- py = final_rect.y - abscentery;
+ px = final_rect->x - abscenterx;
+ py = final_rect->y - abscentery;
p1x = px * cangle - py * sangle + abscenterx;
p1y = px * sangle + py * cangle + abscentery;
/* Top Right */
- px = final_rect.x + final_rect.w - abscenterx;
- py = final_rect.y - abscentery;
+ px = final_rect->x + final_rect->w - abscenterx;
+ py = final_rect->y - abscentery;
p2x = px * cangle - py * sangle + abscenterx;
p2y = px * sangle + py * cangle + abscentery;
/* Bottom Left */
- px = final_rect.x - abscenterx;
- py = final_rect.y + final_rect.h - abscentery;
+ px = final_rect->x - abscenterx;
+ py = final_rect->y + final_rect->h - abscentery;
p3x = px * cangle - py * sangle + abscenterx;
p3y = px * sangle + py * cangle + abscentery;
/* Bottom Right */
- px = final_rect.x + final_rect.w - abscenterx;
- py = final_rect.y + final_rect.h - abscentery;
+ px = final_rect->x + final_rect->w - abscenterx;
+ py = final_rect->y + final_rect->h - abscentery;
p4x = px * cangle - py * sangle + abscenterx;
p4y = px * sangle + py * cangle + abscentery;
@@ -824,6 +544,170 @@ SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
return retval;
}
+static void
+PrepTextureForCopy(const SDL_RenderCommand *cmd)
+{
+ const Uint8 r = cmd->data.draw.r;
+ const Uint8 g = cmd->data.draw.g;
+ const Uint8 b = cmd->data.draw.b;
+ const Uint8 a = cmd->data.draw.a;
+ const SDL_BlendMode blend = cmd->data.draw.blend;
+ SDL_Texture *texture = cmd->data.draw.texture;
+ SDL_Surface *surface = (SDL_Surface *) texture->driverdata;
+
+ if (texture->modMode & SDL_TEXTUREMODULATE_COLOR) {
+ SDL_SetSurfaceRLE(surface, 0);
+ SDL_SetSurfaceColorMod(surface, r, g, b);
+ }
+
+ if ((texture->modMode & SDL_TEXTUREMODULATE_ALPHA) && surface->format->Amask) {
+ SDL_SetSurfaceRLE(surface, 0);
+ SDL_SetSurfaceAlphaMod(surface, a);
+ }
+
+ if ((blend == SDL_BLENDMODE_ADD) || (blend == SDL_BLENDMODE_MOD)) {
+ SDL_SetSurfaceRLE(surface, 0);
+ }
+ SDL_SetSurfaceBlendMode(surface, blend);
+}
+
+static int
+SW_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
+{
+ SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
+ SDL_Surface *surface = SW_ActivateRenderer(renderer);
+ const SDL_Rect *viewport = NULL;
+ const SDL_Rect *cliprect = NULL;
+
+ if (!surface) {
+ return -1;
+ }
+
+ while (cmd) {
+ switch (cmd->command) {
+ case SDL_RENDERCMD_SETDRAWCOLOR: {
+ break; /* Not used in this backend. */
+ }
+
+ case SDL_RENDERCMD_SETVIEWPORT: {
+ viewport = &cmd->data.viewport.rect;
+ SDL_SetClipRect(data->surface, viewport);
+ break;
+ }
+
+ case SDL_RENDERCMD_SETCLIPRECT: {
+ SDL_assert(viewport != NULL);
+ cliprect = cmd->data.cliprect.enabled ? &cmd->data.cliprect.rect : NULL;
+ if (cliprect) {
+ SDL_Rect clip_rect = { cliprect->x + viewport->x, cliprect->y + viewport->y, cliprect->w, cliprect->h };
+ SDL_IntersectRect(viewport, &clip_rect, &clip_rect);
+ SDL_SetClipRect(surface, &clip_rect);
+ } else {
+ SDL_SetClipRect(surface, viewport);
+ }
+ break;
+ }
+
+ case SDL_RENDERCMD_CLEAR: {
+ const Uint8 r = cmd->data.color.r;
+ const Uint8 g = cmd->data.color.g;
+ const Uint8 b = cmd->data.color.b;
+ const Uint8 a = cmd->data.color.a;
+ const SDL_Rect clip_rect = surface->clip_rect;
+ /* By definition the clear ignores the clip rect */
+ SDL_SetClipRect(surface, NULL);
+ SDL_FillRect(surface, NULL, SDL_MapRGBA(surface->format, r, g, b, a));
+ SDL_SetClipRect(surface, &clip_rect);
+ break;
+ }
+
+ case SDL_RENDERCMD_DRAW_POINTS: {
+ const Uint8 r = cmd->data.draw.r;
+ const Uint8 g = cmd->data.draw.g;
+ const Uint8 b = cmd->data.draw.b;
+ const Uint8 a = cmd->data.draw.a;
+ const size_t count = cmd->data.draw.count;
+ const SDL_Point *verts = (SDL_Point *) (((Uint8 *) vertices) + cmd->data.draw.first);
+ const SDL_BlendMode blend = cmd->data.draw.blend;
+ if (blend == SDL_BLENDMODE_NONE) {
+ SDL_DrawPoints(surface, verts, count, SDL_MapRGBA(surface->format, r, g, b, a));
+ } else {
+ SDL_BlendPoints(surface, verts, count, blend, r, g, b, a);
+ }
+ break;
+ }
+
+ case SDL_RENDERCMD_DRAW_LINES: {
+ const Uint8 r = cmd->data.draw.r;
+ const Uint8 g = cmd->data.draw.g;
+ const Uint8 b = cmd->data.draw.b;
+ const Uint8 a = cmd->data.draw.a;
+ const size_t count = cmd->data.draw.count;
+ const SDL_Point *verts = (SDL_Point *) (((Uint8 *) vertices) + cmd->data.draw.first);
+ const SDL_BlendMode blend = cmd->data.draw.blend;
+ if (blend == SDL_BLENDMODE_NONE) {
+ SDL_DrawLines(surface, verts, count, SDL_MapRGBA(surface->format, r, g, b, a));
+ } else {
+ SDL_BlendLines(surface, verts, count, blend, r, g, b, a);
+ }
+ break;
+ }
+
+ case SDL_RENDERCMD_FILL_RECTS: {
+ const Uint8 r = cmd->data.draw.r;
+ const Uint8 g = cmd->data.draw.g;
+ const Uint8 b = cmd->data.draw.b;
+ const Uint8 a = cmd->data.draw.a;
+ const size_t count = cmd->data.draw.count;
+ const SDL_Rect *verts = (SDL_Rect *) (((Uint8 *) vertices) + cmd->data.draw.first);
+ const SDL_BlendMode blend = cmd->data.draw.blend;
+ if (blend == SDL_BLENDMODE_NONE) {
+ SDL_FillRects(surface, verts, count, SDL_MapRGBA(surface->format, r, g, b, a));
+ } else {
+ SDL_BlendFillRects(surface, verts, count, blend, r, g, b, a);
+ }
+ break;
+ }
+
+ case SDL_RENDERCMD_COPY: {
+ SDL_Rect *verts = (SDL_Rect *) (((Uint8 *) vertices) + cmd->data.draw.first);
+ const SDL_Rect *srcrect = verts;
+ SDL_Rect *dstrect = verts + 1;
+ SDL_Texture *texture = cmd->data.draw.texture;
+ SDL_Surface *src = (SDL_Surface *) texture->driverdata;
+
+ PrepTextureForCopy(cmd);
+
+ if ( srcrect->w == dstrect->w && srcrect->h == dstrect->h ) {
+ SDL_BlitSurface(src, srcrect, surface, dstrect);
+ } else {
+ /* If scaling is ever done, permanently disable RLE (which doesn't support scaling)
+ * to avoid potentially frequent RLE encoding/decoding.
+ */
+ SDL_SetSurfaceRLE(surface, 0);
+ SDL_BlitScaled(src, srcrect, surface, dstrect);
+ }
+ break;
+ }
+
+ case SDL_RENDERCMD_COPY_EX: {
+ const CopyExData *copydata = (CopyExData *) (((Uint8 *) vertices) + cmd->data.draw.first);
+ PrepTextureForCopy(cmd);
+ SW_RenderCopyEx(renderer, surface, cmd->data.draw.texture, &copydata->srcrect,
+ &copydata->dstrect, copydata->angle, &copydata->center, copydata->flip);
+ break;
+ }
+
+ case SDL_RENDERCMD_NO_OP:
+ break;
+ }
+
+ cmd = cmd->next;
+ }
+
+ return 0;
+}
+
static int
SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
Uint32 format, void * pixels, int pitch)
@@ -882,6 +766,91 @@ SW_DestroyRenderer(SDL_Renderer * renderer)
SDL_free(renderer);
}
+SDL_Renderer *
+SW_CreateRendererForSurface(SDL_Surface * surface)
+{
+ SDL_Renderer *renderer;
+ SW_RenderData *data;
+
+ if (!surface) {
+ SDL_SetError("Can't create renderer for NULL surface");
+ return NULL;
+ }
+
+ renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
+ if (!renderer) {
+ SDL_OutOfMemory();
+ return NULL;
+ }
+
+ data = (SW_RenderData *) SDL_calloc(1, sizeof(*data));
+ if (!data) {
+ SW_DestroyRenderer(renderer);
+ SDL_OutOfMemory();
+ return NULL;
+ }
+ data->surface = surface;
+ data->window = surface;
+
+ renderer->WindowEvent = SW_WindowEvent;
+ renderer->GetOutputSize = SW_GetOutputSize;
+ renderer->CreateTexture = SW_CreateTexture;
+ renderer->UpdateTexture = SW_UpdateTexture;
+ renderer->LockTexture = SW_LockTexture;
+ renderer->UnlockTexture = SW_UnlockTexture;
+ renderer->SetRenderTarget = SW_SetRenderTarget;
+ renderer->QueueSetViewport = SW_QueueSetViewport;
+ renderer->QueueSetDrawColor = SW_QueueSetViewport; /* SetViewport and SetDrawColor are (currently) no-ops. */
+ renderer->QueueDrawPoints = SW_QueueDrawPoints;
+ renderer->QueueDrawLines = SW_QueueDrawPoints; /* lines and points queue vertices the same way. */
+ renderer->QueueFillRects = SW_QueueFillRects;
+ renderer->QueueCopy = SW_QueueCopy;
+ renderer->QueueCopyEx = SW_QueueCopyEx;
+ renderer->RunCommandQueue = SW_RunCommandQueue;
+ renderer->RenderReadPixels = SW_RenderReadPixels;
+ renderer->RenderPresent = SW_RenderPresent;
+ renderer->DestroyTexture = SW_DestroyTexture;
+ renderer->DestroyRenderer = SW_DestroyRenderer;
+ renderer->info = SW_RenderDriver.info;
+ renderer->driverdata = data;
+
+ SW_ActivateRenderer(renderer);
+
+ return renderer;
+}
+
+SDL_Renderer *
+SW_CreateRenderer(SDL_Window * window, Uint32 flags)
+{
+ SDL_Surface *surface;
+
+ surface = SDL_GetWindowSurface(window);
+ if (!surface) {
+ return NULL;
+ }
+ return SW_CreateRendererForSurface(surface);
+}
+
+SDL_RenderDriver SW_RenderDriver = {
+ SW_CreateRenderer,
+ {
+ "software",
+ SDL_RENDERER_SOFTWARE | SDL_RENDERER_TARGETTEXTURE,
+ 8,
+ {
+ SDL_PIXELFORMAT_ARGB8888,
+ SDL_PIXELFORMAT_ABGR8888,
+ SDL_PIXELFORMAT_RGBA8888,
+ SDL_PIXELFORMAT_BGRA8888,
+ SDL_PIXELFORMAT_RGB888,
+ SDL_PIXELFORMAT_BGR888,
+ SDL_PIXELFORMAT_RGB565,
+ SDL_PIXELFORMAT_RGB555
+ },
+ 0,
+ 0}
+};
+
#endif /* !SDL_RENDER_DISABLED */
/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/video/cocoa/SDL_cocoamodes.m b/src/video/cocoa/SDL_cocoamodes.m
index 97ccd945dc..b614b795b1 100644
--- a/src/video/cocoa/SDL_cocoamodes.m
+++ b/src/video/cocoa/SDL_cocoamodes.m
@@ -187,6 +187,7 @@ Cocoa_InitModes(_THIS)
CGDisplayErr result;
CGDirectDisplayID *displays;
CGDisplayCount numDisplays;
+ SDL_bool isstack;
int pass, i;
result = CGGetOnlineDisplayList(0, NULL, &numDisplays);
@@ -194,11 +195,11 @@ Cocoa_InitModes(_THIS)
CG_SetError("CGGetOnlineDisplayList()", result);
return;
}
- displays = SDL_stack_alloc(CGDirectDisplayID, numDisplays);
+ displays = SDL_small_alloc(CGDirectDisplayID, numDisplays, &isstack);
result = CGGetOnlineDisplayList(numDisplays, displays, &numDisplays);
if (result != kCGErrorSuccess) {
CG_SetError("CGGetOnlineDisplayList()", result);
- SDL_stack_free(displays);
+ SDL_small_free(displays, isstack);
return;
}
@@ -260,7 +261,7 @@ Cocoa_InitModes(_THIS)
SDL_free(display.name);
}
}
- SDL_stack_free(displays);
+ SDL_small_free(displays, isstack);
}}
int
diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c
index b6155e76d9..0759719d38 100644
--- a/src/video/wayland/SDL_waylandvideo.c
+++ b/src/video/wayland/SDL_waylandvideo.c
@@ -47,6 +47,7 @@
#include "xdg-shell-client-protocol.h"
#include "xdg-shell-unstable-v6-client-protocol.h"
+#include "org-kde-kwin-server-decoration-manager-client-protocol.h"
#define WAYLANDVID_DRIVER_NAME "wayland"
@@ -182,6 +183,7 @@ Wayland_CreateDevice(int devindex)
device->SetWindowFullscreen = Wayland_SetWindowFullscreen;
device->MaximizeWindow = Wayland_MaximizeWindow;
device->RestoreWindow = Wayland_RestoreWindow;
+ device->SetWindowBordered = Wayland_SetWindowBordered;
device->SetWindowSize = Wayland_SetWindowSize;
device->SetWindowTitle = Wayland_SetWindowTitle;
device->DestroyWindow = Wayland_DestroyWindow;
@@ -345,6 +347,8 @@ display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
{
SDL_VideoData *d = data;
+ /*printf("WAYLAND INTERFACE: %s\n", interface);*/
+
if (strcmp(interface, "wl_compositor") == 0) {
d->compositor = wl_registry_bind(d->registry, id, &wl_compositor_interface, 1);
} else if (strcmp(interface, "wl_output") == 0) {
@@ -368,6 +372,8 @@ display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
Wayland_display_add_pointer_constraints(d, id);
} else if (strcmp(interface, "wl_data_device_manager") == 0) {
d->data_device_manager = wl_registry_bind(d->registry, id, &wl_data_device_manager_interface, 3);
+ } else if (strcmp(interface, "org_kde_kwin_server_decoration_manager") == 0) {
+ d->kwin_server_decoration_manager = wl_registry_bind(d->registry, id, &org_kde_kwin_server_decoration_manager_interface, 1);
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
} else if (strcmp(interface, "qt_touch_extension") == 0) {
diff --git a/src/video/wayland/SDL_waylandvideo.h b/src/video/wayland/SDL_waylandvideo.h
index c16c0bdd49..4d6658fcae 100644
--- a/src/video/wayland/SDL_waylandvideo.h
+++ b/src/video/wayland/SDL_waylandvideo.h
@@ -61,6 +61,7 @@ typedef struct {
struct zwp_relative_pointer_manager_v1 *relative_pointer_manager;
struct zwp_pointer_constraints_v1 *pointer_constraints;
struct wl_data_device_manager *data_device_manager;
+ struct org_kde_kwin_server_decoration_manager *kwin_server_decoration_manager;
EGLDisplay edpy;
EGLContext context;
diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c
index aa7299181d..828d69c3a4 100644
--- a/src/video/wayland/SDL_waylandwindow.c
+++ b/src/video/wayland/SDL_waylandwindow.c
@@ -35,6 +35,7 @@
#include "xdg-shell-client-protocol.h"
#include "xdg-shell-unstable-v6-client-protocol.h"
+#include "org-kde-kwin-server-decoration-manager-client-protocol.h"
/* On modern desktops, we probably will use the xdg-shell protocol instead
of wl_shell, but wl_shell might be useful on older Wayland installs that
@@ -452,6 +453,17 @@ Wayland_RestoreWindow(_THIS, SDL_Window * window)
}
void
+Wayland_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
+{
+ SDL_WindowData *wind = window->driverdata;
+ const SDL_VideoData *viddata = (const SDL_VideoData *) _this->driverdata;
+ if ((viddata->kwin_server_decoration_manager) && (wind->kwin_server_decoration)) {
+ const enum org_kde_kwin_server_decoration_mode mode = bordered ? ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_SERVER : ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_NONE;
+ org_kde_kwin_server_decoration_request_mode(wind->kwin_server_decoration, mode);
+ }
+}
+
+void
Wayland_MaximizeWindow(_THIS, SDL_Window * window)
{
SDL_WindowData *wind = window->driverdata;
@@ -562,6 +574,15 @@ int Wayland_CreateWindow(_THIS, SDL_Window *window)
}
#endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
+ if (c->kwin_server_decoration_manager) {
+ data->kwin_server_decoration = org_kde_kwin_server_decoration_manager_create(c->kwin_server_decoration_manager, data->surface);
+ if (data->kwin_server_decoration) {
+ const SDL_bool bordered = (window->flags & SDL_WINDOW_BORDERLESS) == 0;
+ const enum org_kde_kwin_server_decoration_mode mode = bordered ? ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_SERVER : ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_NONE;
+ org_kde_kwin_server_decoration_request_mode(data->kwin_server_decoration, mode);
+ }
+ }
+
region = wl_compositor_create_region(c->compositor);
wl_region_add(region, 0, 0, window->w, window->h);
wl_surface_set_opaque_region(data->surface, region);
@@ -636,6 +657,10 @@ void Wayland_DestroyWindow(_THIS, SDL_Window *window)
SDL_EGL_DestroySurface(_this, wind->egl_surface);
WAYLAND_wl_egl_window_destroy(wind->egl_window);
+ if (wind->kwin_server_decoration) {
+ org_kde_kwin_server_decoration_release(wind->kwin_server_decoration);
+ }
+
if (data->shell.xdg) {
if (wind->shell_surface.xdg.roleobj.toplevel) {
xdg_toplevel_destroy(wind->shell_surface.xdg.roleobj.toplevel);
diff --git a/src/video/wayland/SDL_waylandwindow.h b/src/video/wayland/SDL_waylandwindow.h
index 69b9889233..38a204e9a6 100644
--- a/src/video/wayland/SDL_waylandwindow.h
+++ b/src/video/wayland/SDL_waylandwindow.h
@@ -62,6 +62,7 @@ typedef struct {
struct SDL_WaylandInput *keyboard_device;
EGLSurface egl_surface;
struct zwp_locked_pointer_v1 *locked_pointer;
+ struct org_kde_kwin_server_decoration *kwin_server_decoration;
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
struct qt_extended_surface *extended_surface;
@@ -74,6 +75,7 @@ extern void Wayland_SetWindowFullscreen(_THIS, SDL_Window * window,
SDL_bool fullscreen);
extern void Wayland_MaximizeWindow(_THIS, SDL_Window * window);
extern void Wayland_RestoreWindow(_THIS, SDL_Window * window);
+extern void Wayland_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered);
extern int Wayland_CreateWindow(_THIS, SDL_Window *window);
extern void Wayland_SetWindowSize(_THIS, SDL_Window * window);
extern void Wayland_SetWindowTitle(_THIS, SDL_Window * window);
diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c
index e961cf568e..59c11bf225 100644
--- a/src/video/windows/SDL_windowsevents.c
+++ b/src/video/windows/SDL_windowsevents.c
@@ -908,7 +908,8 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
case WM_TOUCH:
if (data->videodata->GetTouchInputInfo && data->videodata->CloseTouchInputHandle) {
UINT i, num_inputs = LOWORD(wParam);
- PTOUCHINPUT inputs = SDL_stack_alloc(TOUCHINPUT, num_inputs);
+ SDL_bool isstack;
+ PTOUCHINPUT inputs = SDL_small_alloc(TOUCHINPUT, num_inputs, &isstack);
if (data->videodata->GetTouchInputInfo((HTOUCHINPUT)lParam, num_inputs, inputs, sizeof(TOUCHINPUT))) {
RECT rect;
float x, y;
@@ -916,7 +917,7 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
if (!GetClientRect(hwnd, &rect) ||
(rect.right == rect.left && rect.bottom == rect.top)) {
if (inputs) {
- SDL_stack_free(inputs);
+ SDL_small_free(inputs, isstack);
}
break;
}
@@ -950,7 +951,7 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
}
}
}
- SDL_stack_free(inputs);
+ SDL_small_free(inputs, isstack);
data->videodata->CloseTouchInputHandle((HTOUCHINPUT)lParam);
return 0;
@@ -961,17 +962,19 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
UINT i;
HDROP drop = (HDROP) wParam;
+ SDL_bool isstack;
UINT count = DragQueryFile(drop, 0xFFFFFFFF, NULL, 0);
for (i = 0; i < count; ++i) {
+ SDL_bool isstack;
UINT size = DragQueryFile(drop, i, NULL, 0) + 1;
- LPTSTR buffer = SDL_stack_alloc(TCHAR, size);
+ LPTSTR buffer = SDL_small_alloc(TCHAR, size, &isstack);
if (buffer) {
if (DragQueryFile(drop, i, buffer, size)) {
char *file = WIN_StringToUTF8(buffer);
SDL_SendDropFile(data->window, file);
SDL_free(file);
}
- SDL_stack_free(buffer);
+ SDL_small_free(buffer, isstack);
}
}
SDL_SendDropComplete(data->window);
diff --git a/src/video/windows/SDL_windowsframebuffer.c b/src/video/windows/SDL_windowsframebuffer.c
index e07d9c4313..f884f7fa0d 100644
--- a/src/video/windows/SDL_windowsframebuffer.c
+++ b/src/video/windows/SDL_windowsframebuffer.c
@@ -27,6 +27,7 @@
int WIN_CreateWindowFramebuffer(_THIS, SDL_Window * window, Uint32 * format, void ** pixels, int *pitch)
{
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+ SDL_bool isstack;
size_t size;
LPBITMAPINFO info;
HBITMAP hbm;
@@ -41,7 +42,7 @@ int WIN_CreateWindowFramebuffer(_THIS, SDL_Window * window, Uint32 * format, voi
/* Find out the format of the screen */
size = sizeof(BITMAPINFOHEADER) + 256 * sizeof (RGBQUAD);
- info = (LPBITMAPINFO)SDL_stack_alloc(Uint8, size);
+ info = (LPBITMAPINFO)SDL_small_alloc(Uint8, size, &isstack);
if (!info) {
return SDL_OutOfMemory();
}
@@ -85,7 +86,7 @@ int WIN_CreateWindowFramebuffer(_THIS, SDL_Window * window, Uint32 * format, voi
data->mdc = CreateCompatibleDC(data->hdc);
data->hbm = CreateDIBSection(data->hdc, info, DIB_RGB_COLORS, pixels, NULL, 0);
- SDL_stack_free(info);
+ SDL_small_free(info, isstack);
if (!data->hbm) {
return WIN_SetError("Unable to create DIB");
diff --git a/src/video/windows/SDL_windowsmouse.c b/src/video/windows/SDL_windowsmouse.c
index eff31605b3..3dc7e79750 100644
--- a/src/video/windows/SDL_windowsmouse.c
+++ b/src/video/windows/SDL_windowsmouse.c
@@ -97,6 +97,7 @@ WIN_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y)
LPVOID pixels;
LPVOID maskbits;
size_t maskbitslen;
+ SDL_bool isstack;
ICONINFO ii;
SDL_zero(bmh);
@@ -112,7 +113,7 @@ WIN_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y)
bmh.bV4BlueMask = 0x000000FF;
maskbitslen = ((surface->w + (pad - (surface->w % pad))) / 8) * surface->h;
- maskbits = SDL_stack_alloc(Uint8,maskbitslen);
+ maskbits = SDL_small_alloc(Uint8,maskbitslen);
if (maskbits == NULL) {
SDL_OutOfMemory();
return NULL;
@@ -129,7 +130,7 @@ WIN_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y)
ii.hbmColor = CreateDIBSection(hdc, (BITMAPINFO*)&bmh, DIB_RGB_COLORS, &pixels, NULL, 0);
ii.hbmMask = CreateBitmap(surface->w, surface->h, 1, 1, maskbits);
ReleaseDC(NULL, hdc);
- SDL_stack_free(maskbits);
+ SDL_small_free(maskbits, isstack);
SDL_assert(surface->format->format == SDL_PIXELFORMAT_ARGB8888);
SDL_assert(surface->pitch == surface->w * 4);
diff --git a/src/video/windows/SDL_windowswindow.c b/src/video/windows/SDL_windowswindow.c
index 45463c4c7f..d56b8dbfe0 100644
--- a/src/video/windows/SDL_windowswindow.c
+++ b/src/video/windows/SDL_windowswindow.c
@@ -380,10 +380,11 @@ WIN_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
HWND hwnd = (HWND) data;
LPTSTR title;
int titleLen;
+ SDL_bool isstack;
/* Query the title from the existing window */
titleLen = GetWindowTextLength(hwnd);
- title = SDL_stack_alloc(TCHAR, titleLen + 1);
+ title = SDL_small_alloc(TCHAR, titleLen + 1, &isstack);
if (title) {
titleLen = GetWindowText(hwnd, title, titleLen);
} else {
@@ -393,7 +394,7 @@ WIN_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
window->title = WIN_StringToUTF8(title);
}
if (title) {
- SDL_stack_free(title);
+ SDL_small_free(title, isstack);
}
if (SetupWindowData(_this, window, hwnd, GetParent(hwnd), SDL_FALSE) < 0) {
@@ -443,14 +444,15 @@ WIN_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
BYTE *icon_bmp;
int icon_len, mask_len, y;
SDL_RWops *dst;
+ SDL_bool isstack;
/* Create temporary buffer for ICONIMAGE structure */
mask_len = (icon->h * (icon->w + 7)/8);
icon_len = 40 + icon->h * icon->w * sizeof(Uint32) + mask_len;
- icon_bmp = SDL_stack_alloc(BYTE, icon_len);
+ icon_bmp = SDL_small_alloc(BYTE, icon_len, &isstack);
dst = SDL_RWFromMem(icon_bmp, icon_len);
if (!dst) {
- SDL_stack_free(icon_bmp);
+ SDL_small_free(icon_bmp, isstack);
return;
}
@@ -481,7 +483,7 @@ WIN_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
hicon = CreateIconFromResource(icon_bmp, icon_len, TRUE, 0x00030000);
SDL_RWclose(dst);
- SDL_stack_free(icon_bmp);
+ SDL_small_free(icon_bmp, isstack);
/* Set the icon for the window */
SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM) hicon);
diff --git a/test/testsprite2.c b/test/testsprite2.c
index b0348f85d7..f471ff3199 100644
--- a/test/testsprite2.c
+++ b/test/testsprite2.c
@@ -37,6 +37,8 @@ static SDL_Rect *positions;
static SDL_Rect *velocities;
static int sprite_w, sprite_h;
static SDL_BlendMode blendMode = SDL_BLENDMODE_BLEND;
+static Uint32 next_fps_check, frames;
+static const Uint32 fps_check_delay = 5000;
/* Number of iterations to move sprites - used for visual tests. */
/* -1: infinite random moves (default); >=0: enables N deterministic moves */
@@ -244,6 +246,7 @@ MoveSprites(SDL_Renderer * renderer, SDL_Texture * sprite)
void
loop()
{
+ Uint32 now;
int i;
SDL_Event event;
@@ -261,13 +264,24 @@ loop()
emscripten_cancel_main_loop();
}
#endif
+
+ frames++;
+ now = SDL_GetTicks();
+ if (SDL_TICKS_PASSED(now, next_fps_check)) {
+ /* Print out some timing information */
+ const Uint32 then = next_fps_check - fps_check_delay;
+ const double fps = ((double) frames * 1000) / (now - then);
+ SDL_Log("%2.2f frames per second\n", fps);
+ next_fps_check = now + fps_check_delay;
+ frames = 0;
+ }
+
}
int
main(int argc, char *argv[])
{
int i;
- Uint32 then, now, frames;
Uint64 seed;
const char *icon = "icon.bmp";
@@ -384,24 +398,17 @@ main(int argc, char *argv[])
/* Main render loop */
frames = 0;
- then = SDL_GetTicks();
+ next_fps_check = SDL_GetTicks() + fps_check_delay;
done = 0;
#ifdef __EMSCRIPTEN__
emscripten_set_main_loop(loop, 0, 1);
#else
while (!done) {
- ++frames;
loop();
}
#endif
- /* Print out some timing information */
- now = SDL_GetTicks();
- if (now > then) {
- double fps = ((double) frames * 1000) / (now - then);
- SDL_Log("%2.2f frames per second\n", fps);
- }
quit(0);
return 0;
}
diff --git a/wayland-protocols/org-kde-kwin-server-decoration-manager.xml b/wayland-protocols/org-kde-kwin-server-decoration-manager.xml
new file mode 100644
index 0000000000..8bc106c7c4
--- /dev/null
+++ b/wayland-protocols/org-kde-kwin-server-decoration-manager.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="server_decoration">
+ <copyright><![CDATA[
+ Copyright (C) 2015 Martin Gräßlin
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ ]]></copyright>
+ <interface name="org_kde_kwin_server_decoration_manager" version="1">
+ <description summary="Server side window decoration manager">
+ This interface allows to coordinate whether the server should create
+ a server-side window decoration around a wl_surface representing a
+ shell surface (wl_shell_surface or similar). By announcing support
+ for this interface the server indicates that it supports server
+ side decorations.
+ </description>
+ <request name="create">
+ <description summary="Create a server-side decoration object for a given surface">
+ When a client creates a server-side decoration object it indicates
+ that it supports the protocol. The client is supposed to tell the
+ server whether it wants server-side decorations or will provide
+ client-side decorations.
+
+ If the client does not create a server-side decoration object for
+ a surface the server interprets this as lack of support for this
+ protocol and considers it as client-side decorated. Nevertheless a
+ client-side decorated surface should use this protocol to indicate
+ to the server that it does not want a server-side deco.
+ </description>
+ <arg name="id" type="new_id" interface="org_kde_kwin_server_decoration"/>
+ <arg name="surface" type="object" interface="wl_surface"/>
+ </request>
+ <enum name="mode">
+ <description summary="Possible values to use in request_mode and the event mode."/>
+ <entry name="None" value="0" summary="Undecorated: The surface is not decorated at all, neither server nor client-side. An example is a popup surface which should not be decorated."/>
+ <entry name="Client" value="1" summary="Client-side decoration: The decoration is part of the surface and the client."/>
+ <entry name="Server" value="2" summary="Server-side decoration: The server embeds the surface into a decoration frame."/>
+ </enum>
+ <event name="default_mode">
+ <description summary="The default mode used on the server">
+ This event is emitted directly after binding the interface. It contains
+ the default mode for the decoration. When a new server decoration object
+ is created this new object will be in the default mode until the first
+ request_mode is requested.
+
+ The server may change the default mode at any time.
+ </description>
+ <arg name="mode" type="uint" summary="The default decoration mode applied to newly created server decorations."/>
+ </event>
+ </interface>
+ <interface name="org_kde_kwin_server_decoration" version="1">
+ <request name="release" type="destructor">
+ <description summary="release the server decoration object"/>
+ </request>
+ <enum name="mode">
+ <description summary="Possible values to use in request_mode and the event mode."/>
+ <entry name="None" value="0" summary="Undecorated: The surface is not decorated at all, neither server nor client-side. An example is a popup surface which should not be decorated."/>
+ <entry name="Client" value="1" summary="Client-side decoration: The decoration is part of the surface and the client."/>
+ <entry name="Server" value="2" summary="Server-side decoration: The server embeds the surface into a decoration frame."/>
+ </enum>
+ <request name="request_mode">
+ <description summary="The decoration mode the surface wants to use."/>
+ <arg name="mode" type="uint" summary="The mode this surface wants to use."/>
+ </request>
+ <event name="mode">
+ <description summary="The new decoration mode applied by the server">
+ This event is emitted directly after the decoration is created and
+ represents the base decoration policy by the server. E.g. a server
+ which wants all surfaces to be client-side decorated will send Client,
+ a server which wants server-side decoration will send Server.
+
+ The client can request a different mode through the decoration request.
+ The server will acknowledge this by another event with the same mode. So
+ even if a server prefers server-side decoration it's possible to force a
+ client-side decoration.
+
+ The server may emit this event at any time. In this case the client can
+ again request a different mode. It's the responsibility of the server to
+ prevent a feedback loop.
+ </description>
+ <arg name="mode" type="uint" summary="The decoration mode applied to the surface by the server."/>
+ </event>
+ </interface>
+</protocol>