comparison src/render/opengl/SDL_renderer_gl.c @ 5157:fb424691cfc7

Moved the rendering code out to a separate directory in the hope that it can someday be completely decoupled from the rest of the library and be expanded to an awesome 2D on 3D library.
author Sam Lantinga <slouken@libsdl.org>
date Wed, 02 Feb 2011 14:34:54 -0800
parents src/video/SDL_renderer_gl.c@1435f8a6425c
children 307ccc9c135e
comparison
equal deleted inserted replaced
5156:3e4086b3bcd2 5157:fb424691cfc7
1 /*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2010 Sam Lantinga
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19 Sam Lantinga
20 slouken@libsdl.org
21 */
22 #include "SDL_config.h"
23
24 #if SDL_VIDEO_RENDER_OGL
25
26 #include "SDL_opengl.h"
27 #include "../SDL_sysrender.h"
28
29 #ifdef __MACOSX__
30 #include <OpenGL/OpenGL.h>
31 #endif
32
33
34 /* OpenGL renderer implementation */
35
36 /* Details on optimizing the texture path on Mac OS X:
37 http://developer.apple.com/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_texturedata/chapter_10_section_2.html
38 */
39
40 /* !!! FIXME: this should go in a higher level than the GL renderer. */
41 static __inline__ int
42 bytes_per_pixel(const Uint32 format)
43 {
44 if (!SDL_ISPIXELFORMAT_FOURCC(format)) {
45 return SDL_BYTESPERPIXEL(format);
46 }
47
48 /* FOURCC format */
49 switch (format) {
50 case SDL_PIXELFORMAT_YV12:
51 case SDL_PIXELFORMAT_IYUV:
52 case SDL_PIXELFORMAT_YUY2:
53 case SDL_PIXELFORMAT_UYVY:
54 case SDL_PIXELFORMAT_YVYU:
55 return 2;
56 default:
57 return 1; /* shouldn't ever hit this. */
58 }
59 }
60
61 /* Used to re-create the window with OpenGL capability */
62 extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags);
63
64 static const float inv255f = 1.0f / 255.0f;
65
66 static SDL_Renderer *GL_CreateRenderer(SDL_Window * window, Uint32 flags);
67 static void GL_WindowEvent(SDL_Renderer * renderer,
68 const SDL_WindowEvent *event);
69 static int GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
70 static int GL_QueryTexturePixels(SDL_Renderer * renderer,
71 SDL_Texture * texture, void **pixels,
72 int *pitch);
73 static int GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
74 const SDL_Rect * rect, const void *pixels,
75 int pitch);
76 static int GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
77 const SDL_Rect * rect, int markDirty, void **pixels,
78 int *pitch);
79 static void GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
80 static void GL_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture,
81 int numrects, const SDL_Rect * rects);
82 static int GL_RenderClear(SDL_Renderer * renderer);
83 static int GL_RenderDrawPoints(SDL_Renderer * renderer,
84 const SDL_Point * points, int count);
85 static int GL_RenderDrawLines(SDL_Renderer * renderer,
86 const SDL_Point * points, int count);
87 static int GL_RenderFillRects(SDL_Renderer * renderer,
88 const SDL_Rect ** rects, int count);
89 static int GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
90 const SDL_Rect * srcrect, const SDL_Rect * dstrect);
91 static int GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
92 Uint32 pixel_format, void * pixels, int pitch);
93 static int GL_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect,
94 Uint32 pixel_format, const void * pixels, int pitch);
95 static void GL_RenderPresent(SDL_Renderer * renderer);
96 static void GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture);
97 static void GL_DestroyRenderer(SDL_Renderer * renderer);
98
99
100 SDL_RenderDriver GL_RenderDriver = {
101 GL_CreateRenderer,
102 {
103 "opengl",
104 (SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED),
105 13,
106 {
107 SDL_PIXELFORMAT_RGB332,
108 SDL_PIXELFORMAT_RGB444,
109 SDL_PIXELFORMAT_RGB555,
110 SDL_PIXELFORMAT_ARGB4444,
111 SDL_PIXELFORMAT_ARGB1555,
112 SDL_PIXELFORMAT_RGB565,
113 SDL_PIXELFORMAT_RGB24,
114 SDL_PIXELFORMAT_BGR24,
115 SDL_PIXELFORMAT_RGB888,
116 SDL_PIXELFORMAT_BGR888,
117 SDL_PIXELFORMAT_ARGB8888,
118 SDL_PIXELFORMAT_ABGR8888,
119 SDL_PIXELFORMAT_ARGB2101010},
120 0,
121 0}
122 };
123
124 typedef struct
125 {
126 SDL_GLContext context;
127 SDL_bool updateSize;
128 SDL_bool GL_ARB_texture_rectangle_supported;
129 SDL_bool GL_EXT_paletted_texture_supported;
130 SDL_bool GL_APPLE_ycbcr_422_supported;
131 SDL_bool GL_MESA_ycbcr_texture_supported;
132 SDL_bool GL_ARB_fragment_program_supported;
133 int blendMode;
134
135 /* OpenGL functions */
136 #define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
137 #include "../../video/SDL_glfuncs.h"
138 #undef SDL_PROC
139
140 void (*glTextureRangeAPPLE) (GLenum target, GLsizei length,
141 const GLvoid * pointer);
142
143 PFNGLGETPROGRAMIVARBPROC glGetProgramivARB;
144 PFNGLGETPROGRAMSTRINGARBPROC glGetProgramStringARB;
145 PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glProgramLocalParameter4fvARB;
146 PFNGLDELETEPROGRAMSARBPROC glDeleteProgramsARB;
147 PFNGLGENPROGRAMSARBPROC glGenProgramsARB;
148 PFNGLBINDPROGRAMARBPROC glBindProgramARB;
149 PFNGLPROGRAMSTRINGARBPROC glProgramStringARB;
150
151 /* (optional) fragment programs */
152 GLuint fragment_program_UYVY;
153 } GL_RenderData;
154
155 typedef struct
156 {
157 GLuint texture;
158 GLuint shader;
159 GLenum type;
160 GLfloat texw;
161 GLfloat texh;
162 GLenum format;
163 GLenum formattype;
164 Uint8 *palette;
165 void *pixels;
166 int pitch;
167 SDL_DirtyRectList dirty;
168 int HACK_RYAN_FIXME;
169 } GL_TextureData;
170
171
172 static void
173 GL_SetError(const char *prefix, GLenum result)
174 {
175 const char *error;
176
177 switch (result) {
178 case GL_NO_ERROR:
179 error = "GL_NO_ERROR";
180 break;
181 case GL_INVALID_ENUM:
182 error = "GL_INVALID_ENUM";
183 break;
184 case GL_INVALID_VALUE:
185 error = "GL_INVALID_VALUE";
186 break;
187 case GL_INVALID_OPERATION:
188 error = "GL_INVALID_OPERATION";
189 break;
190 case GL_STACK_OVERFLOW:
191 error = "GL_STACK_OVERFLOW";
192 break;
193 case GL_STACK_UNDERFLOW:
194 error = "GL_STACK_UNDERFLOW";
195 break;
196 case GL_OUT_OF_MEMORY:
197 error = "GL_OUT_OF_MEMORY";
198 break;
199 case GL_TABLE_TOO_LARGE:
200 error = "GL_TABLE_TOO_LARGE";
201 break;
202 default:
203 error = "UNKNOWN";
204 break;
205 }
206 SDL_SetError("%s: %s", prefix, error);
207 }
208
209 static int
210 GL_LoadFunctions(GL_RenderData * data)
211 {
212 #ifdef __SDL_NOGETPROCADDR__
213 #define SDL_PROC(ret,func,params) data->func=func;
214 #else
215 #define SDL_PROC(ret,func,params) \
216 do { \
217 data->func = SDL_GL_GetProcAddress(#func); \
218 if ( ! data->func ) { \
219 SDL_SetError("Couldn't load GL function %s: %s\n", #func, SDL_GetError()); \
220 return -1; \
221 } \
222 } while ( 0 );
223 #endif /* __SDL_NOGETPROCADDR__ */
224
225 #include "../../video/SDL_glfuncs.h"
226 #undef SDL_PROC
227 return 0;
228 }
229
230 SDL_Renderer *
231 GL_CreateRenderer(SDL_Window * window, Uint32 flags)
232 {
233 SDL_Renderer *renderer;
234 GL_RenderData *data;
235 GLint value;
236 Uint32 window_flags;
237
238 window_flags = SDL_GetWindowFlags(window);
239 if (!(window_flags & SDL_WINDOW_OPENGL)) {
240 if (SDL_RecreateWindow(window, window_flags | SDL_WINDOW_OPENGL) < 0) {
241 return NULL;
242 }
243 }
244
245 renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
246 if (!renderer) {
247 SDL_OutOfMemory();
248 return NULL;
249 }
250
251 data = (GL_RenderData *) SDL_calloc(1, sizeof(*data));
252 if (!data) {
253 GL_DestroyRenderer(renderer);
254 SDL_OutOfMemory();
255 return NULL;
256 }
257
258 renderer->WindowEvent = GL_WindowEvent;
259 renderer->CreateTexture = GL_CreateTexture;
260 renderer->QueryTexturePixels = GL_QueryTexturePixels;
261 renderer->UpdateTexture = GL_UpdateTexture;
262 renderer->LockTexture = GL_LockTexture;
263 renderer->UnlockTexture = GL_UnlockTexture;
264 renderer->DirtyTexture = GL_DirtyTexture;
265 renderer->RenderClear = GL_RenderClear;
266 renderer->RenderDrawPoints = GL_RenderDrawPoints;
267 renderer->RenderDrawLines = GL_RenderDrawLines;
268 renderer->RenderFillRects = GL_RenderFillRects;
269 renderer->RenderCopy = GL_RenderCopy;
270 renderer->RenderReadPixels = GL_RenderReadPixels;
271 renderer->RenderWritePixels = GL_RenderWritePixels;
272 renderer->RenderPresent = GL_RenderPresent;
273 renderer->DestroyTexture = GL_DestroyTexture;
274 renderer->DestroyRenderer = GL_DestroyRenderer;
275 renderer->info = GL_RenderDriver.info;
276 renderer->window = window;
277 renderer->driverdata = data;
278
279 renderer->info.flags = SDL_RENDERER_ACCELERATED;
280
281 if (GL_LoadFunctions(data) < 0) {
282 GL_DestroyRenderer(renderer);
283 return NULL;
284 }
285
286 data->context = SDL_GL_CreateContext(window);
287 if (!data->context) {
288 GL_DestroyRenderer(renderer);
289 return NULL;
290 }
291 if (SDL_GL_MakeCurrent(window, data->context) < 0) {
292 GL_DestroyRenderer(renderer);
293 return NULL;
294 }
295 #ifdef __MACOSX__
296 /* Enable multi-threaded rendering */
297 /* Disabled until Ryan finishes his VBO/PBO code...
298 CGLEnable(CGLGetCurrentContext(), kCGLCEMPEngine);
299 */
300 #endif
301
302 if (flags & SDL_RENDERER_PRESENTVSYNC) {
303 SDL_GL_SetSwapInterval(1);
304 } else {
305 SDL_GL_SetSwapInterval(0);
306 }
307 if (SDL_GL_GetSwapInterval() > 0) {
308 renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
309 }
310
311 data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
312 renderer->info.max_texture_width = value;
313 data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
314 renderer->info.max_texture_height = value;
315
316 if (SDL_GL_ExtensionSupported("GL_ARB_texture_rectangle")
317 || SDL_GL_ExtensionSupported("GL_EXT_texture_rectangle")) {
318 data->GL_ARB_texture_rectangle_supported = SDL_TRUE;
319 }
320 if (SDL_GL_ExtensionSupported("GL_APPLE_ycbcr_422")) {
321 data->GL_APPLE_ycbcr_422_supported = SDL_TRUE;
322 }
323 if (SDL_GL_ExtensionSupported("GL_MESA_ycbcr_texture")) {
324 data->GL_MESA_ycbcr_texture_supported = SDL_TRUE;
325 }
326 if (SDL_GL_ExtensionSupported("GL_APPLE_texture_range")) {
327 data->glTextureRangeAPPLE =
328 (void (*)(GLenum, GLsizei, const GLvoid *))
329 SDL_GL_GetProcAddress("glTextureRangeAPPLE");
330 }
331
332 /* we might use fragment programs for YUV data, etc. */
333 if (SDL_GL_ExtensionSupported("GL_ARB_fragment_program")) {
334 /* !!! FIXME: this doesn't check for errors. */
335 /* !!! FIXME: this should really reuse the glfuncs.h stuff. */
336 data->glGetProgramivARB = (PFNGLGETPROGRAMIVARBPROC)
337 SDL_GL_GetProcAddress("glGetProgramivARB");
338 data->glGetProgramStringARB = (PFNGLGETPROGRAMSTRINGARBPROC)
339 SDL_GL_GetProcAddress("glGetProgramStringARB");
340 data->glProgramLocalParameter4fvARB =
341 (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC)
342 SDL_GL_GetProcAddress("glProgramLocalParameter4fvARB");
343 data->glDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC)
344 SDL_GL_GetProcAddress("glDeleteProgramsARB");
345 data->glGenProgramsARB = (PFNGLGENPROGRAMSARBPROC)
346 SDL_GL_GetProcAddress("glGenProgramsARB");
347 data->glBindProgramARB = (PFNGLBINDPROGRAMARBPROC)
348 SDL_GL_GetProcAddress("glBindProgramARB");
349 data->glProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC)
350 SDL_GL_GetProcAddress("glProgramStringARB");
351 data->GL_ARB_fragment_program_supported = SDL_TRUE;
352 }
353
354 /* Set up parameters for rendering */
355 data->blendMode = -1;
356 data->glDisable(GL_DEPTH_TEST);
357 data->glDisable(GL_CULL_FACE);
358 /* This ended up causing video discrepancies between OpenGL and Direct3D */
359 /*data->glEnable(GL_LINE_SMOOTH);*/
360 if (data->GL_ARB_texture_rectangle_supported) {
361 data->glEnable(GL_TEXTURE_RECTANGLE_ARB);
362 } else {
363 data->glEnable(GL_TEXTURE_2D);
364 }
365 data->updateSize = SDL_TRUE;
366
367 return renderer;
368 }
369
370 static SDL_GLContext SDL_CurrentContext = NULL;
371
372 static int
373 GL_ActivateRenderer(SDL_Renderer * renderer)
374 {
375 GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
376 SDL_Window *window = renderer->window;
377
378 if (SDL_CurrentContext != data->context) {
379 if (SDL_GL_MakeCurrent(window, data->context) < 0) {
380 return -1;
381 }
382 SDL_CurrentContext = data->context;
383 }
384 if (data->updateSize) {
385 int w, h;
386
387 SDL_GetWindowSize(window, &w, &h);
388 data->glMatrixMode(GL_PROJECTION);
389 data->glLoadIdentity();
390 data->glMatrixMode(GL_MODELVIEW);
391 data->glLoadIdentity();
392 data->glViewport(0, 0, w, h);
393 data->glOrtho(0.0, (GLdouble) w, (GLdouble) h, 0.0, 0.0, 1.0);
394 data->updateSize = SDL_FALSE;
395 }
396 return 0;
397 }
398
399 static void
400 GL_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
401 {
402 GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
403
404 if (event->event == SDL_WINDOWEVENT_RESIZED) {
405 /* Rebind the context to the window area and update matrices */
406 SDL_CurrentContext = NULL;
407 data->updateSize = SDL_TRUE;
408 }
409 }
410
411 static __inline__ int
412 power_of_2(int input)
413 {
414 int value = 1;
415
416 while (value < input) {
417 value <<= 1;
418 }
419 return value;
420 }
421
422
423 //#define DEBUG_PROGRAM_COMPILE 1
424
425 static void
426 set_shader_error(GL_RenderData * data, const char *prefix)
427 {
428 GLint pos = 0;
429 const GLubyte *errstr;
430 data->glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &pos);
431 errstr = data->glGetString(GL_PROGRAM_ERROR_STRING_ARB);
432 SDL_SetError("%s: shader compile error at position %d: %s",
433 prefix, (int) pos, (const char *) errstr);
434 }
435
436 static GLuint
437 compile_shader(GL_RenderData * data, GLenum shader_type, const char *_code)
438 {
439 const int have_texture_rects = data->GL_ARB_texture_rectangle_supported;
440 const char *replacement = have_texture_rects ? "RECT" : "2D";
441 const size_t replacementlen = SDL_strlen(replacement);
442 const char *token = "%TEXTURETARGET%";
443 const size_t tokenlen = SDL_strlen(token);
444 char *code = NULL;
445 char *ptr = NULL;
446 GLuint program = 0;
447
448 /*
449 * The TEX instruction needs a different target depending on what we use.
450 * To handle this, we use "%TEXTURETARGET%" and replace the string before
451 * compiling the shader.
452 */
453 code = SDL_strdup(_code);
454 if (code == NULL)
455 return 0;
456
457 for (ptr = SDL_strstr(code, token); ptr; ptr = SDL_strstr(ptr + 1, token)) {
458 SDL_memcpy(ptr, replacement, replacementlen);
459 SDL_memmove(ptr + replacementlen, ptr + tokenlen,
460 SDL_strlen(ptr + tokenlen) + 1);
461 }
462
463 #if DEBUG_PROGRAM_COMPILE
464 printf("compiling shader:\n%s\n\n", code);
465 #endif
466
467 data->glGetError(); /* flush any existing error state. */
468 data->glGenProgramsARB(1, &program);
469 data->glBindProgramARB(shader_type, program);
470 data->glProgramStringARB(shader_type, GL_PROGRAM_FORMAT_ASCII_ARB,
471 (GLsizei)SDL_strlen(code), code);
472
473 SDL_free(code);
474
475 if (data->glGetError() == GL_INVALID_OPERATION) {
476 #if DEBUG_PROGRAM_COMPILE
477 GLint pos = 0;
478 const GLubyte *errstr;
479 data->glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &pos);
480 errstr = data->glGetString(GL_PROGRAM_ERROR_STRING_ARB);
481 printf("program compile error at position %d: %s\n\n",
482 (int) pos, (const char *) errstr);
483 #endif
484 data->glBindProgramARB(shader_type, 0);
485 data->glDeleteProgramsARB(1, &program);
486 return 0;
487 }
488
489 return program;
490 }
491
492
493 /*
494 * Fragment program that renders from UYVY textures.
495 * The UYVY to RGB equasion is:
496 * R = 1.164(Y-16) + 1.596(Cr-128)
497 * G = 1.164(Y-16) - 0.813(Cr-128) - 0.391(Cb-128)
498 * B = 1.164(Y-16) + 2.018(Cb-128)
499 * Byte layout is Cb, Y1, Cr, Y2, stored in the R, G, B, A channels.
500 * 4 bytes == 2 pixels: Y1/Cb/Cr, Y2/Cb/Cr
501 *
502 * !!! FIXME: this ignores blendmodes, etc.
503 * !!! FIXME: this could be more efficient...use a dot product for green, etc.
504 */
505 static const char *fragment_program_UYVY_source_code = "!!ARBfp1.0\n"
506 /* outputs... */
507 "OUTPUT outcolor = result.color;\n"
508 /* scratch registers... */
509 "TEMP uyvy;\n" "TEMP luminance;\n" "TEMP work;\n"
510 /* Halve the coordinates to grab the correct 32 bits for the fragment. */
511 "MUL work, fragment.texcoord, { 0.5, 1.0, 1.0, 1.0 };\n"
512 /* Sample the YUV texture. Cb, Y1, Cr, Y2, are stored in x, y, z, w. */
513 "TEX uyvy, work, texture[0], %TEXTURETARGET%;\n"
514 /* Do subtractions (128/255, 16/255, 128/255, 16/255) */
515 "SUB uyvy, uyvy, { 0.501960784313726, 0.06274509803922, 0.501960784313726, 0.06274509803922 };\n"
516 /* Choose the luminance component by texcoord. */
517 /* !!! FIXME: laziness wins out for now... just average Y1 and Y2. */
518 "ADD luminance, uyvy.yyyy, uyvy.wwww;\n"
519 "MUL luminance, luminance, { 0.5, 0.5, 0.5, 0.5 };\n"
520 /* Multiply luminance by its magic value. */
521 "MUL luminance, luminance, { 1.164, 1.164, 1.164, 1.164 };\n"
522 /* uyvy.xyzw becomes Cr/Cr/Cb/Cb, with multiplications. */
523 "MUL uyvy, uyvy.zzxx, { 1.596, -0.813, 2.018, -0.391 };\n"
524 /* Add luminance to Cr and Cb, store to RGB channels. */
525 "ADD work.rgb, luminance, uyvy;\n"
526 /* Do final addition for Green channel. (!!! FIXME: this should be a DPH?) */
527 "ADD work.g, work.g, uyvy.w;\n"
528 /* Make sure alpha channel is fully opaque. (!!! FIXME: blend modes!) */
529 "MOV work.a, { 1.0 };\n"
530 /* Store out the final fragment color... */
531 "MOV outcolor, work;\n"
532 /* ...and we're done! */
533 "END\n";
534
535 static __inline__ SDL_bool
536 convert_format(GL_RenderData *renderdata, Uint32 pixel_format,
537 GLint* internalFormat, GLenum* format, GLenum* type)
538 {
539 switch (pixel_format) {
540 case SDL_PIXELFORMAT_RGB332:
541 *internalFormat = GL_R3_G3_B2;
542 *format = GL_RGB;
543 *type = GL_UNSIGNED_BYTE_3_3_2;
544 break;
545 case SDL_PIXELFORMAT_RGB444:
546 *internalFormat = GL_RGB4;
547 *format = GL_RGB;
548 *type = GL_UNSIGNED_SHORT_4_4_4_4;
549 break;
550 case SDL_PIXELFORMAT_RGB555:
551 *internalFormat = GL_RGB5;
552 *format = GL_RGB;
553 *type = GL_UNSIGNED_SHORT_5_5_5_1;
554 break;
555 case SDL_PIXELFORMAT_ARGB4444:
556 *internalFormat = GL_RGBA4;
557 *format = GL_BGRA;
558 *type = GL_UNSIGNED_SHORT_4_4_4_4_REV;
559 break;
560 case SDL_PIXELFORMAT_ARGB1555:
561 *internalFormat = GL_RGB5_A1;
562 *format = GL_BGRA;
563 *type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
564 break;
565 case SDL_PIXELFORMAT_RGB565:
566 *internalFormat = GL_RGB8;
567 *format = GL_RGB;
568 *type = GL_UNSIGNED_SHORT_5_6_5;
569 break;
570 case SDL_PIXELFORMAT_RGB24:
571 *internalFormat = GL_RGB8;
572 *format = GL_RGB;
573 *type = GL_UNSIGNED_BYTE;
574 break;
575 case SDL_PIXELFORMAT_RGB888:
576 *internalFormat = GL_RGB8;
577 *format = GL_BGRA;
578 *type = GL_UNSIGNED_BYTE;
579 break;
580 case SDL_PIXELFORMAT_BGR24:
581 *internalFormat = GL_RGB8;
582 *format = GL_BGR;
583 *type = GL_UNSIGNED_BYTE;
584 break;
585 case SDL_PIXELFORMAT_BGR888:
586 *internalFormat = GL_RGB8;
587 *format = GL_RGBA;
588 *type = GL_UNSIGNED_BYTE;
589 break;
590 case SDL_PIXELFORMAT_ARGB8888:
591 #ifdef __MACOSX__
592 *internalFormat = GL_RGBA;
593 *format = GL_BGRA;
594 *type = GL_UNSIGNED_INT_8_8_8_8_REV;
595 #else
596 *internalFormat = GL_RGBA8;
597 *format = GL_BGRA;
598 *type = GL_UNSIGNED_BYTE;
599 #endif
600 break;
601 case SDL_PIXELFORMAT_ABGR8888:
602 *internalFormat = GL_RGBA8;
603 *format = GL_RGBA;
604 *type = GL_UNSIGNED_BYTE;
605 break;
606 case SDL_PIXELFORMAT_ARGB2101010:
607 *internalFormat = GL_RGB10_A2;
608 *format = GL_BGRA;
609 *type = GL_UNSIGNED_INT_2_10_10_10_REV;
610 break;
611 case SDL_PIXELFORMAT_UYVY:
612 if (renderdata->GL_APPLE_ycbcr_422_supported) {
613 *internalFormat = GL_RGB;
614 *format = GL_YCBCR_422_APPLE;
615 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
616 *type = GL_UNSIGNED_SHORT_8_8_APPLE;
617 #else
618 *type = GL_UNSIGNED_SHORT_8_8_REV_APPLE;
619 #endif
620 } else if (renderdata->GL_MESA_ycbcr_texture_supported) {
621 *internalFormat = GL_YCBCR_MESA;
622 *format = GL_YCBCR_MESA;
623 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
624 *type = GL_UNSIGNED_SHORT_8_8_MESA;
625 #else
626 *type = GL_UNSIGNED_SHORT_8_8_REV_MESA;
627 #endif
628 } else if (renderdata->GL_ARB_fragment_program_supported) {
629 *internalFormat = GL_RGBA;
630 *format = GL_RGBA;
631 *type = GL_UNSIGNED_BYTE;
632 } else {
633 return SDL_FALSE;
634 }
635 break;
636 case SDL_PIXELFORMAT_YUY2:
637 if (renderdata->GL_APPLE_ycbcr_422_supported) {
638 *internalFormat = GL_RGB;
639 *format = GL_YCBCR_422_APPLE;
640 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
641 *type = GL_UNSIGNED_SHORT_8_8_REV_APPLE;
642 #else
643 *type = GL_UNSIGNED_SHORT_8_8_APPLE;
644 #endif
645 } else if (renderdata->GL_MESA_ycbcr_texture_supported) {
646 *internalFormat = GL_YCBCR_MESA;
647 *format = GL_YCBCR_MESA;
648 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
649 *type = GL_UNSIGNED_SHORT_8_8_REV_MESA;
650 #else
651 *type = GL_UNSIGNED_SHORT_8_8_MESA;
652 #endif
653 } else {
654 return SDL_FALSE;
655 }
656 break;
657 default:
658 return SDL_FALSE;
659 }
660 return SDL_TRUE;
661 }
662
663 static int
664 GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
665 {
666 GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
667 GL_TextureData *data;
668 GLint internalFormat;
669 GLenum format, type;
670 int texture_w, texture_h;
671 GLuint shader = 0;
672 GLenum result;
673
674 GL_ActivateRenderer(renderer);
675
676 if (!convert_format(renderdata, texture->format, &internalFormat,
677 &format, &type)) {
678 SDL_SetError("Texture format %s not supported by OpenGL",
679 SDL_GetPixelFormatName(texture->format));
680 return -1;
681 }
682 if (texture->format == SDL_PIXELFORMAT_UYVY &&
683 !renderdata->GL_APPLE_ycbcr_422_supported &&
684 !renderdata->GL_MESA_ycbcr_texture_supported &&
685 renderdata->GL_ARB_fragment_program_supported) {
686 if (renderdata->fragment_program_UYVY == 0) {
687 renderdata->fragment_program_UYVY =
688 compile_shader(renderdata, GL_FRAGMENT_PROGRAM_ARB,
689 fragment_program_UYVY_source_code);
690 if (renderdata->fragment_program_UYVY == 0) {
691 set_shader_error(renderdata, "UYVY");
692 return -1;
693 }
694 }
695 shader = renderdata->fragment_program_UYVY;
696 }
697
698 data = (GL_TextureData *) SDL_calloc(1, sizeof(*data));
699 if (!data) {
700 SDL_OutOfMemory();
701 return -1;
702 }
703
704 data->shader = shader;
705
706 if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
707 data->pitch = texture->w * bytes_per_pixel(texture->format);
708 data->pixels = SDL_malloc(texture->h * data->pitch);
709 if (!data->pixels) {
710 SDL_OutOfMemory();
711 SDL_free(data);
712 return -1;
713 }
714 }
715
716 texture->driverdata = data;
717
718 renderdata->glGetError();
719 renderdata->glGenTextures(1, &data->texture);
720 if (renderdata->GL_ARB_texture_rectangle_supported) {
721 data->type = GL_TEXTURE_RECTANGLE_ARB;
722 texture_w = texture->w;
723 texture_h = texture->h;
724 data->texw = (GLfloat) texture_w;
725 data->texh = (GLfloat) texture_h;
726 } else {
727 data->type = GL_TEXTURE_2D;
728 texture_w = power_of_2(texture->w);
729 texture_h = power_of_2(texture->h);
730 data->texw = (GLfloat) (texture->w) / texture_w;
731 data->texh = (GLfloat) texture->h / texture_h;
732 }
733
734 /* YUV formats use RGBA but are really two bytes per pixel */
735 if (internalFormat == GL_RGBA && bytes_per_pixel(texture->format) < 4) {
736 texture_w /= 2;
737 if (data->type == GL_TEXTURE_2D) {
738 data->texw *= 2.0f;
739 }
740 data->HACK_RYAN_FIXME = 2;
741 } else {
742 data->HACK_RYAN_FIXME = 1;
743 }
744
745 data->format = format;
746 data->formattype = type;
747 renderdata->glEnable(data->type);
748 renderdata->glBindTexture(data->type, data->texture);
749 renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
750 GL_LINEAR);
751 renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
752 GL_LINEAR);
753 renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
754 GL_CLAMP_TO_EDGE);
755 renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
756 GL_CLAMP_TO_EDGE);
757 #ifdef __MACOSX__
758 #ifndef GL_TEXTURE_STORAGE_HINT_APPLE
759 #define GL_TEXTURE_STORAGE_HINT_APPLE 0x85BC
760 #endif
761 #ifndef STORAGE_CACHED_APPLE
762 #define STORAGE_CACHED_APPLE 0x85BE
763 #endif
764 #ifndef STORAGE_SHARED_APPLE
765 #define STORAGE_SHARED_APPLE 0x85BF
766 #endif
767 if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
768 renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
769 GL_STORAGE_SHARED_APPLE);
770 } else {
771 renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
772 GL_STORAGE_CACHED_APPLE);
773 }
774 /* This causes a crash in testoverlay for some reason. Apple bug? */
775 #if 0
776 if (texture->access == SDL_TEXTUREACCESS_STREAMING
777 && texture->format == SDL_PIXELFORMAT_ARGB8888) {
778 /*
779 if (renderdata->glTextureRangeAPPLE) {
780 renderdata->glTextureRangeAPPLE(data->type,
781 texture->h * data->pitch,
782 data->pixels);
783 }
784 */
785 renderdata->glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
786 renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
787 texture_h, 0, format, type, data->pixels);
788 } else
789 #endif
790 #endif
791 {
792 renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
793 texture_h, 0, format, type, NULL);
794 }
795 renderdata->glDisable(data->type);
796 result = renderdata->glGetError();
797 if (result != GL_NO_ERROR) {
798 GL_SetError("glTexImage2D()", result);
799 return -1;
800 }
801 return 0;
802 }
803
804 static int
805 GL_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture,
806 void **pixels, int *pitch)
807 {
808 GL_TextureData *data = (GL_TextureData *) texture->driverdata;
809
810 *pixels = data->pixels;
811 *pitch = data->pitch;
812 return 0;
813 }
814
815 static void
816 SetupTextureUpdate(GL_RenderData * renderdata, SDL_Texture * texture,
817 int pitch)
818 {
819 renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
820 renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH,
821 (pitch / bytes_per_pixel(texture->format)) /
822 ((GL_TextureData *) texture->driverdata)->
823 HACK_RYAN_FIXME);
824 }
825
826 static int
827 GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
828 const SDL_Rect * rect, const void *pixels, int pitch)
829 {
830 GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
831 GL_TextureData *data = (GL_TextureData *) texture->driverdata;
832 GLenum result;
833
834 GL_ActivateRenderer(renderer);
835
836 renderdata->glGetError();
837 SetupTextureUpdate(renderdata, texture, pitch);
838 renderdata->glEnable(data->type);
839 renderdata->glBindTexture(data->type, data->texture);
840 renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w,
841 rect->h, data->format, data->formattype,
842 pixels);
843 renderdata->glDisable(data->type);
844 result = renderdata->glGetError();
845 if (result != GL_NO_ERROR) {
846 GL_SetError("glTexSubImage2D()", result);
847 return -1;
848 }
849 return 0;
850 }
851
852 static int
853 GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
854 const SDL_Rect * rect, int markDirty, void **pixels,
855 int *pitch)
856 {
857 GL_TextureData *data = (GL_TextureData *) texture->driverdata;
858
859 if (markDirty) {
860 SDL_AddDirtyRect(&data->dirty, rect);
861 }
862
863 *pixels =
864 (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
865 rect->x * bytes_per_pixel(texture->format));
866 *pitch = data->pitch;
867 return 0;
868 }
869
870 static void
871 GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
872 {
873 }
874
875 static void
876 GL_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture, int numrects,
877 const SDL_Rect * rects)
878 {
879 GL_TextureData *data = (GL_TextureData *) texture->driverdata;
880 int i;
881
882 for (i = 0; i < numrects; ++i) {
883 SDL_AddDirtyRect(&data->dirty, &rects[i]);
884 }
885 }
886
887 static void
888 GL_SetBlendMode(GL_RenderData * data, int blendMode)
889 {
890 if (blendMode != data->blendMode) {
891 switch (blendMode) {
892 case SDL_BLENDMODE_NONE:
893 data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
894 data->glDisable(GL_BLEND);
895 break;
896 case SDL_BLENDMODE_BLEND:
897 data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
898 data->glEnable(GL_BLEND);
899 data->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
900 break;
901 case SDL_BLENDMODE_ADD:
902 data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
903 data->glEnable(GL_BLEND);
904 data->glBlendFunc(GL_SRC_ALPHA, GL_ONE);
905 break;
906 }
907 data->blendMode = blendMode;
908 }
909 }
910
911 static int
912 GL_RenderClear(SDL_Renderer * renderer)
913 {
914 GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
915
916 GL_ActivateRenderer(renderer);
917
918 data->glClearColor((GLfloat) renderer->r * inv255f,
919 (GLfloat) renderer->g * inv255f,
920 (GLfloat) renderer->b * inv255f,
921 (GLfloat) renderer->a * inv255f);
922
923 data->glClear(GL_COLOR_BUFFER_BIT);
924
925 return 0;
926 }
927
928 static int
929 GL_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points,
930 int count)
931 {
932 GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
933 int i;
934
935 GL_ActivateRenderer(renderer);
936
937 GL_SetBlendMode(data, renderer->blendMode);
938
939 data->glColor4f((GLfloat) renderer->r * inv255f,
940 (GLfloat) renderer->g * inv255f,
941 (GLfloat) renderer->b * inv255f,
942 (GLfloat) renderer->a * inv255f);
943
944 data->glBegin(GL_POINTS);
945 for (i = 0; i < count; ++i) {
946 data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
947 }
948 data->glEnd();
949
950 return 0;
951 }
952
953 static int
954 GL_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points,
955 int count)
956 {
957 GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
958 int i;
959
960 GL_ActivateRenderer(renderer);
961
962 GL_SetBlendMode(data, renderer->blendMode);
963
964 data->glColor4f((GLfloat) renderer->r * inv255f,
965 (GLfloat) renderer->g * inv255f,
966 (GLfloat) renderer->b * inv255f,
967 (GLfloat) renderer->a * inv255f);
968
969 if (count > 2 &&
970 points[0].x == points[count-1].x && points[0].y == points[count-1].y) {
971 data->glBegin(GL_LINE_LOOP);
972 /* GL_LINE_LOOP takes care of the final segment */
973 --count;
974 for (i = 0; i < count; ++i) {
975 data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
976 }
977 data->glEnd();
978 } else {
979 #if defined(__APPLE__) || defined(__WIN32__)
980 #else
981 int x1, y1, x2, y2;
982 #endif
983
984 data->glBegin(GL_LINE_STRIP);
985 for (i = 0; i < count; ++i) {
986 data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
987 }
988 data->glEnd();
989
990 /* The line is half open, so we need one more point to complete it.
991 * http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node47.html
992 * If we have to, we can use vertical line and horizontal line textures
993 * for vertical and horizontal lines, and then create custom textures
994 * for diagonal lines and software render those. It's terrible, but at
995 * least it would be pixel perfect.
996 */
997 data->glBegin(GL_POINTS);
998 #if defined(__APPLE__) || defined(__WIN32__)
999 /* Mac OS X and Windows seem to always leave the second point open */
1000 data->glVertex2f(0.5f + points[count-1].x, 0.5f + points[count-1].y);
1001 #else
1002 /* Linux seems to leave the right-most or bottom-most point open */
1003 x1 = points[0].x;
1004 y1 = points[0].y;
1005 x2 = points[count-1].x;
1006 y2 = points[count-1].y;
1007
1008 if (x1 > x2) {
1009 data->glVertex2f(0.5f + x1, 0.5f + y1);
1010 } else if (x2 > x1) {
1011 data->glVertex2f(0.5f + x2, 0.5f + y2);
1012 } else if (y1 > y2) {
1013 data->glVertex2f(0.5f + x1, 0.5f + y1);
1014 } else if (y2 > y1) {
1015 data->glVertex2f(0.5f + x2, 0.5f + y2);
1016 }
1017 #endif
1018 data->glEnd();
1019 }
1020
1021 return 0;
1022 }
1023
1024 static int
1025 GL_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect ** rects, int count)
1026 {
1027 GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
1028 int i;
1029
1030 GL_ActivateRenderer(renderer);
1031
1032 GL_SetBlendMode(data, renderer->blendMode);
1033
1034 data->glColor4f((GLfloat) renderer->r * inv255f,
1035 (GLfloat) renderer->g * inv255f,
1036 (GLfloat) renderer->b * inv255f,
1037 (GLfloat) renderer->a * inv255f);
1038
1039 for (i = 0; i < count; ++i) {
1040 const SDL_Rect *rect = rects[i];
1041
1042 data->glRecti(rect->x, rect->y, rect->x + rect->w, rect->y + rect->h);
1043 }
1044
1045 return 0;
1046 }
1047
1048 static int
1049 GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
1050 const SDL_Rect * srcrect, const SDL_Rect * dstrect)
1051 {
1052 GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
1053 GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
1054 int minx, miny, maxx, maxy;
1055 GLfloat minu, maxu, minv, maxv;
1056
1057 GL_ActivateRenderer(renderer);
1058
1059 if (texturedata->dirty.list) {
1060 SDL_DirtyRect *dirty;
1061 void *pixels;
1062 int bpp = bytes_per_pixel(texture->format);
1063 int pitch = texturedata->pitch;
1064
1065 SetupTextureUpdate(data, texture, pitch);
1066 data->glEnable(texturedata->type);
1067 data->glBindTexture(texturedata->type, texturedata->texture);
1068 for (dirty = texturedata->dirty.list; dirty; dirty = dirty->next) {
1069 SDL_Rect *rect = &dirty->rect;
1070 pixels =
1071 (void *) ((Uint8 *) texturedata->pixels + rect->y * pitch +
1072 rect->x * bpp);
1073 data->glTexSubImage2D(texturedata->type, 0, rect->x, rect->y,
1074 rect->w / texturedata->HACK_RYAN_FIXME,
1075 rect->h, texturedata->format,
1076 texturedata->formattype, pixels);
1077 }
1078 SDL_ClearDirtyRects(&texturedata->dirty);
1079 }
1080
1081 minx = dstrect->x;
1082 miny = dstrect->y;
1083 maxx = dstrect->x + dstrect->w;
1084 maxy = dstrect->y + dstrect->h;
1085
1086 minu = (GLfloat) srcrect->x / texture->w;
1087 minu *= texturedata->texw;
1088 maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
1089 maxu *= texturedata->texw;
1090 minv = (GLfloat) srcrect->y / texture->h;
1091 minv *= texturedata->texh;
1092 maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
1093 maxv *= texturedata->texh;
1094
1095 data->glEnable(texturedata->type);
1096 data->glBindTexture(texturedata->type, texturedata->texture);
1097
1098 if (texture->modMode) {
1099 data->glColor4f((GLfloat) texture->r * inv255f,
1100 (GLfloat) texture->g * inv255f,
1101 (GLfloat) texture->b * inv255f,
1102 (GLfloat) texture->a * inv255f);
1103 } else {
1104 data->glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1105 }
1106
1107 GL_SetBlendMode(data, texture->blendMode);
1108
1109 /* Set up the shader for the copy, if any */
1110 if (texturedata->shader) {
1111 data->glEnable(GL_FRAGMENT_PROGRAM_ARB);
1112 data->glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, texturedata->shader);
1113 }
1114
1115 data->glBegin(GL_TRIANGLE_STRIP);
1116 data->glTexCoord2f(minu, minv);
1117 data->glVertex2f((GLfloat) minx, (GLfloat) miny);
1118 data->glTexCoord2f(maxu, minv);
1119 data->glVertex2f((GLfloat) maxx, (GLfloat) miny);
1120 data->glTexCoord2f(minu, maxv);
1121 data->glVertex2f((GLfloat) minx, (GLfloat) maxy);
1122 data->glTexCoord2f(maxu, maxv);
1123 data->glVertex2f((GLfloat) maxx, (GLfloat) maxy);
1124 data->glEnd();
1125
1126 if (texturedata->shader) {
1127 data->glDisable(GL_FRAGMENT_PROGRAM_ARB);
1128 }
1129
1130 data->glDisable(texturedata->type);
1131
1132 return 0;
1133 }
1134
1135 static int
1136 GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
1137 Uint32 pixel_format, void * pixels, int pitch)
1138 {
1139 GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
1140 SDL_Window *window = renderer->window;
1141 GLint internalFormat;
1142 GLenum format, type;
1143 Uint8 *src, *dst, *tmp;
1144 int w, h, length, rows;
1145
1146 GL_ActivateRenderer(renderer);
1147
1148 if (!convert_format(data, pixel_format, &internalFormat, &format, &type)) {
1149 /* FIXME: Do a temp copy to a format that is supported */
1150 SDL_SetError("Unsupported pixel format");
1151 return -1;
1152 }
1153
1154 SDL_GetWindowSize(window, &w, &h);
1155
1156 data->glPixelStorei(GL_PACK_ALIGNMENT, 1);
1157 data->glPixelStorei(GL_PACK_ROW_LENGTH,
1158 (pitch / bytes_per_pixel(pixel_format)));
1159
1160 data->glReadPixels(rect->x, (h-rect->y)-rect->h, rect->w, rect->h,
1161 format, type, pixels);
1162
1163 /* Flip the rows to be top-down */
1164 length = rect->w * bytes_per_pixel(pixel_format);
1165 src = (Uint8*)pixels + (rect->h-1)*pitch;
1166 dst = (Uint8*)pixels;
1167 tmp = SDL_stack_alloc(Uint8, length);
1168 rows = rect->h / 2;
1169 while (rows--) {
1170 SDL_memcpy(tmp, dst, length);
1171 SDL_memcpy(dst, src, length);
1172 SDL_memcpy(src, tmp, length);
1173 dst += pitch;
1174 src -= pitch;
1175 }
1176 SDL_stack_free(tmp);
1177
1178 return 0;
1179 }
1180
1181 static int
1182 GL_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect,
1183 Uint32 pixel_format, const void * pixels, int pitch)
1184 {
1185 GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
1186 SDL_Window *window = renderer->window;
1187 GLint internalFormat;
1188 GLenum format, type;
1189 Uint8 *src, *dst, *tmp;
1190 int w, h, length, rows;
1191
1192 GL_ActivateRenderer(renderer);
1193
1194 if (!convert_format(data, pixel_format, &internalFormat, &format, &type)) {
1195 /* FIXME: Do a temp copy to a format that is supported */
1196 SDL_SetError("Unsupported pixel format");
1197 return -1;
1198 }
1199
1200 SDL_GetWindowSize(window, &w, &h);
1201
1202 data->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1203 data->glPixelStorei(GL_UNPACK_ROW_LENGTH,
1204 (pitch / bytes_per_pixel(pixel_format)));
1205
1206 /* Flip the rows to be bottom-up */
1207 length = rect->h * rect->w * pitch;
1208 tmp = SDL_stack_alloc(Uint8, length);
1209 src = (Uint8*)pixels + (rect->h-1)*pitch;
1210 dst = (Uint8*)tmp;
1211 rows = rect->h;
1212 while (rows--) {
1213 SDL_memcpy(dst, src, pitch);
1214 dst += pitch;
1215 src -= pitch;
1216 }
1217
1218 data->glRasterPos2i(rect->x, (h-rect->y));
1219 data->glDrawPixels(rect->w, rect->h, format, type, tmp);
1220 SDL_stack_free(tmp);
1221
1222 return 0;
1223 }
1224
1225 static void
1226 GL_RenderPresent(SDL_Renderer * renderer)
1227 {
1228 GL_ActivateRenderer(renderer);
1229
1230 SDL_GL_SwapWindow(renderer->window);
1231 }
1232
1233 static void
1234 GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
1235 {
1236 GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
1237 GL_TextureData *data = (GL_TextureData *) texture->driverdata;
1238
1239 GL_ActivateRenderer(renderer);
1240
1241 if (!data) {
1242 return;
1243 }
1244 if (data->texture) {
1245 renderdata->glDeleteTextures(1, &data->texture);
1246 }
1247 if (data->palette) {
1248 SDL_free(data->palette);
1249 }
1250 if (data->pixels) {
1251 SDL_free(data->pixels);
1252 }
1253 SDL_FreeDirtyRects(&data->dirty);
1254 SDL_free(data);
1255 texture->driverdata = NULL;
1256 }
1257
1258 static void
1259 GL_DestroyRenderer(SDL_Renderer * renderer)
1260 {
1261 GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
1262
1263 if (data) {
1264 if (data->context) {
1265 if (data->GL_ARB_fragment_program_supported) {
1266 data->glDisable(GL_FRAGMENT_PROGRAM_ARB);
1267 data->glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0);
1268 if (data->fragment_program_UYVY &&
1269 data->fragment_program_UYVY != ~0) {
1270 data->glDeleteProgramsARB(1,
1271 &data->fragment_program_UYVY);
1272 }
1273 }
1274
1275 /* SDL_GL_MakeCurrent(0, NULL); *//* doesn't do anything */
1276 SDL_GL_DeleteContext(data->context);
1277 }
1278 SDL_free(data);
1279 }
1280 SDL_free(renderer);
1281 }
1282
1283 #endif /* SDL_VIDEO_RENDER_OGL */
1284
1285 /* vi: set ts=4 sw=4 expandtab: */