SDL_render_gles2.c (70889B)
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_ES2 && !SDL_RENDER_DISABLED 24 25#include "SDL_hints.h" 26#include "SDL_opengles2.h" 27#include "../SDL_sysrender.h" 28#include "../../video/SDL_blit.h" 29#include "SDL_shaders_gles2.h" 30 31/* To prevent unnecessary window recreation, 32 * these should match the defaults selected in SDL_GL_ResetAttributes 33 */ 34#define RENDERER_CONTEXT_MAJOR 2 35#define RENDERER_CONTEXT_MINOR 0 36 37/* Used to re-create the window with OpenGL ES capability */ 38extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags); 39 40/************************************************************************************************* 41 * Bootstrap data * 42 *************************************************************************************************/ 43 44static SDL_Renderer *GLES2_CreateRenderer(SDL_Window *window, Uint32 flags); 45 46SDL_RenderDriver GLES2_RenderDriver = { 47 GLES2_CreateRenderer, 48 { 49 "opengles2", 50 (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE), 51 4, 52 { 53 SDL_PIXELFORMAT_ARGB8888, 54 SDL_PIXELFORMAT_ABGR8888, 55 SDL_PIXELFORMAT_RGB888, 56 SDL_PIXELFORMAT_BGR888 57 }, 58 0, 59 0 60 } 61}; 62 63/************************************************************************************************* 64 * Context structures * 65 *************************************************************************************************/ 66 67typedef struct GLES2_FBOList GLES2_FBOList; 68 69struct GLES2_FBOList 70{ 71 Uint32 w, h; 72 GLuint FBO; 73 GLES2_FBOList *next; 74}; 75 76typedef struct GLES2_TextureData 77{ 78 GLenum texture; 79 GLenum texture_type; 80 GLenum pixel_format; 81 GLenum pixel_type; 82 void *pixel_data; 83 int pitch; 84 /* YUV texture support */ 85 SDL_bool yuv; 86 SDL_bool nv12; 87 GLenum texture_v; 88 GLenum texture_u; 89 GLES2_FBOList *fbo; 90} GLES2_TextureData; 91 92typedef struct GLES2_ShaderCacheEntry 93{ 94 GLuint id; 95 GLES2_ShaderType type; 96 const GLES2_ShaderInstance *instance; 97 int references; 98 Uint8 modulation_r, modulation_g, modulation_b, modulation_a; 99 struct GLES2_ShaderCacheEntry *prev; 100 struct GLES2_ShaderCacheEntry *next; 101} GLES2_ShaderCacheEntry; 102 103typedef struct GLES2_ShaderCache 104{ 105 int count; 106 GLES2_ShaderCacheEntry *head; 107} GLES2_ShaderCache; 108 109typedef struct GLES2_ProgramCacheEntry 110{ 111 GLuint id; 112 SDL_BlendMode blend_mode; 113 GLES2_ShaderCacheEntry *vertex_shader; 114 GLES2_ShaderCacheEntry *fragment_shader; 115 GLuint uniform_locations[16]; 116 Uint8 color_r, color_g, color_b, color_a; 117 Uint8 modulation_r, modulation_g, modulation_b, modulation_a; 118 GLfloat projection[4][4]; 119 struct GLES2_ProgramCacheEntry *prev; 120 struct GLES2_ProgramCacheEntry *next; 121} GLES2_ProgramCacheEntry; 122 123typedef struct GLES2_ProgramCache 124{ 125 int count; 126 GLES2_ProgramCacheEntry *head; 127 GLES2_ProgramCacheEntry *tail; 128} GLES2_ProgramCache; 129 130typedef enum 131{ 132 GLES2_ATTRIBUTE_POSITION = 0, 133 GLES2_ATTRIBUTE_TEXCOORD = 1, 134 GLES2_ATTRIBUTE_ANGLE = 2, 135 GLES2_ATTRIBUTE_CENTER = 3, 136} GLES2_Attribute; 137 138typedef enum 139{ 140 GLES2_UNIFORM_PROJECTION, 141 GLES2_UNIFORM_TEXTURE, 142 GLES2_UNIFORM_MODULATION, 143 GLES2_UNIFORM_COLOR, 144 GLES2_UNIFORM_TEXTURE_U, 145 GLES2_UNIFORM_TEXTURE_V 146} GLES2_Uniform; 147 148typedef enum 149{ 150 GLES2_IMAGESOURCE_SOLID, 151 GLES2_IMAGESOURCE_TEXTURE_ABGR, 152 GLES2_IMAGESOURCE_TEXTURE_ARGB, 153 GLES2_IMAGESOURCE_TEXTURE_RGB, 154 GLES2_IMAGESOURCE_TEXTURE_BGR, 155 GLES2_IMAGESOURCE_TEXTURE_YUV, 156 GLES2_IMAGESOURCE_TEXTURE_NV12, 157 GLES2_IMAGESOURCE_TEXTURE_NV21 158} GLES2_ImageSource; 159 160typedef struct GLES2_DriverContext 161{ 162 SDL_GLContext *context; 163 164 SDL_bool debug_enabled; 165 166 struct { 167 int blendMode; 168 SDL_bool tex_coords; 169 } current; 170 171#define SDL_PROC(ret,func,params) ret (APIENTRY *func) params; 172#include "SDL_gles2funcs.h" 173#undef SDL_PROC 174 GLES2_FBOList *framebuffers; 175 GLuint window_framebuffer; 176 177 int shader_format_count; 178 GLenum *shader_formats; 179 GLES2_ShaderCache shader_cache; 180 GLES2_ProgramCache program_cache; 181 GLES2_ProgramCacheEntry *current_program; 182 Uint8 clear_r, clear_g, clear_b, clear_a; 183} GLES2_DriverContext; 184 185#define GLES2_MAX_CACHED_PROGRAMS 8 186 187 188SDL_FORCE_INLINE const char* 189GL_TranslateError (GLenum error) 190{ 191#define GL_ERROR_TRANSLATE(e) case e: return #e; 192 switch (error) { 193 GL_ERROR_TRANSLATE(GL_INVALID_ENUM) 194 GL_ERROR_TRANSLATE(GL_INVALID_VALUE) 195 GL_ERROR_TRANSLATE(GL_INVALID_OPERATION) 196 GL_ERROR_TRANSLATE(GL_OUT_OF_MEMORY) 197 GL_ERROR_TRANSLATE(GL_NO_ERROR) 198 default: 199 return "UNKNOWN"; 200} 201#undef GL_ERROR_TRANSLATE 202} 203 204SDL_FORCE_INLINE void 205GL_ClearErrors(SDL_Renderer *renderer) 206{ 207 GLES2_DriverContext *data = (GLES2_DriverContext *) renderer->driverdata; 208 209 if (!data->debug_enabled) 210 { 211 return; 212 } 213 while (data->glGetError() != GL_NO_ERROR) { 214 continue; 215 } 216} 217 218SDL_FORCE_INLINE int 219GL_CheckAllErrors (const char *prefix, SDL_Renderer *renderer, const char *file, int line, const char *function) 220{ 221 GLES2_DriverContext *data = (GLES2_DriverContext *) renderer->driverdata; 222 int ret = 0; 223 224 if (!data->debug_enabled) 225 { 226 return 0; 227 } 228 /* check gl errors (can return multiple errors) */ 229 for (;;) { 230 GLenum error = data->glGetError(); 231 if (error != GL_NO_ERROR) { 232 if (prefix == NULL || prefix[0] == '\0') { 233 prefix = "generic"; 234 } 235 SDL_SetError("%s: %s (%d): %s %s (0x%X)", prefix, file, line, function, GL_TranslateError(error), error); 236 ret = -1; 237 } else { 238 break; 239 } 240 } 241 return ret; 242} 243 244#if 0 245#define GL_CheckError(prefix, renderer) 246#elif defined(_MSC_VER) 247#define GL_CheckError(prefix, renderer) GL_CheckAllErrors(prefix, renderer, __FILE__, __LINE__, __FUNCTION__) 248#else 249#define GL_CheckError(prefix, renderer) GL_CheckAllErrors(prefix, renderer, __FILE__, __LINE__, __PRETTY_FUNCTION__) 250#endif 251 252 253/************************************************************************************************* 254 * Renderer state APIs * 255 *************************************************************************************************/ 256 257static int GLES2_ActivateRenderer(SDL_Renderer *renderer); 258static void GLES2_WindowEvent(SDL_Renderer * renderer, 259 const SDL_WindowEvent *event); 260static int GLES2_UpdateViewport(SDL_Renderer * renderer); 261static void GLES2_DestroyRenderer(SDL_Renderer *renderer); 262static int GLES2_SetOrthographicProjection(SDL_Renderer *renderer); 263 264 265static SDL_GLContext SDL_CurrentContext = NULL; 266 267static int GLES2_LoadFunctions(GLES2_DriverContext * data) 268{ 269#if SDL_VIDEO_DRIVER_UIKIT 270#define __SDL_NOGETPROCADDR__ 271#elif SDL_VIDEO_DRIVER_ANDROID 272#define __SDL_NOGETPROCADDR__ 273#elif SDL_VIDEO_DRIVER_PANDORA 274#define __SDL_NOGETPROCADDR__ 275#endif 276 277#if defined __SDL_NOGETPROCADDR__ 278#define SDL_PROC(ret,func,params) data->func=func; 279#else 280#define SDL_PROC(ret,func,params) \ 281 do { \ 282 data->func = SDL_GL_GetProcAddress(#func); \ 283 if ( ! data->func ) { \ 284 return SDL_SetError("Couldn't load GLES2 function %s: %s\n", #func, SDL_GetError()); \ 285 } \ 286 } while ( 0 ); 287#endif /* _SDL_NOGETPROCADDR_ */ 288 289#include "SDL_gles2funcs.h" 290#undef SDL_PROC 291 return 0; 292} 293 294GLES2_FBOList * 295GLES2_GetFBO(GLES2_DriverContext *data, Uint32 w, Uint32 h) 296{ 297 GLES2_FBOList *result = data->framebuffers; 298 while ((result) && ((result->w != w) || (result->h != h)) ) 299 { 300 result = result->next; 301 } 302 if (result == NULL) 303 { 304 result = SDL_malloc(sizeof(GLES2_FBOList)); 305 result->w = w; 306 result->h = h; 307 data->glGenFramebuffers(1, &result->FBO); 308 result->next = data->framebuffers; 309 data->framebuffers = result; 310 } 311 return result; 312} 313 314static int 315GLES2_ActivateRenderer(SDL_Renderer * renderer) 316{ 317 GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata; 318 319 if (SDL_CurrentContext != data->context) { 320 /* Null out the current program to ensure we set it again */ 321 data->current_program = NULL; 322 323 if (SDL_GL_MakeCurrent(renderer->window, data->context) < 0) { 324 return -1; 325 } 326 SDL_CurrentContext = data->context; 327 328 GLES2_UpdateViewport(renderer); 329 } 330 331 GL_ClearErrors(renderer); 332 333 return 0; 334} 335 336static void 337GLES2_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event) 338{ 339 GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata; 340 341 if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED || 342 event->event == SDL_WINDOWEVENT_SHOWN || 343 event->event == SDL_WINDOWEVENT_HIDDEN) { 344 /* Rebind the context to the window area */ 345 SDL_CurrentContext = NULL; 346 } 347 348 if (event->event == SDL_WINDOWEVENT_MINIMIZED) { 349 /* According to Apple documentation, we need to finish drawing NOW! */ 350 data->glFinish(); 351 } 352} 353 354static int 355GLES2_UpdateViewport(SDL_Renderer * renderer) 356{ 357 GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata; 358 359 if (SDL_CurrentContext != data->context) { 360 /* We'll update the viewport after we rebind the context */ 361 return 0; 362 } 363 364 data->glViewport(renderer->viewport.x, renderer->viewport.y, 365 renderer->viewport.w, renderer->viewport.h); 366 367 if (data->current_program) { 368 GLES2_SetOrthographicProjection(renderer); 369 } 370 return GL_CheckError("", renderer); 371} 372 373static int 374GLES2_UpdateClipRect(SDL_Renderer * renderer) 375{ 376 GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata; 377 378 if (SDL_CurrentContext != data->context) { 379 /* We'll update the clip rect after we rebind the context */ 380 return 0; 381 } 382 383 if (renderer->clipping_enabled) { 384 const SDL_Rect *rect = &renderer->clip_rect; 385 data->glEnable(GL_SCISSOR_TEST); 386 data->glScissor(rect->x, renderer->viewport.h - rect->y - rect->h, rect->w, rect->h); 387 } else { 388 data->glDisable(GL_SCISSOR_TEST); 389 } 390 return 0; 391} 392 393static void 394GLES2_DestroyRenderer(SDL_Renderer *renderer) 395{ 396 GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata; 397 398 /* Deallocate everything */ 399 if (data) { 400 GLES2_ActivateRenderer(renderer); 401 402 { 403 GLES2_ShaderCacheEntry *entry; 404 GLES2_ShaderCacheEntry *next; 405 entry = data->shader_cache.head; 406 while (entry) 407 { 408 data->glDeleteShader(entry->id); 409 next = entry->next; 410 SDL_free(entry); 411 entry = next; 412 } 413 } 414 { 415 GLES2_ProgramCacheEntry *entry; 416 GLES2_ProgramCacheEntry *next; 417 entry = data->program_cache.head; 418 while (entry) { 419 data->glDeleteProgram(entry->id); 420 next = entry->next; 421 SDL_free(entry); 422 entry = next; 423 } 424 } 425 if (data->context) { 426 while (data->framebuffers) { 427 GLES2_FBOList *nextnode = data->framebuffers->next; 428 data->glDeleteFramebuffers(1, &data->framebuffers->FBO); 429 GL_CheckError("", renderer); 430 SDL_free(data->framebuffers); 431 data->framebuffers = nextnode; 432 } 433 SDL_GL_DeleteContext(data->context); 434 } 435 SDL_free(data->shader_formats); 436 SDL_free(data); 437 } 438 SDL_free(renderer); 439} 440 441/************************************************************************************************* 442 * Texture APIs * 443 *************************************************************************************************/ 444 445static int GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture); 446static int GLES2_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, 447 const void *pixels, int pitch); 448static int GLES2_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture, 449 const SDL_Rect * rect, 450 const Uint8 *Yplane, int Ypitch, 451 const Uint8 *Uplane, int Upitch, 452 const Uint8 *Vplane, int Vpitch); 453static int GLES2_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, 454 void **pixels, int *pitch); 455static void GLES2_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture); 456static int GLES2_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture); 457static void GLES2_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture); 458 459static GLenum 460GetScaleQuality(void) 461{ 462 const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY); 463 464 if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) { 465 return GL_NEAREST; 466 } else { 467 return GL_LINEAR; 468 } 469} 470 471static int 472GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture) 473{ 474 GLES2_DriverContext *renderdata = (GLES2_DriverContext *)renderer->driverdata; 475 GLES2_TextureData *data; 476 GLenum format; 477 GLenum type; 478 GLenum scaleMode; 479 480 GLES2_ActivateRenderer(renderer); 481 482 /* Determine the corresponding GLES texture format params */ 483 switch (texture->format) 484 { 485 case SDL_PIXELFORMAT_ARGB8888: 486 case SDL_PIXELFORMAT_ABGR8888: 487 case SDL_PIXELFORMAT_RGB888: 488 case SDL_PIXELFORMAT_BGR888: 489 format = GL_RGBA; 490 type = GL_UNSIGNED_BYTE; 491 break; 492 case SDL_PIXELFORMAT_IYUV: 493 case SDL_PIXELFORMAT_YV12: 494 case SDL_PIXELFORMAT_NV12: 495 case SDL_PIXELFORMAT_NV21: 496 format = GL_LUMINANCE; 497 type = GL_UNSIGNED_BYTE; 498 break; 499 default: 500 return SDL_SetError("Texture format not supported"); 501 } 502 503 /* Allocate a texture struct */ 504 data = (GLES2_TextureData *)SDL_calloc(1, sizeof(GLES2_TextureData)); 505 if (!data) { 506 return SDL_OutOfMemory(); 507 } 508 data->texture = 0; 509 data->texture_type = GL_TEXTURE_2D; 510 data->pixel_format = format; 511 data->pixel_type = type; 512 data->yuv = ((texture->format == SDL_PIXELFORMAT_IYUV) || (texture->format == SDL_PIXELFORMAT_YV12)); 513 data->nv12 = ((texture->format == SDL_PIXELFORMAT_NV12) || (texture->format == SDL_PIXELFORMAT_NV21)); 514 data->texture_u = 0; 515 data->texture_v = 0; 516 scaleMode = GetScaleQuality(); 517 518 /* Allocate a blob for image renderdata */ 519 if (texture->access == SDL_TEXTUREACCESS_STREAMING) { 520 size_t size; 521 data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format); 522 size = texture->h * data->pitch; 523 if (data->yuv) { 524 /* Need to add size for the U and V planes */ 525 size += (2 * (texture->h * data->pitch) / 4); 526 } 527 if (data->nv12) { 528 /* Need to add size for the U/V plane */ 529 size += ((texture->h * data->pitch) / 2); 530 } 531 data->pixel_data = SDL_calloc(1, size); 532 if (!data->pixel_data) { 533 SDL_free(data); 534 return SDL_OutOfMemory(); 535 } 536 } 537 538 /* Allocate the texture */ 539 GL_CheckError("", renderer); 540 541 if (data->yuv) { 542 renderdata->glGenTextures(1, &data->texture_v); 543 if (GL_CheckError("glGenTexures()", renderer) < 0) { 544 return -1; 545 } 546 renderdata->glActiveTexture(GL_TEXTURE2); 547 renderdata->glBindTexture(data->texture_type, data->texture_v); 548 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode); 549 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode); 550 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 551 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 552 renderdata->glTexImage2D(data->texture_type, 0, format, texture->w / 2, texture->h / 2, 0, format, type, NULL); 553 554 renderdata->glGenTextures(1, &data->texture_u); 555 if (GL_CheckError("glGenTexures()", renderer) < 0) { 556 return -1; 557 } 558 renderdata->glActiveTexture(GL_TEXTURE1); 559 renderdata->glBindTexture(data->texture_type, data->texture_u); 560 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode); 561 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode); 562 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 563 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 564 renderdata->glTexImage2D(data->texture_type, 0, format, texture->w / 2, texture->h / 2, 0, format, type, NULL); 565 if (GL_CheckError("glTexImage2D()", renderer) < 0) { 566 return -1; 567 } 568 } 569 570 if (data->nv12) { 571 renderdata->glGenTextures(1, &data->texture_u); 572 if (GL_CheckError("glGenTexures()", renderer) < 0) { 573 return -1; 574 } 575 renderdata->glActiveTexture(GL_TEXTURE1); 576 renderdata->glBindTexture(data->texture_type, data->texture_u); 577 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode); 578 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode); 579 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 580 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 581 renderdata->glTexImage2D(data->texture_type, 0, GL_LUMINANCE_ALPHA, texture->w / 2, texture->h / 2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL); 582 if (GL_CheckError("glTexImage2D()", renderer) < 0) { 583 return -1; 584 } 585 } 586 587 renderdata->glGenTextures(1, &data->texture); 588 if (GL_CheckError("glGenTexures()", renderer) < 0) { 589 return -1; 590 } 591 texture->driverdata = data; 592 renderdata->glActiveTexture(GL_TEXTURE0); 593 renderdata->glBindTexture(data->texture_type, data->texture); 594 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode); 595 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode); 596 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 597 renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 598 renderdata->glTexImage2D(data->texture_type, 0, format, texture->w, texture->h, 0, format, type, NULL); 599 if (GL_CheckError("glTexImage2D()", renderer) < 0) { 600 return -1; 601 } 602 603 if (texture->access == SDL_TEXTUREACCESS_TARGET) { 604 data->fbo = GLES2_GetFBO(renderer->driverdata, texture->w, texture->h); 605 } else { 606 data->fbo = NULL; 607 } 608 609 return GL_CheckError("", renderer); 610} 611 612static int 613GLES2_TexSubImage2D(GLES2_DriverContext *data, GLenum target, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels, GLint pitch, GLint bpp) 614{ 615 Uint8 *blob = NULL; 616 Uint8 *src; 617 int src_pitch; 618 int y; 619 620 /* Reformat the texture data into a tightly packed array */ 621 src_pitch = width * bpp; 622 src = (Uint8 *)pixels; 623 if (pitch != src_pitch) { 624 blob = (Uint8 *)SDL_malloc(src_pitch * height); 625 if (!blob) { 626 return SDL_OutOfMemory(); 627 } 628 src = blob; 629 for (y = 0; y < height; ++y) 630 { 631 SDL_memcpy(src, pixels, src_pitch); 632 src += src_pitch; 633 pixels = (Uint8 *)pixels + pitch; 634 } 635 src = blob; 636 } 637 638 data->glTexSubImage2D(target, 0, xoffset, yoffset, width, height, format, type, src); 639 if (blob) { 640 SDL_free(blob); 641 } 642 return 0; 643} 644 645static int 646GLES2_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, 647 const void *pixels, int pitch) 648{ 649 GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata; 650 GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata; 651 652 GLES2_ActivateRenderer(renderer); 653 654 /* Bail out if we're supposed to update an empty rectangle */ 655 if (rect->w <= 0 || rect->h <= 0) 656 return 0; 657 658 /* Create a texture subimage with the supplied data */ 659 data->glBindTexture(tdata->texture_type, tdata->texture); 660 GLES2_TexSubImage2D(data, tdata->texture_type, 661 rect->x, 662 rect->y, 663 rect->w, 664 rect->h, 665 tdata->pixel_format, 666 tdata->pixel_type, 667 pixels, pitch, SDL_BYTESPERPIXEL(texture->format)); 668 669 if (tdata->yuv) { 670 /* Skip to the correct offset into the next texture */ 671 pixels = (const void*)((const Uint8*)pixels + rect->h * pitch); 672 if (texture->format == SDL_PIXELFORMAT_YV12) { 673 data->glBindTexture(tdata->texture_type, tdata->texture_v); 674 } else { 675 data->glBindTexture(tdata->texture_type, tdata->texture_u); 676 } 677 GLES2_TexSubImage2D(data, tdata->texture_type, 678 rect->x / 2, 679 rect->y / 2, 680 rect->w / 2, 681 rect->h / 2, 682 tdata->pixel_format, 683 tdata->pixel_type, 684 pixels, pitch / 2, 1); 685 686 /* Skip to the correct offset into the next texture */ 687 pixels = (const void*)((const Uint8*)pixels + (rect->h * pitch)/4); 688 if (texture->format == SDL_PIXELFORMAT_YV12) { 689 data->glBindTexture(tdata->texture_type, tdata->texture_u); 690 } else { 691 data->glBindTexture(tdata->texture_type, tdata->texture_v); 692 } 693 GLES2_TexSubImage2D(data, tdata->texture_type, 694 rect->x / 2, 695 rect->y / 2, 696 rect->w / 2, 697 rect->h / 2, 698 tdata->pixel_format, 699 tdata->pixel_type, 700 pixels, pitch / 2, 1); 701 } 702 703 if (tdata->nv12) { 704 /* Skip to the correct offset into the next texture */ 705 pixels = (const void*)((const Uint8*)pixels + rect->h * pitch); 706 data->glBindTexture(tdata->texture_type, tdata->texture_u); 707 GLES2_TexSubImage2D(data, tdata->texture_type, 708 rect->x / 2, 709 rect->y / 2, 710 rect->w / 2, 711 rect->h / 2, 712 GL_LUMINANCE_ALPHA, 713 GL_UNSIGNED_BYTE, 714 pixels, pitch, 2); 715 } 716 717 return GL_CheckError("glTexSubImage2D()", renderer); 718} 719 720static int 721GLES2_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture, 722 const SDL_Rect * rect, 723 const Uint8 *Yplane, int Ypitch, 724 const Uint8 *Uplane, int Upitch, 725 const Uint8 *Vplane, int Vpitch) 726{ 727 GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata; 728 GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata; 729 730 GLES2_ActivateRenderer(renderer); 731 732 /* Bail out if we're supposed to update an empty rectangle */ 733 if (rect->w <= 0 || rect->h <= 0) 734 return 0; 735 736 data->glBindTexture(tdata->texture_type, tdata->texture_v); 737 GLES2_TexSubImage2D(data, tdata->texture_type, 738 rect->x / 2, 739 rect->y / 2, 740 rect->w / 2, 741 rect->h / 2, 742 tdata->pixel_format, 743 tdata->pixel_type, 744 Vplane, Vpitch, 1); 745 746 data->glBindTexture(tdata->texture_type, tdata->texture_u); 747 GLES2_TexSubImage2D(data, tdata->texture_type, 748 rect->x / 2, 749 rect->y / 2, 750 rect->w / 2, 751 rect->h / 2, 752 tdata->pixel_format, 753 tdata->pixel_type, 754 Uplane, Upitch, 1); 755 756 data->glBindTexture(tdata->texture_type, tdata->texture); 757 GLES2_TexSubImage2D(data, tdata->texture_type, 758 rect->x, 759 rect->y, 760 rect->w, 761 rect->h, 762 tdata->pixel_format, 763 tdata->pixel_type, 764 Yplane, Ypitch, 1); 765 766 return GL_CheckError("glTexSubImage2D()", renderer); 767} 768 769static int 770GLES2_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, 771 void **pixels, int *pitch) 772{ 773 GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata; 774 775 /* Retrieve the buffer/pitch for the specified region */ 776 *pixels = (Uint8 *)tdata->pixel_data + 777 (tdata->pitch * rect->y) + 778 (rect->x * SDL_BYTESPERPIXEL(texture->format)); 779 *pitch = tdata->pitch; 780 781 return 0; 782} 783 784static void 785GLES2_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture) 786{ 787 GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata; 788 SDL_Rect rect; 789 790 /* We do whole texture updates, at least for now */ 791 rect.x = 0; 792 rect.y = 0; 793 rect.w = texture->w; 794 rect.h = texture->h; 795 GLES2_UpdateTexture(renderer, texture, &rect, tdata->pixel_data, tdata->pitch); 796} 797 798static int 799GLES2_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture) 800{ 801 GLES2_DriverContext *data = (GLES2_DriverContext *) renderer->driverdata; 802 GLES2_TextureData *texturedata = NULL; 803 GLenum status; 804 805 if (texture == NULL) { 806 data->glBindFramebuffer(GL_FRAMEBUFFER, data->window_framebuffer); 807 } else { 808 texturedata = (GLES2_TextureData *) texture->driverdata; 809 data->glBindFramebuffer(GL_FRAMEBUFFER, texturedata->fbo->FBO); 810 /* TODO: check if texture pixel format allows this operation */ 811 data->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texturedata->texture_type, texturedata->texture, 0); 812 /* Check FBO status */ 813 status = data->glCheckFramebufferStatus(GL_FRAMEBUFFER); 814 if (status != GL_FRAMEBUFFER_COMPLETE) { 815 return SDL_SetError("glFramebufferTexture2D() failed"); 816 } 817 } 818 return 0; 819} 820 821static void 822GLES2_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture) 823{ 824 GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata; 825 GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata; 826 827 GLES2_ActivateRenderer(renderer); 828 829 /* Destroy the texture */ 830 if (tdata) 831 { 832 data->glDeleteTextures(1, &tdata->texture); 833 if (tdata->texture_v) { 834 data->glDeleteTextures(1, &tdata->texture_v); 835 } 836 if (tdata->texture_u) { 837 data->glDeleteTextures(1, &tdata->texture_u); 838 } 839 SDL_free(tdata->pixel_data); 840 SDL_free(tdata); 841 texture->driverdata = NULL; 842 } 843} 844 845/************************************************************************************************* 846 * Shader management functions * 847 *************************************************************************************************/ 848 849static GLES2_ShaderCacheEntry *GLES2_CacheShader(SDL_Renderer *renderer, GLES2_ShaderType type, 850 SDL_BlendMode blendMode); 851static void GLES2_EvictShader(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *entry); 852static GLES2_ProgramCacheEntry *GLES2_CacheProgram(SDL_Renderer *renderer, 853 GLES2_ShaderCacheEntry *vertex, 854 GLES2_ShaderCacheEntry *fragment, 855 SDL_BlendMode blendMode); 856static int GLES2_SelectProgram(SDL_Renderer *renderer, GLES2_ImageSource source, 857 SDL_BlendMode blendMode); 858 859static GLES2_ProgramCacheEntry * 860GLES2_CacheProgram(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *vertex, 861 GLES2_ShaderCacheEntry *fragment, SDL_BlendMode blendMode) 862{ 863 GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata; 864 GLES2_ProgramCacheEntry *entry; 865 GLES2_ShaderCacheEntry *shaderEntry; 866 GLint linkSuccessful; 867 868 /* Check if we've already cached this program */ 869 entry = data->program_cache.head; 870 while (entry) 871 { 872 if (entry->vertex_shader == vertex && entry->fragment_shader == fragment) 873 break; 874 entry = entry->next; 875 } 876 if (entry) 877 { 878 if (data->program_cache.head != entry) 879 { 880 if (entry->next) 881 entry->next->prev = entry->prev; 882 if (entry->prev) 883 entry->prev->next = entry->next; 884 entry->prev = NULL; 885 entry->next = data->program_cache.head; 886 data->program_cache.head->prev = entry; 887 data->program_cache.head = entry; 888 } 889 return entry; 890 } 891 892 /* Create a program cache entry */ 893 entry = (GLES2_ProgramCacheEntry *)SDL_calloc(1, sizeof(GLES2_ProgramCacheEntry)); 894 if (!entry) 895 { 896 SDL_OutOfMemory(); 897 return NULL; 898 } 899 entry->vertex_shader = vertex; 900 entry->fragment_shader = fragment; 901 entry->blend_mode = blendMode; 902 903 /* Create the program and link it */ 904 entry->id = data->glCreateProgram(); 905 data->glAttachShader(entry->id, vertex->id); 906 data->glAttachShader(entry->id, fragment->id); 907 data->glBindAttribLocation(entry->id, GLES2_ATTRIBUTE_POSITION, "a_position"); 908 data->glBindAttribLocation(entry->id, GLES2_ATTRIBUTE_TEXCOORD, "a_texCoord"); 909 data->glBindAttribLocation(entry->id, GLES2_ATTRIBUTE_ANGLE, "a_angle"); 910 data->glBindAttribLocation(entry->id, GLES2_ATTRIBUTE_CENTER, "a_center"); 911 data->glLinkProgram(entry->id); 912 data->glGetProgramiv(entry->id, GL_LINK_STATUS, &linkSuccessful); 913 if (!linkSuccessful) 914 { 915 data->glDeleteProgram(entry->id); 916 SDL_free(entry); 917 SDL_SetError("Failed to link shader program"); 918 return NULL; 919 } 920 921 /* Predetermine locations of uniform variables */ 922 entry->uniform_locations[GLES2_UNIFORM_PROJECTION] = 923 data->glGetUniformLocation(entry->id, "u_projection"); 924 entry->uniform_locations[GLES2_UNIFORM_TEXTURE_V] = 925 data->glGetUniformLocation(entry->id, "u_texture_v"); 926 entry->uniform_locations[GLES2_UNIFORM_TEXTURE_U] = 927 data->glGetUniformLocation(entry->id, "u_texture_u"); 928 entry->uniform_locations[GLES2_UNIFORM_TEXTURE] = 929 data->glGetUniformLocation(entry->id, "u_texture"); 930 entry->uniform_locations[GLES2_UNIFORM_MODULATION] = 931 data->glGetUniformLocation(entry->id, "u_modulation"); 932 entry->uniform_locations[GLES2_UNIFORM_COLOR] = 933 data->glGetUniformLocation(entry->id, "u_color"); 934 935 entry->modulation_r = entry->modulation_g = entry->modulation_b = entry->modulation_a = 255; 936 entry->color_r = entry->color_g = entry->color_b = entry->color_a = 255; 937 938 data->glUseProgram(entry->id); 939 data->glUniform1i(entry->uniform_locations[GLES2_UNIFORM_TEXTURE_V], 2); /* always texture unit 2. */ 940 data->glUniform1i(entry->uniform_locations[GLES2_UNIFORM_TEXTURE_U], 1); /* always texture unit 1. */ 941 data->glUniform1i(entry->uniform_locations[GLES2_UNIFORM_TEXTURE], 0); /* always texture unit 0. */ 942 data->glUniformMatrix4fv(entry->uniform_locations[GLES2_UNIFORM_PROJECTION], 1, GL_FALSE, (GLfloat *)entry->projection); 943 data->glUniform4f(entry->uniform_locations[GLES2_UNIFORM_MODULATION], 1.0f, 1.0f, 1.0f, 1.0f); 944 data->glUniform4f(entry->uniform_locations[GLES2_UNIFORM_COLOR], 1.0f, 1.0f, 1.0f, 1.0f); 945 946 /* Cache the linked program */ 947 if (data->program_cache.head) 948 { 949 entry->next = data->program_cache.head; 950 data->program_cache.head->prev = entry; 951 } 952 else 953 { 954 data->program_cache.tail = entry; 955 } 956 data->program_cache.head = entry; 957 ++data->program_cache.count; 958 959 /* Increment the refcount of the shaders we're using */ 960 ++vertex->references; 961 ++fragment->references; 962 963 /* Evict the last entry from the cache if we exceed the limit */ 964 if (data->program_cache.count > GLES2_MAX_CACHED_PROGRAMS) 965 { 966 shaderEntry = data->program_cache.tail->vertex_shader; 967 if (--shaderEntry->references <= 0) 968 GLES2_EvictShader(renderer, shaderEntry); 969 shaderEntry = data->program_cache.tail->fragment_shader; 970 if (--shaderEntry->references <= 0) 971 GLES2_EvictShader(renderer, shaderEntry); 972 data->glDeleteProgram(data->program_cache.tail->id); 973 data->program_cache.tail = data->program_cache.tail->prev; 974 SDL_free(data->program_cache.tail->next); 975 data->program_cache.tail->next = NULL; 976 --data->program_cache.count; 977 } 978 return entry; 979} 980 981static GLES2_ShaderCacheEntry * 982GLES2_CacheShader(SDL_Renderer *renderer, GLES2_ShaderType type, SDL_BlendMode blendMode) 983{ 984 GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata; 985 const GLES2_Shader *shader; 986 const GLES2_ShaderInstance *instance = NULL; 987 GLES2_ShaderCacheEntry *entry = NULL; 988 GLint compileSuccessful = GL_FALSE; 989 int i, j; 990 991 /* Find the corresponding shader */ 992 shader = GLES2_GetShader(type, blendMode); 993 if (!shader) 994 { 995 SDL_SetError("No shader matching the requested characteristics was found"); 996 return NULL; 997 } 998 999 /* Find a matching shader instance that's supported on this hardware */ 1000 for (i = 0; i < shader->instance_count && !instance; ++i) 1001 { 1002 for (j = 0; j < data->shader_format_count && !instance; ++j) 1003 { 1004 if (!shader->instances) 1005 continue; 1006 if (!shader->instances[i]) 1007 continue; 1008 if (shader->instances[i]->format != data->shader_formats[j]) 1009 continue; 1010 instance = shader->instances[i]; 1011 } 1012 } 1013 if (!instance) 1014 { 1015 SDL_SetError("The specified shader cannot be loaded on the current platform"); 1016 return NULL; 1017 } 1018 1019 /* Check if we've already cached this shader */ 1020 entry = data->shader_cache.head; 1021 while (entry) 1022 { 1023 if (entry->instance == instance) 1024 break; 1025 entry = entry->next; 1026 } 1027 if (entry) 1028 return entry; 1029 1030 /* Create a shader cache entry */ 1031 entry = (GLES2_ShaderCacheEntry *)SDL_calloc(1, sizeof(GLES2_ShaderCacheEntry)); 1032 if (!entry) 1033 { 1034 SDL_OutOfMemory(); 1035 return NULL; 1036 } 1037 entry->type = type; 1038 entry->instance = instance; 1039 1040 /* Compile or load the selected shader instance */ 1041 entry->id = data->glCreateShader(instance->type); 1042 if (instance->format == (GLenum)-1) 1043 { 1044 data->glShaderSource(entry->id, 1, (const char **)&instance->data, NULL); 1045 data->glCompileShader(entry->id); 1046 data->glGetShaderiv(entry->id, GL_COMPILE_STATUS, &compileSuccessful); 1047 } 1048 else 1049 { 1050 data->glShaderBinary(1, &entry->id, instance->format, instance->data, instance->length); 1051 compileSuccessful = GL_TRUE; 1052 } 1053 if (!compileSuccessful) 1054 { 1055 char *info = NULL; 1056 int length = 0; 1057 1058 data->glGetShaderiv(entry->id, GL_INFO_LOG_LENGTH, &length); 1059 if (length > 0) { 1060 info = SDL_stack_alloc(char, length); 1061 if (info) { 1062 data->glGetShaderInfoLog(entry->id, length, &length, info); 1063 } 1064 } 1065 if (info) { 1066 SDL_SetError("Failed to load the shader: %s", info); 1067 SDL_stack_free(info); 1068 } else { 1069 SDL_SetError("Failed to load the shader"); 1070 } 1071 data->glDeleteShader(entry->id); 1072 SDL_free(entry); 1073 return NULL; 1074 } 1075 1076 /* Link the shader entry in at the front of the cache */ 1077 if (data->shader_cache.head) 1078 { 1079 entry->next = data->shader_cache.head; 1080 data->shader_cache.head->prev = entry; 1081 } 1082 data->shader_cache.head = entry; 1083 ++data->shader_cache.count; 1084 return entry; 1085} 1086 1087static void 1088GLES2_EvictShader(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *entry) 1089{ 1090 GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata; 1091 1092 /* Unlink the shader from the cache */ 1093 if (entry->next) 1094 entry->next->prev = entry->prev; 1095 if (entry->prev) 1096 entry->prev->next = entry->next; 1097 if (data->shader_cache.head == entry) 1098 data->shader_cache.head = entry->next; 1099 --data->shader_cache.count; 1100 1101 /* Deallocate the shader */ 1102 data->glDeleteShader(entry->id); 1103 SDL_free(entry); 1104} 1105 1106static int 1107GLES2_SelectProgram(SDL_Renderer *renderer, GLES2_ImageSource source, SDL_BlendMode blendMode) 1108{ 1109 GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata; 1110 GLES2_ShaderCacheEntry *vertex = NULL; 1111 GLES2_ShaderCacheEntry *fragment = NULL; 1112 GLES2_ShaderType vtype, ftype; 1113 GLES2_ProgramCacheEntry *program; 1114 1115 /* Select an appropriate shader pair for the specified modes */ 1116 vtype = GLES2_SHADER_VERTEX_DEFAULT; 1117 switch (source) 1118 { 1119 case GLES2_IMAGESOURCE_SOLID: 1120 ftype = GLES2_SHADER_FRAGMENT_SOLID_SRC; 1121 break; 1122 case GLES2_IMAGESOURCE_TEXTURE_ABGR: 1123 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_ABGR_SRC; 1124 break; 1125 case GLES2_IMAGESOURCE_TEXTURE_ARGB: 1126 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_ARGB_SRC; 1127 break; 1128 case GLES2_IMAGESOURCE_TEXTURE_RGB: 1129 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_RGB_SRC; 1130 break; 1131 case GLES2_IMAGESOURCE_TEXTURE_BGR: 1132 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_BGR_SRC; 1133 break; 1134 case GLES2_IMAGESOURCE_TEXTURE_YUV: 1135 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_YUV_SRC; 1136 break; 1137 case GLES2_IMAGESOURCE_TEXTURE_NV12: 1138 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV12_SRC; 1139 break; 1140 case GLES2_IMAGESOURCE_TEXTURE_NV21: 1141 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV21_SRC; 1142 break; 1143 default: 1144 goto fault; 1145 } 1146 1147 /* Load the requested shaders */ 1148 vertex = GLES2_CacheShader(renderer, vtype, blendMode); 1149 if (!vertex) 1150 goto fault; 1151 fragment = GLES2_CacheShader(renderer, ftype, blendMode); 1152 if (!fragment) 1153 goto fault; 1154 1155 /* Check if we need to change programs at all */ 1156 if (data->current_program && 1157 data->current_program->vertex_shader == vertex && 1158 data->current_program->fragment_shader == fragment) 1159 return 0; 1160 1161 /* Generate a matching program */ 1162 program = GLES2_CacheProgram(renderer, vertex, fragment, blendMode); 1163 if (!program) 1164 goto fault; 1165 1166 /* Select that program in OpenGL */ 1167 data->glUseProgram(program->id); 1168 1169 /* Set the current program */ 1170 data->current_program = program; 1171 1172 /* Activate an orthographic projection */ 1173 if (GLES2_SetOrthographicProjection(renderer) < 0) 1174 goto fault; 1175 1176 /* Clean up and return */ 1177 return 0; 1178fault: 1179 if (vertex && vertex->references <= 0) 1180 GLES2_EvictShader(renderer, vertex); 1181 if (fragment && fragment->references <= 0) 1182 GLES2_EvictShader(renderer, fragment); 1183 data->current_program = NULL; 1184 return -1; 1185} 1186 1187static int 1188GLES2_SetOrthographicProjection(SDL_Renderer *renderer) 1189{ 1190 GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata; 1191 GLfloat projection[4][4]; 1192 1193 if (!renderer->viewport.w || !renderer->viewport.h) { 1194 return 0; 1195 } 1196 1197 /* Prepare an orthographic projection */ 1198 projection[0][0] = 2.0f / renderer->viewport.w; 1199 projection[0][1] = 0.0f; 1200 projection[0][2] = 0.0f; 1201 projection[0][3] = 0.0f; 1202 projection[1][0] = 0.0f; 1203 if (renderer->target) { 1204 projection[1][1] = 2.0f / renderer->viewport.h; 1205 } else { 1206 projection[1][1] = -2.0f / renderer->viewport.h; 1207 } 1208 projection[1][2] = 0.0f; 1209 projection[1][3] = 0.0f; 1210 projection[2][0] = 0.0f; 1211 projection[2][1] = 0.0f; 1212 projection[2][2] = 0.0f; 1213 projection[2][3] = 0.0f; 1214 projection[3][0] = -1.0f; 1215 if (renderer->target) { 1216 projection[3][1] = -1.0f; 1217 } else { 1218 projection[3][1] = 1.0f; 1219 } 1220 projection[3][2] = 0.0f; 1221 projection[3][3] = 1.0f; 1222 1223 /* Set the projection matrix */ 1224 if (SDL_memcmp(data->current_program->projection, projection, sizeof (projection)) != 0) { 1225 const GLuint locProjection = data->current_program->uniform_locations[GLES2_UNIFORM_PROJECTION]; 1226 data->glUniformMatrix4fv(locProjection, 1, GL_FALSE, (GLfloat *)projection); 1227 SDL_memcpy(data->current_program->projection, projection, sizeof (projection)); 1228 } 1229 1230 return 0; 1231} 1232 1233/************************************************************************************************* 1234 * Rendering functions * 1235 *************************************************************************************************/ 1236 1237static const float inv255f = 1.0f / 255.0f; 1238 1239static int GLES2_RenderClear(SDL_Renderer *renderer); 1240static int GLES2_RenderDrawPoints(SDL_Renderer *renderer, const SDL_FPoint *points, int count); 1241static int GLES2_RenderDrawLines(SDL_Renderer *renderer, const SDL_FPoint *points, int count); 1242static int GLES2_RenderFillRects(SDL_Renderer *renderer, const SDL_FRect *rects, int count); 1243static int GLES2_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *srcrect, 1244 const SDL_FRect *dstrect); 1245static int GLES2_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture, 1246 const SDL_Rect * srcrect, const SDL_FRect * dstrect, 1247 const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip); 1248static int GLES2_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, 1249 Uint32 pixel_format, void * pixels, int pitch); 1250static void GLES2_RenderPresent(SDL_Renderer *renderer); 1251 1252static SDL_bool 1253CompareColors(Uint8 r1, Uint8 g1, Uint8 b1, Uint8 a1, 1254 Uint8 r2, Uint8 g2, Uint8 b2, Uint8 a2) 1255{ 1256 Uint32 Pixel1, Pixel2; 1257 RGBA8888_FROM_RGBA(Pixel1, r1, g1, b1, a1); 1258 RGBA8888_FROM_RGBA(Pixel2, r2, g2, b2, a2); 1259 return (Pixel1 == Pixel2); 1260} 1261 1262static int 1263GLES2_RenderClear(SDL_Renderer * renderer) 1264{ 1265 Uint8 r, g, b, a; 1266 1267 GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata; 1268 1269 GLES2_ActivateRenderer(renderer); 1270 1271 if (!CompareColors(data->clear_r, data->clear_g, data->clear_b, data->clear_a, 1272 renderer->r, renderer->g, renderer->b, renderer->a)) { 1273 1274 /* Select the color to clear with */ 1275 g = renderer->g; 1276 a = renderer->a; 1277 1278 if (renderer->target && 1279 (renderer->target->format == SDL_PIXELFORMAT_ARGB8888 || 1280 renderer->target->format == SDL_PIXELFORMAT_RGB888)) { 1281 r = renderer->b; 1282 b = renderer->r; 1283 } else { 1284 r = renderer->r; 1285 b = renderer->b; 1286 } 1287 1288 data->glClearColor((GLfloat) r * inv255f, 1289 (GLfloat) g * inv255f, 1290 (GLfloat) b * inv255f, 1291 (GLfloat) a * inv255f); 1292 data->clear_r = renderer->r; 1293 data->clear_g = renderer->g; 1294 data->clear_b = renderer->b; 1295 data->clear_a = renderer->a; 1296 } 1297 1298 data->glClear(GL_COLOR_BUFFER_BIT); 1299 1300 return 0; 1301} 1302 1303static void 1304GLES2_SetBlendMode(GLES2_DriverContext *data, int blendMode) 1305{ 1306 if (blendMode != data->current.blendMode) { 1307 switch (blendMode) { 1308 default: 1309 case SDL_BLENDMODE_NONE: 1310 data->glDisable(GL_BLEND); 1311 break; 1312 case SDL_BLENDMODE_BLEND: 1313 data->glEnable(GL_BLEND); 1314 data->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); 1315 break; 1316 case SDL_BLENDMODE_ADD: 1317 data->glEnable(GL_BLEND); 1318 data->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE); 1319 break; 1320 case SDL_BLENDMODE_MOD: 1321 data->glEnable(GL_BLEND); 1322 data->glBlendFuncSeparate(GL_ZERO, GL_SRC_COLOR, GL_ZERO, GL_ONE); 1323 break; 1324 } 1325 data->current.blendMode = blendMode; 1326 } 1327} 1328 1329static void 1330GLES2_SetTexCoords(GLES2_DriverContext * data, SDL_bool enabled) 1331{ 1332 if (enabled != data->current.tex_coords) { 1333 if (enabled) { 1334 data->glEnableVertexAttribArray(GLES2_ATTRIBUTE_TEXCOORD); 1335 } else { 1336 data->glDisableVertexAttribArray(GLES2_ATTRIBUTE_TEXCOORD); 1337 } 1338 data->current.tex_coords = enabled; 1339 } 1340} 1341 1342static int 1343GLES2_SetDrawingState(SDL_Renderer * renderer) 1344{ 1345 GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata; 1346 const int blendMode = renderer->blendMode; 1347 GLES2_ProgramCacheEntry *program; 1348 Uint8 r, g, b, a; 1349 1350 GLES2_ActivateRenderer(renderer); 1351 1352 GLES2_SetBlendMode(data, blendMode); 1353 1354 GLES2_SetTexCoords(data, SDL_FALSE); 1355 1356 /* Activate an appropriate shader and set the projection matrix */ 1357 if (GLES2_SelectProgram(renderer, GLES2_IMAGESOURCE_SOLID, blendMode) < 0) { 1358 return -1; 1359 } 1360 1361 /* Select the color to draw with */ 1362 g = renderer->g; 1363 a = renderer->a; 1364 1365 if (renderer->target && 1366 (renderer->target->format == SDL_PIXELFORMAT_ARGB8888 || 1367 renderer->target->format == SDL_PIXELFORMAT_RGB888)) { 1368 r = renderer->b; 1369 b = renderer->r; 1370 } else { 1371 r = renderer->r; 1372 b = renderer->b; 1373 } 1374 1375 program = data->current_program; 1376 if (!CompareColors(program->color_r, program->color_g, program->color_b, program->color_a, r, g, b, a)) { 1377 /* Select the color to draw with */ 1378 data->glUniform4f(program->uniform_locations[GLES2_UNIFORM_COLOR], r * inv255f, g * inv255f, b * inv255f, a * inv255f); 1379 program->color_r = r; 1380 program->color_g = g; 1381 program->color_b = b; 1382 program->color_a = a; 1383 } 1384 1385 return 0; 1386} 1387 1388static int 1389GLES2_RenderDrawPoints(SDL_Renderer *renderer, const SDL_FPoint *points, int count) 1390{ 1391 GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata; 1392 GLfloat *vertices; 1393 int idx; 1394 1395 if (GLES2_SetDrawingState(renderer) < 0) { 1396 return -1; 1397 } 1398 1399 /* Emit the specified vertices as points */ 1400 vertices = SDL_stack_alloc(GLfloat, count * 2); 1401 for (idx = 0; idx < count; ++idx) { 1402 GLfloat x = points[idx].x + 0.5f; 1403 GLfloat y = points[idx].y + 0.5f; 1404 1405 vertices[idx * 2] = x; 1406 vertices[(idx * 2) + 1] = y; 1407 } 1408 data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices); 1409 data->glDrawArrays(GL_POINTS, 0, count); 1410 SDL_stack_free(vertices); 1411 return 0; 1412} 1413 1414static int 1415GLES2_RenderDrawLines(SDL_Renderer *renderer, const SDL_FPoint *points, int count) 1416{ 1417 GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata; 1418 GLfloat *vertices; 1419 int idx; 1420 1421 if (GLES2_SetDrawingState(renderer) < 0) { 1422 return -1; 1423 } 1424 1425 /* Emit a line strip including the specified vertices */ 1426 vertices = SDL_stack_alloc(GLfloat, count * 2); 1427 for (idx = 0; idx < count; ++idx) { 1428 GLfloat x = points[idx].x + 0.5f; 1429 GLfloat y = points[idx].y + 0.5f; 1430 1431 vertices[idx * 2] = x; 1432 vertices[(idx * 2) + 1] = y; 1433 } 1434 data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices); 1435 data->glDrawArrays(GL_LINE_STRIP, 0, count); 1436 1437 /* We need to close the endpoint of the line */ 1438 if (count == 2 || 1439 points[0].x != points[count-1].x || points[0].y != points[count-1].y) { 1440 data->glDrawArrays(GL_POINTS, count-1, 1); 1441 } 1442 SDL_stack_free(vertices); 1443 1444 return GL_CheckError("", renderer); 1445} 1446 1447static int 1448GLES2_RenderFillRects(SDL_Renderer *renderer, const SDL_FRect *rects, int count) 1449{ 1450 GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata; 1451 GLfloat vertices[8]; 1452 int idx; 1453 1454 if (GLES2_SetDrawingState(renderer) < 0) { 1455 return -1; 1456 } 1457 1458 /* Emit a line loop for each rectangle */ 1459 for (idx = 0; idx < count; ++idx) { 1460 const SDL_FRect *rect = &rects[idx]; 1461 1462 GLfloat xMin = rect->x; 1463 GLfloat xMax = (rect->x + rect->w); 1464 GLfloat yMin = rect->y; 1465 GLfloat yMax = (rect->y + rect->h); 1466 1467 vertices[0] = xMin; 1468 vertices[1] = yMin; 1469 vertices[2] = xMax; 1470 vertices[3] = yMin; 1471 vertices[4] = xMin; 1472 vertices[5] = yMax; 1473 vertices[6] = xMax; 1474 vertices[7] = yMax; 1475 data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices); 1476 data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 1477 } 1478 return GL_CheckError("", renderer); 1479} 1480 1481static int 1482GLES2_SetupCopy(SDL_Renderer *renderer, SDL_Texture *texture) 1483{ 1484 GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata; 1485 GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata; 1486 GLES2_ImageSource sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR; 1487 SDL_BlendMode blendMode; 1488 GLES2_ProgramCacheEntry *program; 1489 Uint8 r, g, b, a; 1490 1491 /* Activate an appropriate shader and set the projection matrix */ 1492 blendMode = texture->blendMode; 1493 if (renderer->target) { 1494 /* Check if we need to do color mapping between the source and render target textures */ 1495 if (renderer->target->format != texture->format) { 1496 switch (texture->format) 1497 { 1498 case SDL_PIXELFORMAT_ARGB8888: 1499 switch (renderer->target->format) 1500 { 1501 case SDL_PIXELFORMAT_ABGR8888: 1502 case SDL_PIXELFORMAT_BGR888: 1503 sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB; 1504 break; 1505 case SDL_PIXELFORMAT_RGB888: 1506 sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR; 1507 break; 1508 } 1509 break; 1510 case SDL_PIXELFORMAT_ABGR8888: 1511 switch (renderer->target->format) 1512 { 1513 case SDL_PIXELFORMAT_ARGB8888: 1514 case SDL_PIXELFORMAT_RGB888: 1515 sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB; 1516 break; 1517 case SDL_PIXELFORMAT_BGR888: 1518 sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR; 1519 break; 1520 } 1521 break; 1522 case SDL_PIXELFORMAT_RGB888: 1523 switch (renderer->target->format) 1524 { 1525 case SDL_PIXELFORMAT_ABGR8888: 1526 sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB; 1527 break; 1528 case SDL_PIXELFORMAT_ARGB8888: 1529 sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR; 1530 break; 1531 case SDL_PIXELFORMAT_BGR888: 1532 sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB; 1533 break; 1534 } 1535 break; 1536 case SDL_PIXELFORMAT_BGR888: 1537 switch (renderer->target->format) 1538 { 1539 case SDL_PIXELFORMAT_ABGR8888: 1540 sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR; 1541 break; 1542 case SDL_PIXELFORMAT_ARGB8888: 1543 sourceType = GLES2_IMAGESOURCE_TEXTURE_RGB; 1544 break; 1545 case SDL_PIXELFORMAT_RGB888: 1546 sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB; 1547 break; 1548 } 1549 break; 1550 case SDL_PIXELFORMAT_IYUV: 1551 case SDL_PIXELFORMAT_YV12: 1552 sourceType = GLES2_IMAGESOURCE_TEXTURE_YUV; 1553 break; 1554 case SDL_PIXELFORMAT_NV12: 1555 sourceType = GLES2_IMAGESOURCE_TEXTURE_NV12; 1556 break; 1557 case SDL_PIXELFORMAT_NV21: 1558 sourceType = GLES2_IMAGESOURCE_TEXTURE_NV21; 1559 break; 1560 default: 1561 return SDL_SetError("Unsupported texture format"); 1562 } 1563 } 1564 else sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR; /* Texture formats match, use the non color mapping shader (even if the formats are not ABGR) */ 1565 } else { 1566 switch (texture->format) 1567 { 1568 case SDL_PIXELFORMAT_ARGB8888: 1569 sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB; 1570 break; 1571 case SDL_PIXELFORMAT_ABGR8888: 1572 sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR; 1573 break; 1574 case SDL_PIXELFORMAT_RGB888: 1575 sourceType = GLES2_IMAGESOURCE_TEXTURE_RGB; 1576 break; 1577 case SDL_PIXELFORMAT_BGR888: 1578 sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR; 1579 break; 1580 case SDL_PIXELFORMAT_IYUV: 1581 case SDL_PIXELFORMAT_YV12: 1582 sourceType = GLES2_IMAGESOURCE_TEXTURE_YUV; 1583 break; 1584 case SDL_PIXELFORMAT_NV12: 1585 sourceType = GLES2_IMAGESOURCE_TEXTURE_NV12; 1586 break; 1587 case SDL_PIXELFORMAT_NV21: 1588 sourceType = GLES2_IMAGESOURCE_TEXTURE_NV21; 1589 break; 1590 default: 1591 return SDL_SetError("Unsupported texture format"); 1592 } 1593 } 1594 1595 if (GLES2_SelectProgram(renderer, sourceType, blendMode) < 0) { 1596 return -1; 1597 } 1598 1599 /* Select the target texture */ 1600 if (tdata->yuv) { 1601 data->glActiveTexture(GL_TEXTURE2); 1602 data->glBindTexture(tdata->texture_type, tdata->texture_v); 1603 1604 data->glActiveTexture(GL_TEXTURE1); 1605 data->glBindTexture(tdata->texture_type, tdata->texture_u); 1606 1607 data->glActiveTexture(GL_TEXTURE0); 1608 } 1609 if (tdata->nv12) { 1610 data->glActiveTexture(GL_TEXTURE1); 1611 data->glBindTexture(tdata->texture_type, tdata->texture_u); 1612 1613 data->glActiveTexture(GL_TEXTURE0); 1614 } 1615 data->glBindTexture(tdata->texture_type, tdata->texture); 1616 1617 /* Configure color modulation */ 1618 g = texture->g; 1619 a = texture->a; 1620 1621 if (renderer->target && 1622 (renderer->target->format == SDL_PIXELFORMAT_ARGB8888 || 1623 renderer->target->format == SDL_PIXELFORMAT_RGB888)) { 1624 r = texture->b; 1625 b = texture->r; 1626 } else { 1627 r = texture->r; 1628 b = texture->b; 1629 } 1630 1631 program = data->current_program; 1632 1633 if (!CompareColors(program->modulation_r, program->modulation_g, program->modulation_b, program->modulation_a, r, g, b, a)) { 1634 data->glUniform4f(program->uniform_locations[GLES2_UNIFORM_MODULATION], r * inv255f, g * inv255f, b * inv255f, a * inv255f); 1635 program->modulation_r = r; 1636 program->modulation_g = g; 1637 program->modulation_b = b; 1638 program->modulation_a = a; 1639 } 1640 1641 /* Configure texture blending */ 1642 GLES2_SetBlendMode(data, blendMode); 1643 1644 GLES2_SetTexCoords(data, SDL_TRUE); 1645 return 0; 1646} 1647 1648static int 1649GLES2_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *srcrect, 1650 const SDL_FRect *dstrect) 1651{ 1652 GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata; 1653 GLfloat vertices[8]; 1654 GLfloat texCoords[8]; 1655 1656 GLES2_ActivateRenderer(renderer); 1657 1658 if (GLES2_SetupCopy(renderer, texture) < 0) { 1659 return -1; 1660 } 1661 1662 /* Emit the textured quad */ 1663 vertices[0] = dstrect->x; 1664 vertices[1] = dstrect->y; 1665 vertices[2] = (dstrect->x + dstrect->w); 1666 vertices[3] = dstrect->y; 1667 vertices[4] = dstrect->x; 1668 vertices[5] = (dstrect->y + dstrect->h); 1669 vertices[6] = (dstrect->x + dstrect->w); 1670 vertices[7] = (dstrect->y + dstrect->h); 1671 data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices); 1672 texCoords[0] = srcrect->x / (GLfloat)texture->w; 1673 texCoords[1] = srcrect->y / (GLfloat)texture->h; 1674 texCoords[2] = (srcrect->x + srcrect->w) / (GLfloat)texture->w; 1675 texCoords[3] = srcrect->y / (GLfloat)texture->h; 1676 texCoords[4] = srcrect->x / (GLfloat)texture->w; 1677 texCoords[5] = (srcrect->y + srcrect->h) / (GLfloat)texture->h; 1678 texCoords[6] = (srcrect->x + srcrect->w) / (GLfloat)texture->w; 1679 texCoords[7] = (srcrect->y + srcrect->h) / (GLfloat)texture->h; 1680 data->glVertexAttribPointer(GLES2_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, texCoords); 1681 data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 1682 1683 return GL_CheckError("", renderer); 1684} 1685 1686static int 1687GLES2_RenderCopyEx(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *srcrect, 1688 const SDL_FRect *dstrect, const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip) 1689{ 1690 GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata; 1691 GLfloat vertices[8]; 1692 GLfloat texCoords[8]; 1693 GLfloat translate[8]; 1694 GLfloat fAngle[4]; 1695 GLfloat tmp; 1696 1697 GLES2_ActivateRenderer(renderer); 1698 1699 if (GLES2_SetupCopy(renderer, texture) < 0) { 1700 return -1; 1701 } 1702 1703 data->glEnableVertexAttribArray(GLES2_ATTRIBUTE_CENTER); 1704 data->glEnableVertexAttribArray(GLES2_ATTRIBUTE_ANGLE); 1705 fAngle[0] = fAngle[1] = fAngle[2] = fAngle[3] = (GLfloat)(360.0f - angle); 1706 /* Calculate the center of rotation */ 1707 translate[0] = translate[2] = translate[4] = translate[6] = (center->x + dstrect->x); 1708 translate[1] = translate[3] = translate[5] = translate[7] = (center->y + dstrect->y); 1709 1710 /* Emit the textured quad */ 1711 vertices[0] = dstrect->x; 1712 vertices[1] = dstrect->y; 1713 vertices[2] = (dstrect->x + dstrect->w); 1714 vertices[3] = dstrect->y; 1715 vertices[4] = dstrect->x; 1716 vertices[5] = (dstrect->y + dstrect->h); 1717 vertices[6] = (dstrect->x + dstrect->w); 1718 vertices[7] = (dstrect->y + dstrect->h); 1719 if (flip & SDL_FLIP_HORIZONTAL) { 1720 tmp = vertices[0]; 1721 vertices[0] = vertices[4] = vertices[2]; 1722 vertices[2] = vertices[6] = tmp; 1723 } 1724 if (flip & SDL_FLIP_VERTICAL) { 1725 tmp = vertices[1]; 1726 vertices[1] = vertices[3] = vertices[5]; 1727 vertices[5] = vertices[7] = tmp; 1728 } 1729 1730 data->glVertexAttribPointer(GLES2_ATTRIBUTE_ANGLE, 1, GL_FLOAT, GL_FALSE, 0, &fAngle); 1731 data->glVertexAttribPointer(GLES2_ATTRIBUTE_CENTER, 2, GL_FLOAT, GL_FALSE, 0, translate); 1732 data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices); 1733 1734 texCoords[0] = srcrect->x / (GLfloat)texture->w; 1735 texCoords[1] = srcrect->y / (GLfloat)texture->h; 1736 texCoords[2] = (srcrect->x + srcrect->w) / (GLfloat)texture->w; 1737 texCoords[3] = srcrect->y / (GLfloat)texture->h; 1738 texCoords[4] = srcrect->x / (GLfloat)texture->w; 1739 texCoords[5] = (srcrect->y + srcrect->h) / (GLfloat)texture->h; 1740 texCoords[6] = (srcrect->x + srcrect->w) / (GLfloat)texture->w; 1741 texCoords[7] = (srcrect->y + srcrect->h) / (GLfloat)texture->h; 1742 data->glVertexAttribPointer(GLES2_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, texCoords); 1743 data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 1744 data->glDisableVertexAttribArray(GLES2_ATTRIBUTE_CENTER); 1745 data->glDisableVertexAttribArray(GLES2_ATTRIBUTE_ANGLE); 1746 1747 return GL_CheckError("", renderer); 1748} 1749 1750static int 1751GLES2_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, 1752 Uint32 pixel_format, void * pixels, int pitch) 1753{ 1754 GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata; 1755 Uint32 temp_format = SDL_PIXELFORMAT_ABGR8888; 1756 void *temp_pixels; 1757 int temp_pitch; 1758 Uint8 *src, *dst, *tmp; 1759 int w, h, length, rows; 1760 int status; 1761 1762 GLES2_ActivateRenderer(renderer); 1763 1764 temp_pitch = rect->w * SDL_BYTESPERPIXEL(temp_format); 1765 temp_pixels = SDL_malloc(rect->h * temp_pitch); 1766 if (!temp_pixels) { 1767 return SDL_OutOfMemory(); 1768 } 1769 1770 SDL_GetRendererOutputSize(renderer, &w, &h); 1771 1772 data->glReadPixels(rect->x, (h-rect->y)-rect->h, rect->w, rect->h, 1773 GL_RGBA, GL_UNSIGNED_BYTE, temp_pixels); 1774 if (GL_CheckError("glReadPixels()", renderer) < 0) { 1775 return -1; 1776 } 1777 1778 /* Flip the rows to be top-down */ 1779 length = rect->w * SDL_BYTESPERPIXEL(temp_format); 1780 src = (Uint8*)temp_pixels + (rect->h-1)*temp_pitch; 1781 dst = (Uint8*)temp_pixels; 1782 tmp = SDL_stack_alloc(Uint8, length); 1783 rows = rect->h / 2; 1784 while (rows--) { 1785 SDL_memcpy(tmp, dst, length); 1786 SDL_memcpy(dst, src, length); 1787 SDL_memcpy(src, tmp, length); 1788 dst += temp_pitch; 1789 src -= temp_pitch; 1790 } 1791 SDL_stack_free(tmp); 1792 1793 status = SDL_ConvertPixels(rect->w, rect->h, 1794 temp_format, temp_pixels, temp_pitch, 1795 pixel_format, pixels, pitch); 1796 SDL_free(temp_pixels); 1797 1798 return status; 1799} 1800 1801static void 1802GLES2_RenderPresent(SDL_Renderer *renderer) 1803{ 1804 GLES2_ActivateRenderer(renderer); 1805 1806 /* Tell the video driver to swap buffers */ 1807 SDL_GL_SwapWindow(renderer->window); 1808} 1809 1810 1811/************************************************************************************************* 1812 * Bind/unbinding of textures 1813 *************************************************************************************************/ 1814static int GLES2_BindTexture (SDL_Renderer * renderer, SDL_Texture *texture, float *texw, float *texh); 1815static int GLES2_UnbindTexture (SDL_Renderer * renderer, SDL_Texture *texture); 1816 1817static int GLES2_BindTexture (SDL_Renderer * renderer, SDL_Texture *texture, float *texw, float *texh) 1818{ 1819 GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata; 1820 GLES2_TextureData *texturedata = (GLES2_TextureData *)texture->driverdata; 1821 GLES2_ActivateRenderer(renderer); 1822 1823 data->glBindTexture(texturedata->texture_type, texturedata->texture); 1824 1825 if(texw) *texw = 1.0; 1826 if(texh) *texh = 1.0; 1827 1828 return 0; 1829} 1830 1831static int GLES2_UnbindTexture (SDL_Renderer * renderer, SDL_Texture *texture) 1832{ 1833 GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata; 1834 GLES2_TextureData *texturedata = (GLES2_TextureData *)texture->driverdata; 1835 GLES2_ActivateRenderer(renderer); 1836 1837 data->glBindTexture(texturedata->texture_type, 0); 1838 1839 return 0; 1840} 1841 1842 1843/************************************************************************************************* 1844 * Renderer instantiation * 1845 *************************************************************************************************/ 1846 1847#define GL_NVIDIA_PLATFORM_BINARY_NV 0x890B 1848 1849static void 1850GLES2_ResetState(SDL_Renderer *renderer) 1851{ 1852 GLES2_DriverContext *data = (GLES2_DriverContext *) renderer->driverdata; 1853 1854 if (SDL_CurrentContext == data->context) { 1855 GLES2_UpdateViewport(renderer); 1856 } else { 1857 GLES2_ActivateRenderer(renderer); 1858 } 1859 1860 data->current.blendMode = -1; 1861 data->current.tex_coords = SDL_FALSE; 1862 1863 data->glActiveTexture(GL_TEXTURE0); 1864 data->glPixelStorei(GL_PACK_ALIGNMENT, 1); 1865 data->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 1866 1867 data->glClearColor((GLfloat) data->clear_r * inv255f, 1868 (GLfloat) data->clear_g * inv255f, 1869 (GLfloat) data->clear_b * inv255f, 1870 (GLfloat) data->clear_a * inv255f); 1871 1872 data->glEnableVertexAttribArray(GLES2_ATTRIBUTE_POSITION); 1873 data->glDisableVertexAttribArray(GLES2_ATTRIBUTE_TEXCOORD); 1874 1875 GL_CheckError("", renderer); 1876} 1877 1878static SDL_Renderer * 1879GLES2_CreateRenderer(SDL_Window *window, Uint32 flags) 1880{ 1881 SDL_Renderer *renderer; 1882 GLES2_DriverContext *data; 1883 GLint nFormats; 1884#ifndef ZUNE_HD 1885 GLboolean hasCompiler; 1886#endif 1887 Uint32 window_flags; 1888 GLint window_framebuffer; 1889 GLint value; 1890 int profile_mask, major, minor; 1891 SDL_bool changed_window = SDL_FALSE; 1892 1893 SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profile_mask); 1894 SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major); 1895 SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor); 1896 1897 window_flags = SDL_GetWindowFlags(window); 1898 if (!(window_flags & SDL_WINDOW_OPENGL) || 1899 profile_mask != SDL_GL_CONTEXT_PROFILE_ES || major != RENDERER_CONTEXT_MAJOR || minor != RENDERER_CONTEXT_MINOR) { 1900 1901 changed_window = SDL_TRUE; 1902 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); 1903 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, RENDERER_CONTEXT_MAJOR); 1904 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, RENDERER_CONTEXT_MINOR); 1905 1906 if (SDL_RecreateWindow(window, window_flags | SDL_WINDOW_OPENGL) < 0) { 1907 goto error; 1908 } 1909 } 1910 1911 /* Create the renderer struct */ 1912 renderer = (SDL_Renderer *)SDL_calloc(1, sizeof(SDL_Renderer)); 1913 if (!renderer) { 1914 SDL_OutOfMemory(); 1915 goto error; 1916 } 1917 1918 data = (GLES2_DriverContext *)SDL_calloc(1, sizeof(GLES2_DriverContext)); 1919 if (!data) { 1920 GLES2_DestroyRenderer(renderer); 1921 SDL_OutOfMemory(); 1922 goto error; 1923 } 1924 renderer->info = GLES2_RenderDriver.info; 1925 renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE); 1926 renderer->driverdata = data; 1927 renderer->window = window; 1928 1929 /* Create an OpenGL ES 2.0 context */ 1930 data->context = SDL_GL_CreateContext(window); 1931 if (!data->context) { 1932 GLES2_DestroyRenderer(renderer); 1933 goto error; 1934 } 1935 if (SDL_GL_MakeCurrent(window, data->context) < 0) { 1936 GLES2_DestroyRenderer(renderer); 1937 goto error; 1938 } 1939 1940 if (GLES2_LoadFunctions(data) < 0) { 1941 GLES2_DestroyRenderer(renderer); 1942 goto error; 1943 } 1944 1945#if __WINRT__ 1946 /* DLudwig, 2013-11-29: ANGLE for WinRT doesn't seem to work unless VSync 1947 * is turned on. Not doing so will freeze the screen's contents to that 1948 * of the first drawn frame. 1949 */ 1950 flags |= SDL_RENDERER_PRESENTVSYNC; 1951#endif 1952 1953 if (flags & SDL_RENDERER_PRESENTVSYNC) { 1954 SDL_GL_SetSwapInterval(1); 1955 } else { 1956 SDL_GL_SetSwapInterval(0); 1957 } 1958 if (SDL_GL_GetSwapInterval() > 0) { 1959 renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC; 1960 } 1961 1962 /* Check for debug output support */ 1963 if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_FLAGS, &value) == 0 && 1964 (value & SDL_GL_CONTEXT_DEBUG_FLAG)) { 1965 data->debug_enabled = SDL_TRUE; 1966 } 1967 1968 value = 0; 1969 data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value); 1970 renderer->info.max_texture_width = value; 1971 value = 0; 1972 data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value); 1973 renderer->info.max_texture_height = value; 1974 1975 /* Determine supported shader formats */ 1976 /* HACK: glGetInteger is broken on the Zune HD's compositor, so we just hardcode this */ 1977#ifdef ZUNE_HD 1978 nFormats = 1; 1979#else /* !ZUNE_HD */ 1980 data->glGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &nFormats); 1981 data->glGetBooleanv(GL_SHADER_COMPILER, &hasCompiler); 1982 if (hasCompiler) 1983 ++nFormats; 1984#endif /* ZUNE_HD */ 1985 data->shader_formats = (GLenum *)SDL_calloc(nFormats, sizeof(GLenum)); 1986 if (!data->shader_formats) 1987 { 1988 GLES2_DestroyRenderer(renderer); 1989 SDL_OutOfMemory(); 1990 goto error; 1991 } 1992 data->shader_format_count = nFormats; 1993#ifdef ZUNE_HD 1994 data->shader_formats[0] = GL_NVIDIA_PLATFORM_BINARY_NV; 1995#else /* !ZUNE_HD */ 1996 data->glGetIntegerv(GL_SHADER_BINARY_FORMATS, (GLint *)data->shader_formats); 1997 if (hasCompiler) 1998 data->shader_formats[nFormats - 1] = (GLenum)-1; 1999#endif /* ZUNE_HD */ 2000 2001 data->framebuffers = NULL; 2002 data->glGetIntegerv(GL_FRAMEBUFFER_BINDING, &window_framebuffer); 2003 data->window_framebuffer = (GLuint)window_framebuffer; 2004 2005 /* Populate the function pointers for the module */ 2006 renderer->WindowEvent = &GLES2_WindowEvent; 2007 renderer->CreateTexture = &GLES2_CreateTexture; 2008 renderer->UpdateTexture = &GLES2_UpdateTexture; 2009 renderer->UpdateTextureYUV = &GLES2_UpdateTextureYUV; 2010 renderer->LockTexture = &GLES2_LockTexture; 2011 renderer->UnlockTexture = &GLES2_UnlockTexture; 2012 renderer->SetRenderTarget = &GLES2_SetRenderTarget; 2013 renderer->UpdateViewport = &GLES2_UpdateViewport; 2014 renderer->UpdateClipRect = &GLES2_UpdateClipRect; 2015 renderer->RenderClear = &GLES2_RenderClear; 2016 renderer->RenderDrawPoints = &GLES2_RenderDrawPoints; 2017 renderer->RenderDrawLines = &GLES2_RenderDrawLines; 2018 renderer->RenderFillRects = &GLES2_RenderFillRects; 2019 renderer->RenderCopy = &GLES2_RenderCopy; 2020 renderer->RenderCopyEx = &GLES2_RenderCopyEx; 2021 renderer->RenderReadPixels = &GLES2_RenderReadPixels; 2022 renderer->RenderPresent = &GLES2_RenderPresent; 2023 renderer->DestroyTexture = &GLES2_DestroyTexture; 2024 renderer->DestroyRenderer = &GLES2_DestroyRenderer; 2025 renderer->GL_BindTexture = &GLES2_BindTexture; 2026 renderer->GL_UnbindTexture = &GLES2_UnbindTexture; 2027 2028 renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12; 2029 renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV; 2030 renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_NV12; 2031 renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_NV21; 2032 2033 GLES2_ResetState(renderer); 2034 2035 return renderer; 2036 2037error: 2038 if (changed_window) { 2039 /* Uh oh, better try to put it back... */ 2040 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profile_mask); 2041 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major); 2042 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minor); 2043 SDL_RecreateWindow(window, window_flags); 2044 } 2045 return NULL; 2046} 2047 2048#endif /* SDL_VIDEO_RENDER_OGL_ES2 && !SDL_RENDER_DISABLED */ 2049 2050/* vi: set ts=4 sw=4 expandtab: */