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