This repository has been archived by the owner on Feb 11, 2021. It is now read-only.
/
SDL_renderer_gl.c
1299 lines (1168 loc) · 41.4 KB
1
2
/*
SDL - Simple DirectMedia Layer
3
Copyright (C) 1997-2009 Sam Lantinga
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
24
#if SDL_VIDEO_RENDER_OGL
25
26
27
28
29
30
31
#include "SDL_video.h"
#include "SDL_opengl.h"
#include "SDL_sysvideo.h"
#include "SDL_pixels_c.h"
#include "SDL_rect_c.h"
#include "SDL_yuv_sw_c.h"
32
33
34
35
36
#ifdef __MACOSX__
#include <OpenGL/OpenGL.h>
#endif
37
38
39
/* OpenGL renderer implementation */
40
41
42
43
/* Details on optimizing the texture path on Mac OS X:
http://developer.apple.com/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_texturedata/chapter_10_section_2.html
*/
44
45
46
47
/* !!! FIXME: this should go in a higher level than the GL renderer. */
static __inline__ int
bytes_per_pixel(const Uint32 format)
{
48
49
50
51
52
if (!SDL_ISPIXELFORMAT_FOURCC(format)) {
return SDL_BYTESPERPIXEL(format);
}
/* FOURCC format */
53
switch (format) {
54
55
56
57
58
59
60
61
case SDL_PIXELFORMAT_YV12:
case SDL_PIXELFORMAT_IYUV:
case SDL_PIXELFORMAT_YUY2:
case SDL_PIXELFORMAT_UYVY:
case SDL_PIXELFORMAT_YVYU:
return 2;
default:
return 1; /* shouldn't ever hit this. */
62
63
64
65
}
}
66
67
static const float inv255f = 1.0f / 255.0f;
68
static SDL_Renderer *GL_CreateRenderer(SDL_Window * window, Uint32 flags);
69
static int GL_ActivateRenderer(SDL_Renderer * renderer);
70
static int GL_DisplayModeChanged(SDL_Renderer * renderer);
71
static int GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
72
73
74
static int GL_QueryTexturePixels(SDL_Renderer * renderer,
SDL_Texture * texture, void **pixels,
int *pitch);
75
76
77
78
79
80
81
static int GL_SetTexturePalette(SDL_Renderer * renderer,
SDL_Texture * texture,
const SDL_Color * colors, int firstcolor,
int ncolors);
static int GL_GetTexturePalette(SDL_Renderer * renderer,
SDL_Texture * texture, SDL_Color * colors,
int firstcolor, int ncolors);
82
83
84
85
86
87
88
89
static int GL_SetTextureColorMod(SDL_Renderer * renderer,
SDL_Texture * texture);
static int GL_SetTextureAlphaMod(SDL_Renderer * renderer,
SDL_Texture * texture);
static int GL_SetTextureBlendMode(SDL_Renderer * renderer,
SDL_Texture * texture);
static int GL_SetTextureScaleMode(SDL_Renderer * renderer,
SDL_Texture * texture);
90
91
92
93
static int GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
const SDL_Rect * rect, const void *pixels,
int pitch);
static int GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
94
95
const SDL_Rect * rect, int markDirty, void **pixels,
int *pitch);
96
97
98
static void GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
static void GL_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture,
int numrects, const SDL_Rect * rects);
99
100
static int GL_SetDrawColor(SDL_Renderer * renderer);
static int GL_SetDrawBlendMode(SDL_Renderer * renderer);
101
static int GL_RenderPoint(SDL_Renderer * renderer, int x, int y);
102
103
104
static int GL_RenderLine(SDL_Renderer * renderer, int x1, int y1, int x2,
int y2);
static int GL_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect);
105
static int GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
106
const SDL_Rect * srcrect, const SDL_Rect * dstrect);
107
108
109
110
111
112
113
114
115
116
static void GL_RenderPresent(SDL_Renderer * renderer);
static void GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture);
static void GL_DestroyRenderer(SDL_Renderer * renderer);
SDL_RenderDriver GL_RenderDriver = {
GL_CreateRenderer,
{
"opengl",
117
118
(SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_PRESENTDISCARD |
SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED),
119
120
(SDL_TEXTUREMODULATE_NONE | SDL_TEXTUREMODULATE_COLOR |
SDL_TEXTUREMODULATE_ALPHA),
121
122
(SDL_BLENDMODE_NONE | SDL_BLENDMODE_MASK |
SDL_BLENDMODE_BLEND | SDL_BLENDMODE_ADD | SDL_BLENDMODE_MOD),
123
124
(SDL_TEXTURESCALEMODE_NONE | SDL_TEXTURESCALEMODE_FAST |
SDL_TEXTURESCALEMODE_SLOW),
125
15,
126
{
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
SDL_PIXELFORMAT_INDEX1LSB,
SDL_PIXELFORMAT_INDEX1MSB,
SDL_PIXELFORMAT_INDEX8,
SDL_PIXELFORMAT_RGB332,
SDL_PIXELFORMAT_RGB444,
SDL_PIXELFORMAT_RGB555,
SDL_PIXELFORMAT_ARGB4444,
SDL_PIXELFORMAT_ARGB1555,
SDL_PIXELFORMAT_RGB565,
SDL_PIXELFORMAT_RGB24,
SDL_PIXELFORMAT_BGR24,
SDL_PIXELFORMAT_RGB888,
SDL_PIXELFORMAT_BGR888,
SDL_PIXELFORMAT_ARGB8888,
SDL_PIXELFORMAT_ABGR8888,
142
SDL_PIXELFORMAT_ARGB2101010},
143
144
145
146
147
148
149
0,
0}
};
typedef struct
{
SDL_GLContext context;
150
SDL_bool updateSize;
151
SDL_bool GL_ARB_texture_rectangle_supported;
152
SDL_bool GL_EXT_paletted_texture_supported;
153
154
SDL_bool GL_APPLE_ycbcr_422_supported;
SDL_bool GL_MESA_ycbcr_texture_supported;
155
SDL_bool GL_ARB_fragment_program_supported;
156
157
158
159
160
161
162
int blendMode;
int scaleMode;
/* OpenGL functions */
#define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
#include "SDL_glfuncs.h"
#undef SDL_PROC
163
164
PFNGLCOLORTABLEEXTPROC glColorTableEXT;
165
166
void (*glTextureRangeAPPLE) (GLenum target, GLsizei length,
const GLvoid * pointer);
167
168
169
170
171
172
173
174
175
176
177
PFNGLGETPROGRAMIVARBPROC glGetProgramivARB;
PFNGLGETPROGRAMSTRINGARBPROC glGetProgramStringARB;
PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glProgramLocalParameter4fvARB;
PFNGLDELETEPROGRAMSARBPROC glDeleteProgramsARB;
PFNGLGENPROGRAMSARBPROC glGenProgramsARB;
PFNGLBINDPROGRAMARBPROC glBindProgramARB;
PFNGLPROGRAMSTRINGARBPROC glProgramStringARB;
/* (optional) fragment programs */
GLuint fragment_program_UYVY;
178
179
180
181
182
} GL_RenderData;
typedef struct
{
GLuint texture;
183
GLuint shader;
184
GLenum type;
185
186
GLfloat texw;
GLfloat texh;
187
188
GLenum format;
GLenum formattype;
189
Uint8 *palette;
190
191
void *pixels;
int pitch;
192
SDL_DirtyRectList dirty;
193
int HACK_RYAN_FIXME;
194
195
196
} GL_TextureData;
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
static void
GL_SetError(const char *prefix, GLenum result)
{
const char *error;
switch (result) {
case GL_NO_ERROR:
error = "GL_NO_ERROR";
break;
case GL_INVALID_ENUM:
error = "GL_INVALID_ENUM";
break;
case GL_INVALID_VALUE:
error = "GL_INVALID_VALUE";
break;
case GL_INVALID_OPERATION:
error = "GL_INVALID_OPERATION";
break;
case GL_STACK_OVERFLOW:
error = "GL_STACK_OVERFLOW";
break;
case GL_STACK_UNDERFLOW:
error = "GL_STACK_UNDERFLOW";
break;
case GL_OUT_OF_MEMORY:
error = "GL_OUT_OF_MEMORY";
break;
case GL_TABLE_TOO_LARGE:
error = "GL_TABLE_TOO_LARGE";
break;
default:
error = "UNKNOWN";
break;
}
SDL_SetError("%s: %s", prefix, error);
}
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
static int
GL_LoadFunctions(GL_RenderData * data)
{
#if defined(__QNXNTO__) && (_NTO_VERSION < 630)
#define __SDL_NOGETPROCADDR__
#elif defined(__MINT__)
#define __SDL_NOGETPROCADDR__
#endif
#ifdef __SDL_NOGETPROCADDR__
#define SDL_PROC(ret,func,params) data->func=func;
#else
#define SDL_PROC(ret,func,params) \
do { \
data->func = SDL_GL_GetProcAddress(#func); \
if ( ! data->func ) { \
SDL_SetError("Couldn't load GL function %s: %s\n", #func, SDL_GetError()); \
return -1; \
} \
} while ( 0 );
#endif /* __SDL_NOGETPROCADDR__ */
#include "SDL_glfuncs.h"
#undef SDL_PROC
return 0;
}
260
261
262
void
GL_AddRenderDriver(_THIS)
{
263
if (_this->GL_CreateContext) {
264
265
266
267
268
269
270
271
272
SDL_AddRenderDriver(0, &GL_RenderDriver);
}
}
SDL_Renderer *
GL_CreateRenderer(SDL_Window * window, Uint32 flags)
{
SDL_Renderer *renderer;
GL_RenderData *data;
273
GLint value;
274
int doublebuffer;
275
276
277
278
279
280
281
/* Render directly to the window, unless we're compositing */
#ifndef __MACOSX__
if (flags & SDL_RENDERER_SINGLEBUFFER) {
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 0);
}
#endif
282
if (!(window->flags & SDL_WINDOW_OPENGL)) {
283
if (SDL_RecreateWindow(window, window->flags | SDL_WINDOW_OPENGL) < 0) {
284
285
return NULL;
}
286
287
}
288
renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
289
290
291
292
293
if (!renderer) {
SDL_OutOfMemory();
return NULL;
}
294
data = (GL_RenderData *) SDL_calloc(1, sizeof(*data));
295
296
297
298
299
300
if (!data) {
GL_DestroyRenderer(renderer);
SDL_OutOfMemory();
return NULL;
}
301
renderer->ActivateRenderer = GL_ActivateRenderer;
302
renderer->DisplayModeChanged = GL_DisplayModeChanged;
303
renderer->CreateTexture = GL_CreateTexture;
304
renderer->QueryTexturePixels = GL_QueryTexturePixels;
305
306
renderer->SetTexturePalette = GL_SetTexturePalette;
renderer->GetTexturePalette = GL_GetTexturePalette;
307
308
309
310
renderer->SetTextureColorMod = GL_SetTextureColorMod;
renderer->SetTextureAlphaMod = GL_SetTextureAlphaMod;
renderer->SetTextureBlendMode = GL_SetTextureBlendMode;
renderer->SetTextureScaleMode = GL_SetTextureScaleMode;
311
312
313
314
renderer->UpdateTexture = GL_UpdateTexture;
renderer->LockTexture = GL_LockTexture;
renderer->UnlockTexture = GL_UnlockTexture;
renderer->DirtyTexture = GL_DirtyTexture;
315
316
renderer->SetDrawColor = GL_SetDrawColor;
renderer->SetDrawBlendMode = GL_SetDrawBlendMode;
317
renderer->RenderPoint = GL_RenderPoint;
318
renderer->RenderLine = GL_RenderLine;
319
320
321
322
323
324
325
326
327
328
renderer->RenderFill = GL_RenderFill;
renderer->RenderCopy = GL_RenderCopy;
renderer->RenderPresent = GL_RenderPresent;
renderer->DestroyTexture = GL_DestroyTexture;
renderer->DestroyRenderer = GL_DestroyRenderer;
renderer->info = GL_RenderDriver.info;
renderer->window = window->id;
renderer->driverdata = data;
renderer->info.flags =
329
(SDL_RENDERER_PRESENTDISCARD | SDL_RENDERER_ACCELERATED);
330
331
332
333
334
335
if (GL_LoadFunctions(data) < 0) {
GL_DestroyRenderer(renderer);
return NULL;
}
336
337
338
339
340
341
342
343
344
data->context = SDL_GL_CreateContext(window->id);
if (!data->context) {
GL_DestroyRenderer(renderer);
return NULL;
}
if (SDL_GL_MakeCurrent(window->id, data->context) < 0) {
GL_DestroyRenderer(renderer);
return NULL;
}
345
346
347
#ifdef __MACOSX__
/* Enable multi-threaded rendering */
/* Disabled until Ryan finishes his VBO/PBO code...
348
349
CGLEnable(CGLGetCurrentContext(), kCGLCEMPEngine);
*/
350
351
#endif
352
if (flags & SDL_RENDERER_PRESENTVSYNC) {
353
354
355
356
357
SDL_GL_SetSwapInterval(1);
} else {
SDL_GL_SetSwapInterval(0);
}
if (SDL_GL_GetSwapInterval() > 0) {
358
renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
359
360
}
361
362
363
364
365
366
if (SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &doublebuffer) == 0) {
if (!doublebuffer) {
renderer->info.flags |= SDL_RENDERER_SINGLEBUFFER;
}
}
367
368
369
370
data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
renderer->info.max_texture_width = value;
data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
renderer->info.max_texture_height = value;
371
372
373
374
375
if (SDL_GL_ExtensionSupported("GL_ARB_texture_rectangle")
|| SDL_GL_ExtensionSupported("GL_EXT_texture_rectangle")) {
data->GL_ARB_texture_rectangle_supported = SDL_TRUE;
}
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
if (SDL_GL_ExtensionSupported("GL_EXT_paletted_texture")) {
data->GL_EXT_paletted_texture_supported = SDL_TRUE;
data->glColorTableEXT =
(PFNGLCOLORTABLEEXTPROC) SDL_GL_GetProcAddress("glColorTableEXT");
} else {
/* Don't advertise support for 8-bit indexed texture format */
Uint32 i, j;
SDL_RendererInfo *info = &renderer->info;
for (i = 0, j = 0; i < info->num_texture_formats; ++i) {
if (info->texture_formats[i] != SDL_PIXELFORMAT_INDEX8) {
info->texture_formats[j++] = info->texture_formats[i];
}
}
--info->num_texture_formats;
}
391
392
393
394
395
396
if (SDL_GL_ExtensionSupported("GL_APPLE_ycbcr_422")) {
data->GL_APPLE_ycbcr_422_supported = SDL_TRUE;
}
if (SDL_GL_ExtensionSupported("GL_MESA_ycbcr_texture")) {
data->GL_MESA_ycbcr_texture_supported = SDL_TRUE;
}
397
398
399
400
401
if (SDL_GL_ExtensionSupported("GL_APPLE_texture_range")) {
data->glTextureRangeAPPLE =
(void (*)(GLenum, GLsizei, const GLvoid *))
SDL_GL_GetProcAddress("glTextureRangeAPPLE");
}
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
/* we might use fragment programs for YUV data, etc. */
if (SDL_GL_ExtensionSupported("GL_ARB_fragment_program")) {
/* !!! FIXME: this doesn't check for errors. */
/* !!! FIXME: this should really reuse the glfuncs.h stuff. */
data->glGetProgramivARB = (PFNGLGETPROGRAMIVARBPROC)
SDL_GL_GetProcAddress("glGetProgramivARB");
data->glGetProgramStringARB = (PFNGLGETPROGRAMSTRINGARBPROC)
SDL_GL_GetProcAddress("glGetProgramStringARB");
data->glProgramLocalParameter4fvARB =
(PFNGLPROGRAMLOCALPARAMETER4FVARBPROC)
SDL_GL_GetProcAddress("glProgramLocalParameter4fvARB");
data->glDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC)
SDL_GL_GetProcAddress("glDeleteProgramsARB");
data->glGenProgramsARB = (PFNGLGENPROGRAMSARBPROC)
SDL_GL_GetProcAddress("glGenProgramsARB");
data->glBindProgramARB = (PFNGLBINDPROGRAMARBPROC)
SDL_GL_GetProcAddress("glBindProgramARB");
data->glProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC)
SDL_GL_GetProcAddress("glProgramStringARB");
data->GL_ARB_fragment_program_supported = SDL_TRUE;
}
425
/* Set up parameters for rendering */
426
427
428
429
data->blendMode = -1;
data->scaleMode = -1;
data->glDisable(GL_DEPTH_TEST);
data->glDisable(GL_CULL_FACE);
430
data->glEnable(GL_LINE_SMOOTH);
431
if (data->GL_ARB_texture_rectangle_supported) {
432
data->glEnable(GL_TEXTURE_RECTANGLE_ARB);
433
} else {
434
data->glEnable(GL_TEXTURE_2D);
435
}
436
data->updateSize = SDL_TRUE;
437
438
439
440
return renderer;
}
441
442
443
444
445
446
static void
SetBlendMode(GL_RenderData * data, int blendMode)
{
if (blendMode != data->blendMode) {
switch (blendMode) {
case SDL_BLENDMODE_NONE:
447
data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
data->glDisable(GL_BLEND);
break;
case SDL_BLENDMODE_MASK:
case SDL_BLENDMODE_BLEND:
data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
data->glEnable(GL_BLEND);
data->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
break;
case SDL_BLENDMODE_ADD:
data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
data->glEnable(GL_BLEND);
data->glBlendFunc(GL_SRC_ALPHA, GL_ONE);
break;
case SDL_BLENDMODE_MOD:
data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
data->glEnable(GL_BLEND);
data->glBlendFunc(GL_ZERO, GL_SRC_COLOR);
break;
}
data->blendMode = blendMode;
}
}
471
472
473
474
475
476
static int
GL_ActivateRenderer(SDL_Renderer * renderer)
{
GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
SDL_Window *window = SDL_GetWindowFromID(renderer->window);
477
478
479
if (SDL_GL_MakeCurrent(window->id, data->context) < 0) {
return -1;
}
480
if (data->updateSize) {
481
482
483
484
485
486
487
data->glMatrixMode(GL_PROJECTION);
data->glLoadIdentity();
data->glMatrixMode(GL_MODELVIEW);
data->glLoadIdentity();
data->glViewport(0, 0, window->w, window->h);
data->glOrtho(0.0, (GLdouble) window->w, (GLdouble) window->h, 0.0,
0.0, 1.0);
488
489
data->updateSize = SDL_FALSE;
}
490
491
492
493
494
495
496
497
return 0;
}
static int
GL_DisplayModeChanged(SDL_Renderer * renderer)
{
GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
498
499
500
/* Rebind the context to the window area and update matrices */
data->updateSize = SDL_TRUE;
return GL_ActivateRenderer(renderer);
501
502
}
503
504
505
506
507
508
509
510
511
512
513
static __inline__ int
power_of_2(int input)
{
int value = 1;
while (value < input) {
value <<= 1;
}
return value;
}
514
515
//#define DEBUG_PROGRAM_COMPILE 1
516
517
static GLuint
518
compile_shader(GL_RenderData * data, GLenum shader_type, const char *_code)
519
{
520
521
const int have_texture_rects = data->GL_ARB_texture_rectangle_supported;
const char *replacement = have_texture_rects ? "RECT" : "2D";
522
const size_t replacementlen = SDL_strlen(replacement);
523
const char *token = "%TEXTURETARGET%";
524
const size_t tokenlen = SDL_strlen(token);
525
526
527
528
529
530
531
532
533
534
535
536
537
char *code = NULL;
char *ptr = NULL;
GLuint program = 0;
/*
* The TEX instruction needs a different target depending on what we use.
* To handle this, we use "%TEXTURETARGET%" and replace the string before
* compiling the shader.
*/
code = SDL_strdup(_code);
if (code == NULL)
return 0;
538
for (ptr = SDL_strstr(code, token); ptr; ptr = SDL_strstr(ptr + 1, token)) {
539
540
541
SDL_memcpy(ptr, replacement, replacementlen);
SDL_memmove(ptr + replacementlen, ptr + tokenlen,
SDL_strlen(ptr + tokenlen) + 1);
542
543
}
544
#if DEBUG_PROGRAM_COMPILE
545
printf("compiling shader:\n%s\n\n", code);
546
547
#endif
548
data->glGetError(); /* flush any existing error state. */
549
550
551
data->glGenProgramsARB(1, &program);
data->glBindProgramARB(shader_type, program);
data->glProgramStringARB(shader_type, GL_PROGRAM_FORMAT_ASCII_ARB,
552
553
554
SDL_strlen(code), code);
SDL_free(code);
555
556
if (data->glGetError() == GL_INVALID_OPERATION) {
557
558
559
560
561
562
#if DEBUG_PROGRAM_COMPILE
GLint pos = 0;
const GLubyte *errstr;
data->glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &pos);
errstr = data->glGetString(GL_PROGRAM_ERROR_STRING_ARB);
printf("program compile error at position %d: %s\n\n",
563
(int) pos, (const char *) errstr);
564
565
566
567
#endif
data->glBindProgramARB(shader_type, 0);
data->glDeleteProgramsARB(1, &program);
return 0;
568
}
569
570
571
572
return program;
}
573
574
575
576
577
578
579
580
581
582
583
584
585
/*
* Fragment program that renders from UYVY textures.
* The UYVY to RGB equasion is:
* R = 1.164(Y-16) + 1.596(Cr-128)
* G = 1.164(Y-16) - 0.813(Cr-128) - 0.391(Cb-128)
* B = 1.164(Y-16) + 2.018(Cb-128)
* Byte layout is Cb, Y1, Cr, Y2, stored in the R, G, B, A channels.
* 4 bytes == 2 pixels: Y1/Cb/Cr, Y2/Cb/Cr
*
* !!! FIXME: this ignores blendmodes, etc.
* !!! FIXME: this could be more efficient...use a dot product for green, etc.
*/
586
static const char *fragment_program_UYVY_source_code = "!!ARBfp1.0\n"
587
/* outputs... */
588
"OUTPUT outcolor = result.color;\n"
589
/* scratch registers... */
590
"TEMP uyvy;\n" "TEMP luminance;\n" "TEMP work;\n"
591
/* Halve the coordinates to grab the correct 32 bits for the fragment. */
592
"MUL work, fragment.texcoord, { 0.5, 1.0, 1.0, 1.0 };\n"
593
/* Sample the YUV texture. Cb, Y1, Cr, Y2, are stored in x, y, z, w. */
594
"TEX uyvy, work, texture[0], %TEXTURETARGET%;\n"
595
/* Do subtractions (128/255, 16/255, 128/255, 16/255) */
596
"SUB uyvy, uyvy, { 0.501960784313726, 0.06274509803922, 0.501960784313726, 0.06274509803922 };\n"
597
598
/* Choose the luminance component by texcoord. */
/* !!! FIXME: laziness wins out for now... just average Y1 and Y2. */
599
600
"ADD luminance, uyvy.yyyy, uyvy.wwww;\n"
"MUL luminance, luminance, { 0.5, 0.5, 0.5, 0.5 };\n"
601
/* Multiply luminance by its magic value. */
602
"MUL luminance, luminance, { 1.164, 1.164, 1.164, 1.164 };\n"
603
/* uyvy.xyzw becomes Cr/Cr/Cb/Cb, with multiplications. */
604
"MUL uyvy, uyvy.zzxx, { 1.596, -0.813, 2.018, -0.391 };\n"
605
/* Add luminance to Cr and Cb, store to RGB channels. */
606
"ADD work.rgb, luminance, uyvy;\n"
607
/* Do final addition for Green channel. (!!! FIXME: this should be a DPH?) */
608
"ADD work.g, work.g, uyvy.w;\n"
609
/* Make sure alpha channel is fully opaque. (!!! FIXME: blend modes!) */
610
"MOV work.a, { 1.0 };\n"
611
/* Store out the final fragment color... */
612
"MOV outcolor, work;\n"
613
/* ...and we're done! */
614
615
616
"END\n";
617
618
619
620
621
622
static int
GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
{
GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
SDL_Window *window = SDL_GetWindowFromID(renderer->window);
GL_TextureData *data;
623
624
GLint internalFormat;
GLenum format, type;
625
int texture_w, texture_h;
626
GLuint shader = 0;
627
GLenum result;
628
629
switch (texture->format) {
630
631
case SDL_PIXELFORMAT_INDEX1LSB:
case SDL_PIXELFORMAT_INDEX1MSB:
632
633
634
635
internalFormat = GL_RGB;
format = GL_COLOR_INDEX;
type = GL_BITMAP;
break;
636
case SDL_PIXELFORMAT_INDEX8:
637
638
639
640
641
if (!renderdata->GL_EXT_paletted_texture_supported) {
SDL_SetError("Unsupported texture format");
return -1;
}
internalFormat = GL_COLOR_INDEX8_EXT;
642
643
644
format = GL_COLOR_INDEX;
type = GL_UNSIGNED_BYTE;
break;
645
case SDL_PIXELFORMAT_RGB332:
646
647
648
649
internalFormat = GL_R3_G3_B2;
format = GL_RGB;
type = GL_UNSIGNED_BYTE_3_3_2;
break;
650
case SDL_PIXELFORMAT_RGB444:
651
652
653
654
internalFormat = GL_RGB4;
format = GL_RGB;
type = GL_UNSIGNED_SHORT_4_4_4_4;
break;
655
case SDL_PIXELFORMAT_RGB555:
656
657
658
659
internalFormat = GL_RGB5;
format = GL_RGB;
type = GL_UNSIGNED_SHORT_5_5_5_1;
break;
660
case SDL_PIXELFORMAT_ARGB4444:
661
662
663
664
internalFormat = GL_RGBA4;
format = GL_BGRA;
type = GL_UNSIGNED_SHORT_4_4_4_4_REV;
break;
665
case SDL_PIXELFORMAT_ARGB1555:
666
667
668
669
internalFormat = GL_RGB5_A1;
format = GL_BGRA;
type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
break;
670
case SDL_PIXELFORMAT_RGB565:
671
672
673
674
internalFormat = GL_RGB8;
format = GL_RGB;
type = GL_UNSIGNED_SHORT_5_6_5;
break;
675
case SDL_PIXELFORMAT_RGB24:
676
677
678
679
internalFormat = GL_RGB8;
format = GL_RGB;
type = GL_UNSIGNED_BYTE;
break;
680
case SDL_PIXELFORMAT_RGB888:
681
internalFormat = GL_RGB8;
682
683
format = GL_BGRA;
type = GL_UNSIGNED_BYTE;
684
break;
685
case SDL_PIXELFORMAT_BGR24:
686
687
688
689
internalFormat = GL_RGB8;
format = GL_BGR;
type = GL_UNSIGNED_BYTE;
break;
690
case SDL_PIXELFORMAT_BGR888:
691
internalFormat = GL_RGB8;
692
693
format = GL_RGBA;
type = GL_UNSIGNED_BYTE;
694
break;
695
case SDL_PIXELFORMAT_ARGB8888:
696
697
698
699
700
#ifdef __MACOSX__
internalFormat = GL_RGBA;
format = GL_BGRA;
type = GL_UNSIGNED_INT_8_8_8_8_REV;
#else
701
702
internalFormat = GL_RGBA8;
format = GL_BGRA;
703
type = GL_UNSIGNED_BYTE;
704
#endif
705
break;
706
case SDL_PIXELFORMAT_ABGR8888:
707
708
internalFormat = GL_RGBA8;
format = GL_RGBA;
709
type = GL_UNSIGNED_BYTE;
710
break;
711
case SDL_PIXELFORMAT_ARGB2101010:
712
713
714
715
internalFormat = GL_RGB10_A2;
format = GL_BGRA;
type = GL_UNSIGNED_INT_2_10_10_10_REV;
break;
716
case SDL_PIXELFORMAT_UYVY:
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
if (renderdata->GL_APPLE_ycbcr_422_supported) {
internalFormat = GL_RGB;
format = GL_YCBCR_422_APPLE;
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
type = GL_UNSIGNED_SHORT_8_8_APPLE;
#else
type = GL_UNSIGNED_SHORT_8_8_REV_APPLE;
#endif
} else if (renderdata->GL_MESA_ycbcr_texture_supported) {
internalFormat = GL_RGB;
format = GL_YCBCR_MESA;
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
type = GL_UNSIGNED_SHORT_8_8_MESA;
#else
type = GL_UNSIGNED_SHORT_8_8_REV_MESA;
#endif
} else if (renderdata->GL_ARB_fragment_program_supported) {
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
if (renderdata->fragment_program_UYVY == 0) {
renderdata->fragment_program_UYVY =
compile_shader(renderdata, GL_FRAGMENT_PROGRAM_ARB,
fragment_program_UYVY_source_code);
if (renderdata->fragment_program_UYVY == 0) {
SDL_SetError("Fragment program compile error");
return -1;
}
}
shader = renderdata->fragment_program_UYVY;
internalFormat = GL_RGBA;
format = GL_RGBA;
type = GL_UNSIGNED_BYTE;
} else {
SDL_SetError("Unsupported texture format");
return -1;
}
break;
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
case SDL_PIXELFORMAT_YUY2:
if (renderdata->GL_APPLE_ycbcr_422_supported) {
internalFormat = GL_RGB;
format = GL_YCBCR_422_APPLE;
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
type = GL_UNSIGNED_SHORT_8_8_REV_APPLE;
#else
type = GL_UNSIGNED_SHORT_8_8_APPLE;
#endif
} else if (renderdata->GL_MESA_ycbcr_texture_supported) {
internalFormat = GL_RGB;
format = GL_YCBCR_MESA;
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
type = GL_UNSIGNED_SHORT_8_8_REV_MESA;
#else
type = GL_UNSIGNED_SHORT_8_8_MESA;
768
#endif
769
770
771
772
773
} else {
SDL_SetError("Unsupported texture format");
return -1;
}
break;
774
775
776
777
default:
SDL_SetError("Unsupported texture format");
return -1;
}
778
779
data = (GL_TextureData *) SDL_calloc(1, sizeof(*data));
780
781
782
783
784
if (!data) {
SDL_OutOfMemory();
return -1;
}
785
786
data->shader = shader;
787
788
789
790
791
792
793
794
795
796
if (texture->format == SDL_PIXELFORMAT_INDEX8) {
data->palette = (Uint8 *) SDL_malloc(3 * 256 * sizeof(Uint8));
if (!data->palette) {
SDL_OutOfMemory();
SDL_free(data);
return -1;
}
SDL_memset(data->palette, 0xFF, 3 * 256 * sizeof(Uint8));
}
797
if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
798
data->pitch = texture->w * bytes_per_pixel(texture->format);
799
800
801
802
803
804
805
806
data->pixels = SDL_malloc(texture->h * data->pitch);
if (!data->pixels) {
SDL_OutOfMemory();
SDL_free(data);
return -1;
}
}
807
808
texture->driverdata = data;
809
810
renderdata->glGetError();
renderdata->glGenTextures(1, &data->texture);
811
812
813
814
if (renderdata->GL_ARB_texture_rectangle_supported) {
data->type = GL_TEXTURE_RECTANGLE_ARB;
texture_w = texture->w;
texture_h = texture->h;
815
816
data->texw = (GLfloat) texture_w;
data->texh = (GLfloat) texture_h;
817
818
819
820
} else {
data->type = GL_TEXTURE_2D;
texture_w = power_of_2(texture->w);
texture_h = power_of_2(texture->h);
821
data->texw = (GLfloat) (texture->w) / texture_w;
822
823
data->texh = (GLfloat) texture->h / texture_h;
}
824
825
826
/* YUV formats use RGBA but are really two bytes per pixel */
if (internalFormat == GL_RGBA && bytes_per_pixel(texture->format) < 4) {
827
data->HACK_RYAN_FIXME = 2;
828
} else {
829
data->HACK_RYAN_FIXME = 1;
830
}
831
texture_w /= data->HACK_RYAN_FIXME;
832
833
834
data->format = format;
data->formattype = type;
835
renderdata->glEnable(data->type);
836
renderdata->glBindTexture(data->type, data->texture);
837
838
839
840
841
842
843
844
renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
GL_NEAREST);
renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER,
GL_NEAREST);
renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
GL_CLAMP_TO_EDGE);
renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
GL_CLAMP_TO_EDGE);
845
#ifdef __MACOSX__
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
#ifndef GL_TEXTURE_STORAGE_HINT_APPLE
#define GL_TEXTURE_STORAGE_HINT_APPLE 0x85BC
#endif
#ifndef STORAGE_CACHED_APPLE
#define STORAGE_CACHED_APPLE 0x85BE
#endif
#ifndef STORAGE_SHARED_APPLE
#define STORAGE_SHARED_APPLE 0x85BF
#endif
if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
GL_STORAGE_SHARED_APPLE);
} else {
renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
GL_STORAGE_CACHED_APPLE);
}
862
863
/* This causes a crash in testoverlay for some reason. Apple bug? */
#if 0
864
865
if (texture->access == SDL_TEXTUREACCESS_STREAMING
&& texture->format == SDL_PIXELFORMAT_ARGB8888) {
866
/*
867
868
869
870
871
872
if (renderdata->glTextureRangeAPPLE) {
renderdata->glTextureRangeAPPLE(data->type,
texture->h * data->pitch,
data->pixels);
}
*/
873
874
875
876
renderdata->glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
texture_h, 0, format, type, data->pixels);
} else
877
#endif
878
879
880
881
882
#endif
{
renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
texture_h, 0, format, type, NULL);
}
883
result = renderdata->glGetError();
884
885
886
887
if (result != GL_NO_ERROR) {
GL_SetError("glTexImage2D()", result);
return -1;
}
888
889
890
return 0;
}
891
892
893
894
895
896
897
898
899
900
901
static int
GL_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture,
void **pixels, int *pitch)
{
GL_TextureData *data = (GL_TextureData *) texture->driverdata;
*pixels = data->pixels;
*pitch = data->pitch;
return 0;
}
902
903
904
905
906
907
static int
GL_SetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
const SDL_Color * colors, int firstcolor, int ncolors)
{
GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
GL_TextureData *data = (GL_TextureData *) texture->driverdata;
908
Uint8 *palette;
909
910
911
912
913
914
915
916
917
918
919
920
if (!data->palette) {
SDL_SetError("Texture doesn't have a palette");
return -1;
}
palette = data->palette + firstcolor * 3;
while (ncolors--) {
*palette++ = colors->r;
*palette++ = colors->g;
*palette++ = colors->b;
++colors;
}
921
renderdata->glEnable(data->type);
922
923
924
renderdata->glBindTexture(data->type, data->texture);
renderdata->glColorTableEXT(data->type, GL_RGB8, 256, GL_RGB,
GL_UNSIGNED_BYTE, data->palette);
925
926
927
928
929
930
931
return 0;
}
static int
GL_GetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
SDL_Color * colors, int firstcolor, int ncolors)
{
932
GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
933
GL_TextureData *data = (GL_TextureData *) texture->driverdata;
934
Uint8 *palette;
935
936
937
938
939
940
941
942
943
944
945
946
947
if (!data->palette) {
SDL_SetError("Texture doesn't have a palette");
return -1;
}
palette = data->palette + firstcolor * 3;
while (ncolors--) {
colors->r = *palette++;
colors->g = *palette++;
colors->b = *palette++;
colors->unused = SDL_ALPHA_OPAQUE;
++colors;
}
948
949
950
return 0;
}
951
static void
952
953
SetupTextureUpdate(GL_RenderData * renderdata, SDL_Texture * texture,
int pitch)
954
{
955
if (texture->format == SDL_PIXELFORMAT_INDEX1LSB) {
956
renderdata->glPixelStorei(GL_UNPACK_LSB_FIRST, 1);
957
} else if (texture->format == SDL_PIXELFORMAT_INDEX1MSB) {
958
renderdata->glPixelStorei(GL_UNPACK_LSB_FIRST, 0);
959
}
960
renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
961
renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH,
962
963
964
(pitch / bytes_per_pixel(texture->format)) /
((GL_TextureData *) texture->driverdata)->
HACK_RYAN_FIXME);
965
966
}
967
968
969
static int
GL_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture)
{
970
return 0;
971
972
973
974
975
}
static int
GL_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture)
{
976
return 0;
977
978
979
980
981
982
}
static int
GL_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture)
{
switch (texture->blendMode) {
983
984
985
986
987
case SDL_BLENDMODE_NONE:
case SDL_BLENDMODE_MASK:
case SDL_BLENDMODE_BLEND:
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_MOD:
988
989
990
return 0;
default:
SDL_Unsupported();
991
texture->blendMode = SDL_BLENDMODE_NONE;
992
993
994
995
996
997
998
999
1000
return -1;
}
}
static int
GL_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture)
{
switch (texture->scaleMode) {
case SDL_TEXTURESCALEMODE_NONE: