23 #if SDL_VIDEO_RENDER_OGL_ES && !SDL_RENDER_DISABLED
27 #include "../SDL_sysrender.h"
29 #if defined(SDL_VIDEO_DRIVER_PANDORA)
46 static const float inv255f = 1.0f / 255.0f;
64 static int GLES_RenderDrawPoints(
SDL_Renderer * renderer,
81 static void GLES_DestroyRenderer(
SDL_Renderer * renderer);
85 typedef struct GLES_FBOList GLES_FBOList;
115 #define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
116 #define SDL_PROC_OES SDL_PROC
120 SDL_bool GL_OES_framebuffer_object_supported;
122 GLuint window_framebuffer;
125 SDL_bool GL_OES_draw_texture_supported;
126 SDL_bool GL_OES_blend_func_separate_supported;
149 error =
"GL_NO_ERROR";
152 error =
"GL_INVALID_ENUM";
155 error =
"GL_INVALID_VALUE";
158 error =
"GL_INVALID_OPERATION";
161 error =
"GL_STACK_OVERFLOW";
164 error =
"GL_STACK_UNDERFLOW";
167 error =
"GL_OUT_OF_MEMORY";
176 static int GLES_LoadFunctions(GLES_RenderData *
data)
178 #if SDL_VIDEO_DRIVER_UIKIT
179 #define __SDL_NOGETPROCADDR__
180 #elif SDL_VIDEO_DRIVER_ANDROID
181 #define __SDL_NOGETPROCADDR__
182 #elif SDL_VIDEO_DRIVER_PANDORA
183 #define __SDL_NOGETPROCADDR__
186 #ifdef __SDL_NOGETPROCADDR__
187 #define SDL_PROC(ret,func,params) data->func=func;
188 #define SDL_PROC_OES(ret,func,params) data->func=func;
190 #define SDL_PROC(ret,func,params) \
192 data->func = SDL_GL_GetProcAddress(#func); \
193 if ( ! data->func ) { \
194 return SDL_SetError("Couldn't load GLES function %s: %s\n", #func, SDL_GetError()); \
197 #define SDL_PROC_OES(ret,func,params) \
199 data->func = SDL_GL_GetProcAddress(#func); \
214 GLES_FBOList *result = data->framebuffers;
215 while ((result) && ((result->w != w) || (result->h != h)) )
217 result = result->next;
224 data->glGenFramebuffersOES(1, &result->FBO);
225 result->next = data->framebuffers;
226 data->framebuffers =
result;
235 GLES_RenderData *data = (GLES_RenderData *) renderer->
driverdata;
237 if (SDL_CurrentContext != data->context) {
241 SDL_CurrentContext = data->context;
243 GLES_UpdateViewport(renderer);
252 GLES_RenderData *data = (GLES_RenderData *) renderer->
driverdata;
254 if (SDL_CurrentContext == data->context) {
255 GLES_UpdateViewport(renderer);
257 GLES_ActivateRenderer(renderer);
260 data->current.color = 0;
261 data->current.blendMode = -1;
268 data->glLoadIdentity();
279 GLES_RenderData *
data;
302 data = (GLES_RenderData *)
SDL_calloc(1,
sizeof(*data));
304 GLES_DestroyRenderer(renderer);
329 renderer->
info = GLES_RenderDriver.
info;
332 renderer->
window = window;
335 if (!data->context) {
336 GLES_DestroyRenderer(renderer);
340 GLES_DestroyRenderer(renderer);
344 if (GLES_LoadFunctions(data) < 0) {
345 GLES_DestroyRenderer(renderer);
358 #if SDL_VIDEO_DRIVER_PANDORA
359 data->GL_OES_draw_texture_supported =
SDL_FALSE;
363 data->GL_OES_draw_texture_supported =
SDL_TRUE;
366 data->GL_OES_draw_texture_supported =
SDL_FALSE;
380 data->GL_OES_framebuffer_object_supported =
SDL_TRUE;
384 data->glGetIntegerv(GL_FRAMEBUFFER_BINDING_OES, &value);
385 data->window_framebuffer = (
GLuint)value;
387 data->framebuffers =
NULL;
390 data->GL_OES_blend_func_separate_supported =
SDL_TRUE;
394 GLES_ResetState(renderer);
402 GLES_RenderData *data = (GLES_RenderData *) renderer->
driverdata;
408 SDL_CurrentContext =
NULL;
418 power_of_2(
int input)
422 while (value < input) {
433 if (!hint || *hint ==
'0' ||
SDL_strcasecmp(hint,
"nearest") == 0) {
443 GLES_RenderData *renderdata = (GLES_RenderData *) renderer->
driverdata;
444 GLES_TextureData *data;
447 int texture_w, texture_h;
451 GLES_ActivateRenderer(renderer);
453 switch (texture->
format) {
463 data = (GLES_TextureData *)
SDL_calloc(1,
sizeof(*data));
470 data->pixels =
SDL_calloc(1, texture->
h * data->pitch);
479 if (!renderdata->GL_OES_framebuffer_object_supported) {
481 return SDL_SetError(
"GL_OES_framebuffer_object not supported");
483 data->fbo = GLES_GetFBO(renderer->
driverdata, texture->
w, texture->
h);
489 renderdata->glGetError();
491 renderdata->glGenTextures(1, &data->texture);
492 result = renderdata->glGetError();
495 return GLES_SetError(
"glGenTextures()", result);
500 texture_w = power_of_2(texture->
w);
501 texture_h = power_of_2(texture->
h);
502 data->texw = (
GLfloat) texture->
w / texture_w;
503 data->texh = (
GLfloat) texture->
h / texture_h;
506 data->formattype =
type;
508 renderdata->glBindTexture(data->type, data->texture);
514 renderdata->glTexImage2D(data->type, 0,
internalFormat, texture_w,
518 result = renderdata->glGetError();
521 return GLES_SetError(
"glTexImage2D()", result);
532 GLES_RenderData *renderdata = (GLES_RenderData *) renderer->
driverdata;
533 GLES_TextureData *data = (GLES_TextureData *) texture->
driverdata;
539 GLES_ActivateRenderer(renderer);
542 if (rect->
w <= 0 || rect->
h <= 0)
547 src = (
Uint8 *)pixels;
548 if (pitch != srcPitch) {
554 for (y = 0; y < rect->
h; ++
y) {
557 pixels = (
Uint8 *)pixels + pitch;
563 renderdata->glGetError();
564 renderdata->glEnable(data->type);
565 renderdata->glBindTexture(data->type, data->texture);
567 renderdata->glTexSubImage2D(data->type,
587 const SDL_Rect * rect,
void **pixels,
int *pitch)
589 GLES_TextureData *data = (GLES_TextureData *) texture->
driverdata;
592 (
void *) ((
Uint8 *) data->pixels + rect->
y * data->pitch +
594 *pitch = data->pitch;
601 GLES_TextureData *data = (GLES_TextureData *) texture->
driverdata;
609 GLES_UpdateTexture(renderer, texture, &rect, data->pixels, data->pitch);
615 GLES_RenderData *data = (GLES_RenderData *) renderer->
driverdata;
616 GLES_TextureData *texturedata =
NULL;
619 GLES_ActivateRenderer(renderer);
621 if (!data->GL_OES_framebuffer_object_supported) {
622 return SDL_SetError(
"Can't enable render target support in this renderer");
625 if (texture ==
NULL) {
626 data->glBindFramebufferOES(GL_FRAMEBUFFER_OES, data->window_framebuffer);
630 texturedata = (GLES_TextureData *) texture->
driverdata;
631 data->glBindFramebufferOES(GL_FRAMEBUFFER_OES, texturedata->fbo->FBO);
633 data->glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, texturedata->type, texturedata->texture, 0);
635 status = data->glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
636 if (status != GL_FRAMEBUFFER_COMPLETE_OES) {
637 return SDL_SetError(
"glFramebufferTexture2DOES() failed");
645 GLES_RenderData *data = (GLES_RenderData *) renderer->
driverdata;
647 if (SDL_CurrentContext != data->context) {
657 data->glLoadIdentity();
669 GLES_RenderData *data = (GLES_RenderData *) renderer->
driverdata;
672 if (SDL_CurrentContext != data->context) {
679 data->glScissor(rect->
x, renderer->
viewport.
h - rect->
y - rect->
h, rect->
w, rect->
h);
689 Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b);
691 if (color != data->current.color) {
692 data->glColor4f((
GLfloat) r * inv255f,
696 data->current.color =
color;
701 GLES_SetBlendMode(GLES_RenderData * data,
int blendMode)
703 if (blendMode != data->current.blendMode) {
712 if (data->GL_OES_blend_func_separate_supported) {
721 if (data->GL_OES_blend_func_separate_supported) {
730 if (data->GL_OES_blend_func_separate_supported) {
737 data->current.blendMode = blendMode;
744 if (enabled != data->current.tex_coords) {
750 data->current.tex_coords =
enabled;
757 GLES_RenderData *data = (GLES_RenderData *) renderer->
driverdata;
759 GLES_ActivateRenderer(renderer);
761 GLES_SetColor(data, (
GLfloat) renderer->
r,
766 GLES_SetBlendMode(data, renderer->
blendMode);
774 GLES_RenderData *data = (GLES_RenderData *) renderer->
driverdata;
776 GLES_ActivateRenderer(renderer);
778 data->glClearColor((
GLfloat) renderer->
r * inv255f,
792 GLES_RenderData *data = (GLES_RenderData *) renderer->
driverdata;
794 GLES_SetDrawingState(renderer);
796 data->glVertexPointer(2,
GL_FLOAT, 0, points);
806 GLES_RenderData *data = (GLES_RenderData *) renderer->
driverdata;
808 GLES_SetDrawingState(renderer);
810 data->glVertexPointer(2,
GL_FLOAT, 0, points);
812 points[0].
x == points[count-1].
x && points[0].y == points[count-1].y) {
819 data->glDrawArrays(
GL_POINTS, count-1, 1);
829 GLES_RenderData *data = (GLES_RenderData *) renderer->
driverdata;
832 GLES_SetDrawingState(renderer);
850 data->glVertexPointer(2,
GL_FLOAT, 0, vertices);
861 GLES_RenderData *data = (GLES_RenderData *) renderer->
driverdata;
862 GLES_TextureData *texturedata = (GLES_TextureData *) texture->
driverdata;
863 GLfloat minx, miny, maxx, maxy;
868 GLES_ActivateRenderer(renderer);
872 data->glBindTexture(texturedata->type, texturedata->texture);
875 GLES_SetColor(data, texture->
r, texture->
g, texture->
b, texture->
a);
877 GLES_SetColor(data, 255, 255, 255, 255);
880 GLES_SetBlendMode(data, texture->
blendMode);
884 if (data->GL_OES_draw_texture_supported && data->useDrawTexture) {
892 cropRect[0] = srcrect->
x;
893 cropRect[1] = srcrect->
y;
894 cropRect[2] = srcrect->
w;
895 cropRect[3] = srcrect->
h;
896 data->glTexParameteriv(
GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES,
899 dstrect->
w, dstrect->
h);
901 cropRect[0] = srcrect->
x;
902 cropRect[1] = srcrect->
y + srcrect->
h;
903 cropRect[2] = srcrect->
w;
904 cropRect[3] = -srcrect->
h;
905 data->glTexParameteriv(
GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES,
907 data->glDrawTexfOES(renderer->
viewport.
x + dstrect->
x,
908 h - (renderer->
viewport.
y + dstrect->
y) - dstrect->
h, 0,
909 dstrect->
w, dstrect->
h);
915 maxx = dstrect->
x + dstrect->
w;
916 maxy = dstrect->
y + dstrect->
h;
918 minu = (
GLfloat) srcrect->
x / texture->
w;
919 minu *= texturedata->texw;
920 maxu = (
GLfloat) (srcrect->
x + srcrect->
w) / texture->
w;
921 maxu *= texturedata->texw;
922 minv = (
GLfloat) srcrect->
y / texture->
h;
923 minv *= texturedata->texh;
924 maxv = (
GLfloat) (srcrect->
y + srcrect->
h) / texture->
h;
925 maxv *= texturedata->texh;
945 data->glVertexPointer(2,
GL_FLOAT, 0, vertices);
946 data->glTexCoordPointer(2,
GL_FLOAT, 0, texCoords);
960 GLES_RenderData *data = (GLES_RenderData *) renderer->
driverdata;
961 GLES_TextureData *texturedata = (GLES_TextureData *) texture->
driverdata;
962 GLfloat minx, miny, maxx, maxy;
969 GLES_ActivateRenderer(renderer);
973 data->glBindTexture(texturedata->type, texturedata->texture);
976 GLES_SetColor(data, texture->
r, texture->
g, texture->
b, texture->
a);
978 GLES_SetColor(data, 255, 255, 255, 255);
981 GLES_SetBlendMode(data, texture->
blendMode);
989 data->glPushMatrix();
990 data->glTranslatef(dstrect->
x + centerx, dstrect->
y + centery, 0.0f);
991 data->glRotatef((
GLfloat)angle, 0.0
f, 0.0
f, 1.0
f);
994 minx = dstrect->
w - centerx;
998 maxx = dstrect->
w - centerx;
1002 miny = dstrect->
h - centery;
1006 maxy = dstrect->
h - centery;
1009 minu = (
GLfloat) srcrect->
x / texture->
w;
1010 minu *= texturedata->texw;
1011 maxu = (
GLfloat) (srcrect->
x + srcrect->
w) / texture->
w;
1012 maxu *= texturedata->texw;
1013 minv = (
GLfloat) srcrect->
y / texture->
h;
1014 minv *= texturedata->texh;
1015 maxv = (
GLfloat) (srcrect->
y + srcrect->
h) / texture->
h;
1016 maxv *= texturedata->texh;
1027 texCoords[0] =
minu;
1028 texCoords[1] = minv;
1029 texCoords[2] =
maxu;
1030 texCoords[3] = minv;
1031 texCoords[4] =
minu;
1032 texCoords[5] = maxv;
1033 texCoords[6] =
maxu;
1034 texCoords[7] = maxv;
1035 data->glVertexPointer(2,
GL_FLOAT, 0, vertices);
1036 data->glTexCoordPointer(2,
GL_FLOAT, 0, texCoords);
1038 data->glPopMatrix();
1046 Uint32 pixel_format,
void * pixels,
int pitch)
1048 GLES_RenderData *data = (GLES_RenderData *) renderer->
driverdata;
1056 GLES_ActivateRenderer(renderer);
1068 data->glReadPixels(rect->
x, (h-rect->
y)-rect->
h, rect->
w, rect->
h,
1073 src = (
Uint8*)temp_pixels + (rect->
h-1)*temp_pitch;
1087 temp_format, temp_pixels, temp_pitch,
1088 pixel_format, pixels, pitch);
1097 GLES_ActivateRenderer(renderer);
1105 GLES_RenderData *renderdata = (GLES_RenderData *) renderer->
driverdata;
1107 GLES_TextureData *data = (GLES_TextureData *) texture->
driverdata;
1109 GLES_ActivateRenderer(renderer);
1114 if (data->texture) {
1115 renderdata->glDeleteTextures(1, &data->texture);
1125 GLES_RenderData *data = (GLES_RenderData *) renderer->
driverdata;
1128 if (data->context) {
1129 while (data->framebuffers) {
1130 GLES_FBOList *nextnode = data->framebuffers->next;
1131 data->glDeleteFramebuffersOES(1, &data->framebuffers->FBO);
1133 data->framebuffers = nextnode;
1144 GLES_RenderData *data = (GLES_RenderData *) renderer->
driverdata;
1145 GLES_TextureData *texturedata = (GLES_TextureData *) texture->
driverdata;
1146 GLES_ActivateRenderer(renderer);
1149 data->glBindTexture(texturedata->type, texturedata->texture);
1151 if(texw) *texw = (float)texturedata->texw;
1152 if(texh) *texh = (float)texturedata->texh;
1159 GLES_RenderData *data = (GLES_RenderData *) renderer->
driverdata;
1160 GLES_TextureData *texturedata = (GLES_TextureData *) texture->
driverdata;
1161 GLES_ActivateRenderer(renderer);
1162 data->glDisable(texturedata->type);
int(* UpdateClipRect)(SDL_Renderer *renderer)
#define GL_TEXTURE_ENV_MODE
GLfloat GLfloat GLfloat GLfloat h
GLint GLenum GLsizei GLsizei GLsizei GLint GLenum GLenum type
DECLSPEC void *SDLCALL SDL_calloc(size_t nmemb, size_t size)
void(* WindowEvent)(SDL_Renderer *renderer, const SDL_WindowEvent *event)
DECLSPEC int SDLCALL SDL_GL_GetSwapInterval(void)
Get the swap interval for the current OpenGL context.
DECLSPEC int SDLCALL SDL_ConvertPixels(int width, int height, Uint32 src_format, const void *src, int src_pitch, Uint32 dst_format, void *dst, int dst_pitch)
Copy a block of pixels of one format to another format.
int(* RenderClear)(SDL_Renderer *renderer)
#define SDL_stack_free(data)
DECLSPEC SDL_GLContext SDLCALL SDL_GL_CreateContext(SDL_Window *window)
Create an OpenGL context for use with an OpenGL window, and make it current.
int(* RenderDrawPoints)(SDL_Renderer *renderer, const SDL_FPoint *points, int count)
GLenum GLsizei const GLuint GLboolean enabled
int(* SetRenderTarget)(SDL_Renderer *renderer, SDL_Texture *texture)
int(* CreateTexture)(SDL_Renderer *renderer, SDL_Texture *texture)
#define SDL_HINT_RENDER_SCALE_QUALITY
A variable controlling the scaling quality.
DECLSPEC void SDLCALL SDL_free(void *mem)
#define GL_INVALID_OPERATION
EGLSurface EGLint EGLint EGLint EGLint height
GLboolean GLboolean GLboolean GLboolean a
void * SDL_GLContext
An opaque handle to an OpenGL context.
#define SDL_BYTESPERPIXEL(X)
DECLSPEC void SDLCALL SDL_GetWindowSize(SDL_Window *window, int *w, int *h)
Get the size of a window's client area.
void(* UnlockTexture)(SDL_Renderer *renderer, SDL_Texture *texture)
#define GL_TEXTURE_MAG_FILTER
#define GL_STACK_OVERFLOW
DECLSPEC int SDLCALL SDL_GetRendererOutputSize(SDL_Renderer *renderer, int *w, int *h)
Get the output size of a rendering context.
#define GL_TRIANGLE_STRIP
SDL_FORCE_INLINE SDL_bool SDL_RectEmpty(const SDL_Rect *r)
Returns true if the rectangle has no area.
uint32_t Uint32
An unsigned 32-bit integer type.
const GLuint * framebuffers
DECLSPEC int SDLCALL SDL_GL_MakeCurrent(SDL_Window *window, SDL_GLContext context)
Set up an OpenGL context for rendering into an OpenGL window.
int(* LockTexture)(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, void **pixels, int *pitch)
DECLSPEC int SDLCALL SDL_GL_SetAttribute(SDL_GLattr attr, int value)
Set an OpenGL window attribute before window creation.
#define GL_COLOR_BUFFER_BIT
#define GL_TEXTURE_MIN_FILTER
DECLSPEC int SDLCALL SDL_GL_SetSwapInterval(int interval)
Set the swap interval for the current OpenGL context.
int(* UpdateTexture)(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, const void *pixels, int pitch)
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
int SDL_RecreateWindow(SDL_Window *window, Uint32 flags)
EGLSurface EGLint EGLint EGLint width
static int GetScaleQuality(void)
DECLSPEC void SDLCALL SDL_GL_DeleteContext(SDL_GLContext context)
Delete an OpenGL context.
int(* RenderDrawLines)(SDL_Renderer *renderer, const SDL_FPoint *points, int count)
#define GL_PACK_ALIGNMENT
GLint GLenum GLsizei GLsizei GLsizei GLint GLenum format
DECLSPEC int SDLCALL SDL_SetError(const char *fmt,...)
DECLSPEC void *SDLCALL SDL_malloc(size_t size)
#define GL_TEXTURE_COORD_ARRAY
GLint GLint internalFormat
DECLSPEC Uint32 SDLCALL SDL_GetWindowFlags(SDL_Window *window)
Get the window flags.
DECLSPEC const char *SDLCALL SDL_GetHint(const char *name)
Get a hint.
void(* DestroyTexture)(SDL_Renderer *renderer, SDL_Texture *texture)
int(* RenderCopy)(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *srcrect, const SDL_FRect *dstrect)
static __inline ALuint minu(ALuint a, ALuint b)
SDL_RendererFlip
Flip constants for SDL_RenderCopyEx.
Window state change event data (event.window.*)
EGLSurface EGLint EGLint y
#define SDL_OutOfMemory()
GLenum GLenum GLuint texture
GLint GLenum GLsizei GLsizei GLsizei GLint GLenum GLenum const GLvoid * pixels
int(* GL_BindTexture)(SDL_Renderer *renderer, SDL_Texture *texture, float *texw, float *texh)
GLenum GLenum GLenum input
EGLSurface EGLint void ** value
int(* RenderReadPixels)(SDL_Renderer *renderer, const SDL_Rect *rect, Uint32 format, void *pixels, int pitch)
DECLSPEC void *SDLCALL SDL_memcpy(void *dst, const void *src, size_t len)
GLenum GLsizei GLsizei GLsizei GLsizei GLbitfield flags
int(* GL_UnbindTexture)(SDL_Renderer *renderer, SDL_Texture *texture)
#define GL_TEXTURE_WRAP_T
int(* RenderFillRects)(SDL_Renderer *renderer, const SDL_FRect *rects, int count)
uint8_t Uint8
An unsigned 8-bit integer type.
#define GL_TEXTURE_WRAP_S
#define GL_STACK_UNDERFLOW
#define GL_ONE_MINUS_SRC_ALPHA
GLdouble GLdouble GLdouble r
GLdouble GLdouble GLdouble b
GLint GLint GLint GLint z
GLint GLint GLint GLint GLint w
#define SDL_stack_alloc(type, count)
#define GL_UNPACK_ALIGNMENT
int(* UpdateViewport)(SDL_Renderer *renderer)
GLuint GLdouble GLdouble GLint GLint const GLdouble * points
DECLSPEC SDL_bool SDLCALL SDL_GL_ExtensionSupported(const char *extension)
Return true if an OpenGL extension is supported for the current context.
int(* RenderCopyEx)(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *srcquad, const SDL_FRect *dstrect, const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
void(* RenderPresent)(SDL_Renderer *renderer)
void(* DestroyRenderer)(SDL_Renderer *renderer)
DECLSPEC int SDLCALL SDL_strcasecmp(const char *str1, const char *str2)
static __inline ALuint maxu(ALuint a, ALuint b)
A rectangle, with the origin at the upper left.
#define GL_MAX_TEXTURE_SIZE
DECLSPEC void SDLCALL SDL_GL_SwapWindow(SDL_Window *window)
Swap the OpenGL buffers for a window, if double-buffering is supported.