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