From 7ff1a30b4230f6bd3cc07013f641e083d0269b53 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Sun, 8 Mar 2026 18:47:10 +0100 Subject: [PATCH] Update SDL_render_gles for SDL3 --- src/render/opengles/SDL_render_gles.c | 744 +++++++++++++++++--------- 1 file changed, 502 insertions(+), 242 deletions(-) diff --git a/src/render/opengles/SDL_render_gles.c b/src/render/opengles/SDL_render_gles.c index 914758395b..21ef42b638 100644 --- a/src/render/opengles/SDL_render_gles.c +++ b/src/render/opengles/SDL_render_gles.c @@ -18,16 +18,16 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ -#include "../../SDL_internal.h" +#include "SDL_internal.h" -#if SDL_VIDEO_RENDER_OGL_ES - -#include "SDL_hints.h" +#ifdef SDL_VIDEO_RENDER_OGL_ES +#include #include "../../video/SDL_sysvideo.h" /* For SDL_GL_SwapWindowWithResult */ -#include "SDL_opengles.h" +#include #include "../SDL_sysrender.h" #include "../../SDL_utils_c.h" + /* To prevent unnecessary window recreation, * these should match the defaults selected in SDL_GL_ResetAttributes */ @@ -49,11 +49,6 @@ glDrawTexiOES(GLint x, GLint y, GLint z, GLint width, GLint height) /* OpenGL ES 1.1 renderer implementation, based on the OpenGL renderer */ -/* Used to re-create the window with OpenGL ES capability */ -extern int SDL_RecreateWindow(SDL_Window *window, Uint32 flags); - -static const float inv255f = 1.0f / 255.0f; - typedef struct GLES_FBOList GLES_FBOList; struct GLES_FBOList @@ -66,19 +61,21 @@ struct GLES_FBOList typedef struct { SDL_Rect viewport; - SDL_bool viewport_dirty; + bool viewport_dirty; SDL_Texture *texture; SDL_Texture *target; int drawablew; int drawableh; SDL_BlendMode blend; - SDL_bool cliprect_enabled_dirty; - SDL_bool cliprect_enabled; - SDL_bool cliprect_dirty; + bool cliprect_enabled_dirty; + bool cliprect_enabled; + bool cliprect_dirty; SDL_Rect cliprect; - SDL_bool texturing; - Uint32 color; - Uint32 clear_color; + bool texturing; + bool color_dirty; + SDL_FColor color; + bool clear_color_dirty; + SDL_FColor clear_color; } GLES_DrawStateCache; typedef struct @@ -90,22 +87,36 @@ typedef struct #include "SDL_glesfuncs.h" #undef SDL_PROC #undef SDL_PROC_OES - SDL_bool GL_OES_framebuffer_object_supported; + bool GL_OES_framebuffer_object_supported; GLES_FBOList *framebuffers; GLuint window_framebuffer; - SDL_bool GL_OES_blend_func_separate_supported; - SDL_bool GL_OES_blend_equation_separate_supported; - SDL_bool GL_OES_blend_subtract_supported; - SDL_bool GL_EXT_blend_minmax_supported; + bool GL_OES_blend_func_separate_supported; + bool GL_OES_blend_equation_separate_supported; + bool GL_OES_blend_subtract_supported; + bool GL_EXT_blend_minmax_supported; GLES_DrawStateCache drawstate; + + GLenum textype; // ?? + bool pixelart_supported; + + bool debug_enabled; + int errors; + char **error_messages; + bool GL_ARB_debug_output_supported; + } GLES_RenderData; typedef struct { GLuint texture; - GLenum type; +} GL_PaletteData; + +typedef struct +{ + GLuint texture; + GLenum textype; GLfloat texw; GLfloat texh; GLenum format; @@ -115,7 +126,7 @@ typedef struct GLES_FBOList *fbo; } GLES_TextureData; -static int GLES_SetError(const char *prefix, GLenum result) +static bool GLES_SetError(const char *prefix, GLenum result) { const char *error; @@ -148,7 +159,99 @@ static int GLES_SetError(const char *prefix, GLenum result) return SDL_SetError("%s: %s", prefix, error); } -static int GLES_LoadFunctions(GLES_RenderData *data) +static const char *GL_TranslateError(GLenum error) +{ +#define GL_ERROR_TRANSLATE(e) \ + case e: \ + return #e; + switch (error) { + GL_ERROR_TRANSLATE(GL_INVALID_ENUM) + GL_ERROR_TRANSLATE(GL_INVALID_VALUE) + GL_ERROR_TRANSLATE(GL_INVALID_OPERATION) + GL_ERROR_TRANSLATE(GL_OUT_OF_MEMORY) + GL_ERROR_TRANSLATE(GL_NO_ERROR) + GL_ERROR_TRANSLATE(GL_STACK_OVERFLOW) + GL_ERROR_TRANSLATE(GL_STACK_UNDERFLOW) +// GL_ERROR_TRANSLATE(GL_TABLE_TOO_LARGE) + default: + return "UNKNOWN"; + } +#undef GL_ERROR_TRANSLATE +} + +static void GL_ClearErrors(SDL_Renderer *renderer) +{ + GLES_RenderData *data = (GLES_RenderData *)renderer->internal; + + if (!data->debug_enabled) { + return; + } + if (data->GL_ARB_debug_output_supported) { + if (data->errors) { + int i; + for (i = 0; i < data->errors; ++i) { + SDL_free(data->error_messages[i]); + } + SDL_free(data->error_messages); + + data->errors = 0; + data->error_messages = NULL; + } + } else if (data->glGetError) { + while (data->glGetError() != GL_NO_ERROR) { + // continue; + } + } +} + + + +static bool GL_CheckAllErrors(const char *prefix, SDL_Renderer *renderer, const char *file, int line, const char *function) +{ + GLES_RenderData *data = (GLES_RenderData *)renderer->internal; + bool result = true; + + if (!data->debug_enabled) { + return true; + } + if (data->GL_ARB_debug_output_supported) { + if (data->errors) { + int i; + for (i = 0; i < data->errors; ++i) { + SDL_SetError("%s: %s (%d): %s %s", prefix, file, line, function, data->error_messages[i]); + result = false; + } + GL_ClearErrors(renderer); + } + } else { + // check gl errors (can return multiple errors) + for (;;) { + GLenum error = data->glGetError(); + if (error != GL_NO_ERROR) { + if (prefix == NULL || prefix[0] == '\0') { + prefix = "generic"; + } + SDL_SetError("%s: %s (%d): %s %s (0x%X)", prefix, file, line, function, GL_TranslateError(error), error); + result = false; + } else { + break; + } + } + } + return result; +} + + +#if 0 +#define GL_CheckError(prefix, renderer) +#else +#define GL_CheckError(prefix, renderer) GL_CheckAllErrors(prefix, renderer, "SDL_render_gl.c", SDL_LINE, SDL_FUNCTION) +#endif + + + + +static bool GLES_LoadFunctions(GLES_RenderData *data) { #ifdef SDL_VIDEO_DRIVER_UIKIT #define __SDL_NOGETPROCADDR__ @@ -164,21 +267,21 @@ static int GLES_LoadFunctions(GLES_RenderData *data) #else #define SDL_PROC(ret, func, params) \ do { \ - data->func = SDL_GL_GetProcAddress(#func); \ + data->func = (ret (APIENTRY *) params)SDL_GL_GetProcAddress(#func); \ if (!data->func) { \ return SDL_SetError("Couldn't load GLES function %s: %s", #func, SDL_GetError()); \ } \ } while (0); #define SDL_PROC_OES(ret, func, params) \ do { \ - data->func = SDL_GL_GetProcAddress(#func); \ + data->func = (ret (APIENTRY *) params)SDL_GL_GetProcAddress(#func); \ } while (0); #endif /* __SDL_NOGETPROCADDR__ */ #include "SDL_glesfuncs.h" #undef SDL_PROC #undef SDL_PROC_OES - return 0; + return true; } static GLES_FBOList *GLES_GetFBO(GLES_RenderData *data, Uint32 w, Uint32 h) @@ -198,33 +301,33 @@ static GLES_FBOList *GLES_GetFBO(GLES_RenderData *data, Uint32 w, Uint32 h) return result; } -static int GLES_ActivateRenderer(SDL_Renderer *renderer) +static bool GLES_ActivateRenderer(SDL_Renderer *renderer) { - GLES_RenderData *data = (GLES_RenderData *)renderer->driverdata; + GLES_RenderData *data = (GLES_RenderData *)renderer->internal; if (SDL_GL_GetCurrentContext() != data->context) { - if (SDL_GL_MakeCurrent(renderer->window, data->context) < 0) { - return -1; + if (!SDL_GL_MakeCurrent(renderer->window, data->context)) { + return false; } } - return 0; + return true; } static void GLES_WindowEvent(SDL_Renderer *renderer, const SDL_WindowEvent *event) { - GLES_RenderData *data = (GLES_RenderData *)renderer->driverdata; + GLES_RenderData *data = (GLES_RenderData *)renderer->internal; - if (event->event == SDL_WINDOWEVENT_MINIMIZED) { + if (event->type == SDL_EVENT_WINDOW_MINIMIZED) { /* According to Apple documentation, we need to finish drawing NOW! */ data->glFinish(); } } -static int GLES_GetOutputSize(SDL_Renderer *renderer, int *w, int *h) +static bool GLES_GetOutputSize(SDL_Renderer *renderer, int *w, int *h) { - SDL_GL_GetDrawableSize(renderer->window, w, h); - return 0; + SDL_GetWindowSizeInPixels(renderer->window, w, h); + return true; } static GLenum GetBlendFunc(SDL_BlendFactor factor) @@ -273,9 +376,9 @@ static GLenum GetBlendEquation(SDL_BlendOperation operation) } } -static SDL_bool GLES_SupportsBlendMode(SDL_Renderer *renderer, SDL_BlendMode blendMode) +static bool GLES_SupportsBlendMode(SDL_Renderer *renderer, SDL_BlendMode blendMode) { - GLES_RenderData *data = (GLES_RenderData *)renderer->driverdata; + GLES_RenderData *data = (GLES_RenderData *)renderer->internal; SDL_BlendFactor srcColorFactor = SDL_GetBlendModeSrcColorFactor(blendMode); SDL_BlendFactor srcAlphaFactor = SDL_GetBlendModeSrcAlphaFactor(blendMode); SDL_BlendOperation colorOperation = SDL_GetBlendModeColorOperation(blendMode); @@ -289,34 +392,137 @@ static SDL_bool GLES_SupportsBlendMode(SDL_Renderer *renderer, SDL_BlendMode ble GetBlendFunc(dstColorFactor) == GL_INVALID_ENUM || GetBlendFunc(dstAlphaFactor) == GL_INVALID_ENUM || GetBlendEquation(alphaOperation) == GL_INVALID_ENUM) { - return SDL_FALSE; + return false; } if ((srcColorFactor != srcAlphaFactor || dstColorFactor != dstAlphaFactor) && !data->GL_OES_blend_func_separate_supported) { - return SDL_FALSE; + return false; } if (colorOperation != alphaOperation && !data->GL_OES_blend_equation_separate_supported) { - return SDL_FALSE; + return false; } if (colorOperation != SDL_BLENDOPERATION_ADD && !data->GL_OES_blend_subtract_supported) { - return SDL_FALSE; + return false; } if (colorOperation == SDL_BLENDOPERATION_MINIMUM && !data->GL_EXT_blend_minmax_supported) { - return SDL_FALSE; + return false; } if (colorOperation == SDL_BLENDOPERATION_MAXIMUM && !data->GL_EXT_blend_minmax_supported) { - return SDL_FALSE; + return false; } - return SDL_TRUE; + return true; } -static int GLES_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture) + +static bool SetTextureScaleMode(GLES_RenderData *data, GLenum textype, SDL_PixelFormat format, SDL_ScaleMode scaleMode) { - GLES_RenderData *renderdata = (GLES_RenderData *)renderer->driverdata; + switch (scaleMode) { + case SDL_SCALEMODE_NEAREST: + data->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + data->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + break; + case SDL_SCALEMODE_PIXELART: // Uses linear sampling if supported + if (!data->pixelart_supported) { + data->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + data->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + break; + } + SDL_FALLTHROUGH; + case SDL_SCALEMODE_LINEAR: + if (format == SDL_PIXELFORMAT_INDEX8) { + // We'll do linear sampling in the shader + data->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + data->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } else { + data->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + data->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + break; + default: + return SDL_SetError("Unknown texture scale mode: %d", scaleMode); + } + return true; +} + +static GLint TranslateAddressMode(SDL_TextureAddressMode addressMode) +{ + switch (addressMode) { + case SDL_TEXTURE_ADDRESS_CLAMP: + return GL_CLAMP_TO_EDGE; + case SDL_TEXTURE_ADDRESS_WRAP: + return GL_REPEAT; + default: + SDL_assert(!"Unknown texture address mode"); + return GL_CLAMP_TO_EDGE; + } +} + +static void SetTextureAddressMode(GLES_RenderData *data, GLenum textype, SDL_TextureAddressMode addressModeU, SDL_TextureAddressMode addressModeV) +{ + data->glTexParameteri(textype, GL_TEXTURE_WRAP_S, TranslateAddressMode(addressModeU)); + data->glTexParameteri(textype, GL_TEXTURE_WRAP_T, TranslateAddressMode(addressModeV)); +} + +static bool GL_CreatePalette(SDL_Renderer *renderer, SDL_TexturePalette *palette) +{ + GLES_RenderData *data = (GLES_RenderData *)renderer->internal; + GL_PaletteData *palettedata = (GL_PaletteData *)SDL_calloc(1, sizeof(*palettedata)); + if (!palettedata) { + return false; + } + palette->internal = palettedata; + + data->drawstate.texture = NULL; // we trash this state. + + const GLenum textype = data->textype; + data->glGenTextures(1, &palettedata->texture); + data->glBindTexture(textype, palettedata->texture); + data->glTexImage2D(textype, 0, GL_RGBA, 256, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + if (!GL_CheckError("glTexImage2D()", renderer)) { + return false; + } + SetTextureScaleMode(data, textype, SDL_PIXELFORMAT_UNKNOWN, SDL_SCALEMODE_NEAREST); + SetTextureAddressMode(data, textype, SDL_TEXTURE_ADDRESS_CLAMP, SDL_TEXTURE_ADDRESS_CLAMP); + return true; +} + +static bool GL_UpdatePalette(SDL_Renderer *renderer, SDL_TexturePalette *palette, int ncolors, SDL_Color *colors) +{ + GLES_RenderData *data = (GLES_RenderData *)renderer->internal; + GL_PaletteData *palettedata = (GL_PaletteData *)palette->internal; + + GLES_ActivateRenderer(renderer); + + data->drawstate.texture = NULL; // we trash this state. + + const GLenum textype = data->textype; + data->glBindTexture(textype, palettedata->texture); + data->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); +// data->glPixelStorei(GL_UNPACK_ROW_LENGTH, ncolors); + data->glTexSubImage2D(textype, 0, 0, 0, ncolors, 1, GL_RGBA, GL_UNSIGNED_BYTE, colors); + + return GL_CheckError("glTexSubImage2D()", renderer); +} + +static void GL_DestroyPalette(SDL_Renderer *renderer, SDL_TexturePalette *palette) +{ + GLES_RenderData *data = (GLES_RenderData *)renderer->internal; + GL_PaletteData *palettedata = (GL_PaletteData *)palette->internal; + + if (palettedata) { + data->glDeleteTextures(1, &palettedata->texture); + SDL_free(palettedata); + } +} + + + +static bool GLES_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props) +{ + GLES_RenderData *renderdata = (GLES_RenderData *)renderer->internal; GLES_TextureData *data; GLint internalFormat; - GLenum format, type; + GLenum format, textype; int texture_w, texture_h; - GLenum scaleMode; GLenum result; GLES_ActivateRenderer(renderer); @@ -325,7 +531,7 @@ static int GLES_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture) case SDL_PIXELFORMAT_RGBA32: internalFormat = GL_RGBA; format = GL_RGBA; - type = GL_UNSIGNED_BYTE; + textype = GL_UNSIGNED_BYTE; break; default: return SDL_SetError("Texture format not supported"); @@ -350,7 +556,7 @@ static int GLES_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture) SDL_free(data); return SDL_SetError("GL_OES_framebuffer_object not supported"); } - data->fbo = GLES_GetFBO(renderer->driverdata, texture->w, texture->h); + data->fbo = GLES_GetFBO(renderer->internal, texture->w, texture->h); } else { data->fbo = NULL; } @@ -367,7 +573,7 @@ static int GLES_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture) return GLES_SetError("glGenTextures()", result); } - data->type = GL_TEXTURE_2D; + data->textype = GL_TEXTURE_2D; /* no NPOV textures allowed in OpenGL ES (yet) */ texture_w = SDL_powerof2(texture->w); texture_h = SDL_powerof2(texture->h); @@ -375,19 +581,17 @@ static int GLES_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture) data->texh = (GLfloat)texture->h / texture_h; data->format = format; - data->formattype = type; - scaleMode = (texture->scaleMode == SDL_ScaleModeNearest) ? GL_NEAREST : GL_LINEAR; - renderdata->glBindTexture(data->type, data->texture); - renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER, scaleMode); - renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER, scaleMode); - renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + data->formattype = textype; + + renderdata->glBindTexture(data->textype, data->texture); + renderdata->glTexImage2D(data->textype, 0, internalFormat, texture_w, + texture_h, 0, format, textype, NULL); + + SetTextureScaleMode(renderdata, data->textype, texture->format, texture->scaleMode); - renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w, - texture_h, 0, format, type, NULL); renderdata->glDisable(GL_TEXTURE_2D); renderdata->drawstate.texture = texture; - renderdata->drawstate.texturing = SDL_FALSE; + renderdata->drawstate.texturing = false; result = renderdata->glGetError(); if (result != GL_NO_ERROR) { @@ -398,15 +602,15 @@ static int GLES_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture) return GLES_SetError("glTexImage2D()", result); } - texture->driverdata = data; - return 0; + texture->internal = data; + return true; } -static int GLES_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, +static bool GLES_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, const void *pixels, int pitch) { - GLES_RenderData *renderdata = (GLES_RenderData *)renderer->driverdata; - GLES_TextureData *data = (GLES_TextureData *)texture->driverdata; + GLES_RenderData *renderdata = (GLES_RenderData *)renderer->internal; + GLES_TextureData *data = (GLES_TextureData *)texture->internal; Uint8 *blob = NULL; Uint8 *src; int srcPitch; @@ -416,7 +620,7 @@ static int GLES_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, /* Bail out if we're supposed to update an empty rectangle */ if (rect->w <= 0 || rect->h <= 0) { - return 0; + return true; } /* Reformat the texture data into a tightly packed array */ @@ -438,10 +642,10 @@ static int GLES_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, /* Create a texture subimage with the supplied data */ renderdata->glGetError(); - renderdata->glEnable(data->type); - renderdata->glBindTexture(data->type, data->texture); + renderdata->glEnable(data->textype); + renderdata->glBindTexture(data->textype, data->texture); renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - renderdata->glTexSubImage2D(data->type, + renderdata->glTexSubImage2D(data->textype, 0, rect->x, rect->y, @@ -450,33 +654,33 @@ static int GLES_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, data->format, data->formattype, src); - renderdata->glDisable(data->type); + renderdata->glDisable(data->textype); SDL_free(blob); renderdata->drawstate.texture = texture; - renderdata->drawstate.texturing = SDL_FALSE; + renderdata->drawstate.texturing = false; if (renderdata->glGetError() != GL_NO_ERROR) { return SDL_SetError("Failed to update texture"); } - return 0; + return true; } -static int GLES_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, +static bool GLES_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, void **pixels, int *pitch) { - GLES_TextureData *data = (GLES_TextureData *)texture->driverdata; + GLES_TextureData *data = (GLES_TextureData *)texture->internal; *pixels = (void *)((Uint8 *)data->pixels + rect->y * data->pitch + rect->x * SDL_BYTESPERPIXEL(texture->format)); *pitch = data->pitch; - return 0; + return true; } static void GLES_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture) { - GLES_TextureData *data = (GLES_TextureData *)texture->driverdata; + GLES_TextureData *data = (GLES_TextureData *)texture->internal; SDL_Rect rect; /* We do whole texture updates, at least for now */ @@ -487,20 +691,9 @@ static void GLES_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture) GLES_UpdateTexture(renderer, texture, &rect, data->pixels, data->pitch); } -static void GLES_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scaleMode) +static bool GLES_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture) { - GLES_RenderData *renderdata = (GLES_RenderData *)renderer->driverdata; - GLES_TextureData *data = (GLES_TextureData *)texture->driverdata; - GLenum glScaleMode = (scaleMode == SDL_ScaleModeNearest) ? GL_NEAREST : GL_LINEAR; - - renderdata->glBindTexture(data->type, data->texture); - renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER, glScaleMode); - renderdata->glTexParameteri(data->type, GL_TEXTURE_MAG_FILTER, glScaleMode); -} - -static int GLES_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture) -{ - GLES_RenderData *data = (GLES_RenderData *)renderer->driverdata; + GLES_RenderData *data = (GLES_RenderData *)renderer->internal; GLES_TextureData *texturedata = NULL; GLenum status; @@ -508,37 +701,37 @@ static int GLES_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture) return SDL_SetError("Can't enable render target support in this renderer"); } - data->drawstate.viewport_dirty = SDL_TRUE; + data->drawstate.viewport_dirty = true; if (!texture) { data->glBindFramebufferOES(GL_FRAMEBUFFER_OES, data->window_framebuffer); - return 0; + return true; } - texturedata = (GLES_TextureData *)texture->driverdata; + texturedata = (GLES_TextureData *)texture->internal; data->glBindFramebufferOES(GL_FRAMEBUFFER_OES, texturedata->fbo->FBO); /* TODO: check if texture pixel format allows this operation */ - data->glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, texturedata->type, texturedata->texture, 0); + data->glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, texturedata->textype, texturedata->texture, 0); /* Check FBO status */ status = data->glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES); if (status != GL_FRAMEBUFFER_COMPLETE_OES) { return SDL_SetError("glFramebufferTexture2DOES() failed"); } - return 0; + return true; } -static int GLES_QueueSetViewport(SDL_Renderer *renderer, SDL_RenderCommand *cmd) +static bool GLES_QueueSetViewport(SDL_Renderer *renderer, SDL_RenderCommand *cmd) { - return 0; /* nothing to do in this backend. */ + return true; /* nothing to do in this backend. */ } -static int GLES_QueueDrawPoints(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count) +static bool GLES_QueueDrawPoints(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count) { GLfloat *verts = (GLfloat *)SDL_AllocateRenderVertices(renderer, count * 2 * sizeof(GLfloat), 0, &cmd->data.draw.first); int i; if (!verts) { - return -1; + return false; } cmd->data.draw.count = count; @@ -547,10 +740,10 @@ static int GLES_QueueDrawPoints(SDL_Renderer *renderer, SDL_RenderCommand *cmd, *(verts++) = 0.5f + points[i].y; } - return 0; + return true; } -static int GLES_QueueDrawLines(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count) +static bool GLES_QueueDrawLines(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count) { int i; GLfloat prevx, prevy; @@ -558,7 +751,7 @@ static int GLES_QueueDrawLines(SDL_Renderer *renderer, SDL_RenderCommand *cmd, c GLfloat *verts = (GLfloat *)SDL_AllocateRenderVertices(renderer, vertlen, 0, &cmd->data.draw.first); if (!verts) { - return -1; + return false; } cmd->data.draw.count = count; @@ -587,27 +780,28 @@ static int GLES_QueueDrawLines(SDL_Renderer *renderer, SDL_RenderCommand *cmd, c *(verts++) = prevy; } - return 0; + return true; } -static int GLES_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, - const float *xy, int xy_stride, const SDL_Color *color, int color_stride, const float *uv, int uv_stride, +static bool GLES_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, + const float *xy, int xy_stride, const SDL_FColor *color, int color_stride, const float *uv, int uv_stride, int num_vertices, const void *indices, int num_indices, int size_indices, float scale_x, float scale_y) { GLES_TextureData *texturedata = NULL; int i; int count = indices ? num_indices : num_vertices; + const float color_scale = cmd->data.draw.color_scale; GLfloat *verts; int sz = 2 + 4 + (texture ? 2 : 0); verts = (GLfloat *)SDL_AllocateRenderVertices(renderer, count * sz * sizeof(GLfloat), 0, &cmd->data.draw.first); if (!verts) { - return -1; + return false; } if (texture) { - texturedata = (GLES_TextureData *)texture->driverdata; + texturedata = (GLES_TextureData *)texture->internal; } cmd->data.draw.count = count; @@ -616,7 +810,7 @@ static int GLES_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SD for (i = 0; i < count; i++) { int j; float *xy_; - SDL_Color col_; + SDL_FColor *col_; if (size_indices == 4) { j = ((const Uint32 *)indices)[i]; } else if (size_indices == 2) { @@ -628,15 +822,15 @@ static int GLES_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SD } xy_ = (float *)((char *)xy + j * xy_stride); - col_ = *(SDL_Color *)((char *)color + j * color_stride); + col_ = (SDL_FColor *)((char *)color + j * color_stride); *(verts++) = xy_[0] * scale_x; *(verts++) = xy_[1] * scale_y; - *(verts++) = col_.r * inv255f; - *(verts++) = col_.g * inv255f; - *(verts++) = col_.b * inv255f; - *(verts++) = col_.a * inv255f; + *(verts++) = col_->r * color_scale; + *(verts++) = col_->g * color_scale; + *(verts++) = col_->b * color_scale; + *(verts++) = col_->a; if (texture) { float *uv_ = (float *)((char *)uv + j * uv_stride); @@ -644,30 +838,37 @@ static int GLES_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SD *(verts++) = uv_[1] * texturedata->texh; } } - return 0; + return true; } static void SetDrawState(GLES_RenderData *data, const SDL_RenderCommand *cmd) { const SDL_BlendMode blend = cmd->data.draw.blend; - const Uint8 r = cmd->data.draw.r; - const Uint8 g = cmd->data.draw.g; - const Uint8 b = cmd->data.draw.b; - const Uint8 a = cmd->data.draw.a; - const Uint32 color = (((Uint32)a << 24) | (r << 16) | (g << 8) | b); - - if (color != data->drawstate.color) { - const GLfloat fr = ((GLfloat)r) * inv255f; - const GLfloat fg = ((GLfloat)g) * inv255f; - const GLfloat fb = ((GLfloat)b) * inv255f; - const GLfloat fa = ((GLfloat)a) * inv255f; - data->glColor4f(fr, fg, fb, fa); - data->drawstate.color = color; + //case SDL_RENDERCMD_SETDRAWCOLOR: + { + const float r = cmd->data.color.color.r * cmd->data.color.color_scale; + const float g = cmd->data.color.color.g * cmd->data.color.color_scale; + const float b = cmd->data.color.color.b * cmd->data.color.color_scale; + const float a = cmd->data.color.color.a; + if (data->drawstate.color_dirty || + (r != data->drawstate.color.r) || + (g != data->drawstate.color.g) || + (b != data->drawstate.color.b) || + (a != data->drawstate.color.a)) { + data->glColor4f(r, g, b, a); + data->drawstate.color.r = r; + data->drawstate.color.g = g; + data->drawstate.color.b = b; + data->drawstate.color.a = a; + data->drawstate.color_dirty = false; + } } + + if (data->drawstate.viewport_dirty) { const SDL_Rect *viewport = &data->drawstate.viewport; - const SDL_bool istarget = (data->drawstate.target != NULL); + const bool istarget = (data->drawstate.target != NULL); data->glMatrixMode(GL_PROJECTION); data->glLoadIdentity(); data->glViewport(viewport->x, @@ -680,7 +881,7 @@ static void SetDrawState(GLES_RenderData *data, const SDL_RenderCommand *cmd) 0.0, 1.0); } data->glMatrixMode(GL_MODELVIEW); - data->drawstate.viewport_dirty = SDL_FALSE; + data->drawstate.viewport_dirty = false; } if (data->drawstate.cliprect_enabled_dirty) { @@ -689,17 +890,17 @@ static void SetDrawState(GLES_RenderData *data, const SDL_RenderCommand *cmd) } else { data->glDisable(GL_SCISSOR_TEST); } - data->drawstate.cliprect_enabled_dirty = SDL_FALSE; + data->drawstate.cliprect_enabled_dirty = false; } if (data->drawstate.cliprect_enabled && data->drawstate.cliprect_dirty) { const SDL_Rect *viewport = &data->drawstate.viewport; const SDL_Rect *rect = &data->drawstate.cliprect; - const SDL_bool istarget = (data->drawstate.target != NULL); + const bool istarget = (data->drawstate.target != NULL); data->glScissor(viewport->x + rect->x, istarget ? viewport->y + rect->y : data->drawstate.drawableh - viewport->y - rect->y - rect->h, rect->w, rect->h); - data->drawstate.cliprect_dirty = SDL_FALSE; + data->drawstate.cliprect_dirty = false; } if (blend != data->drawstate.blend) { @@ -730,11 +931,11 @@ static void SetDrawState(GLES_RenderData *data, const SDL_RenderCommand *cmd) if (cmd->data.draw.texture == NULL) { data->glDisable(GL_TEXTURE_2D); data->glDisableClientState(GL_TEXTURE_COORD_ARRAY); - data->drawstate.texturing = SDL_FALSE; + data->drawstate.texturing = false; } else { data->glEnable(GL_TEXTURE_2D); data->glEnableClientState(GL_TEXTURE_COORD_ARRAY); - data->drawstate.texturing = SDL_TRUE; + data->drawstate.texturing = true; } } } @@ -745,28 +946,42 @@ static void SetCopyState(GLES_RenderData *data, const SDL_RenderCommand *cmd) SetDrawState(data, cmd); if (texture != data->drawstate.texture) { - GLES_TextureData *texturedata = (GLES_TextureData *)texture->driverdata; + GLES_TextureData *texturedata = (GLES_TextureData *)texture->internal; data->glBindTexture(GL_TEXTURE_2D, texturedata->texture); data->drawstate.texture = texture; } } -static int GLES_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize) +static void GLES_InvalidateCachedState(SDL_Renderer *renderer) { - GLES_RenderData *data = (GLES_RenderData *)renderer->driverdata; + GLES_DrawStateCache *cache = &((GLES_RenderData *)renderer->internal)->drawstate; + cache->viewport_dirty = true; + cache->texture = NULL; + cache->drawablew = 0; + cache->drawableh = 0; + cache->blend = SDL_BLENDMODE_INVALID; + cache->cliprect_enabled_dirty = true; + cache->cliprect_dirty = true; + cache->color_dirty = true; + cache->clear_color_dirty = true; +} - if (GLES_ActivateRenderer(renderer) < 0) { - return -1; +static bool GLES_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize) +{ + GLES_RenderData *data = (GLES_RenderData *)renderer->internal; + + if (!GLES_ActivateRenderer(renderer)) { + return false; } data->drawstate.target = renderer->target; if (!renderer->target) { int w, h; - SDL_GL_GetDrawableSize(renderer->window, &w, &h); + SDL_GetWindowSizeInPixels(renderer->window, &w, &h); if ((w != data->drawstate.drawablew) || (h != data->drawstate.drawableh)) { - data->drawstate.viewport_dirty = SDL_TRUE; // if the window dimensions changed, invalidate the current viewport, etc. - data->drawstate.cliprect_dirty = SDL_TRUE; + data->drawstate.viewport_dirty = true; // if the window dimensions changed, invalidate the current viewport, etc. + data->drawstate.cliprect_dirty = true; data->drawstate.drawablew = w; data->drawstate.drawableh = h; } @@ -784,7 +999,7 @@ static int GLES_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Rect *viewport = &data->drawstate.viewport; if (SDL_memcmp(viewport, &cmd->data.viewport.rect, sizeof(cmd->data.viewport.rect)) != 0) { SDL_copyp(viewport, &cmd->data.viewport.rect); - data->drawstate.viewport_dirty = SDL_TRUE; + data->drawstate.viewport_dirty = true; } break; } @@ -794,29 +1009,32 @@ static int GLES_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_Rect *rect = &cmd->data.cliprect.rect; if (data->drawstate.cliprect_enabled != cmd->data.cliprect.enabled) { data->drawstate.cliprect_enabled = cmd->data.cliprect.enabled; - data->drawstate.cliprect_enabled_dirty = SDL_TRUE; + data->drawstate.cliprect_enabled_dirty = true; } if (SDL_memcmp(&data->drawstate.cliprect, rect, sizeof(*rect)) != 0) { SDL_copyp(&data->drawstate.cliprect, rect); - data->drawstate.cliprect_dirty = SDL_TRUE; + data->drawstate.cliprect_dirty = true; } break; } case SDL_RENDERCMD_CLEAR: { - const Uint8 r = cmd->data.color.r; - const Uint8 g = cmd->data.color.g; - const Uint8 b = cmd->data.color.b; - const Uint8 a = cmd->data.color.a; - const Uint32 color = (((Uint32)a << 24) | (r << 16) | (g << 8) | b); - if (color != data->drawstate.clear_color) { - const GLfloat fr = ((GLfloat)r) * inv255f; - const GLfloat fg = ((GLfloat)g) * inv255f; - const GLfloat fb = ((GLfloat)b) * inv255f; - const GLfloat fa = ((GLfloat)a) * inv255f; - data->glClearColor(fr, fg, fb, fa); - data->drawstate.clear_color = color; + const float r = cmd->data.color.color.r * cmd->data.color.color_scale; + const float g = cmd->data.color.color.g * cmd->data.color.color_scale; + const float b = cmd->data.color.color.b * cmd->data.color.color_scale; + const float a = cmd->data.color.color.a; + if (data->drawstate.clear_color_dirty || + (r != data->drawstate.clear_color.r) || + (g != data->drawstate.clear_color.g) || + (b != data->drawstate.clear_color.b) || + (a != data->drawstate.clear_color.a)) { + data->glClearColor(r, g, b, a); + data->drawstate.clear_color.r = r; + data->drawstate.clear_color.g = g; + data->drawstate.clear_color.b = b; + data->drawstate.clear_color.a = a; + data->drawstate.clear_color_dirty = false; } if (data->drawstate.cliprect_enabled || data->drawstate.cliprect_enabled_dirty) { @@ -893,13 +1111,15 @@ static int GLES_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, cmd = cmd->next; } - return 0; + return true; } -static int GLES_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect, + +/* +static bool GLES_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect, Uint32 pixel_format, void *pixels, int pitch) { - GLES_RenderData *data = (GLES_RenderData *)renderer->driverdata; + GLES_RenderData *data = (GLES_RenderData *)renderer->internal; Uint32 temp_format = renderer->target ? renderer->target->format : SDL_PIXELFORMAT_RGBA32; void *temp_pixels; int temp_pitch; @@ -915,16 +1135,16 @@ static int GLES_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect, return SDL_OutOfMemory(); } - SDL_GetRendererOutputSize(renderer, &w, &h); + SDL_GetCurrentRenderOutputSize(renderer, &w, &h); data->glPixelStorei(GL_PACK_ALIGNMENT, 1); data->glReadPixels(rect->x, renderer->target ? rect->y : (h - rect->y) - rect->h, rect->w, rect->h, GL_RGBA, GL_UNSIGNED_BYTE, temp_pixels); - /* Flip the rows to be top-down if necessary */ + // Flip the rows to be top-down if necessary if (!renderer->target) { - SDL_bool isstack; + bool isstack; length = rect->w * SDL_BYTESPERPIXEL(temp_format); src = (Uint8 *)temp_pixels + (rect->h - 1) * temp_pitch; dst = (Uint8 *)temp_pixels; @@ -947,19 +1167,54 @@ static int GLES_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect, return status; } +*/ +static SDL_Surface *GLES_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect) +{ + GLES_RenderData *data = (GLES_RenderData *)renderer->internal; + SDL_PixelFormat format = renderer->target ? renderer->target->format : SDL_PIXELFORMAT_RGBA32; + SDL_Surface *surface; -static int GLES_RenderPresent(SDL_Renderer *renderer) + surface = SDL_CreateSurface(rect->w, rect->h, format); + if (!surface) { + return NULL; + } + + int y = rect->y; + if (!renderer->target) { + int w, h; + SDL_GetRenderOutputSize(renderer, &w, &h); + y = (h - y) - rect->h; + } + + data->glPixelStorei(GL_PACK_ALIGNMENT, 1); + data->glReadPixels(rect->x, y, rect->w, rect->h, GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels); +/* if (!GL_CheckError("glReadPixels()", renderer)) { + SDL_DestroySurface(surface); + return NULL; + } +*/ + // Flip the rows to be top-down if necessary + if (!renderer->target) { + SDL_FlipSurface(surface, SDL_FLIP_VERTICAL); + } + return surface; +} + + + + +static bool GLES_RenderPresent(SDL_Renderer *renderer) { GLES_ActivateRenderer(renderer); - return SDL_GL_SwapWindowWithResult(renderer->window); + return SDL_GL_SwapWindow(renderer->window); } static void GLES_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture) { - GLES_RenderData *renderdata = (GLES_RenderData *)renderer->driverdata; + GLES_RenderData *renderdata = (GLES_RenderData *)renderer->internal; - GLES_TextureData *data = (GLES_TextureData *)texture->driverdata; + GLES_TextureData *data = (GLES_TextureData *)texture->internal; GLES_ActivateRenderer(renderer); @@ -978,12 +1233,12 @@ static void GLES_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture) } SDL_free(data->pixels); SDL_free(data); - texture->driverdata = NULL; + texture->internal = NULL; } static void GLES_DestroyRenderer(SDL_Renderer *renderer) { - GLES_RenderData *data = (GLES_RenderData *)renderer->driverdata; + GLES_RenderData *data = (GLES_RenderData *)renderer->internal; if (data) { if (data->context) { @@ -993,23 +1248,24 @@ static void GLES_DestroyRenderer(SDL_Renderer *renderer) SDL_free(data->framebuffers); data->framebuffers = nextnode; } - SDL_GL_DeleteContext(data->context); + SDL_GL_DestroyContext(data->context); } SDL_free(data); } } -static int GLES_BindTexture(SDL_Renderer *renderer, SDL_Texture *texture, float *texw, float *texh) +/* TODO TBR +static bool GLES_BindTexture(SDL_Renderer *renderer, SDL_Texture *texture, float *texw, float *texh) { - GLES_RenderData *data = (GLES_RenderData *)renderer->driverdata; - GLES_TextureData *texturedata = (GLES_TextureData *)texture->driverdata; + GLES_RenderData *data = (GLES_RenderData *)renderer->internal; + GLES_TextureData *texturedata = (GLES_TextureData *)texture->internal; GLES_ActivateRenderer(renderer); data->glEnable(GL_TEXTURE_2D); - data->glBindTexture(texturedata->type, texturedata->texture); + data->glBindTexture(texturedata->textype, texturedata->texture); data->drawstate.texture = texture; - data->drawstate.texturing = SDL_TRUE; + data->drawstate.texturing = true; if (texw) { *texw = (float)texturedata->texw; @@ -1018,70 +1274,72 @@ static int GLES_BindTexture(SDL_Renderer *renderer, SDL_Texture *texture, float *texh = (float)texturedata->texh; } - return 0; + return true; } -static int GLES_UnbindTexture(SDL_Renderer *renderer, SDL_Texture *texture) +static bool GLES_UnbindTexture(SDL_Renderer *renderer, SDL_Texture *texture) { - GLES_RenderData *data = (GLES_RenderData *)renderer->driverdata; - GLES_TextureData *texturedata = (GLES_TextureData *)texture->driverdata; + GLES_RenderData *data = (GLES_RenderData *)renderer->internal; + GLES_TextureData *texturedata = (GLES_TextureData *)texture->internal; GLES_ActivateRenderer(renderer); - data->glDisable(texturedata->type); + data->glDisable(texturedata->textype); data->drawstate.texture = NULL; - data->drawstate.texturing = SDL_FALSE; + data->drawstate.texturing = false; - return 0; + return true; } +*/ -static int GLES_SetVSync(SDL_Renderer *renderer, const int vsync) +static bool GLES_SetVSync(SDL_Renderer *renderer, const int vsync) { - int retval; - if (vsync) { - retval = SDL_GL_SetSwapInterval(1); - } else { - retval = SDL_GL_SetSwapInterval(0); + int interval = 0; + + if (!SDL_GL_SetSwapInterval(vsync)) { + return false; } - if (retval != 0) { - return retval; + + if (!SDL_GL_GetSwapInterval(&interval)) { + return false; } - if (SDL_GL_GetSwapInterval() != 0) { - renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC; - } else { - renderer->info.flags &= ~SDL_RENDERER_PRESENTVSYNC; + + if (interval != vsync) { + return SDL_Unsupported(); } - return retval; + return true; } -static int GLES_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, Uint32 flags) +static bool GLES_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_PropertiesID create_props) { GLES_RenderData *data = NULL; GLint value; Uint32 window_flags; int profile_mask = 0, major = 0, minor = 0; - SDL_bool changed_window = SDL_FALSE; + bool changed_window = false; + + SDL_SetupRendererColorspace(renderer, create_props); SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profile_mask); SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major); SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor); + SDL_SyncWindow(window); window_flags = SDL_GetWindowFlags(window); if (!(window_flags & SDL_WINDOW_OPENGL) || profile_mask != SDL_GL_CONTEXT_PROFILE_ES || major != RENDERER_CONTEXT_MAJOR || minor != RENDERER_CONTEXT_MINOR) { - changed_window = SDL_TRUE; + changed_window = true; SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, RENDERER_CONTEXT_MAJOR); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, RENDERER_CONTEXT_MINOR); - if (SDL_RecreateWindow(window, (window_flags & ~(SDL_WINDOW_VULKAN | SDL_WINDOW_METAL)) | SDL_WINDOW_OPENGL) < 0) { + if (!SDL_RecreateWindow(window, (window_flags & ~(SDL_WINDOW_VULKAN | SDL_WINDOW_METAL)) | SDL_WINDOW_OPENGL)) { goto error; } } data = (GLES_RenderData *)SDL_calloc(1, sizeof(*data)); if (!data) { - GLES_DestroyRenderer(renderer); SDL_OutOfMemory(); goto error; } @@ -1089,65 +1347,76 @@ static int GLES_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, Uint3 renderer->WindowEvent = GLES_WindowEvent; renderer->GetOutputSize = GLES_GetOutputSize; renderer->SupportsBlendMode = GLES_SupportsBlendMode; + + renderer->CreatePalette = GL_CreatePalette; + renderer->UpdatePalette = GL_UpdatePalette; + renderer->DestroyPalette = GL_DestroyPalette; renderer->CreateTexture = GLES_CreateTexture; renderer->UpdateTexture = GLES_UpdateTexture; renderer->LockTexture = GLES_LockTexture; renderer->UnlockTexture = GLES_UnlockTexture; - renderer->SetTextureScaleMode = GLES_SetTextureScaleMode; renderer->SetRenderTarget = GLES_SetRenderTarget; renderer->QueueSetViewport = GLES_QueueSetViewport; renderer->QueueSetDrawColor = GLES_QueueSetViewport; /* SetViewport and SetDrawColor are (currently) no-ops. */ renderer->QueueDrawPoints = GLES_QueueDrawPoints; renderer->QueueDrawLines = GLES_QueueDrawLines; renderer->QueueGeometry = GLES_QueueGeometry; + renderer->InvalidateCachedState = GLES_InvalidateCachedState; renderer->RunCommandQueue = GLES_RunCommandQueue; renderer->RenderReadPixels = GLES_RenderReadPixels; renderer->RenderPresent = GLES_RenderPresent; renderer->DestroyTexture = GLES_DestroyTexture; renderer->DestroyRenderer = GLES_DestroyRenderer; renderer->SetVSync = GLES_SetVSync; - renderer->GL_BindTexture = GLES_BindTexture; - renderer->GL_UnbindTexture = GLES_UnbindTexture; - renderer->info = GLES_RenderDriver.info; - renderer->info.flags = SDL_RENDERER_ACCELERATED; - renderer->driverdata = data; + renderer->internal = data; + GLES_InvalidateCachedState(renderer); renderer->window = window; data->context = SDL_GL_CreateContext(window); if (!data->context) { - GLES_DestroyRenderer(renderer); goto error; } - if (SDL_GL_MakeCurrent(window, data->context) < 0) { - GLES_DestroyRenderer(renderer); + if (!SDL_GL_MakeCurrent(window, data->context)) { goto error; } - if (GLES_LoadFunctions(data) < 0) { - GLES_DestroyRenderer(renderer); + if (!GLES_LoadFunctions(data)) { goto error; } - if (flags & SDL_RENDERER_PRESENTVSYNC) { - SDL_GL_SetSwapInterval(1); - } else { - SDL_GL_SetSwapInterval(0); + + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBA32); + + + + // Check for debug output support + if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_FLAGS, &value) && + (value & SDL_GL_CONTEXT_DEBUG_FLAG)) { + data->debug_enabled = true; } - if (SDL_GL_GetSwapInterval() != 0) { - renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC; + + if (data->debug_enabled && SDL_GL_ExtensionSupported("GL_ARB_debug_output")) { + // PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARBFunc = (PFNGLDEBUGMESSAGECALLBACKARBPROC)SDL_GL_GetProcAddress("glDebugMessageCallbackARB"); + + data->GL_ARB_debug_output_supported = true; +// data->glGetPointerv(GL_DEBUG_CALLBACK_FUNCTION_ARB, (GLvoid **)(char *)&data->next_error_callback); +// data->glGetPointerv(GL_DEBUG_CALLBACK_USER_PARAM_ARB, &data->next_error_userparam); +// glDebugMessageCallbackARBFunc(GL_HandleDebugMessage, renderer); + + // Make sure our callback is called when errors actually happen +// data->glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); } + + + value = 0; data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value); - renderer->info.max_texture_width = value; - value = 0; - data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value); - renderer->info.max_texture_height = value; + SDL_SetNumberProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_MAX_TEXTURE_SIZE_NUMBER, value); /* Android does not report GL_OES_framebuffer_object but the functionality seems to be there anyway */ if (SDL_GL_ExtensionSupported("GL_OES_framebuffer_object") || data->glGenFramebuffersOES) { - data->GL_OES_framebuffer_object_supported = SDL_TRUE; - renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE; + data->GL_OES_framebuffer_object_supported = true; value = 0; data->glGetIntegerv(GL_FRAMEBUFFER_BINDING_OES, &value); @@ -1156,16 +1425,16 @@ static int GLES_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, Uint3 data->framebuffers = NULL; if (SDL_GL_ExtensionSupported("GL_OES_blend_func_separate")) { - data->GL_OES_blend_func_separate_supported = SDL_TRUE; + data->GL_OES_blend_func_separate_supported = true; } if (SDL_GL_ExtensionSupported("GL_OES_blend_equation_separate")) { - data->GL_OES_blend_equation_separate_supported = SDL_TRUE; + data->GL_OES_blend_equation_separate_supported = true; } if (SDL_GL_ExtensionSupported("GL_OES_blend_subtract")) { - data->GL_OES_blend_subtract_supported = SDL_TRUE; + data->GL_OES_blend_subtract_supported = true; } if (SDL_GL_ExtensionSupported("GL_EXT_blend_minmax")) { - data->GL_EXT_blend_minmax_supported = SDL_TRUE; + data->GL_EXT_blend_minmax_supported = true; } /* Set up parameters for rendering */ @@ -1181,10 +1450,7 @@ static int GLES_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, Uint3 data->glClearColor(1.0f, 1.0f, 1.0f, 1.0f); data->drawstate.blend = SDL_BLENDMODE_INVALID; - data->drawstate.color = 0xFFFFFFFF; - data->drawstate.clear_color = 0xFFFFFFFF; - - return 0; + return true; error: if (changed_window) { @@ -1194,17 +1460,11 @@ error: SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minor); SDL_RecreateWindow(window, window_flags); } - return -1; + return false; } SDL_RenderDriver GLES_RenderDriver = { - GLES_CreateRenderer, - { "opengles", - (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC), - 1, - { SDL_PIXELFORMAT_RGBA32 }, - 0, - 0 } + GLES_CreateRenderer, "opengles" }; #endif /* SDL_VIDEO_RENDER_OGL_ES */