Atlas - SDL_render_gles2.c
Home / ext / SDL / src / render / opengles2 Lines: 3 | Size: 91817 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "SDL_internal.h" 22 23#ifdef SDL_VIDEO_RENDER_OGL_ES2 24 25#include "../../video/SDL_sysvideo.h" // For SDL_RecreateWindow 26#include <SDL3/SDL_opengles2.h> 27#include "../SDL_sysrender.h" 28#include "../../video/SDL_pixels_c.h" 29#include "SDL_shaders_gles2.h" 30 31/* WebGL doesn't offer client-side arrays, so use Vertex Buffer Objects 32 on Emscripten, which converts GLES2 into WebGL calls. 33 In all other cases, attempt to use client-side arrays, as they tend to 34 be dramatically faster when not batching, and about the same when 35 we are. */ 36#ifdef SDL_PLATFORM_EMSCRIPTEN 37#define USE_VERTEX_BUFFER_OBJECTS 1 38#else 39#define USE_VERTEX_BUFFER_OBJECTS 0 40#endif 41 42/* To prevent unnecessary window recreation, 43 * these should match the defaults selected in SDL_GL_ResetAttributes 44 */ 45#define RENDERER_CONTEXT_MAJOR 2 46#define RENDERER_CONTEXT_MINOR 0 47 48/************************************************************************************************* 49 * Context structures * 50 *************************************************************************************************/ 51 52typedef struct GLES2_FBOList GLES2_FBOList; 53 54struct GLES2_FBOList 55{ 56 Uint32 w, h; 57 GLuint FBO; 58 GLES2_FBOList *next; 59}; 60 61typedef struct 62{ 63 GLuint texture; 64} GLES2_PaletteData; 65 66typedef struct 67{ 68 GLuint texture; 69 bool texture_external; 70 GLenum texture_type; 71 GLenum pixel_format; 72 GLenum pixel_type; 73 void *pixel_data; 74 int pitch; 75#ifdef SDL_HAVE_YUV 76 // YUV texture support 77 bool yuv; 78 bool nv12; 79 GLuint texture_v; 80 GLuint texture_v_external; 81 GLuint texture_u; 82 GLuint texture_u_external; 83#endif 84 GLfloat texel_size[4]; 85 SDL_ScaleMode texture_scale_mode; 86 SDL_TextureAddressMode texture_address_mode_u; 87 SDL_TextureAddressMode texture_address_mode_v; 88 GLES2_FBOList *fbo; 89} GLES2_TextureData; 90 91typedef enum 92{ 93 GLES2_ATTRIBUTE_POSITION = 0, 94 GLES2_ATTRIBUTE_COLOR = 1, 95 GLES2_ATTRIBUTE_TEXCOORD = 2, 96} GLES2_Attribute; 97 98typedef enum 99{ 100 GLES2_UNIFORM_PROJECTION, 101 GLES2_UNIFORM_TEXTURE, 102 GLES2_UNIFORM_TEXTURE_U, 103 GLES2_UNIFORM_TEXTURE_V, 104 GLES2_UNIFORM_PALETTE, 105 GLES2_UNIFORM_TEXEL_SIZE, 106 GLES2_UNIFORM_OFFSET, 107 GLES2_UNIFORM_MATRIX, 108 NUM_GLES2_UNIFORMS 109} GLES2_Uniform; 110 111static const char *GLES2_UniformNames[] = { 112 "u_projection", 113 "u_texture", 114 "u_texture_u", 115 "u_texture_v", 116 "u_palette", 117 "u_texel_size", 118 "u_offset", 119 "u_matrix" 120}; 121SDL_COMPILE_TIME_ASSERT(GLES2_UniformNames, SDL_arraysize(GLES2_UniformNames) == NUM_GLES2_UNIFORMS); 122 123typedef struct GLES2_ProgramCacheEntry 124{ 125 GLuint id; 126 GLuint vertex_shader; 127 GLuint fragment_shader; 128 GLuint uniform_locations[NUM_GLES2_UNIFORMS]; 129 GLfloat projection[4][4]; 130 float *shader_params; 131 struct GLES2_ProgramCacheEntry *prev; 132 struct GLES2_ProgramCacheEntry *next; 133} GLES2_ProgramCacheEntry; 134 135typedef struct GLES2_ProgramCache 136{ 137 int count; 138 GLES2_ProgramCacheEntry *head; 139 GLES2_ProgramCacheEntry *tail; 140} GLES2_ProgramCache; 141 142typedef enum 143{ 144 GLES2_IMAGESOURCE_INVALID, 145 GLES2_IMAGESOURCE_SOLID, 146 GLES2_IMAGESOURCE_TEXTURE_INDEX8, 147 GLES2_IMAGESOURCE_TEXTURE_ABGR, 148 GLES2_IMAGESOURCE_TEXTURE_ARGB, 149 GLES2_IMAGESOURCE_TEXTURE_RGB, 150 GLES2_IMAGESOURCE_TEXTURE_BGR, 151 GLES2_IMAGESOURCE_TEXTURE_YUV, 152 GLES2_IMAGESOURCE_TEXTURE_NV12, 153 GLES2_IMAGESOURCE_TEXTURE_NV21, 154 GLES2_IMAGESOURCE_TEXTURE_EXTERNAL_OES 155} GLES2_ImageSource; 156 157typedef struct 158{ 159 SDL_Rect viewport; 160 bool viewport_dirty; 161 SDL_Texture *texture; 162 SDL_Texture *target; 163 SDL_BlendMode blend; 164 bool cliprect_enabled_dirty; 165 bool cliprect_enabled; 166 bool cliprect_dirty; 167 SDL_Rect cliprect; 168 bool texturing; 169 bool texturing_dirty; 170 SDL_FColor clear_color; 171 bool clear_color_dirty; 172 int drawablew; 173 int drawableh; 174 GLES2_ProgramCacheEntry *program; 175 const float *shader_params; 176 GLfloat projection[4][4]; 177} GLES2_DrawStateCache; 178 179typedef struct GLES2_RenderData 180{ 181 SDL_GLContext context; 182 183 bool debug_enabled; 184 185 bool GL_OES_EGL_image_external_supported; 186 bool GL_EXT_blend_minmax_supported; 187 188#define SDL_PROC(ret, func, params) ret (APIENTRY *func) params; 189#include "SDL_gles2funcs.h" 190#undef SDL_PROC 191 GLES2_FBOList *framebuffers; 192 GLuint window_framebuffer; 193 194 GLuint shader_id_cache[GLES2_SHADER_COUNT]; 195 196 GLES2_ProgramCache program_cache; 197 Uint8 clear_r, clear_g, clear_b, clear_a; 198 199#if USE_VERTEX_BUFFER_OBJECTS 200 GLuint vertex_buffers[8]; 201 size_t vertex_buffer_size[8]; 202 int current_vertex_buffer; 203#endif 204 205 GLES2_DrawStateCache drawstate; 206 GLES2_ShaderIncludeType texcoord_precision_hint; 207} GLES2_RenderData; 208 209#define GLES2_MAX_CACHED_PROGRAMS 8 210 211static const char *GL_TranslateError(GLenum error) 212{ 213#define GL_ERROR_TRANSLATE(e) \ 214 case e: \ 215 return #e; 216 switch (error) { 217 GL_ERROR_TRANSLATE(GL_INVALID_ENUM) 218 GL_ERROR_TRANSLATE(GL_INVALID_VALUE) 219 GL_ERROR_TRANSLATE(GL_INVALID_OPERATION) 220 GL_ERROR_TRANSLATE(GL_OUT_OF_MEMORY) 221 GL_ERROR_TRANSLATE(GL_NO_ERROR) 222 default: 223 return "UNKNOWN"; 224 } 225#undef GL_ERROR_TRANSLATE 226} 227 228static void GL_ClearErrors(SDL_Renderer *renderer) 229{ 230 GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal; 231 232 if (!data->debug_enabled) { 233 return; 234 } 235 while (data->glGetError() != GL_NO_ERROR) { 236 // continue; 237 } 238} 239 240static bool GL_CheckAllErrors(const char *prefix, SDL_Renderer *renderer, const char *file, int line, const char *function) 241{ 242 GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal; 243 bool result = true; 244 245 if (!data->debug_enabled) { 246 return true; 247 } 248 // check gl errors (can return multiple errors) 249 for (;;) { 250 GLenum error = data->glGetError(); 251 if (error != GL_NO_ERROR) { 252 if (!prefix || prefix[0] == '\0') { 253 prefix = "generic"; 254 } 255 SDL_SetError("%s: %s (%d): %s %s (0x%X)", prefix, file, line, function, GL_TranslateError(error), error); 256 result = false; 257 } else { 258 break; 259 } 260 } 261 return result; 262} 263 264#if 0 265#define GL_CheckError(prefix, renderer) 266#else 267#define GL_CheckError(prefix, renderer) GL_CheckAllErrors(prefix, renderer, "SDL_render_gles2.c", SDL_LINE, SDL_FUNCTION) 268#endif 269 270/************************************************************************************************* 271 * Renderer state APIs * 272 *************************************************************************************************/ 273 274static bool GLES2_LoadFunctions(GLES2_RenderData *data) 275{ 276#ifdef SDL_VIDEO_DRIVER_UIKIT 277#define __SDL_NOGETPROCADDR__ 278#elif defined(SDL_VIDEO_DRIVER_ANDROID) 279#define __SDL_NOGETPROCADDR__ 280#endif 281 282#if defined __SDL_NOGETPROCADDR__ 283#define SDL_PROC(ret, func, params) data->func = func; 284#else 285#define SDL_PROC(ret, func, params) \ 286 do { \ 287 data->func = (ret (APIENTRY *) params)SDL_GL_GetProcAddress(#func); \ 288 if (!data->func) { \ 289 return SDL_SetError("Couldn't load GLES2 function %s: %s", #func, SDL_GetError()); \ 290 } \ 291 } while (0); 292#endif // __SDL_NOGETPROCADDR__ 293 294#include "SDL_gles2funcs.h" 295#undef SDL_PROC 296 return true; 297} 298 299static GLES2_FBOList *GLES2_GetFBO(GLES2_RenderData *data, Uint32 w, Uint32 h) 300{ 301 GLES2_FBOList *result = data->framebuffers; 302 while ((result) && ((result->w != w) || (result->h != h))) { 303 result = result->next; 304 } 305 if (!result) { 306 result = (GLES2_FBOList *)SDL_malloc(sizeof(GLES2_FBOList)); 307 result->w = w; 308 result->h = h; 309 data->glGenFramebuffers(1, &result->FBO); 310 result->next = data->framebuffers; 311 data->framebuffers = result; 312 } 313 return result; 314} 315 316static bool GLES2_ActivateRenderer(SDL_Renderer *renderer) 317{ 318 GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal; 319 320 if (SDL_GL_GetCurrentContext() != data->context) { 321 // Null out the current program to ensure we set it again 322 data->drawstate.program = NULL; 323 324 if (!SDL_GL_MakeCurrent(renderer->window, data->context)) { 325 return false; 326 } 327 } 328 329 GL_ClearErrors(renderer); 330 331 return true; 332} 333 334static void GLES2_WindowEvent(SDL_Renderer *renderer, const SDL_WindowEvent *event) 335{ 336 GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal; 337 338 if (event->type == SDL_EVENT_WINDOW_MINIMIZED) { 339 // According to Apple documentation, we need to finish drawing NOW! 340 data->glFinish(); 341 } 342} 343 344static GLenum GetBlendFunc(SDL_BlendFactor factor) 345{ 346 switch (factor) { 347 case SDL_BLENDFACTOR_ZERO: 348 return GL_ZERO; 349 case SDL_BLENDFACTOR_ONE: 350 return GL_ONE; 351 case SDL_BLENDFACTOR_SRC_COLOR: 352 return GL_SRC_COLOR; 353 case SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR: 354 return GL_ONE_MINUS_SRC_COLOR; 355 case SDL_BLENDFACTOR_SRC_ALPHA: 356 return GL_SRC_ALPHA; 357 case SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA: 358 return GL_ONE_MINUS_SRC_ALPHA; 359 case SDL_BLENDFACTOR_DST_COLOR: 360 return GL_DST_COLOR; 361 case SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR: 362 return GL_ONE_MINUS_DST_COLOR; 363 case SDL_BLENDFACTOR_DST_ALPHA: 364 return GL_DST_ALPHA; 365 case SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA: 366 return GL_ONE_MINUS_DST_ALPHA; 367 default: 368 return GL_INVALID_ENUM; 369 } 370} 371 372static GLenum GetBlendEquation(SDL_BlendOperation operation) 373{ 374 switch (operation) { 375 case SDL_BLENDOPERATION_ADD: 376 return GL_FUNC_ADD; 377 case SDL_BLENDOPERATION_SUBTRACT: 378 return GL_FUNC_SUBTRACT; 379 case SDL_BLENDOPERATION_REV_SUBTRACT: 380 return GL_FUNC_REVERSE_SUBTRACT; 381 case SDL_BLENDOPERATION_MINIMUM: 382 return GL_MIN_EXT; 383 case SDL_BLENDOPERATION_MAXIMUM: 384 return GL_MAX_EXT; 385 default: 386 return GL_INVALID_ENUM; 387 } 388} 389 390static bool GLES2_SupportsBlendMode(SDL_Renderer *renderer, SDL_BlendMode blendMode) 391{ 392 GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal; 393 394 SDL_BlendFactor srcColorFactor = SDL_GetBlendModeSrcColorFactor(blendMode); 395 SDL_BlendFactor srcAlphaFactor = SDL_GetBlendModeSrcAlphaFactor(blendMode); 396 SDL_BlendOperation colorOperation = SDL_GetBlendModeColorOperation(blendMode); 397 SDL_BlendFactor dstColorFactor = SDL_GetBlendModeDstColorFactor(blendMode); 398 SDL_BlendFactor dstAlphaFactor = SDL_GetBlendModeDstAlphaFactor(blendMode); 399 SDL_BlendOperation alphaOperation = SDL_GetBlendModeAlphaOperation(blendMode); 400 401 if (GetBlendFunc(srcColorFactor) == GL_INVALID_ENUM || 402 GetBlendFunc(srcAlphaFactor) == GL_INVALID_ENUM || 403 GetBlendEquation(colorOperation) == GL_INVALID_ENUM || 404 GetBlendFunc(dstColorFactor) == GL_INVALID_ENUM || 405 GetBlendFunc(dstAlphaFactor) == GL_INVALID_ENUM || 406 GetBlendEquation(alphaOperation) == GL_INVALID_ENUM) { 407 return false; 408 } 409 410 if (colorOperation == SDL_BLENDOPERATION_MINIMUM && !data->GL_EXT_blend_minmax_supported) { 411 return false; 412 } 413 if (colorOperation == SDL_BLENDOPERATION_MAXIMUM && !data->GL_EXT_blend_minmax_supported) { 414 return false; 415 } 416 417 return true; 418} 419 420static GLES2_ProgramCacheEntry *GLES2_CacheProgram(GLES2_RenderData *data, GLuint vertex, GLuint fragment) 421{ 422 GLES2_ProgramCacheEntry *entry; 423 GLint linkSuccessful; 424 int i; 425 426 // Check if we've already cached this program 427 entry = data->program_cache.head; 428 while (entry) { 429 if (entry->vertex_shader == vertex && entry->fragment_shader == fragment) { 430 break; 431 } 432 entry = entry->next; 433 } 434 if (entry) { 435 if (data->program_cache.head != entry) { 436 if (entry->next) { 437 entry->next->prev = entry->prev; 438 } 439 if (entry->prev) { 440 entry->prev->next = entry->next; 441 } 442 entry->prev = NULL; 443 entry->next = data->program_cache.head; 444 data->program_cache.head->prev = entry; 445 data->program_cache.head = entry; 446 } 447 return entry; 448 } 449 450 // Create a program cache entry 451 entry = (GLES2_ProgramCacheEntry *)SDL_calloc(1, sizeof(GLES2_ProgramCacheEntry)); 452 if (!entry) { 453 return NULL; 454 } 455 entry->vertex_shader = vertex; 456 entry->fragment_shader = fragment; 457 458 // Create the program and link it 459 entry->id = data->glCreateProgram(); 460 data->glAttachShader(entry->id, vertex); 461 data->glAttachShader(entry->id, fragment); 462 data->glBindAttribLocation(entry->id, GLES2_ATTRIBUTE_POSITION, "a_position"); 463 data->glBindAttribLocation(entry->id, GLES2_ATTRIBUTE_COLOR, "a_color"); 464 data->glBindAttribLocation(entry->id, GLES2_ATTRIBUTE_TEXCOORD, "a_texCoord"); 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->shader_params); 470 SDL_free(entry); 471 SDL_SetError("Failed to link shader program"); 472 return NULL; 473 } 474 475 // Predetermine locations of uniform variables 476 for (i = 0; i < NUM_GLES2_UNIFORMS; ++i) { 477 entry->uniform_locations[i] = data->glGetUniformLocation(entry->id, GLES2_UniformNames[i]); 478 } 479 480 data->glUseProgram(entry->id); 481 if (entry->uniform_locations[GLES2_UNIFORM_TEXTURE_V] != -1) { 482 data->glUniform1i(entry->uniform_locations[GLES2_UNIFORM_TEXTURE_V], 2); // always texture unit 2. 483 } 484 if (entry->uniform_locations[GLES2_UNIFORM_TEXTURE_U] != -1) { 485 data->glUniform1i(entry->uniform_locations[GLES2_UNIFORM_TEXTURE_U], 1); // always texture unit 1. 486 } 487 if (entry->uniform_locations[GLES2_UNIFORM_PALETTE] != -1) { 488 data->glUniform1i(entry->uniform_locations[GLES2_UNIFORM_PALETTE], 1); // always texture unit 1. 489 } 490 if (entry->uniform_locations[GLES2_UNIFORM_TEXTURE] != -1) { 491 data->glUniform1i(entry->uniform_locations[GLES2_UNIFORM_TEXTURE], 0); // always texture unit 0. 492 } 493 if (entry->uniform_locations[GLES2_UNIFORM_PROJECTION] != -1) { 494 data->glUniformMatrix4fv(entry->uniform_locations[GLES2_UNIFORM_PROJECTION], 1, GL_FALSE, (GLfloat *)entry->projection); 495 } 496 497 // Cache the linked program 498 if (data->program_cache.head) { 499 entry->next = data->program_cache.head; 500 data->program_cache.head->prev = entry; 501 } else { 502 data->program_cache.tail = entry; 503 } 504 data->program_cache.head = entry; 505 ++data->program_cache.count; 506 507 // Evict the last entry from the cache if we exceed the limit 508 if (data->program_cache.count > GLES2_MAX_CACHED_PROGRAMS) { 509 GLES2_ProgramCacheEntry *oldest = data->program_cache.tail; 510 data->program_cache.tail = oldest->prev; 511 data->glDeleteProgram(oldest->id); 512 SDL_free(oldest->shader_params); 513 SDL_free(oldest); 514 --data->program_cache.count; 515 } 516 return entry; 517} 518 519static bool GLES2_CacheShader(GLES2_RenderData *data, GLES2_ShaderType type, GLenum shader_type) 520{ 521 GLuint id = 0; 522 GLint compileSuccessful = GL_FALSE; 523 int attempt, num_src; 524 const GLchar *shader_src_list[4]; 525 const GLchar *shader_body = GLES2_GetShader(type); 526 527 if (!shader_body) { 528 return SDL_SetError("No shader body src"); 529 } 530 531 for (attempt = 0; attempt < 2 && !compileSuccessful; ++attempt) { 532 num_src = 0; 533 534#ifdef OPENGLES_300 535 shader_src_list[num_src++] = "#version 300 es\n"; 536#endif 537 shader_src_list[num_src++] = GLES2_GetShaderPrologue(type); 538 539 if (shader_type == GL_FRAGMENT_SHADER) { 540 if (attempt == 0) { 541 shader_src_list[num_src++] = GLES2_GetShaderInclude(data->texcoord_precision_hint); 542 } else { 543 shader_src_list[num_src++] = GLES2_GetShaderInclude(GLES2_SHADER_FRAGMENT_INCLUDE_UNDEF_PRECISION); 544 } 545 } 546 547 shader_src_list[num_src++] = shader_body; 548 549 SDL_assert(num_src <= SDL_arraysize(shader_src_list)); 550 551#ifdef DEBUG_PRINT_SHADERS 552 { 553 int i; 554 char *message = NULL; 555 556 SDL_asprintf(&message, "Compiling shader:\n"); 557 for (i = 0; i < num_src; ++i) { 558 char *last_message = message; 559 SDL_asprintf(&message, "%s%s", last_message, shader_src_list[i]); 560 SDL_free(last_message); 561 } 562 SDL_Log("%s", message); 563 SDL_free(message); 564 } 565#endif 566 567 // Compile 568 id = data->glCreateShader(shader_type); 569 data->glShaderSource(id, num_src, shader_src_list, NULL); 570 data->glCompileShader(id); 571 data->glGetShaderiv(id, GL_COMPILE_STATUS, &compileSuccessful); 572 } 573 574 if (!compileSuccessful) { 575 char *info = NULL; 576 int length = 0; 577 578 data->glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length); 579 if (length > 0) { 580 info = (char *)SDL_malloc(length); 581 if (info) { 582 data->glGetShaderInfoLog(id, length, &length, info); 583 } 584 } 585 if (info) { 586 SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Failed to load the shader %d: %s", type, info); 587 SDL_free(info); 588 } else { 589 SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Failed to load the shader %d", type); 590 591 } 592 data->glDeleteShader(id); 593 594 return SDL_SetError("Failed to load the shader %d", type); 595 } 596 597 // Cache 598 data->shader_id_cache[(Uint32)type] = id; 599 600 return true; 601} 602 603static bool GLES2_CacheShaders(GLES2_RenderData *data) 604{ 605 int shader; 606 607 data->texcoord_precision_hint = GLES2_GetTexCoordPrecisionEnumFromHint(); 608 609 for (shader = 0; shader < GLES2_SHADER_FRAGMENT_TEXTURE_EXTERNAL_OES; ++shader) { 610 GLenum shader_type; 611 612 if (shader == GLES2_SHADER_VERTEX_DEFAULT) { 613 shader_type = GL_VERTEX_SHADER; 614 } else { 615 shader_type = GL_FRAGMENT_SHADER; 616 } 617 if (!GLES2_CacheShader(data, (GLES2_ShaderType)shader, shader_type)) { 618 return false; 619 } 620 } 621 return true; 622} 623 624static bool GLES2_SelectProgram(GLES2_RenderData *data, SDL_Texture *texture, GLES2_ImageSource source, SDL_ScaleMode scale_mode, SDL_Colorspace colorspace) 625{ 626 GLuint vertex; 627 GLuint fragment; 628 GLES2_ShaderType vtype, ftype; 629 GLES2_ProgramCacheEntry *program; 630 GLES2_TextureData *tdata = texture ? (GLES2_TextureData *)texture->internal : NULL; 631 const bool colorswap = (data->drawstate.target && (data->drawstate.target->format == SDL_PIXELFORMAT_BGRA32 || data->drawstate.target->format == SDL_PIXELFORMAT_BGRX32)); 632 const float *shader_params = NULL; 633 int shader_params_len = 0; 634 635 // Select an appropriate shader pair for the specified modes 636 vtype = GLES2_SHADER_VERTEX_DEFAULT; 637 switch (source) { 638 case GLES2_IMAGESOURCE_SOLID: 639 ftype = GLES2_SHADER_FRAGMENT_SOLID; 640 break; 641 case GLES2_IMAGESOURCE_TEXTURE_INDEX8: 642 switch (scale_mode) { 643 case SDL_SCALEMODE_NEAREST: 644 if (colorswap) { 645 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_PALETTE_NEAREST_COLORSWAP; 646 } else { 647 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_PALETTE_NEAREST; 648 } 649 break; 650 case SDL_SCALEMODE_LINEAR: 651 if (colorswap) { 652 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_PALETTE_LINEAR_COLORSWAP; 653 } else { 654 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_PALETTE_LINEAR; 655 } 656 shader_params = tdata->texel_size; 657 shader_params_len = 4 * sizeof(float); 658 break; 659 case SDL_SCALEMODE_PIXELART: 660 if (colorswap) { 661 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_PALETTE_PIXELART_COLORSWAP; 662 } else { 663 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_PALETTE_PIXELART; 664 } 665 shader_params = tdata->texel_size; 666 shader_params_len = 4 * sizeof(float); 667 break; 668 default: 669 SDL_assert(!"Unknown scale mode"); 670 goto fault; 671 } 672 break; 673 case GLES2_IMAGESOURCE_TEXTURE_ABGR: 674 if (scale_mode == SDL_SCALEMODE_PIXELART) { 675 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_ABGR_PIXELART; 676 shader_params = tdata->texel_size; 677 shader_params_len = 4 * sizeof(float); 678 } else { 679 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_ABGR; 680 } 681 break; 682 case GLES2_IMAGESOURCE_TEXTURE_ARGB: 683 if (scale_mode == SDL_SCALEMODE_PIXELART) { 684 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_ARGB_PIXELART; 685 shader_params = tdata->texel_size; 686 shader_params_len = 4 * sizeof(float); 687 } else { 688 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_ARGB; 689 } 690 break; 691 case GLES2_IMAGESOURCE_TEXTURE_RGB: 692 if (scale_mode == SDL_SCALEMODE_PIXELART) { 693 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_RGB_PIXELART; 694 shader_params = tdata->texel_size; 695 shader_params_len = 4 * sizeof(float); 696 } else { 697 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_RGB; 698 } 699 break; 700 case GLES2_IMAGESOURCE_TEXTURE_BGR: 701 if (scale_mode == SDL_SCALEMODE_PIXELART) { 702 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_BGR_PIXELART; 703 shader_params = tdata->texel_size; 704 shader_params_len = 4 * sizeof(float); 705 } else { 706 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_BGR; 707 } 708 break; 709#ifdef SDL_HAVE_YUV 710 case GLES2_IMAGESOURCE_TEXTURE_YUV: 711 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_YUV; 712 shader_params = SDL_GetYCbCRtoRGBConversionMatrix(colorspace, 0, 0, 8); 713 if (!shader_params) { 714 SDL_SetError("Unsupported YUV colorspace"); 715 goto fault; 716 } 717 shader_params_len = 16 * sizeof(float); 718 break; 719 case GLES2_IMAGESOURCE_TEXTURE_NV12: 720 if (SDL_GetHintBoolean("SDL_RENDER_OPENGL_NV12_RG_SHADER", false)) { 721 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV12_RG; 722 } else { 723 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV12_RA; 724 } 725 shader_params = SDL_GetYCbCRtoRGBConversionMatrix(colorspace, 0, 0, 8); 726 if (!shader_params) { 727 SDL_SetError("Unsupported YUV colorspace"); 728 goto fault; 729 } 730 shader_params_len = 16 * sizeof(float); 731 break; 732 case GLES2_IMAGESOURCE_TEXTURE_NV21: 733 if (SDL_GetHintBoolean("SDL_RENDER_OPENGL_NV12_RG_SHADER", false)) { 734 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV21_RG; 735 } else { 736 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV21_RA; 737 } 738 shader_params = SDL_GetYCbCRtoRGBConversionMatrix(colorspace, 0, 0, 8); 739 if (!shader_params) { 740 SDL_SetError("Unsupported YUV colorspace"); 741 goto fault; 742 } 743 shader_params_len = 16 * sizeof(float); 744 break; 745#endif // SDL_HAVE_YUV 746 case GLES2_IMAGESOURCE_TEXTURE_EXTERNAL_OES: 747 ftype = GLES2_SHADER_FRAGMENT_TEXTURE_EXTERNAL_OES; 748 break; 749 default: 750 SDL_assert(!"Unknown image source"); 751 goto fault; 752 } 753 754 // Load the requested shaders 755 vertex = data->shader_id_cache[(Uint32)vtype]; 756 if (!vertex) { 757 vertex = GLES2_CacheShader(data, vtype, GL_VERTEX_SHADER); 758 if (!vertex) { 759 goto fault; 760 } 761 } 762 763 fragment = data->shader_id_cache[(Uint32)ftype]; 764 if (!fragment) { 765 fragment = GLES2_CacheShader(data, ftype, GL_FRAGMENT_SHADER); 766 if (!fragment) { 767 goto fault; 768 } 769 } 770 771 // Check if we need to change programs at all 772 if (data->drawstate.program && 773 data->drawstate.program->vertex_shader == vertex && 774 data->drawstate.program->fragment_shader == fragment && 775 data->drawstate.program->shader_params == shader_params) { 776 return true; 777 } 778 779 // Generate a matching program 780 program = GLES2_CacheProgram(data, vertex, fragment); 781 if (!program) { 782 goto fault; 783 } 784 785 // Select that program in OpenGL 786 data->glUseProgram(program->id); 787 788 SDL_assert(!shader_params || shader_params_len > 0); 789 790 if (shader_params && 791 (!program->shader_params || 792 SDL_memcmp(shader_params, program->shader_params, shader_params_len) != 0)) { 793#ifdef SDL_HAVE_YUV 794 if (ftype >= GLES2_SHADER_FRAGMENT_TEXTURE_YUV) { 795 // YUV shader params are Yoffset, 0, Rcoeff, 0, Gcoeff, 0, Bcoeff, 0 796 if (program->uniform_locations[GLES2_UNIFORM_OFFSET] != -1) { 797 data->glUniform3f(program->uniform_locations[GLES2_UNIFORM_OFFSET], shader_params[0], shader_params[1], shader_params[2]); 798 } 799 if (program->uniform_locations[GLES2_UNIFORM_MATRIX] != -1) { 800 GLfloat matrix[3 * 3]; 801 802 matrix[0 * 3 + 0] = shader_params[4]; 803 matrix[0 * 3 + 1] = shader_params[5]; 804 matrix[0 * 3 + 2] = shader_params[6]; 805 matrix[1 * 3 + 0] = shader_params[8]; 806 matrix[1 * 3 + 1] = shader_params[9]; 807 matrix[1 * 3 + 2] = shader_params[10]; 808 matrix[2 * 3 + 0] = shader_params[12]; 809 matrix[2 * 3 + 1] = shader_params[13]; 810 matrix[2 * 3 + 2] = shader_params[14]; 811 data->glUniformMatrix3fv(program->uniform_locations[GLES2_UNIFORM_MATRIX], 1, GL_FALSE, matrix); 812 } 813 } 814 else 815#endif 816 if (shader_params) { 817 data->glUniform4f(program->uniform_locations[GLES2_UNIFORM_TEXEL_SIZE], shader_params[0], shader_params[1], shader_params[2], shader_params[3]); 818 } 819 820 if (!program->shader_params) { 821 program->shader_params = (float *)SDL_malloc(shader_params_len); 822 } 823 if (program->shader_params) { 824 SDL_memcpy(program->shader_params, shader_params, shader_params_len); 825 } 826 } 827 828 // Set the current program 829 data->drawstate.program = program; 830 831 // Clean up and return 832 return true; 833fault: 834 data->drawstate.program = NULL; 835 return false; 836} 837 838static bool GLES2_QueueNoOp(SDL_Renderer *renderer, SDL_RenderCommand *cmd) 839{ 840 return true; // nothing to do in this backend. 841} 842 843static bool GLES2_QueueDrawPoints(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count) 844{ 845 const bool colorswap = (renderer->target && (renderer->target->format == SDL_PIXELFORMAT_BGRA32 || renderer->target->format == SDL_PIXELFORMAT_BGRX32)); 846 SDL_VertexSolid *verts = (SDL_VertexSolid *)SDL_AllocateRenderVertices(renderer, count * sizeof(*verts), 0, &cmd->data.draw.first); 847 int i; 848 SDL_FColor color = cmd->data.draw.color; 849 const float color_scale = cmd->data.draw.color_scale; 850 851 if (!verts) { 852 return false; 853 } 854 855 color.r *= color_scale; 856 color.g *= color_scale; 857 color.b *= color_scale; 858 859 if (colorswap) { 860 float r = color.r; 861 color.r = color.b; 862 color.b = r; 863 } 864 865 cmd->data.draw.count = count; 866 for (i = 0; i < count; i++) { 867 verts->position.x = 0.5f + points[i].x; 868 verts->position.y = 0.5f + points[i].y; 869 verts->color = color; 870 verts++; 871 } 872 873 return true; 874} 875 876static bool GLES2_QueueDrawLines(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count) 877{ 878 const bool colorswap = (renderer->target && (renderer->target->format == SDL_PIXELFORMAT_BGRA32 || renderer->target->format == SDL_PIXELFORMAT_BGRX32)); 879 int i; 880 GLfloat prevx, prevy; 881 SDL_VertexSolid *verts = (SDL_VertexSolid *)SDL_AllocateRenderVertices(renderer, count * sizeof(*verts), 0, &cmd->data.draw.first); 882 SDL_FColor color = cmd->data.draw.color; 883 const float color_scale = cmd->data.draw.color_scale; 884 885 if (!verts) { 886 return false; 887 } 888 889 color.r *= color_scale; 890 color.g *= color_scale; 891 color.b *= color_scale; 892 893 if (colorswap) { 894 float r = color.r; 895 color.r = color.b; 896 color.b = r; 897 } 898 899 cmd->data.draw.count = count; 900 901 // 0.5f offset to hit the center of the pixel. 902 prevx = 0.5f + points->x; 903 prevy = 0.5f + points->y; 904 verts->position.x = prevx; 905 verts->position.y = prevy; 906 verts->color = color; 907 verts++; 908 909 /* bump the end of each line segment out a quarter of a pixel, to provoke 910 the diamond-exit rule. Without this, you won't just drop the last 911 pixel of the last line segment, but you might also drop pixels at the 912 edge of any given line segment along the way too. */ 913 for (i = 1; i < count; i++) { 914 const GLfloat xstart = prevx; 915 const GLfloat ystart = prevy; 916 const GLfloat xend = points[i].x + 0.5f; // 0.5f to hit pixel center. 917 const GLfloat yend = points[i].y + 0.5f; 918 // bump a little in the direction we are moving in. 919 const GLfloat deltax = xend - xstart; 920 const GLfloat deltay = yend - ystart; 921 const GLfloat angle = SDL_atan2f(deltay, deltax); 922 prevx = xend + (SDL_cosf(angle) * 0.25f); 923 prevy = yend + (SDL_sinf(angle) * 0.25f); 924 verts->position.x = prevx; 925 verts->position.y = prevy; 926 verts->color = color; 927 verts++; 928 } 929 930 return true; 931} 932 933static bool GLES2_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, 934 const float *xy, int xy_stride, const SDL_FColor *color, int color_stride, const float *uv, int uv_stride, 935 int num_vertices, const void *indices, int num_indices, int size_indices, 936 float scale_x, float scale_y) 937{ 938 int i; 939 const bool colorswap = (renderer->target && (renderer->target->format == SDL_PIXELFORMAT_BGRA32 || renderer->target->format == SDL_PIXELFORMAT_BGRX32)); 940 int count = indices ? num_indices : num_vertices; 941 const float color_scale = cmd->data.draw.color_scale; 942 943 cmd->data.draw.count = count; 944 size_indices = indices ? size_indices : 0; 945 946 if (texture) { 947 SDL_Vertex *verts = (SDL_Vertex *)SDL_AllocateRenderVertices(renderer, count * sizeof(*verts), 0, &cmd->data.draw.first); 948 if (!verts) { 949 return false; 950 } 951 952 for (i = 0; i < count; i++) { 953 int j; 954 float *xy_; 955 SDL_FColor col_; 956 float *uv_; 957 if (size_indices == 4) { 958 j = ((const Uint32 *)indices)[i]; 959 } else if (size_indices == 2) { 960 j = ((const Uint16 *)indices)[i]; 961 } else if (size_indices == 1) { 962 j = ((const Uint8 *)indices)[i]; 963 } else { 964 j = i; 965 } 966 967 xy_ = (float *)((char *)xy + j * xy_stride); 968 col_ = *(SDL_FColor *)((char *)color + j * color_stride); 969 uv_ = (float *)((char *)uv + j * uv_stride); 970 971 verts->position.x = xy_[0] * scale_x; 972 verts->position.y = xy_[1] * scale_y; 973 974 col_.r *= color_scale; 975 col_.g *= color_scale; 976 col_.b *= color_scale; 977 978 if (colorswap) { 979 float r = col_.r; 980 col_.r = col_.b; 981 col_.b = r; 982 } 983 984 verts->color = col_; 985 verts->tex_coord.x = uv_[0]; 986 verts->tex_coord.y = uv_[1]; 987 verts++; 988 } 989 990 } else { 991 SDL_VertexSolid *verts = (SDL_VertexSolid *)SDL_AllocateRenderVertices(renderer, count * sizeof(*verts), 0, &cmd->data.draw.first); 992 if (!verts) { 993 return false; 994 } 995 996 for (i = 0; i < count; i++) { 997 int j; 998 float *xy_; 999 SDL_FColor col_; 1000 1001 if (size_indices == 4) { 1002 j = ((const Uint32 *)indices)[i]; 1003 } else if (size_indices == 2) { 1004 j = ((const Uint16 *)indices)[i]; 1005 } else if (size_indices == 1) { 1006 j = ((const Uint8 *)indices)[i]; 1007 } else { 1008 j = i; 1009 } 1010 1011 xy_ = (float *)((char *)xy + j * xy_stride); 1012 col_ = *(SDL_FColor *)((char *)color + j * color_stride); 1013 1014 verts->position.x = xy_[0] * scale_x; 1015 verts->position.y = xy_[1] * scale_y; 1016 1017 col_.r *= color_scale; 1018 col_.g *= color_scale; 1019 col_.b *= color_scale; 1020 1021 if (colorswap) { 1022 float r = col_.r; 1023 col_.r = col_.b; 1024 col_.b = r; 1025 } 1026 1027 verts->color = col_; 1028 verts++; 1029 } 1030 } 1031 1032 return true; 1033} 1034 1035static bool SetDrawState(GLES2_RenderData *data, const SDL_RenderCommand *cmd, const GLES2_ImageSource imgsrc, void *vertices) 1036{ 1037 SDL_Texture *texture = cmd->data.draw.texture; 1038 const SDL_BlendMode blend = cmd->data.draw.blend; 1039 GLES2_ProgramCacheEntry *program; 1040 int stride; 1041 1042 SDL_assert((texture != NULL) == (imgsrc != GLES2_IMAGESOURCE_SOLID)); 1043 1044 if (data->drawstate.viewport_dirty) { 1045 const SDL_Rect *viewport = &data->drawstate.viewport; 1046 data->glViewport(viewport->x, 1047 data->drawstate.target ? viewport->y : (data->drawstate.drawableh - viewport->y - viewport->h), 1048 viewport->w, viewport->h); 1049 if (viewport->w && viewport->h) { 1050 data->drawstate.projection[0][0] = 2.0f / viewport->w; 1051 data->drawstate.projection[1][1] = (data->drawstate.target ? 2.0f : -2.0f) / viewport->h; 1052 data->drawstate.projection[3][1] = data->drawstate.target ? -1.0f : 1.0f; 1053 } 1054 data->drawstate.viewport_dirty = false; 1055 } 1056 1057 if (data->drawstate.cliprect_enabled_dirty) { 1058 if (!data->drawstate.cliprect_enabled) { 1059 data->glDisable(GL_SCISSOR_TEST); 1060 } else { 1061 data->glEnable(GL_SCISSOR_TEST); 1062 } 1063 data->drawstate.cliprect_enabled_dirty = false; 1064 } 1065 1066 if (data->drawstate.cliprect_enabled && data->drawstate.cliprect_dirty) { 1067 const SDL_Rect *viewport = &data->drawstate.viewport; 1068 const SDL_Rect *rect = &data->drawstate.cliprect; 1069 data->glScissor(viewport->x + rect->x, 1070 data->drawstate.target ? viewport->y + rect->y : data->drawstate.drawableh - viewport->y - rect->y - rect->h, 1071 rect->w, rect->h); 1072 data->drawstate.cliprect_dirty = false; 1073 } 1074 1075 if (data->drawstate.texturing_dirty || ((texture != NULL) != data->drawstate.texturing)) { 1076 if (!texture) { 1077 data->glDisableVertexAttribArray((GLenum)GLES2_ATTRIBUTE_TEXCOORD); 1078 data->drawstate.texturing = false; 1079 } else { 1080 data->glEnableVertexAttribArray((GLenum)GLES2_ATTRIBUTE_TEXCOORD); 1081 data->drawstate.texturing = true; 1082 } 1083 data->drawstate.texturing_dirty = false; 1084 } 1085 1086 if (texture) { 1087 stride = sizeof(SDL_Vertex); 1088 } else { 1089 stride = sizeof(SDL_VertexSolid); 1090 } 1091 1092 if (texture) { 1093 uintptr_t base = (uintptr_t)vertices + cmd->data.draw.first; // address of first vertex, or base offset when using VBOs. 1094 data->glVertexAttribPointer(GLES2_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, stride, (const GLvoid *)(base + offsetof(SDL_Vertex, tex_coord))); 1095 } 1096 1097 SDL_Colorspace colorspace = texture ? texture->colorspace : SDL_COLORSPACE_SRGB; 1098 if (!GLES2_SelectProgram(data, texture, imgsrc, cmd->data.draw.texture_scale_mode, colorspace)) { 1099 return false; 1100 } 1101 1102 program = data->drawstate.program; 1103 1104 if (program->uniform_locations[GLES2_UNIFORM_PROJECTION] != -1) { 1105 if (SDL_memcmp(program->projection, data->drawstate.projection, sizeof(data->drawstate.projection)) != 0) { 1106 data->glUniformMatrix4fv(program->uniform_locations[GLES2_UNIFORM_PROJECTION], 1, GL_FALSE, (GLfloat *)data->drawstate.projection); 1107 SDL_memcpy(program->projection, data->drawstate.projection, sizeof(data->drawstate.projection)); 1108 } 1109 } 1110 1111 if (blend != data->drawstate.blend) { 1112 if (blend == SDL_BLENDMODE_NONE) { 1113 data->glDisable(GL_BLEND); 1114 } else { 1115 data->glEnable(GL_BLEND); 1116 data->glBlendFuncSeparate(GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blend)), 1117 GetBlendFunc(SDL_GetBlendModeDstColorFactor(blend)), 1118 GetBlendFunc(SDL_GetBlendModeSrcAlphaFactor(blend)), 1119 GetBlendFunc(SDL_GetBlendModeDstAlphaFactor(blend))); 1120 data->glBlendEquationSeparate(GetBlendEquation(SDL_GetBlendModeColorOperation(blend)), 1121 GetBlendEquation(SDL_GetBlendModeAlphaOperation(blend))); 1122 } 1123 data->drawstate.blend = blend; 1124 } 1125 1126 // all drawing commands use this 1127 { 1128 uintptr_t base = (uintptr_t)vertices + cmd->data.draw.first; // address of first vertex, or base offset when using VBOs. 1129 data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, stride, (const GLvoid *)(base + offsetof(SDL_VertexSolid, position))); 1130 data->glVertexAttribPointer(GLES2_ATTRIBUTE_COLOR, 4, GL_FLOAT, GL_TRUE /* Normalized */, stride, (const GLvoid *)(base + offsetof(SDL_VertexSolid, color))); 1131 } 1132 1133 return true; 1134} 1135 1136static bool SetTextureScaleMode(GLES2_RenderData *data, GLenum textype, SDL_PixelFormat format, SDL_ScaleMode scaleMode) 1137{ 1138 switch (scaleMode) { 1139 case SDL_SCALEMODE_NEAREST: 1140 data->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 1141 data->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 1142 break; 1143 case SDL_SCALEMODE_LINEAR: 1144 if (format == SDL_PIXELFORMAT_INDEX8) { 1145 // We'll do linear sampling in the shader 1146 data->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 1147 data->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 1148 } else { 1149 data->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 1150 data->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 1151 } 1152 break; 1153 case SDL_SCALEMODE_PIXELART: 1154#ifdef OPENGLES_300 1155 if (format == SDL_PIXELFORMAT_INDEX8) { 1156 // We'll do linear sampling in the shader 1157 data->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 1158 data->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 1159 } else { 1160 data->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 1161 data->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 1162 } 1163#else // We don't have the functions we need, fall back to nearest sampling 1164 data->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 1165 data->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 1166#endif 1167 break; 1168 default: 1169 return SDL_SetError("Unknown texture scale mode: %d", scaleMode); 1170 } 1171 return true; 1172} 1173 1174static GLint TranslateAddressMode(SDL_TextureAddressMode addressMode) 1175{ 1176 switch (addressMode) { 1177 case SDL_TEXTURE_ADDRESS_CLAMP: 1178 return GL_CLAMP_TO_EDGE; 1179 case SDL_TEXTURE_ADDRESS_WRAP: 1180 return GL_REPEAT; 1181 default: 1182 SDL_assert(!"Unknown texture address mode"); 1183 return GL_CLAMP_TO_EDGE; 1184 } 1185} 1186 1187static void SetTextureAddressMode(GLES2_RenderData *data, GLenum textype, SDL_TextureAddressMode addressModeU, SDL_TextureAddressMode addressModeV) 1188{ 1189 data->glTexParameteri(textype, GL_TEXTURE_WRAP_S, TranslateAddressMode(addressModeU)); 1190 data->glTexParameteri(textype, GL_TEXTURE_WRAP_T, TranslateAddressMode(addressModeV)); 1191} 1192 1193static bool SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, void *vertices) 1194{ 1195 GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal; 1196 GLES2_ImageSource sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR; 1197 SDL_Texture *texture = cmd->data.draw.texture; 1198 GLES2_TextureData *tdata = (GLES2_TextureData *)texture->internal; 1199 int ret; 1200 1201 // Pick an appropriate shader 1202 if (renderer->target) { 1203 // Check if we need to do color mapping between the source and render target textures 1204 if (renderer->target->format != texture->format) { 1205 switch (texture->format) { 1206 case SDL_PIXELFORMAT_INDEX8: 1207 sourceType = GLES2_IMAGESOURCE_TEXTURE_INDEX8; 1208 break; 1209 case SDL_PIXELFORMAT_BGRA32: 1210 switch (renderer->target->format) { 1211 case SDL_PIXELFORMAT_RGBA32: 1212 case SDL_PIXELFORMAT_RGBX32: 1213 sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB; 1214 break; 1215 case SDL_PIXELFORMAT_BGRX32: 1216 sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR; 1217 break; 1218 default: 1219 break; 1220 } 1221 break; 1222 case SDL_PIXELFORMAT_RGBA32: 1223 switch (renderer->target->format) { 1224 case SDL_PIXELFORMAT_BGRA32: 1225 case SDL_PIXELFORMAT_BGRX32: 1226 sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB; 1227 break; 1228 case SDL_PIXELFORMAT_RGBX32: 1229 sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR; 1230 break; 1231 default: 1232 break; 1233 } 1234 break; 1235 case SDL_PIXELFORMAT_BGRX32: 1236 switch (renderer->target->format) { 1237 case SDL_PIXELFORMAT_RGBA32: 1238 sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB; 1239 break; 1240 case SDL_PIXELFORMAT_BGRA32: 1241 sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR; 1242 break; 1243 case SDL_PIXELFORMAT_RGBX32: 1244 sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB; 1245 break; 1246 default: 1247 break; 1248 } 1249 break; 1250 case SDL_PIXELFORMAT_RGBX32: 1251 switch (renderer->target->format) { 1252 case SDL_PIXELFORMAT_RGBA32: 1253 sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR; 1254 break; 1255 case SDL_PIXELFORMAT_BGRA32: 1256 sourceType = GLES2_IMAGESOURCE_TEXTURE_RGB; 1257 break; 1258 case SDL_PIXELFORMAT_BGRX32: 1259 sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB; 1260 break; 1261 default: 1262 break; 1263 } 1264 break; 1265#ifdef SDL_HAVE_YUV 1266 case SDL_PIXELFORMAT_IYUV: 1267 case SDL_PIXELFORMAT_YV12: 1268 sourceType = GLES2_IMAGESOURCE_TEXTURE_YUV; 1269 break; 1270 case SDL_PIXELFORMAT_NV12: 1271 sourceType = GLES2_IMAGESOURCE_TEXTURE_NV12; 1272 break; 1273 case SDL_PIXELFORMAT_NV21: 1274 sourceType = GLES2_IMAGESOURCE_TEXTURE_NV21; 1275 break; 1276#endif 1277 case SDL_PIXELFORMAT_EXTERNAL_OES: 1278 sourceType = GLES2_IMAGESOURCE_TEXTURE_EXTERNAL_OES; 1279 break; 1280 default: 1281 return SDL_SetError("Unsupported texture format"); 1282 } 1283 } else { 1284 sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR; // Texture formats match, use the non color mapping shader (even if the formats are not ABGR) 1285 } 1286 } else { 1287 switch (texture->format) { 1288 case SDL_PIXELFORMAT_INDEX8: 1289 sourceType = GLES2_IMAGESOURCE_TEXTURE_INDEX8; 1290 break; 1291 case SDL_PIXELFORMAT_BGRA32: 1292 sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB; 1293 break; 1294 case SDL_PIXELFORMAT_RGBA32: 1295 sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR; 1296 break; 1297 case SDL_PIXELFORMAT_BGRX32: 1298 sourceType = GLES2_IMAGESOURCE_TEXTURE_RGB; 1299 break; 1300 case SDL_PIXELFORMAT_RGBX32: 1301 sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR; 1302 break; 1303#ifdef SDL_HAVE_YUV 1304 case SDL_PIXELFORMAT_IYUV: 1305 case SDL_PIXELFORMAT_YV12: 1306 sourceType = GLES2_IMAGESOURCE_TEXTURE_YUV; 1307 break; 1308 case SDL_PIXELFORMAT_NV12: 1309 sourceType = GLES2_IMAGESOURCE_TEXTURE_NV12; 1310 break; 1311 case SDL_PIXELFORMAT_NV21: 1312 sourceType = GLES2_IMAGESOURCE_TEXTURE_NV21; 1313 break; 1314#endif 1315 case SDL_PIXELFORMAT_EXTERNAL_OES: 1316 sourceType = GLES2_IMAGESOURCE_TEXTURE_EXTERNAL_OES; 1317 break; 1318 default: 1319 return SDL_SetError("Unsupported texture format"); 1320 } 1321 } 1322 1323 ret = SetDrawState(data, cmd, sourceType, vertices); 1324 1325 if (texture != data->drawstate.texture) { 1326#ifdef SDL_HAVE_YUV 1327 if (tdata->yuv) { 1328 data->glActiveTexture(GL_TEXTURE2); 1329 data->glBindTexture(tdata->texture_type, tdata->texture_v); 1330 1331 data->glActiveTexture(GL_TEXTURE1); 1332 data->glBindTexture(tdata->texture_type, tdata->texture_u); 1333 1334 data->glActiveTexture(GL_TEXTURE0); 1335 } else if (tdata->nv12) { 1336 data->glActiveTexture(GL_TEXTURE1); 1337 data->glBindTexture(tdata->texture_type, tdata->texture_u); 1338 1339 data->glActiveTexture(GL_TEXTURE0); 1340 } 1341#endif 1342 if (texture->palette) { 1343 GLES2_PaletteData *palette = (GLES2_PaletteData *)texture->palette->internal; 1344 data->glActiveTexture(GL_TEXTURE1); 1345 data->glBindTexture(tdata->texture_type, palette->texture); 1346 1347 data->glActiveTexture(GL_TEXTURE0); 1348 } 1349 data->glBindTexture(tdata->texture_type, tdata->texture); 1350 1351 data->drawstate.texture = texture; 1352 } 1353 1354 if (cmd->data.draw.texture_scale_mode != tdata->texture_scale_mode) { 1355#ifdef SDL_HAVE_YUV 1356 if (tdata->yuv) { 1357 data->glActiveTexture(GL_TEXTURE2); 1358 if (!SetTextureScaleMode(data, tdata->texture_type, texture->format, cmd->data.draw.texture_scale_mode)) { 1359 return false; 1360 } 1361 1362 data->glActiveTexture(GL_TEXTURE1); 1363 if (!SetTextureScaleMode(data, tdata->texture_type, texture->format, cmd->data.draw.texture_scale_mode)) { 1364 return false; 1365 } 1366 1367 data->glActiveTexture(GL_TEXTURE0); 1368 } else if (tdata->nv12) { 1369 data->glActiveTexture(GL_TEXTURE1); 1370 if (!SetTextureScaleMode(data, tdata->texture_type, texture->format, cmd->data.draw.texture_scale_mode)) { 1371 return false; 1372 } 1373 1374 data->glActiveTexture(GL_TEXTURE0); 1375 } 1376#endif 1377 if (texture->palette) { 1378 data->glActiveTexture(GL_TEXTURE1); 1379 if (!SetTextureScaleMode(data, tdata->texture_type, SDL_PIXELFORMAT_UNKNOWN, SDL_SCALEMODE_NEAREST)) { 1380 return false; 1381 } 1382 1383 data->glActiveTexture(GL_TEXTURE0); 1384 } 1385 if (!SetTextureScaleMode(data, tdata->texture_type, texture->format, cmd->data.draw.texture_scale_mode)) { 1386 return false; 1387 } 1388 1389 tdata->texture_scale_mode = cmd->data.draw.texture_scale_mode; 1390 } 1391 1392 if (cmd->data.draw.texture_address_mode_u != tdata->texture_address_mode_u || 1393 cmd->data.draw.texture_address_mode_v != tdata->texture_address_mode_v) { 1394#ifdef SDL_HAVE_YUV 1395 if (tdata->yuv) { 1396 data->glActiveTexture(GL_TEXTURE2); 1397 SetTextureAddressMode(data, tdata->texture_type, cmd->data.draw.texture_address_mode_u, cmd->data.draw.texture_address_mode_v); 1398 1399 data->glActiveTexture(GL_TEXTURE1); 1400 SetTextureAddressMode(data, tdata->texture_type, cmd->data.draw.texture_address_mode_u, cmd->data.draw.texture_address_mode_v); 1401 1402 data->glActiveTexture(GL_TEXTURE0); 1403 } else if (tdata->nv12) { 1404 data->glActiveTexture(GL_TEXTURE1); 1405 SetTextureAddressMode(data, tdata->texture_type, cmd->data.draw.texture_address_mode_u, cmd->data.draw.texture_address_mode_v); 1406 1407 data->glActiveTexture(GL_TEXTURE0); 1408 } 1409#endif 1410 if (texture->palette) { 1411 data->glActiveTexture(GL_TEXTURE1); 1412 SetTextureAddressMode(data, tdata->texture_type, SDL_TEXTURE_ADDRESS_CLAMP, SDL_TEXTURE_ADDRESS_CLAMP); 1413 1414 data->glActiveTexture(GL_TEXTURE0); 1415 } 1416 SetTextureAddressMode(data, tdata->texture_type, cmd->data.draw.texture_address_mode_u, cmd->data.draw.texture_address_mode_v); 1417 1418 tdata->texture_address_mode_u = cmd->data.draw.texture_address_mode_u; 1419 tdata->texture_address_mode_v = cmd->data.draw.texture_address_mode_v; 1420 } 1421 1422 return ret; 1423} 1424 1425static void GLES2_InvalidateCachedState(SDL_Renderer *renderer) 1426{ 1427 GLES2_DrawStateCache *cache = &((GLES2_RenderData *)renderer->internal)->drawstate; 1428 cache->viewport_dirty = true; 1429 cache->texture = NULL; 1430 cache->blend = SDL_BLENDMODE_INVALID; 1431 cache->cliprect_enabled_dirty = true; 1432 cache->cliprect_dirty = true; 1433 cache->texturing_dirty = true; 1434 cache->clear_color_dirty = true; 1435 cache->drawablew = 0; 1436 cache->drawableh = 0; 1437 cache->program = NULL; 1438} 1439 1440static bool GLES2_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize) 1441{ 1442 GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal; 1443 const bool colorswap = (renderer->target && (renderer->target->format == SDL_PIXELFORMAT_BGRA32 || renderer->target->format == SDL_PIXELFORMAT_BGRX32)); 1444 1445#if USE_VERTEX_BUFFER_OBJECTS 1446 const int vboidx = data->current_vertex_buffer; 1447 const GLuint vbo = data->vertex_buffers[vboidx]; 1448#endif 1449 1450 if (!GLES2_ActivateRenderer(renderer)) { 1451 return false; 1452 } 1453 1454 data->drawstate.target = renderer->target; 1455 if (!data->drawstate.target) { 1456 int w, h; 1457 SDL_GetWindowSizeInPixels(renderer->window, &w, &h); 1458 if ((w != data->drawstate.drawablew) || (h != data->drawstate.drawableh)) { 1459 data->drawstate.viewport_dirty = true; // if the window dimensions changed, invalidate the current viewport, etc. 1460 data->drawstate.cliprect_dirty = true; 1461 data->drawstate.drawablew = w; 1462 data->drawstate.drawableh = h; 1463 } 1464 } 1465 1466#if USE_VERTEX_BUFFER_OBJECTS 1467 // upload the new VBO data for this set of commands. 1468 data->glBindBuffer(GL_ARRAY_BUFFER, vbo); 1469 if (data->vertex_buffer_size[vboidx] < vertsize) { 1470 data->glBufferData(GL_ARRAY_BUFFER, vertsize, vertices, GL_STREAM_DRAW); 1471 data->vertex_buffer_size[vboidx] = vertsize; 1472 } else { 1473 data->glBufferSubData(GL_ARRAY_BUFFER, 0, vertsize, vertices); 1474 } 1475 1476 // cycle through a few VBOs so the GL has some time with the data before we replace it. 1477 data->current_vertex_buffer++; 1478 if (data->current_vertex_buffer >= SDL_arraysize(data->vertex_buffers)) { 1479 data->current_vertex_buffer = 0; 1480 } 1481 // attrib pointers will be offsets into the VBO. 1482 vertices = (void *)(uintptr_t)0; // must be the exact value 0, not NULL (the representation of NULL is not guaranteed to be 0). 1483#endif 1484 1485 while (cmd) { 1486 switch (cmd->command) { 1487 case SDL_RENDERCMD_SETDRAWCOLOR: 1488 { 1489 break; 1490 } 1491 1492 case SDL_RENDERCMD_SETVIEWPORT: 1493 { 1494 SDL_Rect *viewport = &data->drawstate.viewport; 1495 if (SDL_memcmp(viewport, &cmd->data.viewport.rect, sizeof(cmd->data.viewport.rect)) != 0) { 1496 SDL_copyp(viewport, &cmd->data.viewport.rect); 1497 data->drawstate.viewport_dirty = true; 1498 data->drawstate.cliprect_dirty = true; 1499 } 1500 break; 1501 } 1502 1503 case SDL_RENDERCMD_SETCLIPRECT: 1504 { 1505 const SDL_Rect *rect = &cmd->data.cliprect.rect; 1506 if (data->drawstate.cliprect_enabled != cmd->data.cliprect.enabled) { 1507 data->drawstate.cliprect_enabled = cmd->data.cliprect.enabled; 1508 data->drawstate.cliprect_enabled_dirty = true; 1509 } 1510 1511 if (SDL_memcmp(&data->drawstate.cliprect, rect, sizeof(*rect)) != 0) { 1512 SDL_copyp(&data->drawstate.cliprect, rect); 1513 data->drawstate.cliprect_dirty = true; 1514 } 1515 break; 1516 } 1517 1518 case SDL_RENDERCMD_CLEAR: 1519 { 1520 const float r = (colorswap ? cmd->data.color.color.b : cmd->data.color.color.r) * cmd->data.color.color_scale; 1521 const float g = cmd->data.color.color.g * cmd->data.color.color_scale; 1522 const float b = (colorswap ? cmd->data.color.color.r : cmd->data.color.color.b) * cmd->data.color.color_scale; 1523 const float a = cmd->data.color.color.a; 1524 if (data->drawstate.clear_color_dirty || 1525 (r != data->drawstate.clear_color.r) || 1526 (g != data->drawstate.clear_color.g) || 1527 (b != data->drawstate.clear_color.b) || 1528 (a != data->drawstate.clear_color.a)) { 1529 data->glClearColor(r, g, b, a); 1530 data->drawstate.clear_color.r = r; 1531 data->drawstate.clear_color.g = g; 1532 data->drawstate.clear_color.b = b; 1533 data->drawstate.clear_color.a = a; 1534 data->drawstate.clear_color_dirty = false; 1535 } 1536 1537 if (data->drawstate.cliprect_enabled || data->drawstate.cliprect_enabled_dirty) { 1538 data->glDisable(GL_SCISSOR_TEST); 1539 data->drawstate.cliprect_enabled_dirty = data->drawstate.cliprect_enabled; 1540 } 1541 1542 data->glClear(GL_COLOR_BUFFER_BIT); 1543 break; 1544 } 1545 1546 case SDL_RENDERCMD_FILL_RECTS: // unused 1547 break; 1548 1549 case SDL_RENDERCMD_COPY: // unused 1550 break; 1551 1552 case SDL_RENDERCMD_COPY_EX: // unused 1553 break; 1554 1555 case SDL_RENDERCMD_DRAW_LINES: 1556 { 1557 if (SetDrawState(data, cmd, GLES2_IMAGESOURCE_SOLID, vertices)) { 1558 size_t count = cmd->data.draw.count; 1559 if (count > 2) { 1560 // joined lines cannot be grouped 1561 data->glDrawArrays(GL_LINE_STRIP, 0, (GLsizei)count); 1562 } else { 1563 // let's group non joined lines 1564 SDL_RenderCommand *finalcmd = cmd; 1565 SDL_RenderCommand *nextcmd = cmd->next; 1566 SDL_BlendMode thisblend = cmd->data.draw.blend; 1567 1568 while (nextcmd) { 1569 const SDL_RenderCommandType nextcmdtype = nextcmd->command; 1570 if (nextcmdtype != SDL_RENDERCMD_DRAW_LINES) { 1571 break; // can't go any further on this draw call, different render command up next. 1572 } else if (nextcmd->data.draw.count != 2) { 1573 break; // can't go any further on this draw call, those are joined lines 1574 } else if (nextcmd->data.draw.blend != thisblend) { 1575 break; // can't go any further on this draw call, different blendmode copy up next. 1576 } else { 1577 finalcmd = nextcmd; // we can combine copy operations here. Mark this one as the furthest okay command. 1578 count += nextcmd->data.draw.count; 1579 } 1580 nextcmd = nextcmd->next; 1581 } 1582 1583 data->glDrawArrays(GL_LINES, 0, (GLsizei)count); 1584 cmd = finalcmd; // skip any copy commands we just combined in here. 1585 } 1586 } 1587 break; 1588 } 1589 1590 case SDL_RENDERCMD_DRAW_POINTS: 1591 case SDL_RENDERCMD_GEOMETRY: 1592 { 1593 /* as long as we have the same copy command in a row, with the 1594 same texture, we can combine them all into a single draw call. */ 1595 SDL_Texture *thistexture = cmd->data.draw.texture; 1596 SDL_BlendMode thisblend = cmd->data.draw.blend; 1597 SDL_ScaleMode thisscalemode = cmd->data.draw.texture_scale_mode; 1598 SDL_TextureAddressMode thisaddressmode_u = cmd->data.draw.texture_address_mode_u; 1599 SDL_TextureAddressMode thisaddressmode_v = cmd->data.draw.texture_address_mode_v; 1600 const SDL_RenderCommandType thiscmdtype = cmd->command; 1601 SDL_RenderCommand *finalcmd = cmd; 1602 SDL_RenderCommand *nextcmd = cmd->next; 1603 size_t count = cmd->data.draw.count; 1604 int ret; 1605 while (nextcmd) { 1606 const SDL_RenderCommandType nextcmdtype = nextcmd->command; 1607 if (nextcmdtype != thiscmdtype) { 1608 break; // can't go any further on this draw call, different render command up next. 1609 } else if (nextcmd->data.draw.texture != thistexture || 1610 nextcmd->data.draw.texture_scale_mode != thisscalemode || 1611 nextcmd->data.draw.texture_address_mode_u != thisaddressmode_u || 1612 nextcmd->data.draw.texture_address_mode_v != thisaddressmode_v || 1613 nextcmd->data.draw.blend != thisblend) { 1614 break; // can't go any further on this draw call, different texture/blendmode copy up next. 1615 } else { 1616 finalcmd = nextcmd; // we can combine copy operations here. Mark this one as the furthest okay command. 1617 count += nextcmd->data.draw.count; 1618 } 1619 nextcmd = nextcmd->next; 1620 } 1621 1622 if (thistexture) { 1623 ret = SetCopyState(renderer, cmd, vertices); 1624 } else { 1625 ret = SetDrawState(data, cmd, GLES2_IMAGESOURCE_SOLID, vertices); 1626 } 1627 1628 if (ret) { 1629 int op = GL_TRIANGLES; // SDL_RENDERCMD_GEOMETRY 1630 if (thiscmdtype == SDL_RENDERCMD_DRAW_POINTS) { 1631 op = GL_POINTS; 1632 } 1633 data->glDrawArrays(op, 0, (GLsizei)count); 1634 } 1635 1636 cmd = finalcmd; // skip any copy commands we just combined in here. 1637 break; 1638 } 1639 1640 case SDL_RENDERCMD_NO_OP: 1641 break; 1642 } 1643 1644 cmd = cmd->next; 1645 } 1646 1647 return GL_CheckError("", renderer); 1648} 1649 1650static void GLES2_DestroyRenderer(SDL_Renderer *renderer) 1651{ 1652 GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal; 1653 1654 // Deallocate everything 1655 if (data) { 1656 GLES2_ActivateRenderer(renderer); 1657 1658 { 1659 int i; 1660 for (i = 0; i < GLES2_SHADER_COUNT; i++) { 1661 GLuint id = data->shader_id_cache[i]; 1662 if (id) { 1663 data->glDeleteShader(id); 1664 } 1665 } 1666 } 1667 { 1668 GLES2_ProgramCacheEntry *entry; 1669 GLES2_ProgramCacheEntry *next; 1670 entry = data->program_cache.head; 1671 while (entry) { 1672 next = entry->next; 1673 data->glDeleteProgram(entry->id); 1674 SDL_free(entry->shader_params); 1675 SDL_free(entry); 1676 entry = next; 1677 } 1678 } 1679 1680 if (data->context) { 1681 while (data->framebuffers) { 1682 GLES2_FBOList *nextnode = data->framebuffers->next; 1683 data->glDeleteFramebuffers(1, &data->framebuffers->FBO); 1684 GL_CheckError("", renderer); 1685 SDL_free(data->framebuffers); 1686 data->framebuffers = nextnode; 1687 } 1688 1689#if USE_VERTEX_BUFFER_OBJECTS 1690 data->glDeleteBuffers(SDL_arraysize(data->vertex_buffers), data->vertex_buffers); 1691 GL_CheckError("", renderer); 1692#endif 1693 1694 SDL_GL_DestroyContext(data->context); 1695 } 1696 1697 SDL_free(data); 1698 } 1699} 1700 1701static bool GLES2_CreatePalette(SDL_Renderer *renderer, SDL_TexturePalette *palette) 1702{ 1703 GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal; 1704 GLES2_PaletteData *palettedata = (GLES2_PaletteData *)SDL_calloc(1, sizeof(*palettedata)); 1705 if (!palettedata) { 1706 return false; 1707 } 1708 palette->internal = palettedata; 1709 1710 data->drawstate.texture = NULL; // we trash this state. 1711 1712 data->glGenTextures(1, &palettedata->texture); 1713 if (!GL_CheckError("glGenTexures()", renderer)) { 1714 return false; 1715 } 1716 data->glActiveTexture(GL_TEXTURE1); 1717 data->glBindTexture(GL_TEXTURE_2D, palettedata->texture); 1718 data->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); 1719 if (!GL_CheckError("glTexImage2D()", renderer)) { 1720 return false; 1721 } 1722 SetTextureScaleMode(data, GL_TEXTURE_2D, SDL_PIXELFORMAT_UNKNOWN, SDL_SCALEMODE_NEAREST); 1723 SetTextureAddressMode(data, GL_TEXTURE_2D, SDL_TEXTURE_ADDRESS_CLAMP, SDL_TEXTURE_ADDRESS_CLAMP); 1724 return true; 1725} 1726 1727static bool GLES2_UpdatePalette(SDL_Renderer *renderer, SDL_TexturePalette *palette, int ncolors, SDL_Color *colors) 1728{ 1729 GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal; 1730 GLES2_PaletteData *palettedata = (GLES2_PaletteData *)palette->internal; 1731 1732 GLES2_ActivateRenderer(renderer); 1733 1734 data->drawstate.texture = NULL; // we trash this state. 1735 1736 data->glBindTexture(GL_TEXTURE_2D, palettedata->texture); 1737 data->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, ncolors, 1, GL_RGBA, GL_UNSIGNED_BYTE, colors); 1738 1739 return GL_CheckError("glTexSubImage2D()", renderer); 1740} 1741 1742static void GLES2_DestroyPalette(SDL_Renderer *renderer, SDL_TexturePalette *palette) 1743{ 1744 GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal; 1745 GLES2_PaletteData *palettedata = (GLES2_PaletteData *)palette->internal; 1746 1747 if (palettedata) { 1748 data->glDeleteTextures(1, &palettedata->texture); 1749 SDL_free(palettedata); 1750 } 1751} 1752 1753static bool GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props) 1754{ 1755 GLES2_RenderData *renderdata = (GLES2_RenderData *)renderer->internal; 1756 GLES2_TextureData *data; 1757 GLenum format; 1758 GLenum type; 1759 1760 GLES2_ActivateRenderer(renderer); 1761 1762 renderdata->drawstate.texture = NULL; // we trash this state. 1763 1764 // Determine the corresponding GLES texture format params 1765 switch (texture->format) { 1766 case SDL_PIXELFORMAT_BGRA32: 1767 case SDL_PIXELFORMAT_RGBA32: 1768 case SDL_PIXELFORMAT_BGRX32: 1769 case SDL_PIXELFORMAT_RGBX32: 1770 format = GL_RGBA; 1771 type = GL_UNSIGNED_BYTE; 1772 break; 1773 case SDL_PIXELFORMAT_INDEX8: 1774#ifdef SDL_HAVE_YUV 1775 case SDL_PIXELFORMAT_IYUV: 1776 case SDL_PIXELFORMAT_YV12: 1777 case SDL_PIXELFORMAT_NV12: 1778 case SDL_PIXELFORMAT_NV21: 1779#endif 1780 format = GL_LUMINANCE; 1781 type = GL_UNSIGNED_BYTE; 1782 break; 1783#ifdef GL_TEXTURE_EXTERNAL_OES 1784 case SDL_PIXELFORMAT_EXTERNAL_OES: 1785 if (renderdata->GL_OES_EGL_image_external_supported) { 1786 format = GL_NONE; 1787 type = GL_NONE; 1788 break; 1789 } 1790 SDL_FALLTHROUGH; 1791#endif 1792 default: 1793 return SDL_SetError("Texture format not supported"); 1794 } 1795 1796 if (texture->format == SDL_PIXELFORMAT_EXTERNAL_OES && 1797 texture->access != SDL_TEXTUREACCESS_STATIC) { 1798 return SDL_SetError("Unsupported texture access for SDL_PIXELFORMAT_EXTERNAL_OES"); 1799 } 1800 1801 // Allocate a texture struct 1802 data = (GLES2_TextureData *)SDL_calloc(1, sizeof(GLES2_TextureData)); 1803 if (!data) { 1804 return false; 1805 } 1806 data->texture = 0; 1807#ifdef GL_TEXTURE_EXTERNAL_OES 1808 data->texture_type = (texture->format == SDL_PIXELFORMAT_EXTERNAL_OES) ? GL_TEXTURE_EXTERNAL_OES : GL_TEXTURE_2D; 1809#else 1810 data->texture_type = GL_TEXTURE_2D; 1811#endif 1812 data->pixel_format = format; 1813 data->pixel_type = type; 1814#ifdef SDL_HAVE_YUV 1815 data->yuv = ((texture->format == SDL_PIXELFORMAT_IYUV) || (texture->format == SDL_PIXELFORMAT_YV12)); 1816 data->nv12 = ((texture->format == SDL_PIXELFORMAT_NV12) || (texture->format == SDL_PIXELFORMAT_NV21)); 1817#endif 1818 data->texture_scale_mode = texture->scaleMode; 1819 data->texture_address_mode_u = SDL_TEXTURE_ADDRESS_CLAMP; 1820 data->texture_address_mode_v = SDL_TEXTURE_ADDRESS_CLAMP; 1821 1822 // Allocate a blob for image renderdata 1823 if (texture->access == SDL_TEXTUREACCESS_STREAMING) { 1824 size_t size; 1825 data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format); 1826 size = (size_t)texture->h * data->pitch; 1827#ifdef SDL_HAVE_YUV 1828 if (data->yuv) { 1829 // Need to add size for the U and V planes 1830 size += 2 * ((texture->h + 1) / 2) * ((data->pitch + 1) / 2); 1831 } else if (data->nv12) { 1832 // Need to add size for the U/V plane 1833 size += 2 * ((texture->h + 1) / 2) * ((data->pitch + 1) / 2); 1834 } 1835#endif 1836 data->pixel_data = SDL_calloc(1, size); 1837 if (!data->pixel_data) { 1838 SDL_free(data); 1839 return false; 1840 } 1841 } 1842 1843 // Allocate the texture 1844 GL_CheckError("", renderer); 1845 1846 data->texel_size[0] = 1.0f / texture->w; 1847 data->texel_size[1] = 1.0f / texture->h; 1848 data->texel_size[2] = texture->w; 1849 data->texel_size[3] = texture->h; 1850 1851#ifdef SDL_HAVE_YUV 1852 if (data->yuv) { 1853 data->texture_v = (GLuint)SDL_GetNumberProperty(create_props, SDL_PROP_TEXTURE_CREATE_OPENGLES2_TEXTURE_V_NUMBER, 0); 1854 if (data->texture_v) { 1855 data->texture_v_external = true; 1856 } else { 1857 renderdata->glGenTextures(1, &data->texture_v); 1858 if (!GL_CheckError("glGenTexures()", renderer)) { 1859 SDL_free(data->pixel_data); 1860 SDL_free(data); 1861 return false; 1862 } 1863 } 1864 renderdata->glActiveTexture(GL_TEXTURE2); 1865 renderdata->glBindTexture(data->texture_type, data->texture_v); 1866 renderdata->glTexImage2D(data->texture_type, 0, format, (texture->w + 1) / 2, (texture->h + 1) / 2, 0, format, type, NULL); 1867 if (!GL_CheckError("glTexImage2D()", renderer)) { 1868 SDL_free(data->pixel_data); 1869 SDL_free(data); 1870 return false; 1871 } 1872 SetTextureScaleMode(renderdata, data->texture_type, texture->format, data->texture_scale_mode); 1873 SetTextureAddressMode(renderdata, data->texture_type, data->texture_address_mode_u, data->texture_address_mode_v); 1874 SDL_SetNumberProperty(SDL_GetTextureProperties(texture), SDL_PROP_TEXTURE_OPENGLES2_TEXTURE_V_NUMBER, data->texture_v); 1875 1876 data->texture_u = (GLuint)SDL_GetNumberProperty(create_props, SDL_PROP_TEXTURE_CREATE_OPENGLES2_TEXTURE_U_NUMBER, 0); 1877 if (data->texture_u) { 1878 data->texture_u_external = true; 1879 } else { 1880 renderdata->glGenTextures(1, &data->texture_u); 1881 if (!GL_CheckError("glGenTexures()", renderer)) { 1882 SDL_free(data->pixel_data); 1883 SDL_free(data); 1884 return false; 1885 } 1886 } 1887 renderdata->glActiveTexture(GL_TEXTURE1); 1888 renderdata->glBindTexture(data->texture_type, data->texture_u); 1889 renderdata->glTexImage2D(data->texture_type, 0, format, (texture->w + 1) / 2, (texture->h + 1) / 2, 0, format, type, NULL); 1890 if (!GL_CheckError("glTexImage2D()", renderer)) { 1891 SDL_free(data->pixel_data); 1892 SDL_free(data); 1893 return false; 1894 } 1895 SetTextureScaleMode(renderdata, data->texture_type, texture->format, data->texture_scale_mode); 1896 SetTextureAddressMode(renderdata, data->texture_type, data->texture_address_mode_u, data->texture_address_mode_v); 1897 SDL_SetNumberProperty(SDL_GetTextureProperties(texture), SDL_PROP_TEXTURE_OPENGLES2_TEXTURE_U_NUMBER, data->texture_u); 1898 1899 if (!SDL_GetYCbCRtoRGBConversionMatrix(texture->colorspace, texture->w, texture->h, 8)) { 1900 SDL_free(data->pixel_data); 1901 SDL_free(data); 1902 return SDL_SetError("Unsupported YUV colorspace"); 1903 } 1904 } else if (data->nv12) { 1905 data->texture_u = (GLuint)SDL_GetNumberProperty(create_props, SDL_PROP_TEXTURE_CREATE_OPENGLES2_TEXTURE_UV_NUMBER, 0); 1906 if (data->texture_u) { 1907 data->texture_u_external = true; 1908 } else { 1909 renderdata->glGenTextures(1, &data->texture_u); 1910 if (!GL_CheckError("glGenTexures()", renderer)) { 1911 SDL_free(data->pixel_data); 1912 SDL_free(data); 1913 return false; 1914 } 1915 } 1916 renderdata->glActiveTexture(GL_TEXTURE1); 1917 renderdata->glBindTexture(data->texture_type, data->texture_u); 1918 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); 1919 if (!GL_CheckError("glTexImage2D()", renderer)) { 1920 SDL_free(data->pixel_data); 1921 SDL_free(data); 1922 return false; 1923 } 1924 SetTextureScaleMode(renderdata, data->texture_type, texture->format, data->texture_scale_mode); 1925 SetTextureAddressMode(renderdata, data->texture_type, data->texture_address_mode_u, data->texture_address_mode_v); 1926 SDL_SetNumberProperty(SDL_GetTextureProperties(texture), SDL_PROP_TEXTURE_OPENGLES2_TEXTURE_UV_NUMBER, data->texture_u); 1927 1928 if (!SDL_GetYCbCRtoRGBConversionMatrix(texture->colorspace, texture->w, texture->h, 8)) { 1929 SDL_free(data->pixel_data); 1930 SDL_free(data); 1931 return SDL_SetError("Unsupported YUV colorspace"); 1932 } 1933 } 1934#endif 1935 1936 data->texture = (GLuint)SDL_GetNumberProperty(create_props, SDL_PROP_TEXTURE_CREATE_OPENGLES2_TEXTURE_NUMBER, 0); 1937 if (data->texture) { 1938 data->texture_external = true; 1939 } else { 1940 renderdata->glGenTextures(1, &data->texture); 1941 if (!GL_CheckError("glGenTexures()", renderer)) { 1942 SDL_free(data->pixel_data); 1943 SDL_free(data); 1944 return false; 1945 } 1946 } 1947 texture->internal = data; 1948 renderdata->glActiveTexture(GL_TEXTURE0); 1949 renderdata->glBindTexture(data->texture_type, data->texture); 1950 if (texture->format != SDL_PIXELFORMAT_EXTERNAL_OES) { 1951 renderdata->glTexImage2D(data->texture_type, 0, format, texture->w, texture->h, 0, format, type, NULL); 1952 if (!GL_CheckError("glTexImage2D()", renderer)) { 1953 return false; 1954 } 1955 } 1956 SetTextureScaleMode(renderdata, data->texture_type, texture->format, data->texture_scale_mode); 1957 SetTextureAddressMode(renderdata, data->texture_type, data->texture_address_mode_u, data->texture_address_mode_v); 1958 SDL_SetNumberProperty(SDL_GetTextureProperties(texture), SDL_PROP_TEXTURE_OPENGLES2_TEXTURE_NUMBER, data->texture); 1959 SDL_SetNumberProperty(SDL_GetTextureProperties(texture), SDL_PROP_TEXTURE_OPENGLES2_TEXTURE_TARGET_NUMBER, data->texture_type); 1960 1961 if (texture->access == SDL_TEXTUREACCESS_TARGET) { 1962 data->fbo = GLES2_GetFBO((GLES2_RenderData *)renderer->internal, texture->w, texture->h); 1963 } else { 1964 data->fbo = NULL; 1965 } 1966 1967 return GL_CheckError("", renderer); 1968} 1969 1970static bool 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) 1971{ 1972 Uint8 *blob = NULL; 1973 Uint8 *src; 1974 size_t src_pitch; 1975 int y; 1976 1977 if ((width == 0) || (height == 0) || (bpp == 0)) { 1978 return true; // nothing to do 1979 } 1980 1981 // Reformat the texture data into a tightly packed array 1982 src_pitch = (size_t)width * bpp; 1983 src = (Uint8 *)pixels; 1984 if ((size_t)pitch != src_pitch) { 1985 blob = (Uint8 *)SDL_malloc(src_pitch * height); 1986 if (!blob) { 1987 return false; 1988 } 1989 src = blob; 1990 for (y = 0; y < height; ++y) { 1991 SDL_memcpy(src, pixels, src_pitch); 1992 src += src_pitch; 1993 pixels = (Uint8 *)pixels + pitch; 1994 } 1995 src = blob; 1996 } 1997 1998 data->glTexSubImage2D(target, 0, xoffset, yoffset, width, height, format, type, src); 1999 SDL_free(blob); 2000 return true; 2001} 2002 2003static bool GLES2_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, 2004 const void *pixels, int pitch) 2005{ 2006 GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal; 2007 GLES2_TextureData *tdata = (GLES2_TextureData *)texture->internal; 2008 2009 GLES2_ActivateRenderer(renderer); 2010 2011 // Bail out if we're supposed to update an empty rectangle 2012 if (rect->w <= 0 || rect->h <= 0) { 2013 return true; 2014 } 2015 2016 data->drawstate.texture = NULL; // we trash this state. 2017 2018 // Create a texture subimage with the supplied data 2019 data->glBindTexture(tdata->texture_type, tdata->texture); 2020 GLES2_TexSubImage2D(data, tdata->texture_type, 2021 rect->x, 2022 rect->y, 2023 rect->w, 2024 rect->h, 2025 tdata->pixel_format, 2026 tdata->pixel_type, 2027 pixels, pitch, SDL_BYTESPERPIXEL(texture->format)); 2028 2029#ifdef SDL_HAVE_YUV 2030 if (tdata->yuv) { 2031 // Skip to the correct offset into the next texture 2032 pixels = (const void *)((const Uint8 *)pixels + rect->h * pitch); 2033 if (texture->format == SDL_PIXELFORMAT_YV12) { 2034 data->glBindTexture(tdata->texture_type, tdata->texture_v); 2035 } else { 2036 data->glBindTexture(tdata->texture_type, tdata->texture_u); 2037 } 2038 GLES2_TexSubImage2D(data, tdata->texture_type, 2039 rect->x / 2, 2040 rect->y / 2, 2041 (rect->w + 1) / 2, 2042 (rect->h + 1) / 2, 2043 tdata->pixel_format, 2044 tdata->pixel_type, 2045 pixels, (pitch + 1) / 2, 1); 2046 2047 // Skip to the correct offset into the next texture 2048 pixels = (const void *)((const Uint8 *)pixels + ((rect->h + 1) / 2) * ((pitch + 1) / 2)); 2049 if (texture->format == SDL_PIXELFORMAT_YV12) { 2050 data->glBindTexture(tdata->texture_type, tdata->texture_u); 2051 } else { 2052 data->glBindTexture(tdata->texture_type, tdata->texture_v); 2053 } 2054 GLES2_TexSubImage2D(data, tdata->texture_type, 2055 rect->x / 2, 2056 rect->y / 2, 2057 (rect->w + 1) / 2, 2058 (rect->h + 1) / 2, 2059 tdata->pixel_format, 2060 tdata->pixel_type, 2061 pixels, (pitch + 1) / 2, 1); 2062 } else if (tdata->nv12) { 2063 // Skip to the correct offset into the next texture 2064 pixels = (const void *)((const Uint8 *)pixels + rect->h * pitch); 2065 data->glBindTexture(tdata->texture_type, tdata->texture_u); 2066 GLES2_TexSubImage2D(data, tdata->texture_type, 2067 rect->x / 2, 2068 rect->y / 2, 2069 (rect->w + 1) / 2, 2070 (rect->h + 1) / 2, 2071 GL_LUMINANCE_ALPHA, 2072 GL_UNSIGNED_BYTE, 2073 pixels, 2 * ((pitch + 1) / 2), 2); 2074 } 2075#endif 2076 2077 return GL_CheckError("glTexSubImage2D()", renderer); 2078} 2079 2080#ifdef SDL_HAVE_YUV 2081static bool GLES2_UpdateTextureYUV(SDL_Renderer *renderer, SDL_Texture *texture, 2082 const SDL_Rect *rect, 2083 const Uint8 *Yplane, int Ypitch, 2084 const Uint8 *Uplane, int Upitch, 2085 const Uint8 *Vplane, int Vpitch) 2086{ 2087 GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal; 2088 GLES2_TextureData *tdata = (GLES2_TextureData *)texture->internal; 2089 2090 GLES2_ActivateRenderer(renderer); 2091 2092 // Bail out if we're supposed to update an empty rectangle 2093 if (rect->w <= 0 || rect->h <= 0) { 2094 return true; 2095 } 2096 2097 data->drawstate.texture = NULL; // we trash this state. 2098 2099 data->glBindTexture(tdata->texture_type, tdata->texture_v); 2100 GLES2_TexSubImage2D(data, tdata->texture_type, 2101 rect->x / 2, 2102 rect->y / 2, 2103 (rect->w + 1) / 2, 2104 (rect->h + 1) / 2, 2105 tdata->pixel_format, 2106 tdata->pixel_type, 2107 Vplane, Vpitch, 1); 2108 2109 data->glBindTexture(tdata->texture_type, tdata->texture_u); 2110 GLES2_TexSubImage2D(data, tdata->texture_type, 2111 rect->x / 2, 2112 rect->y / 2, 2113 (rect->w + 1) / 2, 2114 (rect->h + 1) / 2, 2115 tdata->pixel_format, 2116 tdata->pixel_type, 2117 Uplane, Upitch, 1); 2118 2119 data->glBindTexture(tdata->texture_type, tdata->texture); 2120 GLES2_TexSubImage2D(data, tdata->texture_type, 2121 rect->x, 2122 rect->y, 2123 rect->w, 2124 rect->h, 2125 tdata->pixel_format, 2126 tdata->pixel_type, 2127 Yplane, Ypitch, 1); 2128 2129 return GL_CheckError("glTexSubImage2D()", renderer); 2130} 2131 2132static bool GLES2_UpdateTextureNV(SDL_Renderer *renderer, SDL_Texture *texture, 2133 const SDL_Rect *rect, 2134 const Uint8 *Yplane, int Ypitch, 2135 const Uint8 *UVplane, int UVpitch) 2136{ 2137 GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal; 2138 GLES2_TextureData *tdata = (GLES2_TextureData *)texture->internal; 2139 2140 GLES2_ActivateRenderer(renderer); 2141 2142 // Bail out if we're supposed to update an empty rectangle 2143 if (rect->w <= 0 || rect->h <= 0) { 2144 return true; 2145 } 2146 2147 data->drawstate.texture = NULL; // we trash this state. 2148 2149 data->glBindTexture(tdata->texture_type, tdata->texture_u); 2150 GLES2_TexSubImage2D(data, tdata->texture_type, 2151 rect->x / 2, 2152 rect->y / 2, 2153 (rect->w + 1) / 2, 2154 (rect->h + 1) / 2, 2155 GL_LUMINANCE_ALPHA, 2156 GL_UNSIGNED_BYTE, 2157 UVplane, UVpitch, 2); 2158 2159 data->glBindTexture(tdata->texture_type, tdata->texture); 2160 GLES2_TexSubImage2D(data, tdata->texture_type, 2161 rect->x, 2162 rect->y, 2163 rect->w, 2164 rect->h, 2165 tdata->pixel_format, 2166 tdata->pixel_type, 2167 Yplane, Ypitch, 1); 2168 2169 return GL_CheckError("glTexSubImage2D()", renderer); 2170} 2171#endif 2172 2173static bool GLES2_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, 2174 void **pixels, int *pitch) 2175{ 2176 GLES2_TextureData *tdata = (GLES2_TextureData *)texture->internal; 2177 2178 // Retrieve the buffer/pitch for the specified region 2179 *pixels = (Uint8 *)tdata->pixel_data + 2180 (tdata->pitch * rect->y) + 2181 (rect->x * SDL_BYTESPERPIXEL(texture->format)); 2182 *pitch = tdata->pitch; 2183 2184 return true; 2185} 2186 2187static void GLES2_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture) 2188{ 2189 GLES2_TextureData *tdata = (GLES2_TextureData *)texture->internal; 2190 SDL_Rect rect; 2191 2192 // We do whole texture updates, at least for now 2193 rect.x = 0; 2194 rect.y = 0; 2195 rect.w = texture->w; 2196 rect.h = texture->h; 2197 GLES2_UpdateTexture(renderer, texture, &rect, tdata->pixel_data, tdata->pitch); 2198} 2199 2200static bool GLES2_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture) 2201{ 2202 GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal; 2203 GLES2_TextureData *texturedata = NULL; 2204 GLenum status; 2205 2206 data->drawstate.viewport_dirty = true; 2207 2208 if (!texture) { 2209 data->glBindFramebuffer(GL_FRAMEBUFFER, data->window_framebuffer); 2210 } else { 2211 texturedata = (GLES2_TextureData *)texture->internal; 2212 data->glBindFramebuffer(GL_FRAMEBUFFER, texturedata->fbo->FBO); 2213 // TODO: check if texture pixel format allows this operation 2214 data->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texturedata->texture_type, texturedata->texture, 0); 2215 // Check FBO status 2216 status = data->glCheckFramebufferStatus(GL_FRAMEBUFFER); 2217 if (status != GL_FRAMEBUFFER_COMPLETE) { 2218 return SDL_SetError("glFramebufferTexture2D() failed"); 2219 } 2220 } 2221 return true; 2222} 2223 2224static void GLES2_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture) 2225{ 2226 GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal; 2227 GLES2_TextureData *tdata = (GLES2_TextureData *)texture->internal; 2228 2229 GLES2_ActivateRenderer(renderer); 2230 2231 if (data->drawstate.texture == texture) { 2232 data->drawstate.texture = NULL; 2233 data->drawstate.shader_params = NULL; 2234 } 2235 if (data->drawstate.target == texture) { 2236 data->drawstate.target = NULL; 2237 } 2238 2239 // Destroy the texture 2240 if (tdata) { 2241 if (tdata->texture && !tdata->texture_external) { 2242 data->glDeleteTextures(1, &tdata->texture); 2243 } 2244#ifdef SDL_HAVE_YUV 2245 if (tdata->texture_v && !tdata->texture_v_external) { 2246 data->glDeleteTextures(1, &tdata->texture_v); 2247 } 2248 if (tdata->texture_u && !tdata->texture_u_external) { 2249 data->glDeleteTextures(1, &tdata->texture_u); 2250 } 2251#endif 2252 SDL_free(tdata->pixel_data); 2253 SDL_free(tdata); 2254 texture->internal = NULL; 2255 } 2256} 2257 2258static SDL_Surface *GLES2_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect) 2259{ 2260 GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal; 2261 SDL_PixelFormat format = renderer->target ? renderer->target->format : SDL_PIXELFORMAT_RGBA32; 2262 SDL_Surface *surface; 2263 2264 surface = SDL_CreateSurface(rect->w, rect->h, format); 2265 if (!surface) { 2266 return NULL; 2267 } 2268 2269 int y = rect->y; 2270 if (!renderer->target) { 2271 int w, h; 2272 SDL_GetRenderOutputSize(renderer, &w, &h); 2273 y = (h - y) - rect->h; 2274 } 2275 2276 data->glReadPixels(rect->x, y, rect->w, rect->h, GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels); 2277 if (!GL_CheckError("glReadPixels()", renderer)) { 2278 SDL_DestroySurface(surface); 2279 return NULL; 2280 } 2281 2282 // Flip the rows to be top-down if necessary 2283 if (!renderer->target) { 2284 SDL_FlipSurface(surface, SDL_FLIP_VERTICAL); 2285 } 2286 return surface; 2287} 2288 2289static bool GLES2_RenderPresent(SDL_Renderer *renderer) 2290{ 2291 // Tell the video driver to swap buffers 2292 return SDL_GL_SwapWindow(renderer->window); 2293} 2294 2295static bool GLES2_SetVSync(SDL_Renderer *renderer, const int vsync) 2296{ 2297 int interval = 0; 2298 2299 if (!SDL_GL_SetSwapInterval(vsync)) { 2300 return false; 2301 } 2302 2303 if (!SDL_GL_GetSwapInterval(&interval)) { 2304 return false; 2305 } 2306 2307 if (interval != vsync) { 2308 return SDL_Unsupported(); 2309 } 2310 return true; 2311} 2312 2313/************************************************************************************************* 2314 * Renderer instantiation * 2315 *************************************************************************************************/ 2316 2317static bool GLES2_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_PropertiesID create_props) 2318{ 2319 GLES2_RenderData *data = NULL; 2320 SDL_WindowFlags window_flags = 0; 2321 GLint window_framebuffer; 2322 GLint value; 2323 int profile_mask = 0, major = 0, minor = 0; 2324 bool changed_window = false; 2325 2326 SDL_SetupRendererColorspace(renderer, create_props); 2327 2328 if (renderer->output_colorspace != SDL_COLORSPACE_SRGB) { 2329 SDL_SetError("Unsupported output colorspace"); 2330 goto error; 2331 } 2332 2333 if (!SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profile_mask)) { 2334 goto error; 2335 } 2336 if (!SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major)) { 2337 goto error; 2338 } 2339 if (!SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor)) { 2340 goto error; 2341 } 2342 2343 SDL_SyncWindow(window); 2344 window_flags = SDL_GetWindowFlags(window); 2345 2346 // OpenGL ES 3.0 is a superset of OpenGL ES 2.0 2347 if (!(window_flags & SDL_WINDOW_OPENGL) || 2348 profile_mask != SDL_GL_CONTEXT_PROFILE_ES || major < RENDERER_CONTEXT_MAJOR) { 2349 2350 changed_window = true; 2351 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); 2352 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, RENDERER_CONTEXT_MAJOR); 2353 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, RENDERER_CONTEXT_MINOR); 2354 2355 if (!SDL_ReconfigureWindow(window, (window_flags & ~(SDL_WINDOW_VULKAN | SDL_WINDOW_METAL)) | SDL_WINDOW_OPENGL)) { 2356 goto error; 2357 } 2358 } 2359 2360 data = (GLES2_RenderData *)SDL_calloc(1, sizeof(GLES2_RenderData)); 2361 if (!data) { 2362 goto error; 2363 } 2364 renderer->internal = data; 2365 GLES2_InvalidateCachedState(renderer); 2366 renderer->window = window; 2367 2368 // Populate the function pointers for the module 2369 renderer->WindowEvent = GLES2_WindowEvent; 2370 renderer->SupportsBlendMode = GLES2_SupportsBlendMode; 2371 renderer->CreatePalette = GLES2_CreatePalette; 2372 renderer->UpdatePalette = GLES2_UpdatePalette; 2373 renderer->DestroyPalette = GLES2_DestroyPalette; 2374 renderer->CreateTexture = GLES2_CreateTexture; 2375 renderer->UpdateTexture = GLES2_UpdateTexture; 2376#ifdef SDL_HAVE_YUV 2377 renderer->UpdateTextureYUV = GLES2_UpdateTextureYUV; 2378 renderer->UpdateTextureNV = GLES2_UpdateTextureNV; 2379#endif 2380 renderer->LockTexture = GLES2_LockTexture; 2381 renderer->UnlockTexture = GLES2_UnlockTexture; 2382 renderer->SetRenderTarget = GLES2_SetRenderTarget; 2383 renderer->QueueSetViewport = GLES2_QueueNoOp; 2384 renderer->QueueSetDrawColor = GLES2_QueueNoOp; 2385 renderer->QueueDrawPoints = GLES2_QueueDrawPoints; 2386 renderer->QueueDrawLines = GLES2_QueueDrawLines; 2387 renderer->QueueGeometry = GLES2_QueueGeometry; 2388 renderer->InvalidateCachedState = GLES2_InvalidateCachedState; 2389 renderer->RunCommandQueue = GLES2_RunCommandQueue; 2390 renderer->RenderReadPixels = GLES2_RenderReadPixels; 2391 renderer->RenderPresent = GLES2_RenderPresent; 2392 renderer->DestroyTexture = GLES2_DestroyTexture; 2393 renderer->DestroyRenderer = GLES2_DestroyRenderer; 2394 renderer->SetVSync = GLES2_SetVSync; 2395 renderer->name = GLES2_RenderDriver.name; 2396 2397 // Create an OpenGL ES 2.0 context 2398 data->context = SDL_GL_CreateContext(window); 2399 if (!data->context) { 2400 goto error; 2401 } 2402 if (!SDL_GL_MakeCurrent(window, data->context)) { 2403 goto error; 2404 } 2405 2406 if (!GLES2_LoadFunctions(data)) { 2407 goto error; 2408 } 2409 2410 if (!GLES2_CacheShaders(data)) { 2411 goto error; 2412 } 2413 2414 // Check for debug output support 2415 if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_FLAGS, &value) && 2416 (value & SDL_GL_CONTEXT_DEBUG_FLAG)) { 2417 data->debug_enabled = true; 2418 } 2419 2420 value = 0; 2421 data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value); 2422 SDL_SetNumberProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_MAX_TEXTURE_SIZE_NUMBER, value); 2423 2424#if USE_VERTEX_BUFFER_OBJECTS 2425 // we keep a few of these and cycle through them, so data can live for a few frames. 2426 data->glGenBuffers(SDL_arraysize(data->vertex_buffers), data->vertex_buffers); 2427#endif 2428 2429 data->framebuffers = NULL; 2430 data->glGetIntegerv(GL_FRAMEBUFFER_BINDING, &window_framebuffer); 2431 data->window_framebuffer = (GLuint)window_framebuffer; 2432 2433 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_BGRA32); // SDL_PIXELFORMAT_ARGB8888 on little endian systems 2434 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBA32); 2435 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_BGRX32); 2436 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBX32); 2437 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_INDEX8); 2438#ifdef SDL_HAVE_YUV 2439 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_YV12); 2440 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_IYUV); 2441 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_NV12); 2442 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_NV21); 2443#endif 2444#ifdef GL_TEXTURE_EXTERNAL_OES 2445 if (SDL_GL_ExtensionSupported("GL_OES_EGL_image_external")) { 2446 data->GL_OES_EGL_image_external_supported = true; 2447 if (!GLES2_CacheShader(data, GLES2_SHADER_FRAGMENT_TEXTURE_EXTERNAL_OES, GL_FRAGMENT_SHADER)) { 2448 goto error; 2449 } 2450 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_EXTERNAL_OES); 2451 } 2452#endif 2453 2454 if (SDL_GL_ExtensionSupported("GL_EXT_blend_minmax")) { 2455 data->GL_EXT_blend_minmax_supported = true; 2456 } 2457 2458 // Full NPOT textures (that can use GL_REPEAT, etc) are a core feature of GLES3, 2459 // and an extension in GLES2. 2460 if ((major < 3) && !SDL_GL_ExtensionSupported("GL_ARB_texture_non_power_of_two")) { 2461 renderer->npot_texture_wrap_unsupported = true; 2462 } 2463 2464 // Set up parameters for rendering 2465 data->glDisable(GL_DEPTH_TEST); 2466 data->glDisable(GL_CULL_FACE); 2467 data->glActiveTexture(GL_TEXTURE0); 2468 data->glPixelStorei(GL_PACK_ALIGNMENT, 1); 2469 data->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 2470 2471 data->glEnableVertexAttribArray(GLES2_ATTRIBUTE_POSITION); 2472 data->glEnableVertexAttribArray(GLES2_ATTRIBUTE_COLOR); 2473 data->glDisableVertexAttribArray(GLES2_ATTRIBUTE_TEXCOORD); 2474 2475 data->glClearColor(1.0f, 1.0f, 1.0f, 1.0f); 2476 2477 data->drawstate.clear_color.r = 1.0f; 2478 data->drawstate.clear_color.g = 1.0f; 2479 data->drawstate.clear_color.b = 1.0f; 2480 data->drawstate.clear_color.a = 1.0f; 2481 data->drawstate.projection[3][0] = -1.0f; 2482 data->drawstate.projection[3][3] = 1.0f; 2483 2484 GL_CheckError("", renderer); 2485 2486 return true; 2487 2488error: 2489 if (changed_window) { 2490 // Uh oh, better try to put it back... 2491 char *error = SDL_strdup(SDL_GetError()); 2492 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profile_mask); 2493 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major); 2494 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minor); 2495 SDL_RecreateWindow(window, window_flags); 2496 SDL_SetError("%s", error); 2497 SDL_free(error); 2498 } 2499 return false; 2500} 2501 2502SDL_RenderDriver GLES2_RenderDriver = { 2503 GLES2_CreateRenderer, "opengles2" 2504}; 2505 2506#endif // SDL_VIDEO_RENDER_OGL_ES2 2507[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.