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