SDL_render_gles.c (42420B)
1 /* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20 */ 21 #include "../../SDL_internal.h" 22 23 #if SDL_VIDEO_RENDER_OGL_ES && !SDL_RENDER_DISABLED 24 25 #include "SDL_hints.h" 26 #include "SDL_opengles.h" 27 #include "../SDL_sysrender.h" 28 29 /* To prevent unnecessary window recreation, 30 * these should match the defaults selected in SDL_GL_ResetAttributes 31 */ 32 33 #define RENDERER_CONTEXT_MAJOR 1 34 #define RENDERER_CONTEXT_MINOR 1 35 36 #if defined(SDL_VIDEO_DRIVER_PANDORA) 37 38 /* Empty function stub to get OpenGL ES 1.x support without */ 39 /* OpenGL ES extension GL_OES_draw_texture supported */ 40 GL_API void GL_APIENTRY 41 glDrawTexiOES(GLint x, GLint y, GLint z, GLint width, GLint height) 42 { 43 return; 44 } 45 46 #endif /* SDL_VIDEO_DRIVER_PANDORA */ 47 48 /* OpenGL ES 1.1 renderer implementation, based on the OpenGL renderer */ 49 50 /* Used to re-create the window with OpenGL ES capability */ 51 extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags); 52 53 static const float inv255f = 1.0f / 255.0f; 54 55 typedef struct GLES_FBOList GLES_FBOList; 56 57 struct GLES_FBOList 58 { 59 Uint32 w, h; 60 GLuint FBO; 61 GLES_FBOList *next; 62 }; 63 64 typedef struct 65 { 66 SDL_Rect viewport; 67 SDL_bool viewport_dirty; 68 SDL_Texture *texture; 69 SDL_Texture *target; 70 int drawablew; 71 int drawableh; 72 SDL_BlendMode blend; 73 SDL_bool cliprect_enabled_dirty; 74 SDL_bool cliprect_enabled; 75 SDL_bool cliprect_dirty; 76 SDL_Rect cliprect; 77 SDL_bool texturing; 78 Uint32 color; 79 Uint32 clear_color; 80 } GLES_DrawStateCache; 81 82 typedef struct 83 { 84 SDL_GLContext context; 85 86 #define SDL_PROC(ret,func,params) ret (APIENTRY *func) params; 87 #define SDL_PROC_OES SDL_PROC 88 #include "SDL_glesfuncs.h" 89 #undef SDL_PROC 90 #undef SDL_PROC_OES 91 SDL_bool GL_OES_framebuffer_object_supported; 92 GLES_FBOList *framebuffers; 93 GLuint window_framebuffer; 94 95 SDL_bool GL_OES_blend_func_separate_supported; 96 SDL_bool GL_OES_blend_equation_separate_supported; 97 SDL_bool GL_OES_blend_subtract_supported; 98 99 GLES_DrawStateCache drawstate; 100 } GLES_RenderData; 101 102 typedef struct 103 { 104 GLuint texture; 105 GLenum type; 106 GLfloat texw; 107 GLfloat texh; 108 GLenum format; 109 GLenum formattype; 110 void *pixels; 111 int pitch; 112 GLES_FBOList *fbo; 113 } GLES_TextureData; 114 115 static int 116 GLES_SetError(const char *prefix, GLenum result) 117 { 118 const char *error; 119 120 switch (result) { 121 case GL_NO_ERROR: 122 error = "GL_NO_ERROR"; 123 break; 124 case GL_INVALID_ENUM: 125 error = "GL_INVALID_ENUM"; 126 break; 127 case GL_INVALID_VALUE: 128 error = "GL_INVALID_VALUE"; 129 break; 130 case GL_INVALID_OPERATION: 131 error = "GL_INVALID_OPERATION"; 132 break; 133 case GL_STACK_OVERFLOW: 134 error = "GL_STACK_OVERFLOW"; 135 break; 136 case GL_STACK_UNDERFLOW: 137 error = "GL_STACK_UNDERFLOW"; 138 break; 139 case GL_OUT_OF_MEMORY: 140 error = "GL_OUT_OF_MEMORY"; 141 break; 142 default: 143 error = "UNKNOWN"; 144 break; 145 } 146 return SDL_SetError("%s: %s", prefix, error); 147 } 148 149 static int GLES_LoadFunctions(GLES_RenderData * data) 150 { 151 #if SDL_VIDEO_DRIVER_UIKIT 152 #define __SDL_NOGETPROCADDR__ 153 #elif SDL_VIDEO_DRIVER_ANDROID 154 #define __SDL_NOGETPROCADDR__ 155 #elif SDL_VIDEO_DRIVER_PANDORA 156 #define __SDL_NOGETPROCADDR__ 157 #endif 158 159 #ifdef __SDL_NOGETPROCADDR__ 160 #define SDL_PROC(ret,func,params) data->func=func; 161 #define SDL_PROC_OES(ret,func,params) data->func=func; 162 #else 163 #define SDL_PROC(ret,func,params) \ 164 do { \ 165 data->func = SDL_GL_GetProcAddress(#func); \ 166 if ( ! data->func ) { \ 167 return SDL_SetError("Couldn't load GLES function %s: %s", #func, SDL_GetError()); \ 168 } \ 169 } while ( 0 ); 170 #define SDL_PROC_OES(ret,func,params) \ 171 do { \ 172 data->func = SDL_GL_GetProcAddress(#func); \ 173 } while ( 0 ); 174 #endif /* __SDL_NOGETPROCADDR__ */ 175 176 #include "SDL_glesfuncs.h" 177 #undef SDL_PROC 178 #undef SDL_PROC_OES 179 return 0; 180 } 181 182 static GLES_FBOList * 183 GLES_GetFBO(GLES_RenderData *data, Uint32 w, Uint32 h) 184 { 185 GLES_FBOList *result = data->framebuffers; 186 while ((result) && ((result->w != w) || (result->h != h)) ) { 187 result = result->next; 188 } 189 if (result == NULL) { 190 result = SDL_malloc(sizeof(GLES_FBOList)); 191 result->w = w; 192 result->h = h; 193 data->glGenFramebuffersOES(1, &result->FBO); 194 result->next = data->framebuffers; 195 data->framebuffers = result; 196 } 197 return result; 198 } 199 200 201 static int 202 GLES_ActivateRenderer(SDL_Renderer * renderer) 203 { 204 GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata; 205 206 if (SDL_GL_GetCurrentContext() != data->context) { 207 if (SDL_GL_MakeCurrent(renderer->window, data->context) < 0) { 208 return -1; 209 } 210 } 211 212 return 0; 213 } 214 215 static void 216 GLES_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event) 217 { 218 GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata; 219 220 if (event->event == SDL_WINDOWEVENT_MINIMIZED) { 221 /* According to Apple documentation, we need to finish drawing NOW! */ 222 data->glFinish(); 223 } 224 } 225 226 static int 227 GLES_GetOutputSize(SDL_Renderer * renderer, int *w, int *h) 228 { 229 SDL_GL_GetDrawableSize(renderer->window, w, h); 230 return 0; 231 } 232 233 static GLenum GetBlendFunc(SDL_BlendFactor factor) 234 { 235 switch (factor) { 236 case SDL_BLENDFACTOR_ZERO: 237 return GL_ZERO; 238 case SDL_BLENDFACTOR_ONE: 239 return GL_ONE; 240 case SDL_BLENDFACTOR_SRC_COLOR: 241 return GL_SRC_COLOR; 242 case SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR: 243 return GL_ONE_MINUS_SRC_COLOR; 244 case SDL_BLENDFACTOR_SRC_ALPHA: 245 return GL_SRC_ALPHA; 246 case SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA: 247 return GL_ONE_MINUS_SRC_ALPHA; 248 case SDL_BLENDFACTOR_DST_COLOR: 249 return GL_DST_COLOR; 250 case SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR: 251 return GL_ONE_MINUS_DST_COLOR; 252 case SDL_BLENDFACTOR_DST_ALPHA: 253 return GL_DST_ALPHA; 254 case SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA: 255 return GL_ONE_MINUS_DST_ALPHA; 256 default: 257 return GL_INVALID_ENUM; 258 } 259 } 260 261 static GLenum GetBlendEquation(SDL_BlendOperation operation) 262 { 263 switch (operation) { 264 case SDL_BLENDOPERATION_ADD: 265 return GL_FUNC_ADD_OES; 266 case SDL_BLENDOPERATION_SUBTRACT: 267 return GL_FUNC_SUBTRACT_OES; 268 case SDL_BLENDOPERATION_REV_SUBTRACT: 269 return GL_FUNC_REVERSE_SUBTRACT_OES; 270 default: 271 return GL_INVALID_ENUM; 272 } 273 } 274 275 static SDL_bool 276 GLES_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode) 277 { 278 GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata; 279 SDL_BlendFactor srcColorFactor = SDL_GetBlendModeSrcColorFactor(blendMode); 280 SDL_BlendFactor srcAlphaFactor = SDL_GetBlendModeSrcAlphaFactor(blendMode); 281 SDL_BlendOperation colorOperation = SDL_GetBlendModeColorOperation(blendMode); 282 SDL_BlendFactor dstColorFactor = SDL_GetBlendModeDstColorFactor(blendMode); 283 SDL_BlendFactor dstAlphaFactor = SDL_GetBlendModeDstAlphaFactor(blendMode); 284 SDL_BlendOperation alphaOperation = SDL_GetBlendModeAlphaOperation(blendMode); 285 286 if (GetBlendFunc(srcColorFactor) == GL_INVALID_ENUM || 287 GetBlendFunc(srcAlphaFactor) == GL_INVALID_ENUM || 288 GetBlendEquation(colorOperation) == GL_INVALID_ENUM || 289 GetBlendFunc(dstColorFactor) == GL_INVALID_ENUM || 290 GetBlendFunc(dstAlphaFactor) == GL_INVALID_ENUM || 291 GetBlendEquation(alphaOperation) == GL_INVALID_ENUM) { 292 return SDL_FALSE; 293 } 294 if ((srcColorFactor != srcAlphaFactor || dstColorFactor != dstAlphaFactor) && !data->GL_OES_blend_func_separate_supported) { 295 return SDL_FALSE; 296 } 297 if (colorOperation != alphaOperation && !data->GL_OES_blend_equation_separate_supported) { 298 return SDL_FALSE; 299 } 300 if (colorOperation != SDL_BLENDOPERATION_ADD && !data->GL_OES_blend_subtract_supported) { 301 return SDL_FALSE; 302 } 303 return SDL_TRUE; 304 } 305 306 static SDL_INLINE int 307 power_of_2(int input) 308 { 309 int value = 1; 310 311 while (value < input) { 312 value <<= 1; 313 } 314 return value; 315 } 316 317 static int 318 GLES_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) 319 { 320 GLES_RenderData *renderdata = (GLES_RenderData *) renderer->driverdata; 321 GLES_TextureData *data; 322 GLint internalFormat; 323 GLenum format, type; 324 int texture_w, texture_h; 325 GLenum scaleMode; 326 GLenum result; 327 328 GLES_ActivateRenderer(renderer); 329 330 switch (texture->format) { 331 case SDL_PIXELFORMAT_ABGR8888: 332 internalFormat = GL_RGBA; 333 format = GL_RGBA; 334 type = GL_UNSIGNED_BYTE; 335 break; 336 default: 337 return SDL_SetError("Texture format not supported"); 338 } 339 340 data = (GLES_TextureData *) SDL_calloc(1, sizeof(*data)); 341 if (!data) { 342 return SDL_OutOfMemory(); 343 } 344 345 if (texture->access == SDL_TEXTUREACCESS_STREAMING) { 346 data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format); 347 data->pixels = SDL_calloc(1, texture->h * data->pitch); 348 if (!data->pixels) { 349 SDL_free(data); 350 return SDL_OutOfMemory(); 351 } 352 } 353 354 355 if (texture->access == SDL_TEXTUREACCESS_TARGET) { 356 if (!renderdata->GL_OES_framebuffer_object_supported) { 357 SDL_free(data); 358 return SDL_SetError("GL_OES_framebuffer_object not supported"); 359 } 360 data->fbo = GLES_GetFBO(renderer->driverdata, texture->w, texture->h); 361 } else { 362 data->fbo = NULL; 363 } 364 365 366 renderdata->glGetError(); 367 renderdata->glEnable(GL_TEXTURE_2D); 368 renderdata->glGenTextures(1, &data->texture); 369 result = renderdata->glGetError(); 370 if (result != GL_NO_ERROR) { 371 SDL_free(data); 372 return GLES_SetError("glGenTextures()", result); 373 } 374 375 data->type = GL_TEXTURE_2D; 376 /* no NPOV textures allowed in OpenGL ES (yet) */ 377 texture_w = power_of_2(texture->w); 378 texture_h = power_of_2(texture->h); 379 data->texw = (GLfloat) texture->w / texture_w; 380 data->texh = (GLfloat) texture->h / texture_h; 381 382 data->format = format; 383 data->formattype = type; 384 scaleMode = (texture->scaleMode == SDL_ScaleModeNearest) ? GL_NEAREST : GL_LINEAR; 385 renderdata->glBindTexture(data->type, data->texture); 386 renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER, scaleMode); 387 renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER, scaleMode); 388 renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 389 renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 390 391 renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w, 392 texture_h, 0, format, type, NULL); 393 renderdata->glDisable(GL_TEXTURE_2D); 394 renderdata->drawstate.texture = texture; 395 renderdata->drawstate.texturing = SDL_FALSE; 396 397 result = renderdata->glGetError(); 398 if (result != GL_NO_ERROR) { 399 SDL_free(data); 400 return GLES_SetError("glTexImage2D()", result); 401 } 402 403 texture->driverdata = data; 404 return 0; 405 } 406 407 static int 408 GLES_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, 409 const SDL_Rect * rect, const void *pixels, int pitch) 410 { 411 GLES_RenderData *renderdata = (GLES_RenderData *) renderer->driverdata; 412 GLES_TextureData *data = (GLES_TextureData *) texture->driverdata; 413 Uint8 *blob = NULL; 414 Uint8 *src; 415 int srcPitch; 416 int y; 417 418 GLES_ActivateRenderer(renderer); 419 420 /* Bail out if we're supposed to update an empty rectangle */ 421 if (rect->w <= 0 || rect->h <= 0) { 422 return 0; 423 } 424 425 /* Reformat the texture data into a tightly packed array */ 426 srcPitch = rect->w * SDL_BYTESPERPIXEL(texture->format); 427 src = (Uint8 *)pixels; 428 if (pitch != srcPitch) { 429 blob = (Uint8 *)SDL_malloc(srcPitch * rect->h); 430 if (!blob) { 431 return SDL_OutOfMemory(); 432 } 433 src = blob; 434 for (y = 0; y < rect->h; ++y) { 435 SDL_memcpy(src, pixels, srcPitch); 436 src += srcPitch; 437 pixels = (Uint8 *)pixels + pitch; 438 } 439 src = blob; 440 } 441 442 /* Create a texture subimage with the supplied data */ 443 renderdata->glGetError(); 444 renderdata->glEnable(data->type); 445 renderdata->glBindTexture(data->type, data->texture); 446 renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 447 renderdata->glTexSubImage2D(data->type, 448 0, 449 rect->x, 450 rect->y, 451 rect->w, 452 rect->h, 453 data->format, 454 data->formattype, 455 src); 456 renderdata->glDisable(data->type); 457 SDL_free(blob); 458 459 renderdata->drawstate.texture = texture; 460 renderdata->drawstate.texturing = SDL_FALSE; 461 462 if (renderdata->glGetError() != GL_NO_ERROR) { 463 return SDL_SetError("Failed to update texture"); 464 } 465 return 0; 466 } 467 468 static int 469 GLES_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, 470 const SDL_Rect * rect, void **pixels, int *pitch) 471 { 472 GLES_TextureData *data = (GLES_TextureData *) texture->driverdata; 473 474 *pixels = 475 (void *) ((Uint8 *) data->pixels + rect->y * data->pitch + 476 rect->x * SDL_BYTESPERPIXEL(texture->format)); 477 *pitch = data->pitch; 478 return 0; 479 } 480 481 static void 482 GLES_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture) 483 { 484 GLES_TextureData *data = (GLES_TextureData *) texture->driverdata; 485 SDL_Rect rect; 486 487 /* We do whole texture updates, at least for now */ 488 rect.x = 0; 489 rect.y = 0; 490 rect.w = texture->w; 491 rect.h = texture->h; 492 GLES_UpdateTexture(renderer, texture, &rect, data->pixels, data->pitch); 493 } 494 495 static void 496 GLES_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture, SDL_ScaleMode scaleMode) 497 { 498 GLES_RenderData *renderdata = (GLES_RenderData *) renderer->driverdata; 499 GLES_TextureData *data = (GLES_TextureData *) texture->driverdata; 500 GLenum glScaleMode = (scaleMode == SDL_ScaleModeNearest) ? GL_NEAREST : GL_LINEAR; 501 502 renderdata->glBindTexture(data->type, data->texture); 503 renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER, glScaleMode); 504 renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER, glScaleMode); 505 } 506 507 static int 508 GLES_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture) 509 { 510 GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata; 511 GLES_TextureData *texturedata = NULL; 512 GLenum status; 513 514 if (!data->GL_OES_framebuffer_object_supported) { 515 return SDL_SetError("Can't enable render target support in this renderer"); 516 } 517 518 data->drawstate.viewport_dirty = SDL_TRUE; 519 520 if (texture == NULL) { 521 data->glBindFramebufferOES(GL_FRAMEBUFFER_OES, data->window_framebuffer); 522 return 0; 523 } 524 525 texturedata = (GLES_TextureData *) texture->driverdata; 526 data->glBindFramebufferOES(GL_FRAMEBUFFER_OES, texturedata->fbo->FBO); 527 /* TODO: check if texture pixel format allows this operation */ 528 data->glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, texturedata->type, texturedata->texture, 0); 529 /* Check FBO status */ 530 status = data->glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES); 531 if (status != GL_FRAMEBUFFER_COMPLETE_OES) { 532 return SDL_SetError("glFramebufferTexture2DOES() failed"); 533 } 534 return 0; 535 } 536 537 538 static int 539 GLES_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd) 540 { 541 return 0; /* nothing to do in this backend. */ 542 } 543 544 static int 545 GLES_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count) 546 { 547 GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, count * 2 * sizeof (GLfloat), 0, &cmd->data.draw.first); 548 int i; 549 550 if (!verts) { 551 return -1; 552 } 553 554 cmd->data.draw.count = count; 555 for (i = 0; i < count; i++) { 556 *(verts++) = 0.5f + points[i].x; 557 *(verts++) = 0.5f + points[i].y; 558 } 559 560 return 0; 561 } 562 563 static int 564 GLES_QueueDrawLines(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count) 565 { 566 int i; 567 const size_t vertlen = (sizeof (GLfloat) * 2) * count; 568 GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, vertlen, 0, &cmd->data.draw.first); 569 if (!verts) { 570 return -1; 571 } 572 cmd->data.draw.count = count; 573 574 /* Offset to hit the center of the pixel. */ 575 for (i = 0; i < count; i++) { 576 *(verts++) = 0.5f + points[i].x; 577 *(verts++) = 0.5f + points[i].y; 578 } 579 580 /* Make the last line segment one pixel longer, to satisfy the 581 diamond-exit rule. */ 582 verts -= 4; 583 { 584 const GLfloat xstart = verts[0]; 585 const GLfloat ystart = verts[1]; 586 const GLfloat xend = verts[2]; 587 const GLfloat yend = verts[3]; 588 589 if (ystart == yend) { /* horizontal line */ 590 verts[2] += (xend > xstart) ? 1.0f : -1.0f; 591 } else if (xstart == xend) { /* vertical line */ 592 verts[3] += (yend > ystart) ? 1.0f : -1.0f; 593 } else { /* bump a pixel in the direction we are moving in. */ 594 const GLfloat deltax = xend - xstart; 595 const GLfloat deltay = yend - ystart; 596 const GLfloat angle = SDL_atan2f(deltay, deltax); 597 verts[2] += SDL_cosf(angle); 598 verts[3] += SDL_sinf(angle); 599 } 600 } 601 602 return 0; 603 } 604 605 static int 606 GLES_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects, int count) 607 { 608 GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, count * 8 * sizeof (GLfloat), 0, &cmd->data.draw.first); 609 int i; 610 611 if (!verts) { 612 return -1; 613 } 614 615 cmd->data.draw.count = count; 616 617 for (i = 0; i < count; i++) { 618 const SDL_FRect *rect = &rects[i]; 619 const GLfloat minx = rect->x; 620 const GLfloat maxx = rect->x + rect->w; 621 const GLfloat miny = rect->y; 622 const GLfloat maxy = rect->y + rect->h; 623 *(verts++) = minx; 624 *(verts++) = miny; 625 *(verts++) = maxx; 626 *(verts++) = miny; 627 *(verts++) = minx; 628 *(verts++) = maxy; 629 *(verts++) = maxx; 630 *(verts++) = maxy; 631 } 632 633 return 0; 634 } 635 636 static int 637 GLES_QueueCopy(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture, 638 const SDL_Rect * srcrect, const SDL_FRect * dstrect) 639 { 640 GLES_TextureData *texturedata = (GLES_TextureData *) texture->driverdata; 641 GLfloat minx, miny, maxx, maxy; 642 GLfloat minu, maxu, minv, maxv; 643 GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, 16 * sizeof (GLfloat), 0, &cmd->data.draw.first); 644 645 if (!verts) { 646 return -1; 647 } 648 649 cmd->data.draw.count = 1; 650 651 minx = dstrect->x; 652 miny = dstrect->y; 653 maxx = dstrect->x + dstrect->w; 654 maxy = dstrect->y + dstrect->h; 655 656 minu = (GLfloat) srcrect->x / texture->w; 657 minu *= texturedata->texw; 658 maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w; 659 maxu *= texturedata->texw; 660 minv = (GLfloat) srcrect->y / texture->h; 661 minv *= texturedata->texh; 662 maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h; 663 maxv *= texturedata->texh; 664 665 *(verts++) = minx; 666 *(verts++) = miny; 667 *(verts++) = maxx; 668 *(verts++) = miny; 669 *(verts++) = minx; 670 *(verts++) = maxy; 671 *(verts++) = maxx; 672 *(verts++) = maxy; 673 674 *(verts++) = minu; 675 *(verts++) = minv; 676 *(verts++) = maxu; 677 *(verts++) = minv; 678 *(verts++) = minu; 679 *(verts++) = maxv; 680 *(verts++) = maxu; 681 *(verts++) = maxv; 682 683 return 0; 684 } 685 686 static int 687 GLES_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture, 688 const SDL_Rect * srcquad, const SDL_FRect * dstrect, 689 const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip) 690 { 691 GLES_TextureData *texturedata = (GLES_TextureData *) texture->driverdata; 692 GLfloat minx, miny, maxx, maxy; 693 GLfloat centerx, centery; 694 GLfloat minu, maxu, minv, maxv; 695 GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, 19 * sizeof (GLfloat), 0, &cmd->data.draw.first); 696 697 if (!verts) { 698 return -1; 699 } 700 701 centerx = center->x; 702 centery = center->y; 703 704 if (flip & SDL_FLIP_HORIZONTAL) { 705 minx = dstrect->w - centerx; 706 maxx = -centerx; 707 } 708 else { 709 minx = -centerx; 710 maxx = dstrect->w - centerx; 711 } 712 713 if (flip & SDL_FLIP_VERTICAL) { 714 miny = dstrect->h - centery; 715 maxy = -centery; 716 } 717 else { 718 miny = -centery; 719 maxy = dstrect->h - centery; 720 } 721 722 minu = (GLfloat) srcquad->x / texture->w; 723 minu *= texturedata->texw; 724 maxu = (GLfloat) (srcquad->x + srcquad->w) / texture->w; 725 maxu *= texturedata->texw; 726 minv = (GLfloat) srcquad->y / texture->h; 727 minv *= texturedata->texh; 728 maxv = (GLfloat) (srcquad->y + srcquad->h) / texture->h; 729 maxv *= texturedata->texh; 730 731 cmd->data.draw.count = 1; 732 733 *(verts++) = minx; 734 *(verts++) = miny; 735 *(verts++) = maxx; 736 *(verts++) = miny; 737 *(verts++) = minx; 738 *(verts++) = maxy; 739 *(verts++) = maxx; 740 *(verts++) = maxy; 741 742 *(verts++) = minu; 743 *(verts++) = minv; 744 *(verts++) = maxu; 745 *(verts++) = minv; 746 *(verts++) = minu; 747 *(verts++) = maxv; 748 *(verts++) = maxu; 749 *(verts++) = maxv; 750 751 *(verts++) = (GLfloat) dstrect->x + centerx; 752 *(verts++) = (GLfloat) dstrect->y + centery; 753 *(verts++) = (GLfloat) angle; 754 755 return 0; 756 } 757 758 static void 759 SetDrawState(GLES_RenderData *data, const SDL_RenderCommand *cmd) 760 { 761 const SDL_BlendMode blend = cmd->data.draw.blend; 762 const Uint8 r = cmd->data.draw.r; 763 const Uint8 g = cmd->data.draw.g; 764 const Uint8 b = cmd->data.draw.b; 765 const Uint8 a = cmd->data.draw.a; 766 const Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b); 767 768 if (color != data->drawstate.color) { 769 const GLfloat fr = ((GLfloat) r) * inv255f; 770 const GLfloat fg = ((GLfloat) g) * inv255f; 771 const GLfloat fb = ((GLfloat) b) * inv255f; 772 const GLfloat fa = ((GLfloat) a) * inv255f; 773 data->glColor4f(fr, fg, fb, fa); 774 data->drawstate.color = color; 775 } 776 777 if (data->drawstate.viewport_dirty) { 778 const SDL_Rect *viewport = &data->drawstate.viewport; 779 const SDL_bool istarget = (data->drawstate.target != NULL); 780 data->glMatrixMode(GL_PROJECTION); 781 data->glLoadIdentity(); 782 data->glViewport(viewport->x, 783 istarget ? viewport->y : (data->drawstate.drawableh - viewport->y - viewport->h), 784 viewport->w, viewport->h); 785 if (viewport->w && viewport->h) { 786 data->glOrthof((GLfloat) 0, (GLfloat) viewport->w, 787 (GLfloat) (istarget ? 0 : viewport->h), 788 (GLfloat) (istarget ? viewport->h : 0), 789 0.0, 1.0); 790 } 791 data->glMatrixMode(GL_MODELVIEW); 792 data->drawstate.viewport_dirty = SDL_FALSE; 793 } 794 795 if (data->drawstate.cliprect_enabled_dirty) { 796 if (data->drawstate.cliprect_enabled) { 797 data->glEnable(GL_SCISSOR_TEST); 798 } else { 799 data->glDisable(GL_SCISSOR_TEST); 800 } 801 data->drawstate.cliprect_enabled_dirty = SDL_FALSE; 802 } 803 804 if (data->drawstate.cliprect_enabled && data->drawstate.cliprect_dirty) { 805 const SDL_Rect *viewport = &data->drawstate.viewport; 806 const SDL_Rect *rect = &data->drawstate.cliprect; 807 const SDL_bool istarget = (data->drawstate.target != NULL); 808 data->glScissor(viewport->x + rect->x, 809 istarget ? viewport->y + rect->y : data->drawstate.drawableh - viewport->y - rect->y - rect->h, 810 rect->w, rect->h); 811 data->drawstate.cliprect_dirty = SDL_FALSE; 812 } 813 814 if (blend != data->drawstate.blend) { 815 if (blend == SDL_BLENDMODE_NONE) { 816 data->glDisable(GL_BLEND); 817 } else { 818 data->glEnable(GL_BLEND); 819 if (data->GL_OES_blend_func_separate_supported) { 820 data->glBlendFuncSeparateOES(GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blend)), 821 GetBlendFunc(SDL_GetBlendModeDstColorFactor(blend)), 822 GetBlendFunc(SDL_GetBlendModeSrcAlphaFactor(blend)), 823 GetBlendFunc(SDL_GetBlendModeDstAlphaFactor(blend))); 824 } else { 825 data->glBlendFunc(GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blend)), 826 GetBlendFunc(SDL_GetBlendModeDstColorFactor(blend))); 827 } 828 if (data->GL_OES_blend_equation_separate_supported) { 829 data->glBlendEquationSeparateOES(GetBlendEquation(SDL_GetBlendModeColorOperation(blend)), 830 GetBlendEquation(SDL_GetBlendModeAlphaOperation(blend))); 831 } else if (data->GL_OES_blend_subtract_supported) { 832 data->glBlendEquationOES(GetBlendEquation(SDL_GetBlendModeColorOperation(blend))); 833 } 834 } 835 data->drawstate.blend = blend; 836 } 837 838 if ((cmd->data.draw.texture != NULL) != data->drawstate.texturing) { 839 if (cmd->data.draw.texture == NULL) { 840 data->glDisable(GL_TEXTURE_2D); 841 data->glDisableClientState(GL_TEXTURE_COORD_ARRAY); 842 data->drawstate.texturing = SDL_FALSE; 843 } else { 844 data->glEnable(GL_TEXTURE_2D); 845 data->glEnableClientState(GL_TEXTURE_COORD_ARRAY); 846 data->drawstate.texturing = SDL_TRUE; 847 } 848 } 849 } 850 851 static void 852 SetCopyState(GLES_RenderData *data, const SDL_RenderCommand *cmd) 853 { 854 SDL_Texture *texture = cmd->data.draw.texture; 855 SetDrawState(data, cmd); 856 857 if (texture != data->drawstate.texture) { 858 GLES_TextureData *texturedata = (GLES_TextureData *) texture->driverdata; 859 data->glBindTexture(GL_TEXTURE_2D, texturedata->texture); 860 data->drawstate.texture = texture; 861 } 862 } 863 864 static int 865 GLES_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize) 866 { 867 GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata; 868 size_t i; 869 870 if (GLES_ActivateRenderer(renderer) < 0) { 871 return -1; 872 } 873 874 data->drawstate.target = renderer->target; 875 876 if (!renderer->target) { 877 SDL_GL_GetDrawableSize(renderer->window, &data->drawstate.drawablew, &data->drawstate.drawableh); 878 } 879 880 while (cmd) { 881 switch (cmd->command) { 882 case SDL_RENDERCMD_SETDRAWCOLOR: { 883 break; /* not used in this render backend. */ 884 } 885 886 case SDL_RENDERCMD_SETVIEWPORT: { 887 SDL_Rect *viewport = &data->drawstate.viewport; 888 if (SDL_memcmp(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect)) != 0) { 889 SDL_memcpy(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect)); 890 data->drawstate.viewport_dirty = SDL_TRUE; 891 } 892 break; 893 } 894 895 case SDL_RENDERCMD_SETCLIPRECT: { 896 const SDL_Rect *rect = &cmd->data.cliprect.rect; 897 if (data->drawstate.cliprect_enabled != cmd->data.cliprect.enabled) { 898 data->drawstate.cliprect_enabled = cmd->data.cliprect.enabled; 899 data->drawstate.cliprect_enabled_dirty = SDL_TRUE; 900 } 901 if (SDL_memcmp(&data->drawstate.cliprect, rect, sizeof (SDL_Rect)) != 0) { 902 SDL_memcpy(&data->drawstate.cliprect, rect, sizeof (SDL_Rect)); 903 data->drawstate.cliprect_dirty = SDL_TRUE; 904 } 905 break; 906 } 907 908 case SDL_RENDERCMD_CLEAR: { 909 const Uint8 r = cmd->data.color.r; 910 const Uint8 g = cmd->data.color.g; 911 const Uint8 b = cmd->data.color.b; 912 const Uint8 a = cmd->data.color.a; 913 const Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b); 914 if (color != data->drawstate.clear_color) { 915 const GLfloat fr = ((GLfloat) r) * inv255f; 916 const GLfloat fg = ((GLfloat) g) * inv255f; 917 const GLfloat fb = ((GLfloat) b) * inv255f; 918 const GLfloat fa = ((GLfloat) a) * inv255f; 919 data->glClearColor(fr, fg, fb, fa); 920 data->drawstate.clear_color = color; 921 } 922 923 if (data->drawstate.cliprect_enabled || data->drawstate.cliprect_enabled_dirty) { 924 data->glDisable(GL_SCISSOR_TEST); 925 data->drawstate.cliprect_enabled_dirty = data->drawstate.cliprect_enabled; 926 } 927 928 data->glClear(GL_COLOR_BUFFER_BIT); 929 930 break; 931 } 932 933 case SDL_RENDERCMD_DRAW_POINTS: { 934 const size_t count = cmd->data.draw.count; 935 const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first); 936 SetDrawState(data, cmd); 937 data->glVertexPointer(2, GL_FLOAT, 0, verts); 938 data->glDrawArrays(GL_POINTS, 0, (GLsizei) count); 939 break; 940 } 941 942 case SDL_RENDERCMD_DRAW_LINES: { 943 const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first); 944 const size_t count = cmd->data.draw.count; 945 SDL_assert(count >= 2); 946 SetDrawState(data, cmd); 947 data->glVertexPointer(2, GL_FLOAT, 0, verts); 948 data->glDrawArrays(GL_LINE_STRIP, 0, (GLsizei) count); 949 break; 950 } 951 952 case SDL_RENDERCMD_FILL_RECTS: { 953 const size_t count = cmd->data.draw.count; 954 const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first); 955 GLsizei offset = 0; 956 SetDrawState(data, cmd); 957 data->glVertexPointer(2, GL_FLOAT, 0, verts); 958 for (i = 0; i < count; ++i, offset += 4) { 959 data->glDrawArrays(GL_TRIANGLE_STRIP, offset, 4); 960 } 961 break; 962 } 963 964 case SDL_RENDERCMD_COPY: { 965 const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first); 966 SetCopyState(data, cmd); 967 data->glVertexPointer(2, GL_FLOAT, 0, verts); 968 data->glTexCoordPointer(2, GL_FLOAT, 0, verts + 8); 969 data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 970 break; 971 } 972 973 case SDL_RENDERCMD_COPY_EX: { 974 const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first); 975 const GLfloat translatex = verts[16]; 976 const GLfloat translatey = verts[17]; 977 const GLfloat angle = verts[18]; 978 SetCopyState(data, cmd); 979 data->glVertexPointer(2, GL_FLOAT, 0, verts); 980 data->glTexCoordPointer(2, GL_FLOAT, 0, verts + 8); 981 982 /* Translate to flip, rotate, translate to position */ 983 data->glPushMatrix(); 984 data->glTranslatef(translatex, translatey, 0.0f); 985 data->glRotatef(angle, 0.0, 0.0, 1.0); 986 data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 987 data->glPopMatrix(); 988 break; 989 } 990 991 case SDL_RENDERCMD_NO_OP: 992 break; 993 } 994 995 cmd = cmd->next; 996 } 997 998 return 0; 999 } 1000 1001 static int 1002 GLES_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, 1003 Uint32 pixel_format, void * pixels, int pitch) 1004 { 1005 GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata; 1006 Uint32 temp_format = renderer->target ? renderer->target->format : SDL_PIXELFORMAT_ABGR8888; 1007 void *temp_pixels; 1008 int temp_pitch; 1009 Uint8 *src, *dst, *tmp; 1010 int w, h, length, rows; 1011 int status; 1012 1013 GLES_ActivateRenderer(renderer); 1014 1015 temp_pitch = rect->w * SDL_BYTESPERPIXEL(temp_format); 1016 temp_pixels = SDL_malloc(rect->h * temp_pitch); 1017 if (!temp_pixels) { 1018 return SDL_OutOfMemory(); 1019 } 1020 1021 SDL_GetRendererOutputSize(renderer, &w, &h); 1022 1023 data->glPixelStorei(GL_PACK_ALIGNMENT, 1); 1024 1025 data->glReadPixels(rect->x, renderer->target ? rect->y : (h-rect->y)-rect->h, 1026 rect->w, rect->h, GL_RGBA, GL_UNSIGNED_BYTE, temp_pixels); 1027 1028 /* Flip the rows to be top-down if necessary */ 1029 if (!renderer->target) { 1030 SDL_bool isstack; 1031 length = rect->w * SDL_BYTESPERPIXEL(temp_format); 1032 src = (Uint8*)temp_pixels + (rect->h-1)*temp_pitch; 1033 dst = (Uint8*)temp_pixels; 1034 tmp = SDL_small_alloc(Uint8, length, &isstack); 1035 rows = rect->h / 2; 1036 while (rows--) { 1037 SDL_memcpy(tmp, dst, length); 1038 SDL_memcpy(dst, src, length); 1039 SDL_memcpy(src, tmp, length); 1040 dst += temp_pitch; 1041 src -= temp_pitch; 1042 } 1043 SDL_small_free(tmp, isstack); 1044 } 1045 1046 status = SDL_ConvertPixels(rect->w, rect->h, 1047 temp_format, temp_pixels, temp_pitch, 1048 pixel_format, pixels, pitch); 1049 SDL_free(temp_pixels); 1050 1051 return status; 1052 } 1053 1054 static void 1055 GLES_RenderPresent(SDL_Renderer * renderer) 1056 { 1057 GLES_ActivateRenderer(renderer); 1058 1059 SDL_GL_SwapWindow(renderer->window); 1060 } 1061 1062 static void 1063 GLES_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture) 1064 { 1065 GLES_RenderData *renderdata = (GLES_RenderData *) renderer->driverdata; 1066 1067 GLES_TextureData *data = (GLES_TextureData *) texture->driverdata; 1068 1069 GLES_ActivateRenderer(renderer); 1070 1071 if (renderdata->drawstate.texture == texture) { 1072 renderdata->drawstate.texture = NULL; 1073 } 1074 if (renderdata->drawstate.target == texture) { 1075 renderdata->drawstate.target = NULL; 1076 } 1077 1078 if (!data) { 1079 return; 1080 } 1081 if (data->texture) { 1082 renderdata->glDeleteTextures(1, &data->texture); 1083 } 1084 SDL_free(data->pixels); 1085 SDL_free(data); 1086 texture->driverdata = NULL; 1087 } 1088 1089 static void 1090 GLES_DestroyRenderer(SDL_Renderer * renderer) 1091 { 1092 GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata; 1093 1094 if (data) { 1095 if (data->context) { 1096 while (data->framebuffers) { 1097 GLES_FBOList *nextnode = data->framebuffers->next; 1098 data->glDeleteFramebuffersOES(1, &data->framebuffers->FBO); 1099 SDL_free(data->framebuffers); 1100 data->framebuffers = nextnode; 1101 } 1102 SDL_GL_DeleteContext(data->context); 1103 } 1104 SDL_free(data); 1105 } 1106 SDL_free(renderer); 1107 } 1108 1109 static int GLES_BindTexture (SDL_Renderer * renderer, SDL_Texture *texture, float *texw, float *texh) 1110 { 1111 GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata; 1112 GLES_TextureData *texturedata = (GLES_TextureData *) texture->driverdata; 1113 GLES_ActivateRenderer(renderer); 1114 1115 data->glEnable(GL_TEXTURE_2D); 1116 data->glBindTexture(texturedata->type, texturedata->texture); 1117 1118 data->drawstate.texture = texture; 1119 data->drawstate.texturing = SDL_TRUE; 1120 1121 if (texw) { 1122 *texw = (float)texturedata->texw; 1123 } 1124 if (texh) { 1125 *texh = (float)texturedata->texh; 1126 } 1127 1128 return 0; 1129 } 1130 1131 static int GLES_UnbindTexture (SDL_Renderer * renderer, SDL_Texture *texture) 1132 { 1133 GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata; 1134 GLES_TextureData *texturedata = (GLES_TextureData *) texture->driverdata; 1135 GLES_ActivateRenderer(renderer); 1136 data->glDisable(texturedata->type); 1137 1138 data->drawstate.texture = NULL; 1139 data->drawstate.texturing = SDL_FALSE; 1140 1141 return 0; 1142 } 1143 1144 static SDL_Renderer * 1145 GLES_CreateRenderer(SDL_Window * window, Uint32 flags) 1146 { 1147 SDL_Renderer *renderer; 1148 GLES_RenderData *data; 1149 GLint value; 1150 Uint32 window_flags; 1151 int profile_mask = 0, major = 0, minor = 0; 1152 SDL_bool changed_window = SDL_FALSE; 1153 1154 SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profile_mask); 1155 SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major); 1156 SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor); 1157 1158 window_flags = SDL_GetWindowFlags(window); 1159 if (!(window_flags & SDL_WINDOW_OPENGL) || 1160 profile_mask != SDL_GL_CONTEXT_PROFILE_ES || major != RENDERER_CONTEXT_MAJOR || minor != RENDERER_CONTEXT_MINOR) { 1161 1162 changed_window = SDL_TRUE; 1163 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); 1164 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, RENDERER_CONTEXT_MAJOR); 1165 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, RENDERER_CONTEXT_MINOR); 1166 1167 if (SDL_RecreateWindow(window, (window_flags & ~(SDL_WINDOW_VULKAN | SDL_WINDOW_METAL)) | SDL_WINDOW_OPENGL) < 0) { 1168 goto error; 1169 } 1170 } 1171 1172 renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer)); 1173 if (!renderer) { 1174 SDL_OutOfMemory(); 1175 goto error; 1176 } 1177 1178 data = (GLES_RenderData *) SDL_calloc(1, sizeof(*data)); 1179 if (!data) { 1180 GLES_DestroyRenderer(renderer); 1181 SDL_OutOfMemory(); 1182 goto error; 1183 } 1184 1185 renderer->WindowEvent = GLES_WindowEvent; 1186 renderer->GetOutputSize = GLES_GetOutputSize; 1187 renderer->SupportsBlendMode = GLES_SupportsBlendMode; 1188 renderer->CreateTexture = GLES_CreateTexture; 1189 renderer->UpdateTexture = GLES_UpdateTexture; 1190 renderer->LockTexture = GLES_LockTexture; 1191 renderer->UnlockTexture = GLES_UnlockTexture; 1192 renderer->SetTextureScaleMode = GLES_SetTextureScaleMode; 1193 renderer->SetRenderTarget = GLES_SetRenderTarget; 1194 renderer->QueueSetViewport = GLES_QueueSetViewport; 1195 renderer->QueueSetDrawColor = GLES_QueueSetViewport; /* SetViewport and SetDrawColor are (currently) no-ops. */ 1196 renderer->QueueDrawPoints = GLES_QueueDrawPoints; 1197 renderer->QueueDrawLines = GLES_QueueDrawLines; 1198 renderer->QueueFillRects = GLES_QueueFillRects; 1199 renderer->QueueCopy = GLES_QueueCopy; 1200 renderer->QueueCopyEx = GLES_QueueCopyEx; 1201 renderer->RunCommandQueue = GLES_RunCommandQueue; 1202 renderer->RenderReadPixels = GLES_RenderReadPixels; 1203 renderer->RenderPresent = GLES_RenderPresent; 1204 renderer->DestroyTexture = GLES_DestroyTexture; 1205 renderer->DestroyRenderer = GLES_DestroyRenderer; 1206 renderer->GL_BindTexture = GLES_BindTexture; 1207 renderer->GL_UnbindTexture = GLES_UnbindTexture; 1208 renderer->info = GLES_RenderDriver.info; 1209 renderer->info.flags = SDL_RENDERER_ACCELERATED; 1210 renderer->driverdata = data; 1211 renderer->window = window; 1212 1213 data->context = SDL_GL_CreateContext(window); 1214 if (!data->context) { 1215 GLES_DestroyRenderer(renderer); 1216 goto error; 1217 } 1218 if (SDL_GL_MakeCurrent(window, data->context) < 0) { 1219 GLES_DestroyRenderer(renderer); 1220 goto error; 1221 } 1222 1223 if (GLES_LoadFunctions(data) < 0) { 1224 GLES_DestroyRenderer(renderer); 1225 goto error; 1226 } 1227 1228 if (flags & SDL_RENDERER_PRESENTVSYNC) { 1229 SDL_GL_SetSwapInterval(1); 1230 } else { 1231 SDL_GL_SetSwapInterval(0); 1232 } 1233 if (SDL_GL_GetSwapInterval() > 0) { 1234 renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC; 1235 } 1236 1237 value = 0; 1238 data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value); 1239 renderer->info.max_texture_width = value; 1240 value = 0; 1241 data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value); 1242 renderer->info.max_texture_height = value; 1243 1244 /* Android does not report GL_OES_framebuffer_object but the functionality seems to be there anyway */ 1245 if (SDL_GL_ExtensionSupported("GL_OES_framebuffer_object") || data->glGenFramebuffersOES) { 1246 data->GL_OES_framebuffer_object_supported = SDL_TRUE; 1247 renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE; 1248 1249 value = 0; 1250 data->glGetIntegerv(GL_FRAMEBUFFER_BINDING_OES, &value); 1251 data->window_framebuffer = (GLuint)value; 1252 } 1253 data->framebuffers = NULL; 1254 1255 if (SDL_GL_ExtensionSupported("GL_OES_blend_func_separate")) { 1256 data->GL_OES_blend_func_separate_supported = SDL_TRUE; 1257 } 1258 if (SDL_GL_ExtensionSupported("GL_OES_blend_equation_separate")) { 1259 data->GL_OES_blend_equation_separate_supported = SDL_TRUE; 1260 } 1261 if (SDL_GL_ExtensionSupported("GL_OES_blend_subtract")) { 1262 data->GL_OES_blend_subtract_supported = SDL_TRUE; 1263 } 1264 1265 /* Set up parameters for rendering */ 1266 data->glDisable(GL_DEPTH_TEST); 1267 data->glDisable(GL_CULL_FACE); 1268 1269 data->glMatrixMode(GL_MODELVIEW); 1270 data->glLoadIdentity(); 1271 1272 data->glEnableClientState(GL_VERTEX_ARRAY); 1273 data->glDisableClientState(GL_TEXTURE_COORD_ARRAY); 1274 1275 data->glClearColor(1.0f, 1.0f, 1.0f, 1.0f); 1276 1277 data->drawstate.blend = SDL_BLENDMODE_INVALID; 1278 data->drawstate.color = 0xFFFFFFFF; 1279 data->drawstate.clear_color = 0xFFFFFFFF; 1280 1281 return renderer; 1282 1283 error: 1284 if (changed_window) { 1285 /* Uh oh, better try to put it back... */ 1286 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profile_mask); 1287 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major); 1288 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minor); 1289 SDL_RecreateWindow(window, window_flags); 1290 } 1291 return NULL; 1292 } 1293 1294 SDL_RenderDriver GLES_RenderDriver = { 1295 GLES_CreateRenderer, 1296 { 1297 "opengles", 1298 (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC), 1299 1, 1300 {SDL_PIXELFORMAT_ABGR8888}, 1301 0, 1302 0 1303 } 1304 }; 1305 1306 #endif /* SDL_VIDEO_RENDER_OGL_ES && !SDL_RENDER_DISABLED */ 1307 1308 /* vi: set ts=4 sw=4 expandtab: */