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