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