1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
4 
5   This software is provided 'as-is', without any express or implied
6   warranty.  In no event will the authors be held liable for any damages
7   arising from the use of this software.
8 
9   Permission is granted to anyone to use this software for any purpose,
10   including commercial applications, and to alter it and redistribute it
11   freely, subject to the following restrictions:
12 
13   1. The origin of this software must not be misrepresented; you must not
14      claim that you wrote the original software. If you use this software
15      in a product, an acknowledgment in the product documentation would be
16      appreciated but is not required.
17   2. Altered source versions must be plainly marked as such, and must not be
18      misrepresented as being the original software.
19   3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "../../SDL_internal.h"
22 
23 #if SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED
24 
25 #include "SDL_hints.h"
26 #include "SDL_log.h"
27 #include "SDL_assert.h"
28 #include "SDL_opengl.h"
29 #include "../SDL_sysrender.h"
30 #include "SDL_shaders_gl.h"
31 
32 #ifdef __MACOSX__
33 #include <OpenGL/OpenGL.h>
34 #endif
35 
36 /* To prevent unnecessary window recreation,
37  * these should match the defaults selected in SDL_GL_ResetAttributes
38  */
39 
40 #define RENDERER_CONTEXT_MAJOR 2
41 #define RENDERER_CONTEXT_MINOR 1
42 
43 /* OpenGL renderer implementation */
44 
45 /* Details on optimizing the texture path on Mac OS X:
46    http://developer.apple.com/library/mac/#documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_texturedata/opengl_texturedata.html
47 */
48 
49 /* Used to re-create the window with OpenGL capability */
50 extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags);
51 
52 static const float inv255f = 1.0f / 255.0f;
53 
54 static SDL_Renderer *GL_CreateRenderer(SDL_Window * window, Uint32 flags);
55 static void GL_WindowEvent(SDL_Renderer * renderer,
56                            const SDL_WindowEvent *event);
57 static int GL_GetOutputSize(SDL_Renderer * renderer, int *w, int *h);
58 static SDL_bool GL_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode);
59 static int GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
60 static int GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
61                             const SDL_Rect * rect, const void *pixels,
62                             int pitch);
63 static int GL_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
64                                const SDL_Rect * rect,
65                                const Uint8 *Yplane, int Ypitch,
66                                const Uint8 *Uplane, int Upitch,
67                                const Uint8 *Vplane, int Vpitch);
68 static int GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
69                           const SDL_Rect * rect, void **pixels, int *pitch);
70 static void GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
71 static int GL_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture);
72 static int GL_UpdateViewport(SDL_Renderer * renderer);
73 static int GL_UpdateClipRect(SDL_Renderer * renderer);
74 static int GL_RenderClear(SDL_Renderer * renderer);
75 static int GL_RenderDrawPoints(SDL_Renderer * renderer,
76                                const SDL_FPoint * points, int count);
77 static int GL_RenderDrawLines(SDL_Renderer * renderer,
78                               const SDL_FPoint * points, int count);
79 static int GL_RenderFillRects(SDL_Renderer * renderer,
80                               const SDL_FRect * rects, int count);
81 static int GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
82                          const SDL_Rect * srcrect, const SDL_FRect * dstrect);
83 static int GL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
84                          const SDL_Rect * srcrect, const SDL_FRect * dstrect,
85                          const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip);
86 static int GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
87                                Uint32 pixel_format, void * pixels, int pitch);
88 static void GL_RenderPresent(SDL_Renderer * renderer);
89 static void GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture);
90 static void GL_DestroyRenderer(SDL_Renderer * renderer);
91 static int GL_BindTexture (SDL_Renderer * renderer, SDL_Texture *texture, float *texw, float *texh);
92 static int GL_UnbindTexture (SDL_Renderer * renderer, SDL_Texture *texture);
93 
94 SDL_RenderDriver GL_RenderDriver = {
95     GL_CreateRenderer,
96     {
97      "opengl",
98      (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
99      1,
100      {SDL_PIXELFORMAT_ARGB8888},
101      0,
102      0}
103 };
104 
105 typedef struct GL_FBOList GL_FBOList;
106 
107 struct GL_FBOList
108 {
109     Uint32 w, h;
110     GLuint FBO;
111     GL_FBOList *next;
112 };
113 
114 typedef struct
115 {
116     SDL_GLContext context;
117 
118     SDL_bool debug_enabled;
119     SDL_bool GL_ARB_debug_output_supported;
120     int errors;
121     char **error_messages;
122     GLDEBUGPROCARB next_error_callback;
123     GLvoid *next_error_userparam;
124 
125     SDL_bool GL_ARB_texture_non_power_of_two_supported;
126     SDL_bool GL_ARB_texture_rectangle_supported;
127     struct {
128         GL_Shader shader;
129         Uint32 color;
130         SDL_BlendMode blendMode;
131     } current;
132 
133     SDL_bool GL_EXT_framebuffer_object_supported;
134     GL_FBOList *framebuffers;
135 
136     /* OpenGL functions */
137 #define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
138 #include "SDL_glfuncs.h"
139 #undef SDL_PROC
140 
141     /* Multitexture support */
142     SDL_bool GL_ARB_multitexture_supported;
143     PFNGLACTIVETEXTUREARBPROC glActiveTextureARB;
144     GLint num_texture_units;
145 
146     PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT;
147     PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT;
148     PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT;
149     PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT;
150     PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT;
151 
152     /* Shader support */
153     GL_ShaderContext *shaders;
154 
155 } GL_RenderData;
156 
157 typedef struct
158 {
159     GLuint texture;
160     GLenum type;
161     GLfloat texw;
162     GLfloat texh;
163     GLenum format;
164     GLenum formattype;
165     void *pixels;
166     int pitch;
167     SDL_Rect locked_rect;
168 
169     /* YUV texture support */
170     SDL_bool yuv;
171     SDL_bool nv12;
172     GLuint utexture;
173     GLuint vtexture;
174 
175     GL_FBOList *fbo;
176 } GL_TextureData;
177 
178 SDL_FORCE_INLINE const char*
GL_TranslateError(GLenum error)179 GL_TranslateError (GLenum error)
180 {
181 #define GL_ERROR_TRANSLATE(e) case e: return #e;
182     switch (error) {
183     GL_ERROR_TRANSLATE(GL_INVALID_ENUM)
184     GL_ERROR_TRANSLATE(GL_INVALID_VALUE)
185     GL_ERROR_TRANSLATE(GL_INVALID_OPERATION)
186     GL_ERROR_TRANSLATE(GL_OUT_OF_MEMORY)
187     GL_ERROR_TRANSLATE(GL_NO_ERROR)
188     GL_ERROR_TRANSLATE(GL_STACK_OVERFLOW)
189     GL_ERROR_TRANSLATE(GL_STACK_UNDERFLOW)
190     GL_ERROR_TRANSLATE(GL_TABLE_TOO_LARGE)
191     default:
192         return "UNKNOWN";
193 }
194 #undef GL_ERROR_TRANSLATE
195 }
196 
197 SDL_FORCE_INLINE void
GL_ClearErrors(SDL_Renderer * renderer)198 GL_ClearErrors(SDL_Renderer *renderer)
199 {
200     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
201 
202     if (!data->debug_enabled)
203     {
204         return;
205     }
206     if (data->GL_ARB_debug_output_supported) {
207         if (data->errors) {
208             int i;
209             for (i = 0; i < data->errors; ++i) {
210                 SDL_free(data->error_messages[i]);
211             }
212             SDL_free(data->error_messages);
213 
214             data->errors = 0;
215             data->error_messages = NULL;
216         }
217     } else {
218         while (data->glGetError() != GL_NO_ERROR) {
219             continue;
220         }
221     }
222 }
223 
224 SDL_FORCE_INLINE int
GL_CheckAllErrors(const char * prefix,SDL_Renderer * renderer,const char * file,int line,const char * function)225 GL_CheckAllErrors (const char *prefix, SDL_Renderer *renderer, const char *file, int line, const char *function)
226 {
227     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
228     int ret = 0;
229 
230     if (!data->debug_enabled)
231     {
232         return 0;
233     }
234     if (data->GL_ARB_debug_output_supported) {
235         if (data->errors) {
236             int i;
237             for (i = 0; i < data->errors; ++i) {
238                 SDL_SetError("%s: %s (%d): %s %s", prefix, file, line, function, data->error_messages[i]);
239                 ret = -1;
240             }
241             GL_ClearErrors(renderer);
242         }
243     } else {
244         /* check gl errors (can return multiple errors) */
245         for (;;) {
246             GLenum error = data->glGetError();
247             if (error != GL_NO_ERROR) {
248                 if (prefix == NULL || prefix[0] == '\0') {
249                     prefix = "generic";
250                 }
251                 SDL_SetError("%s: %s (%d): %s %s (0x%X)", prefix, file, line, function, GL_TranslateError(error), error);
252                 ret = -1;
253             } else {
254                 break;
255             }
256         }
257     }
258     return ret;
259 }
260 
261 #if 0
262 #define GL_CheckError(prefix, renderer)
263 #else
264 #define GL_CheckError(prefix, renderer) GL_CheckAllErrors(prefix, renderer, SDL_FILE, SDL_LINE, SDL_FUNCTION)
265 #endif
266 
267 static int
GL_LoadFunctions(GL_RenderData * data)268 GL_LoadFunctions(GL_RenderData * data)
269 {
270 #ifdef __SDL_NOGETPROCADDR__
271 #define SDL_PROC(ret,func,params) data->func=func;
272 #else
273 #define SDL_PROC(ret,func,params) \
274     do { \
275         data->func = SDL_GL_GetProcAddress(#func); \
276         if ( ! data->func ) { \
277             return SDL_SetError("Couldn't load GL function %s: %s", #func, SDL_GetError()); \
278         } \
279     } while ( 0 );
280 #endif /* __SDL_NOGETPROCADDR__ */
281 
282 #include "SDL_glfuncs.h"
283 #undef SDL_PROC
284     return 0;
285 }
286 
287 static SDL_GLContext SDL_CurrentContext = NULL;
288 
289 static int
GL_ActivateRenderer(SDL_Renderer * renderer)290 GL_ActivateRenderer(SDL_Renderer * renderer)
291 {
292     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
293 
294     if (SDL_CurrentContext != data->context ||
295         SDL_GL_GetCurrentContext() != data->context) {
296         if (SDL_GL_MakeCurrent(renderer->window, data->context) < 0) {
297             return -1;
298         }
299         SDL_CurrentContext = data->context;
300 
301         GL_UpdateViewport(renderer);
302     }
303 
304     GL_ClearErrors(renderer);
305 
306     return 0;
307 }
308 
309 /* This is called if we need to invalidate all of the SDL OpenGL state */
310 static void
GL_ResetState(SDL_Renderer * renderer)311 GL_ResetState(SDL_Renderer *renderer)
312 {
313     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
314 
315     if (SDL_GL_GetCurrentContext() == data->context) {
316         GL_UpdateViewport(renderer);
317     } else {
318         GL_ActivateRenderer(renderer);
319     }
320 
321     data->current.shader = SHADER_NONE;
322     data->current.color = 0xffffffff;
323     data->current.blendMode = SDL_BLENDMODE_INVALID;
324 
325     data->glDisable(GL_DEPTH_TEST);
326     data->glDisable(GL_CULL_FACE);
327     /* This ended up causing video discrepancies between OpenGL and Direct3D */
328     /* data->glEnable(GL_LINE_SMOOTH); */
329 
330     data->glMatrixMode(GL_MODELVIEW);
331     data->glLoadIdentity();
332 
333     GL_CheckError("", renderer);
334 }
335 
336 static void APIENTRY
GL_HandleDebugMessage(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const char * message,const void * userParam)337 GL_HandleDebugMessage(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char *message, const void *userParam)
338 {
339     SDL_Renderer *renderer = (SDL_Renderer *) userParam;
340     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
341 
342     if (type == GL_DEBUG_TYPE_ERROR_ARB) {
343         /* Record this error */
344         int errors = data->errors + 1;
345         char **error_messages = SDL_realloc(data->error_messages, errors * sizeof(*data->error_messages));
346         if (error_messages) {
347             data->errors = errors;
348             data->error_messages = error_messages;
349             data->error_messages[data->errors-1] = SDL_strdup(message);
350         }
351     }
352 
353     /* If there's another error callback, pass it along, otherwise log it */
354     if (data->next_error_callback) {
355         data->next_error_callback(source, type, id, severity, length, message, data->next_error_userparam);
356     } else {
357         if (type == GL_DEBUG_TYPE_ERROR_ARB) {
358             SDL_LogError(SDL_LOG_CATEGORY_RENDER, "%s", message);
359         } else {
360             SDL_LogDebug(SDL_LOG_CATEGORY_RENDER, "%s", message);
361         }
362     }
363 }
364 
365 static GL_FBOList *
GL_GetFBO(GL_RenderData * data,Uint32 w,Uint32 h)366 GL_GetFBO(GL_RenderData *data, Uint32 w, Uint32 h)
367 {
368     GL_FBOList *result = data->framebuffers;
369 
370     while (result && ((result->w != w) || (result->h != h))) {
371         result = result->next;
372     }
373 
374     if (!result) {
375         result = SDL_malloc(sizeof(GL_FBOList));
376         if (result) {
377             result->w = w;
378             result->h = h;
379             data->glGenFramebuffersEXT(1, &result->FBO);
380             result->next = data->framebuffers;
381             data->framebuffers = result;
382         }
383     }
384     return result;
385 }
386 
387 SDL_Renderer *
GL_CreateRenderer(SDL_Window * window,Uint32 flags)388 GL_CreateRenderer(SDL_Window * window, Uint32 flags)
389 {
390     SDL_Renderer *renderer;
391     GL_RenderData *data;
392     GLint value;
393     Uint32 window_flags;
394     int profile_mask = 0, major = 0, minor = 0;
395     SDL_bool changed_window = SDL_FALSE;
396 
397     SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profile_mask);
398     SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major);
399     SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor);
400 
401     window_flags = SDL_GetWindowFlags(window);
402     if (!(window_flags & SDL_WINDOW_OPENGL) ||
403         profile_mask == SDL_GL_CONTEXT_PROFILE_ES || major != RENDERER_CONTEXT_MAJOR || minor != RENDERER_CONTEXT_MINOR) {
404 
405         changed_window = SDL_TRUE;
406         SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0);
407         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, RENDERER_CONTEXT_MAJOR);
408         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, RENDERER_CONTEXT_MINOR);
409 
410         if (SDL_RecreateWindow(window, window_flags | SDL_WINDOW_OPENGL) < 0) {
411             goto error;
412         }
413     }
414 
415     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
416     if (!renderer) {
417         SDL_OutOfMemory();
418         goto error;
419     }
420 
421     data = (GL_RenderData *) SDL_calloc(1, sizeof(*data));
422     if (!data) {
423         GL_DestroyRenderer(renderer);
424         SDL_OutOfMemory();
425         goto error;
426     }
427 
428     renderer->WindowEvent = GL_WindowEvent;
429     renderer->GetOutputSize = GL_GetOutputSize;
430     renderer->SupportsBlendMode = GL_SupportsBlendMode;
431     renderer->CreateTexture = GL_CreateTexture;
432     renderer->UpdateTexture = GL_UpdateTexture;
433     renderer->UpdateTextureYUV = GL_UpdateTextureYUV;
434     renderer->LockTexture = GL_LockTexture;
435     renderer->UnlockTexture = GL_UnlockTexture;
436     renderer->SetRenderTarget = GL_SetRenderTarget;
437     renderer->UpdateViewport = GL_UpdateViewport;
438     renderer->UpdateClipRect = GL_UpdateClipRect;
439     renderer->RenderClear = GL_RenderClear;
440     renderer->RenderDrawPoints = GL_RenderDrawPoints;
441     renderer->RenderDrawLines = GL_RenderDrawLines;
442     renderer->RenderFillRects = GL_RenderFillRects;
443     renderer->RenderCopy = GL_RenderCopy;
444     renderer->RenderCopyEx = GL_RenderCopyEx;
445     renderer->RenderReadPixels = GL_RenderReadPixels;
446     renderer->RenderPresent = GL_RenderPresent;
447     renderer->DestroyTexture = GL_DestroyTexture;
448     renderer->DestroyRenderer = GL_DestroyRenderer;
449     renderer->GL_BindTexture = GL_BindTexture;
450     renderer->GL_UnbindTexture = GL_UnbindTexture;
451     renderer->info = GL_RenderDriver.info;
452     renderer->info.flags = SDL_RENDERER_ACCELERATED;
453     renderer->driverdata = data;
454     renderer->window = window;
455 
456     data->context = SDL_GL_CreateContext(window);
457     if (!data->context) {
458         GL_DestroyRenderer(renderer);
459         goto error;
460     }
461     if (SDL_GL_MakeCurrent(window, data->context) < 0) {
462         GL_DestroyRenderer(renderer);
463         goto error;
464     }
465 
466     if (GL_LoadFunctions(data) < 0) {
467         GL_DestroyRenderer(renderer);
468         goto error;
469     }
470 
471 #ifdef __MACOSX__
472     /* Enable multi-threaded rendering */
473     /* Disabled until Ryan finishes his VBO/PBO code...
474        CGLEnable(CGLGetCurrentContext(), kCGLCEMPEngine);
475      */
476 #endif
477 
478     if (flags & SDL_RENDERER_PRESENTVSYNC) {
479         SDL_GL_SetSwapInterval(1);
480     } else {
481         SDL_GL_SetSwapInterval(0);
482     }
483     if (SDL_GL_GetSwapInterval() > 0) {
484         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
485     }
486 
487     /* Check for debug output support */
488     if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_FLAGS, &value) == 0 &&
489         (value & SDL_GL_CONTEXT_DEBUG_FLAG)) {
490         data->debug_enabled = SDL_TRUE;
491     }
492     if (data->debug_enabled && SDL_GL_ExtensionSupported("GL_ARB_debug_output")) {
493         PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARBFunc = (PFNGLDEBUGMESSAGECALLBACKARBPROC) SDL_GL_GetProcAddress("glDebugMessageCallbackARB");
494 
495         data->GL_ARB_debug_output_supported = SDL_TRUE;
496         data->glGetPointerv(GL_DEBUG_CALLBACK_FUNCTION_ARB, (GLvoid **)(char *)&data->next_error_callback);
497         data->glGetPointerv(GL_DEBUG_CALLBACK_USER_PARAM_ARB, &data->next_error_userparam);
498         glDebugMessageCallbackARBFunc(GL_HandleDebugMessage, renderer);
499 
500         /* Make sure our callback is called when errors actually happen */
501         data->glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
502     }
503 
504     if (SDL_GL_ExtensionSupported("GL_ARB_texture_non_power_of_two")) {
505         data->GL_ARB_texture_non_power_of_two_supported = SDL_TRUE;
506     } else if (SDL_GL_ExtensionSupported("GL_ARB_texture_rectangle") ||
507                SDL_GL_ExtensionSupported("GL_EXT_texture_rectangle")) {
508         data->GL_ARB_texture_rectangle_supported = SDL_TRUE;
509     }
510     if (data->GL_ARB_texture_rectangle_supported) {
511         data->glGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB, &value);
512         renderer->info.max_texture_width = value;
513         renderer->info.max_texture_height = value;
514     } else {
515         data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
516         renderer->info.max_texture_width = value;
517         renderer->info.max_texture_height = value;
518     }
519 
520     /* Check for multitexture support */
521     if (SDL_GL_ExtensionSupported("GL_ARB_multitexture")) {
522         data->glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC) SDL_GL_GetProcAddress("glActiveTextureARB");
523         if (data->glActiveTextureARB) {
524             data->GL_ARB_multitexture_supported = SDL_TRUE;
525             data->glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &data->num_texture_units);
526         }
527     }
528 
529     /* Check for shader support */
530     if (SDL_GetHintBoolean(SDL_HINT_RENDER_OPENGL_SHADERS, SDL_TRUE)) {
531         data->shaders = GL_CreateShaderContext();
532     }
533     SDL_LogInfo(SDL_LOG_CATEGORY_RENDER, "OpenGL shaders: %s",
534                 data->shaders ? "ENABLED" : "DISABLED");
535 
536     /* We support YV12 textures using 3 textures and a shader */
537     if (data->shaders && data->num_texture_units >= 3) {
538         renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;
539         renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
540         renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_NV12;
541         renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_NV21;
542     }
543 
544 #ifdef __MACOSX__
545     renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_UYVY;
546 #endif
547 
548     if (SDL_GL_ExtensionSupported("GL_EXT_framebuffer_object")) {
549         data->GL_EXT_framebuffer_object_supported = SDL_TRUE;
550         data->glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC)
551             SDL_GL_GetProcAddress("glGenFramebuffersEXT");
552         data->glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC)
553             SDL_GL_GetProcAddress("glDeleteFramebuffersEXT");
554         data->glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)
555             SDL_GL_GetProcAddress("glFramebufferTexture2DEXT");
556         data->glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)
557             SDL_GL_GetProcAddress("glBindFramebufferEXT");
558         data->glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)
559             SDL_GL_GetProcAddress("glCheckFramebufferStatusEXT");
560         renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE;
561     }
562     data->framebuffers = NULL;
563 
564     /* Set up parameters for rendering */
565     GL_ResetState(renderer);
566 
567     return renderer;
568 
569 error:
570     if (changed_window) {
571         /* Uh oh, better try to put it back... */
572         SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profile_mask);
573         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major);
574         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minor);
575         SDL_RecreateWindow(window, window_flags);
576     }
577     return NULL;
578 }
579 
580 static void
GL_WindowEvent(SDL_Renderer * renderer,const SDL_WindowEvent * event)581 GL_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
582 {
583     if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED ||
584         event->event == SDL_WINDOWEVENT_SHOWN ||
585         event->event == SDL_WINDOWEVENT_HIDDEN) {
586         /* Rebind the context to the window area and update matrices */
587         SDL_CurrentContext = NULL;
588     }
589 }
590 
591 static int
GL_GetOutputSize(SDL_Renderer * renderer,int * w,int * h)592 GL_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
593 {
594     SDL_GL_GetDrawableSize(renderer->window, w, h);
595     return 0;
596 }
597 
GetBlendFunc(SDL_BlendFactor factor)598 static GLenum GetBlendFunc(SDL_BlendFactor factor)
599 {
600     switch (factor) {
601     case SDL_BLENDFACTOR_ZERO:
602         return GL_ZERO;
603     case SDL_BLENDFACTOR_ONE:
604         return GL_ONE;
605     case SDL_BLENDFACTOR_SRC_COLOR:
606         return GL_SRC_COLOR;
607     case SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR:
608         return GL_ONE_MINUS_SRC_COLOR;
609     case SDL_BLENDFACTOR_SRC_ALPHA:
610         return GL_SRC_ALPHA;
611     case SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA:
612         return GL_ONE_MINUS_SRC_ALPHA;
613     case SDL_BLENDFACTOR_DST_COLOR:
614         return GL_DST_COLOR;
615     case SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR:
616         return GL_ONE_MINUS_DST_COLOR;
617     case SDL_BLENDFACTOR_DST_ALPHA:
618         return GL_DST_ALPHA;
619     case SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA:
620         return GL_ONE_MINUS_DST_ALPHA;
621     default:
622         return GL_INVALID_ENUM;
623     }
624 }
625 
GetBlendEquation(SDL_BlendOperation operation)626 static GLenum GetBlendEquation(SDL_BlendOperation operation)
627 {
628     switch (operation) {
629     case SDL_BLENDOPERATION_ADD:
630         return GL_FUNC_ADD;
631     case SDL_BLENDOPERATION_SUBTRACT:
632         return GL_FUNC_SUBTRACT;
633     case SDL_BLENDOPERATION_REV_SUBTRACT:
634         return GL_FUNC_REVERSE_SUBTRACT;
635     default:
636         return GL_INVALID_ENUM;
637     }
638 }
639 
640 static SDL_bool
GL_SupportsBlendMode(SDL_Renderer * renderer,SDL_BlendMode blendMode)641 GL_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
642 {
643     SDL_BlendFactor srcColorFactor = SDL_GetBlendModeSrcColorFactor(blendMode);
644     SDL_BlendFactor srcAlphaFactor = SDL_GetBlendModeSrcAlphaFactor(blendMode);
645     SDL_BlendOperation colorOperation = SDL_GetBlendModeColorOperation(blendMode);
646     SDL_BlendFactor dstColorFactor = SDL_GetBlendModeDstColorFactor(blendMode);
647     SDL_BlendFactor dstAlphaFactor = SDL_GetBlendModeDstAlphaFactor(blendMode);
648     SDL_BlendOperation alphaOperation = SDL_GetBlendModeAlphaOperation(blendMode);
649 
650     if (GetBlendFunc(srcColorFactor) == GL_INVALID_ENUM ||
651         GetBlendFunc(srcAlphaFactor) == GL_INVALID_ENUM ||
652         GetBlendEquation(colorOperation) == GL_INVALID_ENUM ||
653         GetBlendFunc(dstColorFactor) == GL_INVALID_ENUM ||
654         GetBlendFunc(dstAlphaFactor) == GL_INVALID_ENUM ||
655         GetBlendEquation(alphaOperation) == GL_INVALID_ENUM) {
656         return SDL_FALSE;
657     }
658     if (colorOperation != alphaOperation) {
659         return SDL_FALSE;
660     }
661     return SDL_TRUE;
662 }
663 
664 SDL_FORCE_INLINE int
power_of_2(int input)665 power_of_2(int input)
666 {
667     int value = 1;
668 
669     while (value < input) {
670         value <<= 1;
671     }
672     return value;
673 }
674 
675 SDL_FORCE_INLINE SDL_bool
convert_format(GL_RenderData * renderdata,Uint32 pixel_format,GLint * internalFormat,GLenum * format,GLenum * type)676 convert_format(GL_RenderData *renderdata, Uint32 pixel_format,
677                GLint* internalFormat, GLenum* format, GLenum* type)
678 {
679     switch (pixel_format) {
680     case SDL_PIXELFORMAT_ARGB8888:
681         *internalFormat = GL_RGBA8;
682         *format = GL_BGRA;
683         *type = GL_UNSIGNED_INT_8_8_8_8_REV;
684         break;
685     case SDL_PIXELFORMAT_YV12:
686     case SDL_PIXELFORMAT_IYUV:
687     case SDL_PIXELFORMAT_NV12:
688     case SDL_PIXELFORMAT_NV21:
689         *internalFormat = GL_LUMINANCE;
690         *format = GL_LUMINANCE;
691         *type = GL_UNSIGNED_BYTE;
692         break;
693 #ifdef __MACOSX__
694     case SDL_PIXELFORMAT_UYVY:
695         *internalFormat = GL_RGB8;
696         *format = GL_YCBCR_422_APPLE;
697         *type = GL_UNSIGNED_SHORT_8_8_APPLE;
698         break;
699 #endif
700     default:
701         return SDL_FALSE;
702     }
703     return SDL_TRUE;
704 }
705 
706 static GLenum
GetScaleQuality(void)707 GetScaleQuality(void)
708 {
709     const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
710 
711     if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) {
712         return GL_NEAREST;
713     } else {
714         return GL_LINEAR;
715     }
716 }
717 
718 static int
GL_CreateTexture(SDL_Renderer * renderer,SDL_Texture * texture)719 GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
720 {
721     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
722     GL_TextureData *data;
723     GLint internalFormat;
724     GLenum format, type;
725     int texture_w, texture_h;
726     GLenum scaleMode;
727 
728     GL_ActivateRenderer(renderer);
729 
730     if (texture->access == SDL_TEXTUREACCESS_TARGET &&
731         !renderdata->GL_EXT_framebuffer_object_supported) {
732         return SDL_SetError("Render targets not supported by OpenGL");
733     }
734 
735     if (!convert_format(renderdata, texture->format, &internalFormat,
736                         &format, &type)) {
737         return SDL_SetError("Texture format %s not supported by OpenGL",
738                             SDL_GetPixelFormatName(texture->format));
739     }
740 
741     data = (GL_TextureData *) SDL_calloc(1, sizeof(*data));
742     if (!data) {
743         return SDL_OutOfMemory();
744     }
745 
746     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
747         size_t size;
748         data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);
749         size = texture->h * data->pitch;
750         if (texture->format == SDL_PIXELFORMAT_YV12 ||
751             texture->format == SDL_PIXELFORMAT_IYUV) {
752             /* Need to add size for the U and V planes */
753             size += 2 * ((texture->h + 1) / 2) * ((data->pitch + 1) / 2);
754         }
755         if (texture->format == SDL_PIXELFORMAT_NV12 ||
756             texture->format == SDL_PIXELFORMAT_NV21) {
757             /* Need to add size for the U/V plane */
758             size += 2 * ((texture->h + 1) / 2) * ((data->pitch + 1) / 2);
759         }
760         data->pixels = SDL_calloc(1, size);
761         if (!data->pixels) {
762             SDL_free(data);
763             return SDL_OutOfMemory();
764         }
765     }
766 
767     if (texture->access == SDL_TEXTUREACCESS_TARGET) {
768         data->fbo = GL_GetFBO(renderdata, texture->w, texture->h);
769     } else {
770         data->fbo = NULL;
771     }
772 
773     GL_CheckError("", renderer);
774     renderdata->glGenTextures(1, &data->texture);
775     if (GL_CheckError("glGenTextures()", renderer) < 0) {
776         if (data->pixels) {
777             SDL_free(data->pixels);
778         }
779         SDL_free(data);
780         return -1;
781     }
782     texture->driverdata = data;
783 
784     if (renderdata->GL_ARB_texture_non_power_of_two_supported) {
785         data->type = GL_TEXTURE_2D;
786         texture_w = texture->w;
787         texture_h = texture->h;
788         data->texw = 1.0f;
789         data->texh = 1.0f;
790     } else if (renderdata->GL_ARB_texture_rectangle_supported) {
791         data->type = GL_TEXTURE_RECTANGLE_ARB;
792         texture_w = texture->w;
793         texture_h = texture->h;
794         data->texw = (GLfloat) texture_w;
795         data->texh = (GLfloat) texture_h;
796     } else {
797         data->type = GL_TEXTURE_2D;
798         texture_w = power_of_2(texture->w);
799         texture_h = power_of_2(texture->h);
800         data->texw = (GLfloat) (texture->w) / texture_w;
801         data->texh = (GLfloat) texture->h / texture_h;
802     }
803 
804     data->format = format;
805     data->formattype = type;
806     scaleMode = GetScaleQuality();
807     renderdata->glEnable(data->type);
808     renderdata->glBindTexture(data->type, data->texture);
809     renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER, scaleMode);
810     renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER, scaleMode);
811     /* According to the spec, CLAMP_TO_EDGE is the default for TEXTURE_RECTANGLE
812        and setting it causes an INVALID_ENUM error in the latest NVidia drivers.
813     */
814     if (data->type != GL_TEXTURE_RECTANGLE_ARB) {
815         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
816                                     GL_CLAMP_TO_EDGE);
817         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
818                                     GL_CLAMP_TO_EDGE);
819     }
820 #ifdef __MACOSX__
821 #ifndef GL_TEXTURE_STORAGE_HINT_APPLE
822 #define GL_TEXTURE_STORAGE_HINT_APPLE       0x85BC
823 #endif
824 #ifndef STORAGE_CACHED_APPLE
825 #define STORAGE_CACHED_APPLE                0x85BE
826 #endif
827 #ifndef STORAGE_SHARED_APPLE
828 #define STORAGE_SHARED_APPLE                0x85BF
829 #endif
830     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
831         renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
832                                     GL_STORAGE_SHARED_APPLE);
833     } else {
834         renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
835                                     GL_STORAGE_CACHED_APPLE);
836     }
837     if (texture->access == SDL_TEXTUREACCESS_STREAMING
838         && texture->format == SDL_PIXELFORMAT_ARGB8888
839         && (texture->w % 8) == 0) {
840         renderdata->glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
841         renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
842         renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH,
843                           (data->pitch / SDL_BYTESPERPIXEL(texture->format)));
844         renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
845                                  texture_h, 0, format, type, data->pixels);
846         renderdata->glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
847     }
848     else
849 #endif
850     {
851         renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
852                                  texture_h, 0, format, type, NULL);
853     }
854     renderdata->glDisable(data->type);
855     if (GL_CheckError("glTexImage2D()", renderer) < 0) {
856         return -1;
857     }
858 
859     if (texture->format == SDL_PIXELFORMAT_YV12 ||
860         texture->format == SDL_PIXELFORMAT_IYUV) {
861         data->yuv = SDL_TRUE;
862 
863         renderdata->glGenTextures(1, &data->utexture);
864         renderdata->glGenTextures(1, &data->vtexture);
865         renderdata->glEnable(data->type);
866 
867         renderdata->glBindTexture(data->type, data->utexture);
868         renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
869                                     scaleMode);
870         renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
871                                     scaleMode);
872         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
873                                     GL_CLAMP_TO_EDGE);
874         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
875                                     GL_CLAMP_TO_EDGE);
876         renderdata->glTexImage2D(data->type, 0, internalFormat, (texture_w+1)/2,
877                                  (texture_h+1)/2, 0, format, type, NULL);
878 
879         renderdata->glBindTexture(data->type, data->vtexture);
880         renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
881                                     scaleMode);
882         renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
883                                     scaleMode);
884         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
885                                     GL_CLAMP_TO_EDGE);
886         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
887                                     GL_CLAMP_TO_EDGE);
888         renderdata->glTexImage2D(data->type, 0, internalFormat, (texture_w+1)/2,
889                                  (texture_h+1)/2, 0, format, type, NULL);
890 
891         renderdata->glDisable(data->type);
892     }
893 
894     if (texture->format == SDL_PIXELFORMAT_NV12 ||
895         texture->format == SDL_PIXELFORMAT_NV21) {
896         data->nv12 = SDL_TRUE;
897 
898         renderdata->glGenTextures(1, &data->utexture);
899         renderdata->glEnable(data->type);
900 
901         renderdata->glBindTexture(data->type, data->utexture);
902         renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
903                                     scaleMode);
904         renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
905                                     scaleMode);
906         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
907                                     GL_CLAMP_TO_EDGE);
908         renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
909                                     GL_CLAMP_TO_EDGE);
910         renderdata->glTexImage2D(data->type, 0, GL_LUMINANCE_ALPHA, (texture_w+1)/2,
911                                  (texture_h+1)/2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL);
912         renderdata->glDisable(data->type);
913     }
914 
915     return GL_CheckError("", renderer);
916 }
917 
918 static int
GL_UpdateTexture(SDL_Renderer * renderer,SDL_Texture * texture,const SDL_Rect * rect,const void * pixels,int pitch)919 GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
920                  const SDL_Rect * rect, const void *pixels, int pitch)
921 {
922     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
923     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
924     const int texturebpp = SDL_BYTESPERPIXEL(texture->format);
925 
926     SDL_assert(texturebpp != 0);  /* otherwise, division by zero later. */
927 
928     GL_ActivateRenderer(renderer);
929 
930     renderdata->glEnable(data->type);
931     renderdata->glBindTexture(data->type, data->texture);
932     renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
933     renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, (pitch / texturebpp));
934     renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w,
935                                 rect->h, data->format, data->formattype,
936                                 pixels);
937     if (data->yuv) {
938         renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, ((pitch + 1) / 2));
939 
940         /* Skip to the correct offset into the next texture */
941         pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
942         if (texture->format == SDL_PIXELFORMAT_YV12) {
943             renderdata->glBindTexture(data->type, data->vtexture);
944         } else {
945             renderdata->glBindTexture(data->type, data->utexture);
946         }
947         renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
948                                     (rect->w+1)/2, (rect->h+1)/2,
949                                     data->format, data->formattype, pixels);
950 
951         /* Skip to the correct offset into the next texture */
952         pixels = (const void*)((const Uint8*)pixels + ((rect->h + 1) / 2) * ((pitch + 1) / 2));
953         if (texture->format == SDL_PIXELFORMAT_YV12) {
954             renderdata->glBindTexture(data->type, data->utexture);
955         } else {
956             renderdata->glBindTexture(data->type, data->vtexture);
957         }
958         renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
959                                     (rect->w+1)/2, (rect->h+1)/2,
960                                     data->format, data->formattype, pixels);
961     }
962 
963     if (data->nv12) {
964         renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, ((pitch + 1) / 2));
965 
966         /* Skip to the correct offset into the next texture */
967         pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
968         renderdata->glBindTexture(data->type, data->utexture);
969         renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
970                                     (rect->w + 1)/2, (rect->h + 1)/2,
971                                     GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, pixels);
972     }
973     renderdata->glDisable(data->type);
974 
975     return GL_CheckError("glTexSubImage2D()", renderer);
976 }
977 
978 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)979 GL_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
980                     const SDL_Rect * rect,
981                     const Uint8 *Yplane, int Ypitch,
982                     const Uint8 *Uplane, int Upitch,
983                     const Uint8 *Vplane, int Vpitch)
984 {
985     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
986     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
987 
988     GL_ActivateRenderer(renderer);
989 
990     renderdata->glEnable(data->type);
991     renderdata->glBindTexture(data->type, data->texture);
992     renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
993     renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, Ypitch);
994     renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w,
995                                 rect->h, data->format, data->formattype,
996                                 Yplane);
997 
998     renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, Upitch);
999     renderdata->glBindTexture(data->type, data->utexture);
1000     renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
1001                                 (rect->w + 1)/2, (rect->h + 1)/2,
1002                                 data->format, data->formattype, Uplane);
1003 
1004     renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, Vpitch);
1005     renderdata->glBindTexture(data->type, data->vtexture);
1006     renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
1007                                 (rect->w + 1)/2, (rect->h + 1)/2,
1008                                 data->format, data->formattype, Vplane);
1009     renderdata->glDisable(data->type);
1010 
1011     return GL_CheckError("glTexSubImage2D()", renderer);
1012 }
1013 
1014 static int
GL_LockTexture(SDL_Renderer * renderer,SDL_Texture * texture,const SDL_Rect * rect,void ** pixels,int * pitch)1015 GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
1016                const SDL_Rect * rect, void **pixels, int *pitch)
1017 {
1018     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
1019 
1020     data->locked_rect = *rect;
1021     *pixels =
1022         (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
1023                   rect->x * SDL_BYTESPERPIXEL(texture->format));
1024     *pitch = data->pitch;
1025     return 0;
1026 }
1027 
1028 static void
GL_UnlockTexture(SDL_Renderer * renderer,SDL_Texture * texture)1029 GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
1030 {
1031     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
1032     const SDL_Rect *rect;
1033     void *pixels;
1034 
1035     rect = &data->locked_rect;
1036     pixels =
1037         (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
1038                   rect->x * SDL_BYTESPERPIXEL(texture->format));
1039     GL_UpdateTexture(renderer, texture, rect, pixels, data->pitch);
1040 }
1041 
1042 static int
GL_SetRenderTarget(SDL_Renderer * renderer,SDL_Texture * texture)1043 GL_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
1044 {
1045     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
1046     GL_TextureData *texturedata;
1047     GLenum status;
1048 
1049     GL_ActivateRenderer(renderer);
1050 
1051     if (!data->GL_EXT_framebuffer_object_supported) {
1052         return SDL_SetError("Render targets not supported by OpenGL");
1053     }
1054 
1055     if (texture == NULL) {
1056         data->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1057         return 0;
1058     }
1059 
1060     texturedata = (GL_TextureData *) texture->driverdata;
1061     data->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, texturedata->fbo->FBO);
1062     /* TODO: check if texture pixel format allows this operation */
1063     data->glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, texturedata->type, texturedata->texture, 0);
1064     /* Check FBO status */
1065     status = data->glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
1066     if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
1067         return SDL_SetError("glFramebufferTexture2DEXT() failed");
1068     }
1069     return 0;
1070 }
1071 
1072 static int
GL_UpdateViewport(SDL_Renderer * renderer)1073 GL_UpdateViewport(SDL_Renderer * renderer)
1074 {
1075     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
1076 
1077     if (SDL_CurrentContext != data->context) {
1078         /* We'll update the viewport after we rebind the context */
1079         return 0;
1080     }
1081 
1082     if (renderer->target) {
1083         data->glViewport(renderer->viewport.x, renderer->viewport.y,
1084                          renderer->viewport.w, renderer->viewport.h);
1085     } else {
1086         int w, h;
1087 
1088         SDL_GL_GetDrawableSize(renderer->window, &w, &h);
1089         data->glViewport(renderer->viewport.x, (h - renderer->viewport.y - renderer->viewport.h),
1090                          renderer->viewport.w, renderer->viewport.h);
1091     }
1092 
1093     data->glMatrixMode(GL_PROJECTION);
1094     data->glLoadIdentity();
1095     if (renderer->viewport.w && renderer->viewport.h) {
1096         if (renderer->target) {
1097             data->glOrtho((GLdouble) 0,
1098                           (GLdouble) renderer->viewport.w,
1099                           (GLdouble) 0,
1100                           (GLdouble) renderer->viewport.h,
1101                            0.0, 1.0);
1102         } else {
1103             data->glOrtho((GLdouble) 0,
1104                           (GLdouble) renderer->viewport.w,
1105                           (GLdouble) renderer->viewport.h,
1106                           (GLdouble) 0,
1107                            0.0, 1.0);
1108         }
1109     }
1110     data->glMatrixMode(GL_MODELVIEW);
1111 
1112     return GL_CheckError("", renderer);
1113 }
1114 
1115 static int
GL_UpdateClipRect(SDL_Renderer * renderer)1116 GL_UpdateClipRect(SDL_Renderer * renderer)
1117 {
1118     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
1119 
1120     if (renderer->clipping_enabled) {
1121         const SDL_Rect *rect = &renderer->clip_rect;
1122         data->glEnable(GL_SCISSOR_TEST);
1123         if (renderer->target) {
1124             data->glScissor(renderer->viewport.x + rect->x, renderer->viewport.y + rect->y, rect->w, rect->h);
1125         } else {
1126             int w, h;
1127 
1128             SDL_GL_GetDrawableSize(renderer->window, &w, &h);
1129             data->glScissor(renderer->viewport.x + rect->x, h - renderer->viewport.y - rect->y - rect->h, rect->w, rect->h);
1130         }
1131     } else {
1132         data->glDisable(GL_SCISSOR_TEST);
1133     }
1134     return 0;
1135 }
1136 
1137 static void
GL_SetShader(GL_RenderData * data,GL_Shader shader)1138 GL_SetShader(GL_RenderData * data, GL_Shader shader)
1139 {
1140     if (data->shaders && shader != data->current.shader) {
1141         GL_SelectShader(data->shaders, shader);
1142         data->current.shader = shader;
1143     }
1144 }
1145 
1146 static void
GL_SetColor(GL_RenderData * data,Uint8 r,Uint8 g,Uint8 b,Uint8 a)1147 GL_SetColor(GL_RenderData * data, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1148 {
1149     Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b);
1150 
1151     if (color != data->current.color) {
1152         data->glColor4f((GLfloat) r * inv255f,
1153                         (GLfloat) g * inv255f,
1154                         (GLfloat) b * inv255f,
1155                         (GLfloat) a * inv255f);
1156         data->current.color = color;
1157     }
1158 }
1159 
1160 static void
GL_SetBlendMode(GL_RenderData * data,SDL_BlendMode blendMode)1161 GL_SetBlendMode(GL_RenderData * data, SDL_BlendMode blendMode)
1162 {
1163     if (blendMode != data->current.blendMode) {
1164         if (blendMode == SDL_BLENDMODE_NONE) {
1165             data->glDisable(GL_BLEND);
1166         } else {
1167             data->glEnable(GL_BLEND);
1168             data->glBlendFuncSeparate(GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blendMode)),
1169                                       GetBlendFunc(SDL_GetBlendModeDstColorFactor(blendMode)),
1170                                       GetBlendFunc(SDL_GetBlendModeSrcAlphaFactor(blendMode)),
1171                                       GetBlendFunc(SDL_GetBlendModeDstAlphaFactor(blendMode)));
1172             data->glBlendEquation(GetBlendEquation(SDL_GetBlendModeColorOperation(blendMode)));
1173         }
1174         data->current.blendMode = blendMode;
1175     }
1176 }
1177 
1178 static void
GL_SetDrawingState(SDL_Renderer * renderer)1179 GL_SetDrawingState(SDL_Renderer * renderer)
1180 {
1181     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
1182 
1183     GL_ActivateRenderer(renderer);
1184 
1185     GL_SetColor(data, renderer->r,
1186                       renderer->g,
1187                       renderer->b,
1188                       renderer->a);
1189 
1190     GL_SetBlendMode(data, renderer->blendMode);
1191 
1192     GL_SetShader(data, SHADER_SOLID);
1193 }
1194 
1195 static int
GL_RenderClear(SDL_Renderer * renderer)1196 GL_RenderClear(SDL_Renderer * renderer)
1197 {
1198     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
1199 
1200     GL_ActivateRenderer(renderer);
1201 
1202     data->glClearColor((GLfloat) renderer->r * inv255f,
1203                        (GLfloat) renderer->g * inv255f,
1204                        (GLfloat) renderer->b * inv255f,
1205                        (GLfloat) renderer->a * inv255f);
1206 
1207     if (renderer->clipping_enabled) {
1208         data->glDisable(GL_SCISSOR_TEST);
1209     }
1210 
1211     data->glClear(GL_COLOR_BUFFER_BIT);
1212 
1213     if (renderer->clipping_enabled) {
1214         data->glEnable(GL_SCISSOR_TEST);
1215     }
1216 
1217     return 0;
1218 }
1219 
1220 static int
GL_RenderDrawPoints(SDL_Renderer * renderer,const SDL_FPoint * points,int count)1221 GL_RenderDrawPoints(SDL_Renderer * renderer, const SDL_FPoint * points,
1222                     int count)
1223 {
1224     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
1225     int i;
1226 
1227     GL_SetDrawingState(renderer);
1228 
1229     data->glBegin(GL_POINTS);
1230     for (i = 0; i < count; ++i) {
1231         data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
1232     }
1233     data->glEnd();
1234 
1235     return 0;
1236 }
1237 
1238 static int
GL_RenderDrawLines(SDL_Renderer * renderer,const SDL_FPoint * points,int count)1239 GL_RenderDrawLines(SDL_Renderer * renderer, const SDL_FPoint * points,
1240                    int count)
1241 {
1242     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
1243     int i;
1244 
1245     GL_SetDrawingState(renderer);
1246 
1247     if (count > 2 &&
1248         points[0].x == points[count-1].x && points[0].y == points[count-1].y) {
1249         data->glBegin(GL_LINE_LOOP);
1250         /* GL_LINE_LOOP takes care of the final segment */
1251         --count;
1252         for (i = 0; i < count; ++i) {
1253             data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
1254         }
1255         data->glEnd();
1256     } else {
1257 #if defined(__MACOSX__) || defined(__WIN32__)
1258 #else
1259         int x1, y1, x2, y2;
1260 #endif
1261 
1262         data->glBegin(GL_LINE_STRIP);
1263         for (i = 0; i < count; ++i) {
1264             data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
1265         }
1266         data->glEnd();
1267 
1268         /* The line is half open, so we need one more point to complete it.
1269          * http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node47.html
1270          * If we have to, we can use vertical line and horizontal line textures
1271          * for vertical and horizontal lines, and then create custom textures
1272          * for diagonal lines and software render those.  It's terrible, but at
1273          * least it would be pixel perfect.
1274          */
1275         data->glBegin(GL_POINTS);
1276 #if defined(__MACOSX__) || defined(__WIN32__)
1277         /* Mac OS X and Windows seem to always leave the last point open */
1278         data->glVertex2f(0.5f + points[count-1].x, 0.5f + points[count-1].y);
1279 #else
1280         /* Linux seems to leave the right-most or bottom-most point open */
1281         x1 = points[0].x;
1282         y1 = points[0].y;
1283         x2 = points[count-1].x;
1284         y2 = points[count-1].y;
1285 
1286         if (x1 > x2) {
1287             data->glVertex2f(0.5f + x1, 0.5f + y1);
1288         } else if (x2 > x1) {
1289             data->glVertex2f(0.5f + x2, 0.5f + y2);
1290         }
1291         if (y1 > y2) {
1292             data->glVertex2f(0.5f + x1, 0.5f + y1);
1293         } else if (y2 > y1) {
1294             data->glVertex2f(0.5f + x2, 0.5f + y2);
1295         }
1296 #endif
1297         data->glEnd();
1298     }
1299     return GL_CheckError("", renderer);
1300 }
1301 
1302 static int
GL_RenderFillRects(SDL_Renderer * renderer,const SDL_FRect * rects,int count)1303 GL_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects, int count)
1304 {
1305     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
1306     int i;
1307 
1308     GL_SetDrawingState(renderer);
1309 
1310     for (i = 0; i < count; ++i) {
1311         const SDL_FRect *rect = &rects[i];
1312 
1313         data->glRectf(rect->x, rect->y, rect->x + rect->w, rect->y + rect->h);
1314     }
1315     return GL_CheckError("", renderer);
1316 }
1317 
1318 static int
GL_SetupCopy(SDL_Renderer * renderer,SDL_Texture * texture)1319 GL_SetupCopy(SDL_Renderer * renderer, SDL_Texture * texture)
1320 {
1321     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
1322     GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
1323 
1324     data->glEnable(texturedata->type);
1325     if (texturedata->yuv) {
1326         data->glActiveTextureARB(GL_TEXTURE2_ARB);
1327         data->glBindTexture(texturedata->type, texturedata->vtexture);
1328 
1329         data->glActiveTextureARB(GL_TEXTURE1_ARB);
1330         data->glBindTexture(texturedata->type, texturedata->utexture);
1331 
1332         data->glActiveTextureARB(GL_TEXTURE0_ARB);
1333     }
1334     if (texturedata->nv12) {
1335         data->glActiveTextureARB(GL_TEXTURE1_ARB);
1336         data->glBindTexture(texturedata->type, texturedata->utexture);
1337 
1338         data->glActiveTextureARB(GL_TEXTURE0_ARB);
1339     }
1340     data->glBindTexture(texturedata->type, texturedata->texture);
1341 
1342     if (texture->modMode) {
1343         GL_SetColor(data, texture->r, texture->g, texture->b, texture->a);
1344     } else {
1345         GL_SetColor(data, 255, 255, 255, 255);
1346     }
1347 
1348     GL_SetBlendMode(data, texture->blendMode);
1349 
1350     if (texturedata->yuv || texturedata->nv12) {
1351         switch (SDL_GetYUVConversionModeForResolution(texture->w, texture->h)) {
1352         case SDL_YUV_CONVERSION_JPEG:
1353             if (texturedata->yuv) {
1354                 GL_SetShader(data, SHADER_YUV_JPEG);
1355             } else if (texture->format == SDL_PIXELFORMAT_NV12) {
1356                 GL_SetShader(data, SHADER_NV12_JPEG);
1357             } else {
1358                 GL_SetShader(data, SHADER_NV21_JPEG);
1359             }
1360             break;
1361         case SDL_YUV_CONVERSION_BT601:
1362             if (texturedata->yuv) {
1363                 GL_SetShader(data, SHADER_YUV_BT601);
1364             } else if (texture->format == SDL_PIXELFORMAT_NV12) {
1365                 GL_SetShader(data, SHADER_NV12_BT601);
1366             } else {
1367                 GL_SetShader(data, SHADER_NV21_BT601);
1368             }
1369             break;
1370         case SDL_YUV_CONVERSION_BT709:
1371             if (texturedata->yuv) {
1372                 GL_SetShader(data, SHADER_YUV_BT709);
1373             } else if (texture->format == SDL_PIXELFORMAT_NV12) {
1374                 GL_SetShader(data, SHADER_NV12_BT709);
1375             } else {
1376                 GL_SetShader(data, SHADER_NV21_BT709);
1377             }
1378             break;
1379         default:
1380             return SDL_SetError("Unsupported YUV conversion mode");
1381         }
1382     } else {
1383         GL_SetShader(data, SHADER_RGB);
1384     }
1385     return 0;
1386 }
1387 
1388 static int
GL_RenderCopy(SDL_Renderer * renderer,SDL_Texture * texture,const SDL_Rect * srcrect,const SDL_FRect * dstrect)1389 GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
1390               const SDL_Rect * srcrect, const SDL_FRect * dstrect)
1391 {
1392     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
1393     GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
1394     GLfloat minx, miny, maxx, maxy;
1395     GLfloat minu, maxu, minv, maxv;
1396 
1397     GL_ActivateRenderer(renderer);
1398 
1399     if (GL_SetupCopy(renderer, texture) < 0) {
1400         return -1;
1401     }
1402 
1403     minx = dstrect->x;
1404     miny = dstrect->y;
1405     maxx = dstrect->x + dstrect->w;
1406     maxy = dstrect->y + dstrect->h;
1407 
1408     minu = (GLfloat) srcrect->x / texture->w;
1409     minu *= texturedata->texw;
1410     maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
1411     maxu *= texturedata->texw;
1412     minv = (GLfloat) srcrect->y / texture->h;
1413     minv *= texturedata->texh;
1414     maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
1415     maxv *= texturedata->texh;
1416 
1417     data->glBegin(GL_TRIANGLE_STRIP);
1418     data->glTexCoord2f(minu, minv);
1419     data->glVertex2f(minx, miny);
1420     data->glTexCoord2f(maxu, minv);
1421     data->glVertex2f(maxx, miny);
1422     data->glTexCoord2f(minu, maxv);
1423     data->glVertex2f(minx, maxy);
1424     data->glTexCoord2f(maxu, maxv);
1425     data->glVertex2f(maxx, maxy);
1426     data->glEnd();
1427 
1428     data->glDisable(texturedata->type);
1429 
1430     return GL_CheckError("", renderer);
1431 }
1432 
1433 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)1434 GL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
1435               const SDL_Rect * srcrect, const SDL_FRect * dstrect,
1436               const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
1437 {
1438     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
1439     GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
1440     GLfloat minx, miny, maxx, maxy;
1441     GLfloat centerx, centery;
1442     GLfloat minu, maxu, minv, maxv;
1443 
1444     GL_ActivateRenderer(renderer);
1445 
1446     if (GL_SetupCopy(renderer, texture) < 0) {
1447         return -1;
1448     }
1449 
1450     centerx = center->x;
1451     centery = center->y;
1452 
1453     if (flip & SDL_FLIP_HORIZONTAL) {
1454         minx =  dstrect->w - centerx;
1455         maxx = -centerx;
1456     }
1457     else {
1458         minx = -centerx;
1459         maxx =  dstrect->w - centerx;
1460     }
1461 
1462     if (flip & SDL_FLIP_VERTICAL) {
1463         miny =  dstrect->h - centery;
1464         maxy = -centery;
1465     }
1466     else {
1467         miny = -centery;
1468         maxy =  dstrect->h - centery;
1469     }
1470 
1471     minu = (GLfloat) srcrect->x / texture->w;
1472     minu *= texturedata->texw;
1473     maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
1474     maxu *= texturedata->texw;
1475     minv = (GLfloat) srcrect->y / texture->h;
1476     minv *= texturedata->texh;
1477     maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
1478     maxv *= texturedata->texh;
1479 
1480     /* Translate to flip, rotate, translate to position */
1481     data->glPushMatrix();
1482     data->glTranslatef((GLfloat)dstrect->x + centerx, (GLfloat)dstrect->y + centery, (GLfloat)0.0);
1483     data->glRotated(angle, (GLdouble)0.0, (GLdouble)0.0, (GLdouble)1.0);
1484 
1485     data->glBegin(GL_TRIANGLE_STRIP);
1486     data->glTexCoord2f(minu, minv);
1487     data->glVertex2f(minx, miny);
1488     data->glTexCoord2f(maxu, minv);
1489     data->glVertex2f(maxx, miny);
1490     data->glTexCoord2f(minu, maxv);
1491     data->glVertex2f(minx, maxy);
1492     data->glTexCoord2f(maxu, maxv);
1493     data->glVertex2f(maxx, maxy);
1494     data->glEnd();
1495     data->glPopMatrix();
1496 
1497     data->glDisable(texturedata->type);
1498 
1499     return GL_CheckError("", renderer);
1500 }
1501 
1502 static int
GL_RenderReadPixels(SDL_Renderer * renderer,const SDL_Rect * rect,Uint32 pixel_format,void * pixels,int pitch)1503 GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
1504                     Uint32 pixel_format, void * pixels, int pitch)
1505 {
1506     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
1507     Uint32 temp_format = renderer->target ? renderer->target->format : SDL_PIXELFORMAT_ARGB8888;
1508     void *temp_pixels;
1509     int temp_pitch;
1510     GLint internalFormat;
1511     GLenum format, type;
1512     Uint8 *src, *dst, *tmp;
1513     int w, h, length, rows;
1514     int status;
1515 
1516     GL_ActivateRenderer(renderer);
1517 
1518     if (!convert_format(data, temp_format, &internalFormat, &format, &type)) {
1519         return SDL_SetError("Texture format %s not supported by OpenGL",
1520                             SDL_GetPixelFormatName(temp_format));
1521     }
1522 
1523     if (!rect->w || !rect->h) {
1524         return 0;  /* nothing to do. */
1525     }
1526 
1527     temp_pitch = rect->w * SDL_BYTESPERPIXEL(temp_format);
1528     temp_pixels = SDL_malloc(rect->h * temp_pitch);
1529     if (!temp_pixels) {
1530         return SDL_OutOfMemory();
1531     }
1532 
1533     SDL_GetRendererOutputSize(renderer, &w, &h);
1534 
1535     data->glPixelStorei(GL_PACK_ALIGNMENT, 1);
1536     data->glPixelStorei(GL_PACK_ROW_LENGTH,
1537                         (temp_pitch / SDL_BYTESPERPIXEL(temp_format)));
1538 
1539     data->glReadPixels(rect->x, renderer->target ? rect->y : (h-rect->y)-rect->h,
1540                        rect->w, rect->h, format, type, temp_pixels);
1541 
1542     if (GL_CheckError("glReadPixels()", renderer) < 0) {
1543         SDL_free(temp_pixels);
1544         return -1;
1545     }
1546 
1547     /* Flip the rows to be top-down if necessary */
1548     if (!renderer->target) {
1549         length = rect->w * SDL_BYTESPERPIXEL(temp_format);
1550         src = (Uint8*)temp_pixels + (rect->h-1)*temp_pitch;
1551         dst = (Uint8*)temp_pixels;
1552         tmp = SDL_stack_alloc(Uint8, length);
1553         rows = rect->h / 2;
1554         while (rows--) {
1555             SDL_memcpy(tmp, dst, length);
1556             SDL_memcpy(dst, src, length);
1557             SDL_memcpy(src, tmp, length);
1558             dst += temp_pitch;
1559             src -= temp_pitch;
1560         }
1561         SDL_stack_free(tmp);
1562     }
1563 
1564     status = SDL_ConvertPixels(rect->w, rect->h,
1565                                temp_format, temp_pixels, temp_pitch,
1566                                pixel_format, pixels, pitch);
1567     SDL_free(temp_pixels);
1568 
1569     return status;
1570 }
1571 
1572 static void
GL_RenderPresent(SDL_Renderer * renderer)1573 GL_RenderPresent(SDL_Renderer * renderer)
1574 {
1575     GL_ActivateRenderer(renderer);
1576 
1577     SDL_GL_SwapWindow(renderer->window);
1578 }
1579 
1580 static void
GL_DestroyTexture(SDL_Renderer * renderer,SDL_Texture * texture)1581 GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
1582 {
1583     GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
1584     GL_TextureData *data = (GL_TextureData *) texture->driverdata;
1585 
1586     GL_ActivateRenderer(renderer);
1587 
1588     if (!data) {
1589         return;
1590     }
1591     if (data->texture) {
1592         renderdata->glDeleteTextures(1, &data->texture);
1593     }
1594     if (data->yuv) {
1595         renderdata->glDeleteTextures(1, &data->utexture);
1596         renderdata->glDeleteTextures(1, &data->vtexture);
1597     }
1598     SDL_free(data->pixels);
1599     SDL_free(data);
1600     texture->driverdata = NULL;
1601 }
1602 
1603 static void
GL_DestroyRenderer(SDL_Renderer * renderer)1604 GL_DestroyRenderer(SDL_Renderer * renderer)
1605 {
1606     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
1607 
1608     if (data) {
1609         if (data->context != NULL) {
1610             /* make sure we delete the right resources! */
1611             GL_ActivateRenderer(renderer);
1612         }
1613 
1614         GL_ClearErrors(renderer);
1615         if (data->GL_ARB_debug_output_supported) {
1616             PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARBFunc = (PFNGLDEBUGMESSAGECALLBACKARBPROC) SDL_GL_GetProcAddress("glDebugMessageCallbackARB");
1617 
1618             /* Uh oh, we don't have a safe way of removing ourselves from the callback chain, if it changed after we set our callback. */
1619             /* For now, just always replace the callback with the original one */
1620             glDebugMessageCallbackARBFunc(data->next_error_callback, data->next_error_userparam);
1621         }
1622         if (data->shaders) {
1623             GL_DestroyShaderContext(data->shaders);
1624         }
1625         if (data->context) {
1626             while (data->framebuffers) {
1627                 GL_FBOList *nextnode = data->framebuffers->next;
1628                 /* delete the framebuffer object */
1629                 data->glDeleteFramebuffersEXT(1, &data->framebuffers->FBO);
1630                 GL_CheckError("", renderer);
1631                 SDL_free(data->framebuffers);
1632                 data->framebuffers = nextnode;
1633             }
1634             SDL_GL_DeleteContext(data->context);
1635         }
1636         SDL_free(data);
1637     }
1638     SDL_free(renderer);
1639 }
1640 
1641 static int
GL_BindTexture(SDL_Renderer * renderer,SDL_Texture * texture,float * texw,float * texh)1642 GL_BindTexture (SDL_Renderer * renderer, SDL_Texture *texture, float *texw, float *texh)
1643 {
1644     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
1645     GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
1646     GL_ActivateRenderer(renderer);
1647 
1648     data->glEnable(texturedata->type);
1649     if (texturedata->yuv) {
1650         data->glActiveTextureARB(GL_TEXTURE2_ARB);
1651         data->glBindTexture(texturedata->type, texturedata->vtexture);
1652 
1653         data->glActiveTextureARB(GL_TEXTURE1_ARB);
1654         data->glBindTexture(texturedata->type, texturedata->utexture);
1655 
1656         data->glActiveTextureARB(GL_TEXTURE0_ARB);
1657     }
1658     data->glBindTexture(texturedata->type, texturedata->texture);
1659 
1660     if(texw) *texw = (float)texturedata->texw;
1661     if(texh) *texh = (float)texturedata->texh;
1662 
1663     return 0;
1664 }
1665 
1666 static int
GL_UnbindTexture(SDL_Renderer * renderer,SDL_Texture * texture)1667 GL_UnbindTexture (SDL_Renderer * renderer, SDL_Texture *texture)
1668 {
1669     GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
1670     GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
1671     GL_ActivateRenderer(renderer);
1672 
1673     if (texturedata->yuv) {
1674         data->glActiveTextureARB(GL_TEXTURE2_ARB);
1675         data->glDisable(texturedata->type);
1676 
1677         data->glActiveTextureARB(GL_TEXTURE1_ARB);
1678         data->glDisable(texturedata->type);
1679 
1680         data->glActiveTextureARB(GL_TEXTURE0_ARB);
1681     }
1682 
1683     data->glDisable(texturedata->type);
1684 
1685     return 0;
1686 }
1687 
1688 #endif /* SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED */
1689 
1690 /* vi: set ts=4 sw=4 expandtab: */
1691