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