src/render/opengles2/SDL_render_gles2.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 01 Oct 2016 11:34:04 -0700
changeset 10405 b8ca95a8eea9
parent 9998 f67cf37e9cd4
child 10406 ef00f5640e86
permissions -rw-r--r--
Fixed bug 3350 - GL renderers don't need to flip rows after reading back pixels from the target texture

Simon Hug

All OpenGL renderers always flip the rows of the pixels that come from glReadPixels. This is unnecessary for target textures since these are already top down.

Also, the rect->y value can be used directly for target textures for the same reason. I don't see any code that would handle the logical render size for target textures. Or am I missing something?

The attached patch makes the renderers only the flip rows if the data comes from the default framebuffer.
slouken@5201
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@9998
     3
  Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
slouken@5201
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
slouken@5201
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
slouken@5201
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@5201
    20
*/
icculus@8093
    21
#include "../../SDL_internal.h"
slouken@5201
    22
slouken@5226
    23
#if SDL_VIDEO_RENDER_OGL_ES2 && !SDL_RENDER_DISABLED
slouken@5201
    24
slouken@5484
    25
#include "SDL_hints.h"
slouken@5204
    26
#include "SDL_opengles2.h"
slouken@5201
    27
#include "../SDL_sysrender.h"
slouken@7785
    28
#include "../../video/SDL_blit.h"
slouken@5201
    29
#include "SDL_shaders_gles2.h"
slouken@5201
    30
icculus@9299
    31
/* !!! FIXME: Emscripten makes these into WebGL calls, and WebGL doesn't offer
icculus@9299
    32
   !!! FIXME:  client-side arrays (without an Emscripten compatibility hack,
icculus@9299
    33
   !!! FIXME:  at least), but the current VBO code here is dramatically
icculus@9299
    34
   !!! FIXME:  slower on actual iOS devices, even though the iOS Simulator
icculus@9299
    35
   !!! FIXME:  is okay. Some time after 2.0.4 ships, we should revisit this,
icculus@9299
    36
   !!! FIXME:  fix the performance bottleneck, and make everything use VBOs.
icculus@9299
    37
*/
icculus@9299
    38
#ifdef __EMSCRIPTEN__
icculus@9299
    39
#define SDL_GLES2_USE_VBOS 1
icculus@9299
    40
#else
icculus@9299
    41
#define SDL_GLES2_USE_VBOS 0
icculus@9299
    42
#endif
icculus@9299
    43
icculus@9299
    44
/* To prevent unnecessary window recreation,
gabomdq@8264
    45
 * these should match the defaults selected in SDL_GL_ResetAttributes 
gabomdq@8264
    46
 */
gabomdq@8257
    47
#define RENDERER_CONTEXT_MAJOR 2
gabomdq@8257
    48
#define RENDERER_CONTEXT_MINOR 0
gabomdq@8257
    49
slouken@6190
    50
/* Used to re-create the window with OpenGL ES capability */
slouken@6188
    51
extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags);
slouken@6188
    52
slouken@5201
    53
/*************************************************************************************************
slouken@5201
    54
 * Bootstrap data                                                                                *
slouken@5201
    55
 *************************************************************************************************/
slouken@5201
    56
slouken@5201
    57
static SDL_Renderer *GLES2_CreateRenderer(SDL_Window *window, Uint32 flags);
slouken@5201
    58
slouken@5201
    59
SDL_RenderDriver GLES2_RenderDriver = {
slouken@5201
    60
    GLES2_CreateRenderer,
slouken@5201
    61
    {
slouken@5201
    62
        "opengles2",
slouken@6237
    63
        (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
slouken@6113
    64
        4,
slouken@8904
    65
        {
slouken@6113
    66
        SDL_PIXELFORMAT_ARGB8888,
slouken@8904
    67
        SDL_PIXELFORMAT_ABGR8888,
slouken@6113
    68
        SDL_PIXELFORMAT_RGB888,
slouken@8904
    69
        SDL_PIXELFORMAT_BGR888
slouken@8904
    70
        },
slouken@5201
    71
        0,
slouken@5201
    72
        0
slouken@5201
    73
    }
slouken@5201
    74
};
slouken@5201
    75
slouken@5201
    76
/*************************************************************************************************
slouken@5201
    77
 * Context structures                                                                            *
slouken@5201
    78
 *************************************************************************************************/
slouken@5201
    79
slouken@6232
    80
typedef struct GLES2_FBOList GLES2_FBOList;
slouken@6232
    81
slouken@6232
    82
struct GLES2_FBOList
slouken@6232
    83
{
slouken@6232
    84
   Uint32 w, h;
slouken@6232
    85
   GLuint FBO;
slouken@6232
    86
   GLES2_FBOList *next;
slouken@6232
    87
};
slouken@6232
    88
slouken@5201
    89
typedef struct GLES2_TextureData
slouken@5201
    90
{
slouken@5201
    91
    GLenum texture;
slouken@5201
    92
    GLenum texture_type;
slouken@5201
    93
    GLenum pixel_format;
slouken@5201
    94
    GLenum pixel_type;
slouken@5201
    95
    void *pixel_data;
slouken@8983
    96
    int pitch;
slouken@9046
    97
    /* YUV texture support */
slouken@8835
    98
    SDL_bool yuv;
slouken@9046
    99
    SDL_bool nv12;
slouken@8835
   100
    GLenum texture_v;
slouken@8835
   101
    GLenum texture_u;
slouken@6232
   102
    GLES2_FBOList *fbo;
slouken@5201
   103
} GLES2_TextureData;
slouken@5201
   104
slouken@5201
   105
typedef struct GLES2_ShaderCacheEntry
slouken@5201
   106
{
slouken@5201
   107
    GLuint id;
slouken@5201
   108
    GLES2_ShaderType type;
slouken@5201
   109
    const GLES2_ShaderInstance *instance;
slouken@5201
   110
    int references;
icculus@7784
   111
    Uint8 modulation_r, modulation_g, modulation_b, modulation_a;
slouken@5201
   112
    struct GLES2_ShaderCacheEntry *prev;
slouken@5201
   113
    struct GLES2_ShaderCacheEntry *next;
slouken@5201
   114
} GLES2_ShaderCacheEntry;
slouken@5201
   115
slouken@5201
   116
typedef struct GLES2_ShaderCache
slouken@5201
   117
{
slouken@5201
   118
    int count;
slouken@5201
   119
    GLES2_ShaderCacheEntry *head;
slouken@5201
   120
} GLES2_ShaderCache;
slouken@5201
   121
slouken@5201
   122
typedef struct GLES2_ProgramCacheEntry
slouken@5201
   123
{
slouken@5201
   124
    GLuint id;
slouken@5201
   125
    SDL_BlendMode blend_mode;
slouken@5201
   126
    GLES2_ShaderCacheEntry *vertex_shader;
slouken@5201
   127
    GLES2_ShaderCacheEntry *fragment_shader;
slouken@5201
   128
    GLuint uniform_locations[16];
icculus@7784
   129
    Uint8 color_r, color_g, color_b, color_a;
icculus@7784
   130
    Uint8 modulation_r, modulation_g, modulation_b, modulation_a;
icculus@7784
   131
    GLfloat projection[4][4];
slouken@5201
   132
    struct GLES2_ProgramCacheEntry *prev;
slouken@5201
   133
    struct GLES2_ProgramCacheEntry *next;
slouken@5201
   134
} GLES2_ProgramCacheEntry;
slouken@5201
   135
slouken@5201
   136
typedef struct GLES2_ProgramCache
slouken@5201
   137
{
slouken@5201
   138
    int count;
slouken@5201
   139
    GLES2_ProgramCacheEntry *head;
slouken@5201
   140
    GLES2_ProgramCacheEntry *tail;
slouken@5201
   141
} GLES2_ProgramCache;
slouken@5201
   142
slouken@5201
   143
typedef enum
slouken@5201
   144
{
slouken@5201
   145
    GLES2_ATTRIBUTE_POSITION = 0,
gabomdq@6320
   146
    GLES2_ATTRIBUTE_TEXCOORD = 1,
gabomdq@6320
   147
    GLES2_ATTRIBUTE_ANGLE = 2,
gabomdq@6320
   148
    GLES2_ATTRIBUTE_CENTER = 3,
slouken@5201
   149
} GLES2_Attribute;
slouken@5201
   150
slouken@5201
   151
typedef enum
slouken@5201
   152
{
slouken@5201
   153
    GLES2_UNIFORM_PROJECTION,
slouken@5201
   154
    GLES2_UNIFORM_TEXTURE,
slouken@5201
   155
    GLES2_UNIFORM_MODULATION,
slouken@8835
   156
    GLES2_UNIFORM_COLOR,
slouken@8835
   157
    GLES2_UNIFORM_TEXTURE_U,
slouken@8835
   158
    GLES2_UNIFORM_TEXTURE_V
slouken@5201
   159
} GLES2_Uniform;
slouken@5201
   160
slouken@5201
   161
typedef enum
slouken@5201
   162
{
slouken@5201
   163
    GLES2_IMAGESOURCE_SOLID,
slouken@6113
   164
    GLES2_IMAGESOURCE_TEXTURE_ABGR,
slouken@6113
   165
    GLES2_IMAGESOURCE_TEXTURE_ARGB,
slouken@6113
   166
    GLES2_IMAGESOURCE_TEXTURE_RGB,
slouken@8835
   167
    GLES2_IMAGESOURCE_TEXTURE_BGR,
slouken@9046
   168
    GLES2_IMAGESOURCE_TEXTURE_YUV,
slouken@9046
   169
    GLES2_IMAGESOURCE_TEXTURE_NV12,
slouken@9046
   170
    GLES2_IMAGESOURCE_TEXTURE_NV21
slouken@5201
   171
} GLES2_ImageSource;
slouken@5201
   172
slouken@5201
   173
typedef struct GLES2_DriverContext
slouken@5201
   174
{
slouken@5201
   175
    SDL_GLContext *context;
slouken@7780
   176
slouken@7780
   177
    SDL_bool debug_enabled;
slouken@7780
   178
slouken@5355
   179
    struct {
slouken@5355
   180
        int blendMode;
slouken@5355
   181
        SDL_bool tex_coords;
slouken@5355
   182
    } current;
slouken@5355
   183
slouken@6188
   184
#define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
slouken@6188
   185
#include "SDL_gles2funcs.h"
slouken@6188
   186
#undef SDL_PROC
slouken@6232
   187
    GLES2_FBOList *framebuffers;
slouken@6271
   188
    GLuint window_framebuffer;
slouken@6188
   189
slouken@5201
   190
    int shader_format_count;
slouken@5201
   191
    GLenum *shader_formats;
slouken@5201
   192
    GLES2_ShaderCache shader_cache;
slouken@5201
   193
    GLES2_ProgramCache program_cache;
slouken@5201
   194
    GLES2_ProgramCacheEntry *current_program;
icculus@7784
   195
    Uint8 clear_r, clear_g, clear_b, clear_a;
icculus@9278
   196
icculus@9299
   197
#if SDL_GLES2_USE_VBOS
icculus@9278
   198
    GLuint vertex_buffers[4];
icculus@9278
   199
    GLsizeiptr vertex_buffer_size[4];
icculus@9299
   200
#endif
slouken@5201
   201
} GLES2_DriverContext;
slouken@5201
   202
slouken@5201
   203
#define GLES2_MAX_CACHED_PROGRAMS 8
slouken@5201
   204
slouken@7780
   205
slouken@7780
   206
SDL_FORCE_INLINE const char*
slouken@7780
   207
GL_TranslateError (GLenum error)
slouken@7780
   208
{
slouken@7780
   209
#define GL_ERROR_TRANSLATE(e) case e: return #e;
slouken@7780
   210
    switch (error) {
slouken@7780
   211
    GL_ERROR_TRANSLATE(GL_INVALID_ENUM)
slouken@7780
   212
    GL_ERROR_TRANSLATE(GL_INVALID_VALUE)
slouken@7780
   213
    GL_ERROR_TRANSLATE(GL_INVALID_OPERATION)
slouken@7780
   214
    GL_ERROR_TRANSLATE(GL_OUT_OF_MEMORY)
slouken@7780
   215
    GL_ERROR_TRANSLATE(GL_NO_ERROR)
slouken@7780
   216
    default:
slouken@7780
   217
        return "UNKNOWN";
slouken@7780
   218
}
slouken@7780
   219
#undef GL_ERROR_TRANSLATE
slouken@7780
   220
}
slouken@7780
   221
slouken@7780
   222
SDL_FORCE_INLINE void
slouken@7780
   223
GL_ClearErrors(SDL_Renderer *renderer)
slouken@7780
   224
{
slouken@7780
   225
    GLES2_DriverContext *data = (GLES2_DriverContext *) renderer->driverdata;
slouken@7780
   226
slime73@9604
   227
    if (!data->debug_enabled) {
slouken@7780
   228
        return;
slouken@7780
   229
    }
slouken@7780
   230
    while (data->glGetError() != GL_NO_ERROR) {
slouken@7780
   231
        continue;
slouken@7780
   232
    }
slouken@7780
   233
}
slouken@7780
   234
slouken@7780
   235
SDL_FORCE_INLINE int
slouken@7780
   236
GL_CheckAllErrors (const char *prefix, SDL_Renderer *renderer, const char *file, int line, const char *function)
slouken@7780
   237
{
slouken@7780
   238
    GLES2_DriverContext *data = (GLES2_DriverContext *) renderer->driverdata;
slouken@7780
   239
    int ret = 0;
slouken@7780
   240
slime73@9604
   241
    if (!data->debug_enabled) {
slouken@7780
   242
        return 0;
slouken@7780
   243
    }
slouken@7780
   244
    /* check gl errors (can return multiple errors) */
slouken@7780
   245
    for (;;) {
slouken@7780
   246
        GLenum error = data->glGetError();
slouken@7780
   247
        if (error != GL_NO_ERROR) {
slouken@7780
   248
            if (prefix == NULL || prefix[0] == '\0') {
slouken@7780
   249
                prefix = "generic";
slouken@7780
   250
            }
slouken@7780
   251
            SDL_SetError("%s: %s (%d): %s %s (0x%X)", prefix, file, line, function, GL_TranslateError(error), error);
slouken@7780
   252
            ret = -1;
slouken@7780
   253
        } else {
slouken@7780
   254
            break;
slouken@7780
   255
        }
slouken@7780
   256
    }
slouken@7780
   257
    return ret;
slouken@7780
   258
}
slouken@7780
   259
slouken@7780
   260
#if 0
slouken@7780
   261
#define GL_CheckError(prefix, renderer)
slouken@7780
   262
#elif defined(_MSC_VER)
slouken@7780
   263
#define GL_CheckError(prefix, renderer) GL_CheckAllErrors(prefix, renderer, __FILE__, __LINE__, __FUNCTION__)
slouken@7780
   264
#else
slouken@7780
   265
#define GL_CheckError(prefix, renderer) GL_CheckAllErrors(prefix, renderer, __FILE__, __LINE__, __PRETTY_FUNCTION__)
slouken@7780
   266
#endif
slouken@7780
   267
slouken@7780
   268
slouken@5201
   269
/*************************************************************************************************
slouken@5201
   270
 * Renderer state APIs                                                                           *
slouken@5201
   271
 *************************************************************************************************/
slouken@5201
   272
slouken@5224
   273
static int GLES2_ActivateRenderer(SDL_Renderer *renderer);
slouken@5201
   274
static void GLES2_WindowEvent(SDL_Renderer * renderer,
slouken@5201
   275
                              const SDL_WindowEvent *event);
slouken@5297
   276
static int GLES2_UpdateViewport(SDL_Renderer * renderer);
slouken@5201
   277
static void GLES2_DestroyRenderer(SDL_Renderer *renderer);
slouken@6246
   278
static int GLES2_SetOrthographicProjection(SDL_Renderer *renderer);
slouken@5201
   279
slouken@6232
   280
slouken@5201
   281
static SDL_GLContext SDL_CurrentContext = NULL;
slouken@5201
   282
slouken@6188
   283
static int GLES2_LoadFunctions(GLES2_DriverContext * data)
slouken@6188
   284
{
slouken@6190
   285
#if SDL_VIDEO_DRIVER_UIKIT
slouken@6190
   286
#define __SDL_NOGETPROCADDR__
slouken@6190
   287
#elif SDL_VIDEO_DRIVER_ANDROID
slouken@6190
   288
#define __SDL_NOGETPROCADDR__
slouken@6190
   289
#elif SDL_VIDEO_DRIVER_PANDORA
slouken@6190
   290
#define __SDL_NOGETPROCADDR__
slouken@6190
   291
#endif
slouken@6190
   292
slouken@6190
   293
#if defined __SDL_NOGETPROCADDR__
slouken@6188
   294
#define SDL_PROC(ret,func,params) data->func=func;
slouken@6188
   295
#else
slouken@6188
   296
#define SDL_PROC(ret,func,params) \
slouken@6188
   297
    do { \
slouken@6188
   298
        data->func = SDL_GL_GetProcAddress(#func); \
slouken@6188
   299
        if ( ! data->func ) { \
icculus@7037
   300
            return SDL_SetError("Couldn't load GLES2 function %s: %s\n", #func, SDL_GetError()); \
slouken@6188
   301
        } \
slouken@6232
   302
    } while ( 0 );
philipp@9709
   303
#endif /* __SDL_NOGETPROCADDR__ */
slouken@6188
   304
slouken@6188
   305
#include "SDL_gles2funcs.h"
slouken@6188
   306
#undef SDL_PROC
slouken@6188
   307
    return 0;
slouken@6188
   308
}
slouken@6188
   309
slouken@6232
   310
GLES2_FBOList *
slouken@6232
   311
GLES2_GetFBO(GLES2_DriverContext *data, Uint32 w, Uint32 h)
slouken@6232
   312
{
slouken@6232
   313
   GLES2_FBOList *result = data->framebuffers;
slime73@9604
   314
   while ((result) && ((result->w != w) || (result->h != h)) ) {
slouken@6232
   315
       result = result->next;
slouken@6232
   316
   }
slime73@9604
   317
   if (result == NULL) {
slouken@6232
   318
       result = SDL_malloc(sizeof(GLES2_FBOList));
slouken@6232
   319
       result->w = w;
slouken@6232
   320
       result->h = h;
slouken@6269
   321
       data->glGenFramebuffers(1, &result->FBO);
slouken@6232
   322
       result->next = data->framebuffers;
slouken@6232
   323
       data->framebuffers = result;
slouken@6232
   324
   }
slouken@6232
   325
   return result;
slouken@6232
   326
}
slouken@6232
   327
slouken@5201
   328
static int
slouken@5201
   329
GLES2_ActivateRenderer(SDL_Renderer * renderer)
slouken@5201
   330
{
slouken@7780
   331
    GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
slouken@5201
   332
slouken@7780
   333
    if (SDL_CurrentContext != data->context) {
slouken@5201
   334
        /* Null out the current program to ensure we set it again */
slouken@7780
   335
        data->current_program = NULL;
slouken@5201
   336
slouken@7780
   337
        if (SDL_GL_MakeCurrent(renderer->window, data->context) < 0) {
slouken@5201
   338
            return -1;
slouken@5201
   339
        }
slouken@7780
   340
        SDL_CurrentContext = data->context;
slouken@5201
   341
slouken@5297
   342
        GLES2_UpdateViewport(renderer);
slouken@5201
   343
    }
slouken@7780
   344
slouken@7780
   345
    GL_ClearErrors(renderer);
slouken@7780
   346
slouken@5201
   347
    return 0;
slouken@5201
   348
}
slouken@5201
   349
slouken@5201
   350
static void
slouken@5201
   351
GLES2_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
slouken@5201
   352
{
slouken@7780
   353
    GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
slouken@6232
   354
slouken@6260
   355
    if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED ||
slouken@6260
   356
        event->event == SDL_WINDOWEVENT_SHOWN ||
slouken@6260
   357
        event->event == SDL_WINDOWEVENT_HIDDEN) {
slouken@5201
   358
        /* Rebind the context to the window area */
slouken@5201
   359
        SDL_CurrentContext = NULL;
slouken@5201
   360
    }
slouken@6060
   361
slouken@6060
   362
    if (event->event == SDL_WINDOWEVENT_MINIMIZED) {
slouken@6060
   363
        /* According to Apple documentation, we need to finish drawing NOW! */
slouken@7780
   364
        data->glFinish();
slouken@6060
   365
    }
slouken@5201
   366
}
slouken@5201
   367
slouken@5297
   368
static int
slime73@9530
   369
GLES2_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
slime73@9530
   370
{
slime73@9530
   371
    SDL_GL_GetDrawableSize(renderer->window, w, h);
slime73@9530
   372
    return 0;
slime73@9530
   373
}
slime73@9530
   374
slime73@9530
   375
static int
slouken@5297
   376
GLES2_UpdateViewport(SDL_Renderer * renderer)
slouken@5224
   377
{
slouken@7780
   378
    GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
slouken@5224
   379
slouken@7780
   380
    if (SDL_CurrentContext != data->context) {
slouken@5297
   381
        /* We'll update the viewport after we rebind the context */
slouken@5297
   382
        return 0;
slouken@5297
   383
    }
slouken@5224
   384
slouken@9680
   385
    if (renderer->target) {
slouken@9680
   386
        data->glViewport(renderer->viewport.x, renderer->viewport.y,
slouken@9680
   387
                         renderer->viewport.w, renderer->viewport.h);
slouken@9680
   388
    } else {
slouken@9680
   389
        int w, h;
slouken@9680
   390
slouken@9680
   391
        SDL_GetRendererOutputSize(renderer, &w, &h);
slouken@9680
   392
        data->glViewport(renderer->viewport.x, (h - renderer->viewport.y - renderer->viewport.h),
slouken@9680
   393
                         renderer->viewport.w, renderer->viewport.h);
slouken@9680
   394
    }
slouken@6268
   395
slouken@7780
   396
    if (data->current_program) {
slouken@6268
   397
        GLES2_SetOrthographicProjection(renderer);
slouken@6268
   398
    }
slouken@7780
   399
    return GL_CheckError("", renderer);
slouken@5224
   400
}
slouken@5224
   401
slouken@7141
   402
static int
slouken@7141
   403
GLES2_UpdateClipRect(SDL_Renderer * renderer)
slouken@7141
   404
{
slouken@7780
   405
    GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
slouken@7141
   406
slouken@7780
   407
    if (SDL_CurrentContext != data->context) {
gabomdq@7160
   408
        /* We'll update the clip rect after we rebind the context */
gabomdq@7160
   409
        return 0;
gabomdq@7160
   410
    }
gabomdq@7160
   411
jorgenpt@8728
   412
    if (renderer->clipping_enabled) {
jorgenpt@8728
   413
        const SDL_Rect *rect = &renderer->clip_rect;
slouken@7780
   414
        data->glEnable(GL_SCISSOR_TEST);
slouken@9680
   415
        if (renderer->target) {
slouken@9680
   416
            data->glScissor(renderer->viewport.x + rect->x, renderer->viewport.y + rect->y, rect->w, rect->h);
slouken@9680
   417
        } else {
slouken@9680
   418
            int w, h;
slouken@9680
   419
slouken@9680
   420
            SDL_GetRendererOutputSize(renderer, &w, &h);
icculus@9977
   421
            data->glScissor(renderer->viewport.x + rect->x, h - renderer->viewport.y - rect->y - rect->h, rect->w, rect->h);
slouken@9680
   422
        }
slouken@7141
   423
    } else {
slouken@7780
   424
        data->glDisable(GL_SCISSOR_TEST);
slouken@7141
   425
    }
slouken@7141
   426
    return 0;
slouken@7141
   427
}
slouken@7141
   428
slouken@5224
   429
static void
slouken@5201
   430
GLES2_DestroyRenderer(SDL_Renderer *renderer)
slouken@5201
   431
{
slouken@7780
   432
    GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
slouken@5201
   433
slouken@5209
   434
    /* Deallocate everything */
slouken@7780
   435
    if (data) {
slouken@5209
   436
        GLES2_ActivateRenderer(renderer);
slouken@5201
   437
slouken@6178
   438
        {
slouken@6178
   439
            GLES2_ShaderCacheEntry *entry;
slouken@6178
   440
            GLES2_ShaderCacheEntry *next;
slouken@7780
   441
            entry = data->shader_cache.head;
slime73@9604
   442
            while (entry) {
slouken@7780
   443
                data->glDeleteShader(entry->id);
slouken@6052
   444
                next = entry->next;
slouken@6052
   445
                SDL_free(entry);
slouken@6052
   446
                entry = next;
slouken@6178
   447
            }
slouken@6178
   448
        }
slouken@6178
   449
        {
slouken@6178
   450
            GLES2_ProgramCacheEntry *entry;
slouken@6178
   451
            GLES2_ProgramCacheEntry *next;
slouken@7780
   452
            entry = data->program_cache.head;
slouken@6052
   453
            while (entry) {
slouken@7780
   454
                data->glDeleteProgram(entry->id);
slouken@6052
   455
                next = entry->next;
slouken@6052
   456
                SDL_free(entry);
slouken@6052
   457
                entry = next;
slouken@6052
   458
            }
slouken@6178
   459
        }
slouken@7780
   460
        if (data->context) {
slouken@7780
   461
            while (data->framebuffers) {
slouken@7780
   462
                GLES2_FBOList *nextnode = data->framebuffers->next;
slouken@7780
   463
                data->glDeleteFramebuffers(1, &data->framebuffers->FBO);
slouken@7780
   464
                GL_CheckError("", renderer);
slouken@7780
   465
                SDL_free(data->framebuffers);
slouken@7780
   466
                data->framebuffers = nextnode;
slouken@6232
   467
            }
slouken@7780
   468
            SDL_GL_DeleteContext(data->context);
slouken@5209
   469
        }
slouken@7780
   470
        SDL_free(data->shader_formats);
slouken@7780
   471
        SDL_free(data);
slouken@5201
   472
    }
slouken@5201
   473
    SDL_free(renderer);
slouken@5201
   474
}
slouken@5201
   475
slouken@5201
   476
/*************************************************************************************************
slouken@5201
   477
 * Texture APIs                                                                                  *
slouken@5201
   478
 *************************************************************************************************/
slouken@5201
   479
slouken@5201
   480
static int GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture);
slouken@7780
   481
static int GLES2_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect,
slouken@7780
   482
                               const void *pixels, int pitch);
slouken@8835
   483
static int GLES2_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@8835
   484
                               const SDL_Rect * rect,
slouken@8835
   485
                               const Uint8 *Yplane, int Ypitch,
slouken@8835
   486
                               const Uint8 *Uplane, int Upitch,
slouken@8835
   487
                               const Uint8 *Vplane, int Vpitch);
slouken@5201
   488
static int GLES2_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect,
slouken@5201
   489
                             void **pixels, int *pitch);
slouken@5201
   490
static void GLES2_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture);
slouken@6247
   491
static int GLES2_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture);
slouken@7780
   492
static void GLES2_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture);
slouken@5201
   493
slouken@5484
   494
static GLenum
slouken@5484
   495
GetScaleQuality(void)
slouken@5484
   496
{
slouken@5484
   497
    const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
slouken@5484
   498
slouken@5484
   499
    if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) {
slouken@5484
   500
        return GL_NEAREST;
slouken@5484
   501
    } else {
slouken@5484
   502
        return GL_LINEAR;
slouken@5484
   503
    }
slouken@5484
   504
}
slouken@5484
   505
slouken@5201
   506
static int
slouken@5201
   507
GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture)
slouken@5201
   508
{
slouken@7780
   509
    GLES2_DriverContext *renderdata = (GLES2_DriverContext *)renderer->driverdata;
slouken@7780
   510
    GLES2_TextureData *data;
slouken@5201
   511
    GLenum format;
slouken@5201
   512
    GLenum type;
slouken@5503
   513
    GLenum scaleMode;
slouken@5201
   514
slouken@5201
   515
    GLES2_ActivateRenderer(renderer);
slouken@5201
   516
slouken@5201
   517
    /* Determine the corresponding GLES texture format params */
slouken@5201
   518
    switch (texture->format)
slouken@5201
   519
    {
slouken@8904
   520
    case SDL_PIXELFORMAT_ARGB8888:
slouken@5201
   521
    case SDL_PIXELFORMAT_ABGR8888:
slouken@8904
   522
    case SDL_PIXELFORMAT_RGB888:
slouken@6113
   523
    case SDL_PIXELFORMAT_BGR888:
slouken@5201
   524
        format = GL_RGBA;
slouken@5201
   525
        type = GL_UNSIGNED_BYTE;
slouken@5201
   526
        break;
slouken@8835
   527
    case SDL_PIXELFORMAT_IYUV:
slouken@8835
   528
    case SDL_PIXELFORMAT_YV12:
slouken@9046
   529
    case SDL_PIXELFORMAT_NV12:
slouken@9046
   530
    case SDL_PIXELFORMAT_NV21:
slouken@8835
   531
        format = GL_LUMINANCE;
slouken@8835
   532
        type = GL_UNSIGNED_BYTE;
slouken@8835
   533
        break;
slouken@5201
   534
    default:
icculus@7037
   535
        return SDL_SetError("Texture format not supported");
slouken@5201
   536
    }
slouken@5201
   537
slouken@5201
   538
    /* Allocate a texture struct */
slouken@7780
   539
    data = (GLES2_TextureData *)SDL_calloc(1, sizeof(GLES2_TextureData));
slouken@7780
   540
    if (!data) {
icculus@7037
   541
        return SDL_OutOfMemory();
slouken@5201
   542
    }
slouken@7780
   543
    data->texture = 0;
slouken@7780
   544
    data->texture_type = GL_TEXTURE_2D;
slouken@7780
   545
    data->pixel_format = format;
slouken@7780
   546
    data->pixel_type = type;
slouken@8835
   547
    data->yuv = ((texture->format == SDL_PIXELFORMAT_IYUV) || (texture->format == SDL_PIXELFORMAT_YV12));
slouken@9046
   548
    data->nv12 = ((texture->format == SDL_PIXELFORMAT_NV12) || (texture->format == SDL_PIXELFORMAT_NV21));
slouken@8835
   549
    data->texture_u = 0;
slouken@8835
   550
    data->texture_v = 0;
slouken@5503
   551
    scaleMode = GetScaleQuality();
slouken@5201
   552
slouken@7780
   553
    /* Allocate a blob for image renderdata */
icculus@7037
   554
    if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
slouken@8835
   555
        size_t size;
slouken@7780
   556
        data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);
slouken@8835
   557
        size = texture->h * data->pitch;
slouken@8835
   558
        if (data->yuv) {
slouken@8835
   559
            /* Need to add size for the U and V planes */
slouken@8835
   560
            size += (2 * (texture->h * data->pitch) / 4);
slouken@8835
   561
        }
slouken@9046
   562
        if (data->nv12) {
slouken@9046
   563
            /* Need to add size for the U/V plane */
slouken@9046
   564
            size += ((texture->h * data->pitch) / 2);
slouken@9046
   565
        }
slouken@8835
   566
        data->pixel_data = SDL_calloc(1, size);
slouken@7780
   567
        if (!data->pixel_data) {
slouken@7780
   568
            SDL_free(data);
icculus@7037
   569
            return SDL_OutOfMemory();
slouken@5201
   570
        }
slouken@5201
   571
    }
slouken@5201
   572
slouken@5201
   573
    /* Allocate the texture */
slouken@7780
   574
    GL_CheckError("", renderer);
slouken@8835
   575
slouken@8835
   576
    if (data->yuv) {
slouken@8835
   577
        renderdata->glGenTextures(1, &data->texture_v);
slouken@8835
   578
        if (GL_CheckError("glGenTexures()", renderer) < 0) {
slouken@8835
   579
            return -1;
slouken@8835
   580
        }
slouken@8835
   581
        renderdata->glActiveTexture(GL_TEXTURE2);
slouken@8835
   582
        renderdata->glBindTexture(data->texture_type, data->texture_v);
slouken@8835
   583
        renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode);
slouken@8835
   584
        renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode);
slouken@8835
   585
        renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
slouken@8835
   586
        renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
slouken@8835
   587
        renderdata->glTexImage2D(data->texture_type, 0, format, texture->w / 2, texture->h / 2, 0, format, type, NULL);
slouken@8835
   588
slouken@8835
   589
        renderdata->glGenTextures(1, &data->texture_u);
slouken@8835
   590
        if (GL_CheckError("glGenTexures()", renderer) < 0) {
slouken@8835
   591
            return -1;
slouken@8835
   592
        }
slouken@8835
   593
        renderdata->glActiveTexture(GL_TEXTURE1);
slouken@8835
   594
        renderdata->glBindTexture(data->texture_type, data->texture_u);
slouken@8835
   595
        renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode);
slouken@8835
   596
        renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode);
slouken@8835
   597
        renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
slouken@8835
   598
        renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
slouken@8835
   599
        renderdata->glTexImage2D(data->texture_type, 0, format, texture->w / 2, texture->h / 2, 0, format, type, NULL);
slouken@8835
   600
        if (GL_CheckError("glTexImage2D()", renderer) < 0) {
slouken@8835
   601
            return -1;
slouken@8835
   602
        }
slouken@8835
   603
    }
slouken@8835
   604
slouken@9046
   605
    if (data->nv12) {
slouken@9046
   606
        renderdata->glGenTextures(1, &data->texture_u);
slouken@9046
   607
        if (GL_CheckError("glGenTexures()", renderer) < 0) {
slouken@9046
   608
            return -1;
slouken@9046
   609
        }
slouken@9046
   610
        renderdata->glActiveTexture(GL_TEXTURE1);
slouken@9046
   611
        renderdata->glBindTexture(data->texture_type, data->texture_u);
slouken@9046
   612
        renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode);
slouken@9046
   613
        renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode);
slouken@9046
   614
        renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
slouken@9046
   615
        renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
slouken@9046
   616
        renderdata->glTexImage2D(data->texture_type, 0, GL_LUMINANCE_ALPHA, texture->w / 2, texture->h / 2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL);
slouken@9046
   617
        if (GL_CheckError("glTexImage2D()", renderer) < 0) {
slouken@9046
   618
            return -1;
slouken@9046
   619
        }
slouken@9046
   620
    }
slouken@9046
   621
slouken@7780
   622
    renderdata->glGenTextures(1, &data->texture);
slouken@7780
   623
    if (GL_CheckError("glGenTexures()", renderer) < 0) {
slouken@7780
   624
        return -1;
slouken@7780
   625
    }
slouken@7780
   626
    texture->driverdata = data;
slouken@8835
   627
    renderdata->glActiveTexture(GL_TEXTURE0);
slouken@7780
   628
    renderdata->glBindTexture(data->texture_type, data->texture);
slouken@7780
   629
    renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode);
slouken@7780
   630
    renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode);
slouken@7780
   631
    renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
slouken@7780
   632
    renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
slouken@7780
   633
    renderdata->glTexImage2D(data->texture_type, 0, format, texture->w, texture->h, 0, format, type, NULL);
slouken@7780
   634
    if (GL_CheckError("glTexImage2D()", renderer) < 0) {
slouken@7780
   635
        return -1;
slouken@7780
   636
    }
slouken@6232
   637
slouken@6232
   638
    if (texture->access == SDL_TEXTUREACCESS_TARGET) {
slouken@7780
   639
       data->fbo = GLES2_GetFBO(renderer->driverdata, texture->w, texture->h);
slouken@6232
   640
    } else {
slouken@7780
   641
       data->fbo = NULL;
slouken@6232
   642
    }
slouken@6232
   643
slouken@7780
   644
    return GL_CheckError("", renderer);
slouken@5201
   645
}
slouken@5201
   646
slouken@7780
   647
static int
slouken@8890
   648
GLES2_TexSubImage2D(GLES2_DriverContext *data, GLenum target, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels, GLint pitch, GLint bpp)
slouken@8890
   649
{
slouken@8890
   650
    Uint8 *blob = NULL;
slouken@8890
   651
    Uint8 *src;
slouken@8890
   652
    int src_pitch;
slouken@8890
   653
    int y;
slouken@8890
   654
slouken@8890
   655
    /* Reformat the texture data into a tightly packed array */
slouken@8890
   656
    src_pitch = width * bpp;
slouken@8923
   657
    src = (Uint8 *)pixels;
slouken@8890
   658
    if (pitch != src_pitch) {
slouken@8890
   659
        blob = (Uint8 *)SDL_malloc(src_pitch * height);
slouken@8890
   660
        if (!blob) {
slouken@8890
   661
            return SDL_OutOfMemory();
slouken@8890
   662
        }
slouken@8890
   663
        src = blob;
slouken@8890
   664
        for (y = 0; y < height; ++y)
slouken@8890
   665
        {
slouken@8890
   666
            SDL_memcpy(src, pixels, src_pitch);
slouken@8890
   667
            src += src_pitch;
slouken@8890
   668
            pixels = (Uint8 *)pixels + pitch;
slouken@8890
   669
        }
slouken@8890
   670
        src = blob;
slouken@8890
   671
    }
slouken@8890
   672
slouken@8890
   673
    data->glTexSubImage2D(target, 0, xoffset, yoffset, width, height, format, type, src);
slouken@8890
   674
    if (blob) {
slouken@8890
   675
        SDL_free(blob);
slouken@8890
   676
    }
slouken@8890
   677
    return 0;
slouken@8890
   678
}
slouken@8890
   679
slouken@8890
   680
static int
slouken@7780
   681
GLES2_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect,
slouken@7780
   682
                    const void *pixels, int pitch)
slouken@5201
   683
{
slouken@7780
   684
    GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
slouken@5201
   685
    GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
slouken@5201
   686
slouken@5201
   687
    GLES2_ActivateRenderer(renderer);
slouken@5201
   688
slouken@7780
   689
    /* Bail out if we're supposed to update an empty rectangle */
slime73@9604
   690
    if (rect->w <= 0 || rect->h <= 0) {
slouken@7780
   691
        return 0;
slime73@9604
   692
    }
slouken@7780
   693
slouken@7780
   694
    /* Create a texture subimage with the supplied data */
slouken@7780
   695
    data->glBindTexture(tdata->texture_type, tdata->texture);
slouken@8890
   696
    GLES2_TexSubImage2D(data, tdata->texture_type,
slouken@7780
   697
                    rect->x,
slouken@7780
   698
                    rect->y,
slouken@7780
   699
                    rect->w,
slouken@7780
   700
                    rect->h,
slouken@7780
   701
                    tdata->pixel_format,
slouken@7780
   702
                    tdata->pixel_type,
slouken@8890
   703
                    pixels, pitch, SDL_BYTESPERPIXEL(texture->format));
slouken@7780
   704
slouken@8923
   705
    if (tdata->yuv) {
slouken@8923
   706
        /* Skip to the correct offset into the next texture */
slouken@8923
   707
        pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
slouken@8923
   708
        if (texture->format == SDL_PIXELFORMAT_YV12) {
slouken@8923
   709
            data->glBindTexture(tdata->texture_type, tdata->texture_v);
slouken@8923
   710
        } else {
slouken@8923
   711
            data->glBindTexture(tdata->texture_type, tdata->texture_u);
slouken@8923
   712
        }
slouken@8923
   713
        GLES2_TexSubImage2D(data, tdata->texture_type,
slouken@8923
   714
                rect->x / 2,
slouken@8923
   715
                rect->y / 2,
slouken@8923
   716
                rect->w / 2,
slouken@8923
   717
                rect->h / 2,
slouken@8923
   718
                tdata->pixel_format,
slouken@8923
   719
                tdata->pixel_type,
slouken@8923
   720
                pixels, pitch / 2, 1);
slouken@8923
   721
slouken@8923
   722
        /* Skip to the correct offset into the next texture */
slouken@8923
   723
        pixels = (const void*)((const Uint8*)pixels + (rect->h * pitch)/4);
slouken@8923
   724
        if (texture->format == SDL_PIXELFORMAT_YV12) {
slouken@8923
   725
            data->glBindTexture(tdata->texture_type, tdata->texture_u);
slouken@8923
   726
        } else {
slouken@8923
   727
            data->glBindTexture(tdata->texture_type, tdata->texture_v);
slouken@8923
   728
        }
slouken@8923
   729
        GLES2_TexSubImage2D(data, tdata->texture_type,
slouken@8923
   730
                rect->x / 2,
slouken@8923
   731
                rect->y / 2,
slouken@8923
   732
                rect->w / 2,
slouken@8923
   733
                rect->h / 2,
slouken@8923
   734
                tdata->pixel_format,
slouken@8923
   735
                tdata->pixel_type,
slouken@8923
   736
                pixels, pitch / 2, 1);
slouken@8923
   737
    }
slouken@8923
   738
slouken@9046
   739
    if (tdata->nv12) {
slouken@9046
   740
        /* Skip to the correct offset into the next texture */
slouken@9046
   741
        pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
slouken@9046
   742
        data->glBindTexture(tdata->texture_type, tdata->texture_u);
slouken@9046
   743
        GLES2_TexSubImage2D(data, tdata->texture_type,
slouken@9046
   744
                rect->x / 2,
slouken@9046
   745
                rect->y / 2,
slouken@9046
   746
                rect->w / 2,
slouken@9046
   747
                rect->h / 2,
slouken@9046
   748
                GL_LUMINANCE_ALPHA,
slouken@9046
   749
                GL_UNSIGNED_BYTE,
slouken@9046
   750
                pixels, pitch, 2);
slouken@9046
   751
    }
slouken@9046
   752
slouken@7780
   753
    return GL_CheckError("glTexSubImage2D()", renderer);
slouken@5201
   754
}
slouken@5201
   755
slouken@5201
   756
static int
slouken@8835
   757
GLES2_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@8835
   758
                    const SDL_Rect * rect,
slouken@8835
   759
                    const Uint8 *Yplane, int Ypitch,
slouken@8835
   760
                    const Uint8 *Uplane, int Upitch,
slouken@8835
   761
                    const Uint8 *Vplane, int Vpitch)
slouken@8835
   762
{
slouken@8835
   763
    GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
slouken@8835
   764
    GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
slouken@8835
   765
slouken@8890
   766
    GLES2_ActivateRenderer(renderer);
slouken@8890
   767
slouken@8890
   768
    /* Bail out if we're supposed to update an empty rectangle */
slime73@9604
   769
    if (rect->w <= 0 || rect->h <= 0) {
slouken@8890
   770
        return 0;
slime73@9604
   771
    }
slouken@8890
   772
slouken@8835
   773
    data->glBindTexture(tdata->texture_type, tdata->texture_v);
slouken@8890
   774
    GLES2_TexSubImage2D(data, tdata->texture_type,
slouken@8959
   775
                    rect->x / 2,
slouken@8959
   776
                    rect->y / 2,
slouken@8835
   777
                    rect->w / 2,
slouken@8835
   778
                    rect->h / 2,
slouken@8835
   779
                    tdata->pixel_format,
slouken@8835
   780
                    tdata->pixel_type,
slouken@8890
   781
                    Vplane, Vpitch, 1);
slouken@8835
   782
slouken@8835
   783
    data->glBindTexture(tdata->texture_type, tdata->texture_u);
slouken@8890
   784
    GLES2_TexSubImage2D(data, tdata->texture_type,
slouken@8959
   785
                    rect->x / 2,
slouken@8959
   786
                    rect->y / 2,
slouken@8835
   787
                    rect->w / 2,
slouken@8835
   788
                    rect->h / 2,
slouken@8835
   789
                    tdata->pixel_format,
slouken@8835
   790
                    tdata->pixel_type,
slouken@8890
   791
                    Uplane, Upitch, 1);
slouken@8835
   792
slouken@8835
   793
    data->glBindTexture(tdata->texture_type, tdata->texture);
slouken@8890
   794
    GLES2_TexSubImage2D(data, tdata->texture_type,
slouken@8835
   795
                    rect->x,
slouken@8835
   796
                    rect->y,
slouken@8835
   797
                    rect->w,
slouken@8835
   798
                    rect->h,
slouken@8835
   799
                    tdata->pixel_format,
slouken@8835
   800
                    tdata->pixel_type,
slouken@8923
   801
                    Yplane, Ypitch, 1);
slouken@8835
   802
slouken@8835
   803
    return GL_CheckError("glTexSubImage2D()", renderer);
slouken@8835
   804
}
slouken@8835
   805
slouken@8835
   806
static int
slouken@5201
   807
GLES2_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect,
slouken@5201
   808
                  void **pixels, int *pitch)
slouken@5201
   809
{
slouken@5201
   810
    GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
slouken@5201
   811
slouken@5201
   812
    /* Retrieve the buffer/pitch for the specified region */
slouken@5201
   813
    *pixels = (Uint8 *)tdata->pixel_data +
slouken@5201
   814
              (tdata->pitch * rect->y) +
slouken@5201
   815
              (rect->x * SDL_BYTESPERPIXEL(texture->format));
slouken@5201
   816
    *pitch = tdata->pitch;
slouken@5201
   817
slouken@5201
   818
    return 0;
slouken@5201
   819
}
slouken@5201
   820
slouken@5201
   821
static void
slouken@5201
   822
GLES2_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
slouken@5201
   823
{
slouken@5201
   824
    GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
slouken@5227
   825
    SDL_Rect rect;
slouken@5201
   826
slouken@5227
   827
    /* We do whole texture updates, at least for now */
slouken@5227
   828
    rect.x = 0;
slouken@5227
   829
    rect.y = 0;
slouken@5227
   830
    rect.w = texture->w;
slouken@5227
   831
    rect.h = texture->h;
slouken@5227
   832
    GLES2_UpdateTexture(renderer, texture, &rect, tdata->pixel_data, tdata->pitch);
slouken@5201
   833
}
slouken@5201
   834
slouken@5201
   835
static int
slouken@6247
   836
GLES2_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@6246
   837
{
slouken@6246
   838
    GLES2_DriverContext *data = (GLES2_DriverContext *) renderer->driverdata;
slouken@6246
   839
    GLES2_TextureData *texturedata = NULL;
slouken@6246
   840
    GLenum status;
slouken@6246
   841
slouken@6246
   842
    if (texture == NULL) {
slouken@6271
   843
        data->glBindFramebuffer(GL_FRAMEBUFFER, data->window_framebuffer);
slouken@6246
   844
    } else {
slouken@6246
   845
        texturedata = (GLES2_TextureData *) texture->driverdata;
slouken@6246
   846
        data->glBindFramebuffer(GL_FRAMEBUFFER, texturedata->fbo->FBO);
slouken@6246
   847
        /* TODO: check if texture pixel format allows this operation */
slouken@6246
   848
        data->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texturedata->texture_type, texturedata->texture, 0);
slouken@6246
   849
        /* Check FBO status */
slouken@6246
   850
        status = data->glCheckFramebufferStatus(GL_FRAMEBUFFER);
slouken@6246
   851
        if (status != GL_FRAMEBUFFER_COMPLETE) {
icculus@7037
   852
            return SDL_SetError("glFramebufferTexture2D() failed");
slouken@6246
   853
        }
slouken@6246
   854
    }
slouken@6246
   855
    return 0;
slouken@6246
   856
}
slouken@6246
   857
slouken@7780
   858
static void
slouken@7780
   859
GLES2_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture)
slouken@7780
   860
{
slouken@7780
   861
    GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
slouken@7780
   862
    GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
slouken@7780
   863
slouken@7780
   864
    GLES2_ActivateRenderer(renderer);
slouken@7780
   865
slouken@7780
   866
    /* Destroy the texture */
slime73@9604
   867
    if (tdata) {
slouken@7780
   868
        data->glDeleteTextures(1, &tdata->texture);
slouken@8835
   869
        if (tdata->texture_v) {
slouken@8835
   870
            data->glDeleteTextures(1, &tdata->texture_v);
slouken@8835
   871
        }
slouken@8835
   872
        if (tdata->texture_u) {
slouken@8835
   873
            data->glDeleteTextures(1, &tdata->texture_u);
slouken@8835
   874
        }
slouken@7780
   875
        SDL_free(tdata->pixel_data);
slouken@7780
   876
        SDL_free(tdata);
slouken@7780
   877
        texture->driverdata = NULL;
slouken@7780
   878
    }
slouken@7780
   879
}
slouken@7780
   880
slouken@5201
   881
/*************************************************************************************************
slouken@5201
   882
 * Shader management functions                                                                   *
slouken@5201
   883
 *************************************************************************************************/
slouken@5201
   884
slouken@5201
   885
static GLES2_ShaderCacheEntry *GLES2_CacheShader(SDL_Renderer *renderer, GLES2_ShaderType type,
slouken@5201
   886
                                                 SDL_BlendMode blendMode);
slouken@5201
   887
static void GLES2_EvictShader(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *entry);
slouken@5201
   888
static GLES2_ProgramCacheEntry *GLES2_CacheProgram(SDL_Renderer *renderer,
slouken@5201
   889
                                                   GLES2_ShaderCacheEntry *vertex,
slouken@5201
   890
                                                   GLES2_ShaderCacheEntry *fragment,
slouken@5201
   891
                                                   SDL_BlendMode blendMode);
slouken@5201
   892
static int GLES2_SelectProgram(SDL_Renderer *renderer, GLES2_ImageSource source,
slouken@5201
   893
                               SDL_BlendMode blendMode);
slouken@5201
   894
slouken@5201
   895
static GLES2_ProgramCacheEntry *
slouken@5201
   896
GLES2_CacheProgram(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *vertex,
slouken@5201
   897
                   GLES2_ShaderCacheEntry *fragment, SDL_BlendMode blendMode)
slouken@5201
   898
{
slouken@7780
   899
    GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
slouken@5201
   900
    GLES2_ProgramCacheEntry *entry;
slouken@5201
   901
    GLES2_ShaderCacheEntry *shaderEntry;
slouken@5201
   902
    GLint linkSuccessful;
slouken@5201
   903
slouken@5201
   904
    /* Check if we've already cached this program */
slouken@7780
   905
    entry = data->program_cache.head;
slime73@9604
   906
    while (entry) {
slime73@9604
   907
        if (entry->vertex_shader == vertex && entry->fragment_shader == fragment) {
slouken@5201
   908
            break;
slime73@9604
   909
        }
slouken@5201
   910
        entry = entry->next;
slouken@5201
   911
    }
slime73@9604
   912
    if (entry) {
slime73@9604
   913
        if (data->program_cache.head != entry) {
slime73@9604
   914
            if (entry->next) {
slouken@5201
   915
                entry->next->prev = entry->prev;
slime73@9604
   916
            }
slime73@9604
   917
            if (entry->prev) {
slouken@5201
   918
                entry->prev->next = entry->next;
slime73@9604
   919
            }
slouken@5201
   920
            entry->prev = NULL;
slouken@7780
   921
            entry->next = data->program_cache.head;
slouken@7780
   922
            data->program_cache.head->prev = entry;
slouken@7780
   923
            data->program_cache.head = entry;
slouken@5201
   924
        }
slouken@5201
   925
        return entry;
slouken@5201
   926
    }
slouken@5201
   927
slouken@5201
   928
    /* Create a program cache entry */
slouken@5201
   929
    entry = (GLES2_ProgramCacheEntry *)SDL_calloc(1, sizeof(GLES2_ProgramCacheEntry));
slime73@9604
   930
    if (!entry) {
slouken@5201
   931
        SDL_OutOfMemory();
slouken@5201
   932
        return NULL;
slouken@5201
   933
    }
slouken@5201
   934
    entry->vertex_shader = vertex;
slouken@5201
   935
    entry->fragment_shader = fragment;
slouken@5201
   936
    entry->blend_mode = blendMode;
slouken@6232
   937
slouken@5201
   938
    /* Create the program and link it */
slouken@7780
   939
    entry->id = data->glCreateProgram();
slouken@7780
   940
    data->glAttachShader(entry->id, vertex->id);
slouken@7780
   941
    data->glAttachShader(entry->id, fragment->id);
slouken@7780
   942
    data->glBindAttribLocation(entry->id, GLES2_ATTRIBUTE_POSITION, "a_position");
slouken@7780
   943
    data->glBindAttribLocation(entry->id, GLES2_ATTRIBUTE_TEXCOORD, "a_texCoord");
slouken@7780
   944
    data->glBindAttribLocation(entry->id, GLES2_ATTRIBUTE_ANGLE, "a_angle");
slouken@7780
   945
    data->glBindAttribLocation(entry->id, GLES2_ATTRIBUTE_CENTER, "a_center");
slouken@7780
   946
    data->glLinkProgram(entry->id);
slouken@7780
   947
    data->glGetProgramiv(entry->id, GL_LINK_STATUS, &linkSuccessful);
slime73@9604
   948
    if (!linkSuccessful) {
slouken@7780
   949
        data->glDeleteProgram(entry->id);
slouken@5201
   950
        SDL_free(entry);
icculus@7037
   951
        SDL_SetError("Failed to link shader program");
slouken@5201
   952
        return NULL;
slouken@5201
   953
    }
slouken@6232
   954
slouken@5201
   955
    /* Predetermine locations of uniform variables */
slouken@5201
   956
    entry->uniform_locations[GLES2_UNIFORM_PROJECTION] =
slouken@7780
   957
        data->glGetUniformLocation(entry->id, "u_projection");
slouken@8835
   958
    entry->uniform_locations[GLES2_UNIFORM_TEXTURE_V] =
slouken@8835
   959
        data->glGetUniformLocation(entry->id, "u_texture_v");
slouken@8835
   960
    entry->uniform_locations[GLES2_UNIFORM_TEXTURE_U] =
slouken@8835
   961
        data->glGetUniformLocation(entry->id, "u_texture_u");
slouken@5201
   962
    entry->uniform_locations[GLES2_UNIFORM_TEXTURE] =
slouken@7780
   963
        data->glGetUniformLocation(entry->id, "u_texture");
slouken@5201
   964
    entry->uniform_locations[GLES2_UNIFORM_MODULATION] =
slouken@7780
   965
        data->glGetUniformLocation(entry->id, "u_modulation");
slouken@5201
   966
    entry->uniform_locations[GLES2_UNIFORM_COLOR] =
icculus@7784
   967
        data->glGetUniformLocation(entry->id, "u_color");
icculus@7784
   968
slouken@8070
   969
    entry->modulation_r = entry->modulation_g = entry->modulation_b = entry->modulation_a = 255;
slouken@8070
   970
    entry->color_r = entry->color_g = entry->color_b = entry->color_a = 255;
icculus@7784
   971
icculus@7784
   972
    data->glUseProgram(entry->id);
slouken@8835
   973
    data->glUniform1i(entry->uniform_locations[GLES2_UNIFORM_TEXTURE_V], 2);  /* always texture unit 2. */
slouken@8835
   974
    data->glUniform1i(entry->uniform_locations[GLES2_UNIFORM_TEXTURE_U], 1);  /* always texture unit 1. */
slouken@8835
   975
    data->glUniform1i(entry->uniform_locations[GLES2_UNIFORM_TEXTURE], 0);  /* always texture unit 0. */
icculus@7784
   976
    data->glUniformMatrix4fv(entry->uniform_locations[GLES2_UNIFORM_PROJECTION], 1, GL_FALSE, (GLfloat *)entry->projection);
icculus@7784
   977
    data->glUniform4f(entry->uniform_locations[GLES2_UNIFORM_MODULATION], 1.0f, 1.0f, 1.0f, 1.0f);
icculus@7784
   978
    data->glUniform4f(entry->uniform_locations[GLES2_UNIFORM_COLOR], 1.0f, 1.0f, 1.0f, 1.0f);
slouken@5201
   979
slouken@5201
   980
    /* Cache the linked program */
slime73@9604
   981
    if (data->program_cache.head) {
slouken@7780
   982
        entry->next = data->program_cache.head;
slouken@7780
   983
        data->program_cache.head->prev = entry;
slime73@9604
   984
    } else {
slouken@7780
   985
        data->program_cache.tail = entry;
slouken@5201
   986
    }
slouken@7780
   987
    data->program_cache.head = entry;
slouken@7780
   988
    ++data->program_cache.count;
slouken@5201
   989
slouken@5201
   990
    /* Increment the refcount of the shaders we're using */
slouken@5201
   991
    ++vertex->references;
slouken@5201
   992
    ++fragment->references;
slouken@5201
   993
slouken@5201
   994
    /* Evict the last entry from the cache if we exceed the limit */
slime73@9604
   995
    if (data->program_cache.count > GLES2_MAX_CACHED_PROGRAMS) {
slouken@7780
   996
        shaderEntry = data->program_cache.tail->vertex_shader;
slime73@9604
   997
        if (--shaderEntry->references <= 0) {
slouken@5201
   998
            GLES2_EvictShader(renderer, shaderEntry);
slime73@9604
   999
        }
slouken@7780
  1000
        shaderEntry = data->program_cache.tail->fragment_shader;
slime73@9604
  1001
        if (--shaderEntry->references <= 0) {
slouken@5201
  1002
            GLES2_EvictShader(renderer, shaderEntry);
slime73@9604
  1003
        }
slouken@7780
  1004
        data->glDeleteProgram(data->program_cache.tail->id);
slouken@7780
  1005
        data->program_cache.tail = data->program_cache.tail->prev;
slouken@7780
  1006
        SDL_free(data->program_cache.tail->next);
slouken@7780
  1007
        data->program_cache.tail->next = NULL;
slouken@7780
  1008
        --data->program_cache.count;
slouken@5201
  1009
    }
slouken@5201
  1010
    return entry;
slouken@5201
  1011
}
slouken@5201
  1012
slouken@5201
  1013
static GLES2_ShaderCacheEntry *
slouken@5201
  1014
GLES2_CacheShader(SDL_Renderer *renderer, GLES2_ShaderType type, SDL_BlendMode blendMode)
slouken@5201
  1015
{
slouken@7780
  1016
    GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
slouken@5201
  1017
    const GLES2_Shader *shader;
slouken@5201
  1018
    const GLES2_ShaderInstance *instance = NULL;
slouken@5201
  1019
    GLES2_ShaderCacheEntry *entry = NULL;
slouken@5201
  1020
    GLint compileSuccessful = GL_FALSE;
slouken@5201
  1021
    int i, j;
slouken@5201
  1022
slouken@5201
  1023
    /* Find the corresponding shader */
slouken@5201
  1024
    shader = GLES2_GetShader(type, blendMode);
slime73@9604
  1025
    if (!shader) {
slouken@5201
  1026
        SDL_SetError("No shader matching the requested characteristics was found");
slouken@5201
  1027
        return NULL;
slouken@5201
  1028
    }
slouken@6232
  1029
slouken@5201
  1030
    /* Find a matching shader instance that's supported on this hardware */
slime73@9604
  1031
    for (i = 0; i < shader->instance_count && !instance; ++i) {
slime73@9604
  1032
        for (j = 0; j < data->shader_format_count && !instance; ++j) {
slime73@9604
  1033
            if (!shader->instances[i]) {
slouken@5206
  1034
                continue;
slime73@9604
  1035
            }
slime73@9604
  1036
            if (shader->instances[i]->format != data->shader_formats[j]) {
slouken@5201
  1037
                continue;
slime73@9604
  1038
            }
slouken@5201
  1039
            instance = shader->instances[i];
slouken@5201
  1040
        }
slouken@5201
  1041
    }
slime73@9604
  1042
    if (!instance) {
slouken@5201
  1043
        SDL_SetError("The specified shader cannot be loaded on the current platform");
slouken@5201
  1044
        return NULL;
slouken@5201
  1045
    }
slouken@5201
  1046
slouken@5201
  1047
    /* Check if we've already cached this shader */
slouken@7780
  1048
    entry = data->shader_cache.head;
slime73@9604
  1049
    while (entry) {
slime73@9604
  1050
        if (entry->instance == instance) {
slouken@5201
  1051
            break;
slime73@9604
  1052
        }
slouken@5201
  1053
        entry = entry->next;
slouken@5201
  1054
    }
slime73@9604
  1055
    if (entry) {
slouken@5201
  1056
        return entry;
slime73@9604
  1057
    }
slouken@5201
  1058
slouken@5201
  1059
    /* Create a shader cache entry */
slouken@5201
  1060
    entry = (GLES2_ShaderCacheEntry *)SDL_calloc(1, sizeof(GLES2_ShaderCacheEntry));
slime73@9604
  1061
    if (!entry) {
slouken@5201
  1062
        SDL_OutOfMemory();
slouken@5201
  1063
        return NULL;
slouken@5201
  1064
    }
slouken@5201
  1065
    entry->type = type;
slouken@5201
  1066
    entry->instance = instance;
slouken@5201
  1067
slouken@5201
  1068
    /* Compile or load the selected shader instance */
slouken@7780
  1069
    entry->id = data->glCreateShader(instance->type);
slime73@9604
  1070
    if (instance->format == (GLenum)-1) {
slouken@7780
  1071
        data->glShaderSource(entry->id, 1, (const char **)&instance->data, NULL);
slouken@7780
  1072
        data->glCompileShader(entry->id);
slouken@7780
  1073
        data->glGetShaderiv(entry->id, GL_COMPILE_STATUS, &compileSuccessful);
slime73@9604
  1074
    } else {
slouken@7780
  1075
        data->glShaderBinary(1, &entry->id, instance->format, instance->data, instance->length);
slouken@5201
  1076
        compileSuccessful = GL_TRUE;
slouken@5201
  1077
    }
slime73@9604
  1078
    if (!compileSuccessful) {
slouken@5212
  1079
        char *info = NULL;
slouken@6113
  1080
        int length = 0;
slouken@5212
  1081
slouken@7780
  1082
        data->glGetShaderiv(entry->id, GL_INFO_LOG_LENGTH, &length);
slouken@5212
  1083
        if (length > 0) {
slouken@5212
  1084
            info = SDL_stack_alloc(char, length);
slouken@5212
  1085
            if (info) {
slouken@7780
  1086
                data->glGetShaderInfoLog(entry->id, length, &length, info);
slouken@5212
  1087
            }
slouken@5212
  1088
        }
slouken@5212
  1089
        if (info) {
slouken@5212
  1090
            SDL_SetError("Failed to load the shader: %s", info);
slouken@5212
  1091
            SDL_stack_free(info);
slouken@5212
  1092
        } else {
slouken@5212
  1093
            SDL_SetError("Failed to load the shader");
slouken@5212
  1094
        }
slouken@7780
  1095
        data->glDeleteShader(entry->id);
slouken@5201
  1096
        SDL_free(entry);
slouken@5201
  1097
        return NULL;
slouken@5201
  1098
    }
slouken@5201
  1099
slouken@5201
  1100
    /* Link the shader entry in at the front of the cache */
slime73@9604
  1101
    if (data->shader_cache.head) {
slouken@7780
  1102
        entry->next = data->shader_cache.head;
slouken@7780
  1103
        data->shader_cache.head->prev = entry;
slouken@5201
  1104
    }
slouken@7780
  1105
    data->shader_cache.head = entry;
slouken@7780
  1106
    ++data->shader_cache.count;
slouken@5201
  1107
    return entry;
slouken@5201
  1108
}
slouken@5201
  1109
slouken@5201
  1110
static void
slouken@5201
  1111
GLES2_EvictShader(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *entry)
slouken@5201
  1112
{
slouken@7780
  1113
    GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
slouken@5201
  1114
slouken@5201
  1115
    /* Unlink the shader from the cache */
slime73@9604
  1116
    if (entry->next) {
slouken@5201
  1117
        entry->next->prev = entry->prev;
slime73@9604
  1118
    }
slime73@9604
  1119
    if (entry->prev) {
slouken@5201
  1120
        entry->prev->next = entry->next;
slime73@9604
  1121
    }
slime73@9604
  1122
    if (data->shader_cache.head == entry) {
slouken@7780
  1123
        data->shader_cache.head = entry->next;
slime73@9604
  1124
    }
slouken@7780
  1125
    --data->shader_cache.count;
slouken@5201
  1126
slouken@5201
  1127
    /* Deallocate the shader */
slouken@7780
  1128
    data->glDeleteShader(entry->id);
slouken@5201
  1129
    SDL_free(entry);
slouken@5201
  1130
}
slouken@5201
  1131
slouken@5201
  1132
static int
slouken@5201
  1133
GLES2_SelectProgram(SDL_Renderer *renderer, GLES2_ImageSource source, SDL_BlendMode blendMode)
slouken@5201
  1134
{
slouken@7780
  1135
    GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
slouken@5201
  1136
    GLES2_ShaderCacheEntry *vertex = NULL;
slouken@5201
  1137
    GLES2_ShaderCacheEntry *fragment = NULL;
slouken@5201
  1138
    GLES2_ShaderType vtype, ftype;
slouken@5201
  1139
    GLES2_ProgramCacheEntry *program;
slouken@5201
  1140
slouken@5201
  1141
    /* Select an appropriate shader pair for the specified modes */
slouken@5201
  1142
    vtype = GLES2_SHADER_VERTEX_DEFAULT;
slime73@9604
  1143
    switch (source) {
slouken@5201
  1144
    case GLES2_IMAGESOURCE_SOLID:
slouken@5201
  1145
        ftype = GLES2_SHADER_FRAGMENT_SOLID_SRC;
slouken@5201
  1146
        break;
slouken@6113
  1147
    case GLES2_IMAGESOURCE_TEXTURE_ABGR:
slouken@6113
  1148
        ftype = GLES2_SHADER_FRAGMENT_TEXTURE_ABGR_SRC;
slouken@6341
  1149
        break;
slouken@6113
  1150
    case GLES2_IMAGESOURCE_TEXTURE_ARGB:
slouken@6113
  1151
        ftype = GLES2_SHADER_FRAGMENT_TEXTURE_ARGB_SRC;
slouken@5201
  1152
        break;
slouken@6113
  1153
    case GLES2_IMAGESOURCE_TEXTURE_RGB:
slouken@6113
  1154
        ftype = GLES2_SHADER_FRAGMENT_TEXTURE_RGB_SRC;
slouken@6113
  1155
        break;
slouken@6113
  1156
    case GLES2_IMAGESOURCE_TEXTURE_BGR:
slouken@6113
  1157
        ftype = GLES2_SHADER_FRAGMENT_TEXTURE_BGR_SRC;
slouken@6113
  1158
        break;
slouken@8835
  1159
    case GLES2_IMAGESOURCE_TEXTURE_YUV:
slouken@8835
  1160
        ftype = GLES2_SHADER_FRAGMENT_TEXTURE_YUV_SRC;
slouken@8835
  1161
        break;
slouken@9046
  1162
    case GLES2_IMAGESOURCE_TEXTURE_NV12:
slouken@9046
  1163
        ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV12_SRC;
slouken@9046
  1164
        break;
slouken@9046
  1165
    case GLES2_IMAGESOURCE_TEXTURE_NV21:
slouken@9046
  1166
        ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV21_SRC;
slouken@9046
  1167
        break;
slouken@6113
  1168
    default:
slouken@6113
  1169
        goto fault;
slouken@5201
  1170
    }
slouken@5201
  1171
slouken@5201
  1172
    /* Load the requested shaders */
slouken@5201
  1173
    vertex = GLES2_CacheShader(renderer, vtype, blendMode);
slime73@9604
  1174
    if (!vertex) {
slouken@5201
  1175
        goto fault;
slime73@9604
  1176
    }
slouken@5201
  1177
    fragment = GLES2_CacheShader(renderer, ftype, blendMode);
slime73@9604
  1178
    if (!fragment) {
slouken@5201
  1179
        goto fault;
slime73@9604
  1180
    }
slouken@5201
  1181
slouken@5201
  1182
    /* Check if we need to change programs at all */
slouken@7780
  1183
    if (data->current_program &&
slouken@7780
  1184
        data->current_program->vertex_shader == vertex &&
slime73@9604
  1185
        data->current_program->fragment_shader == fragment) {
slouken@5201
  1186
        return 0;
slime73@9604
  1187
    }
slouken@5201
  1188
slouken@5201
  1189
    /* Generate a matching program */
slouken@5201
  1190
    program = GLES2_CacheProgram(renderer, vertex, fragment, blendMode);
slime73@9604
  1191
    if (!program) {
slouken@5201
  1192
        goto fault;
slime73@9604
  1193
    }
slouken@5201
  1194
slouken@5201
  1195
    /* Select that program in OpenGL */
slouken@7780
  1196
    data->glUseProgram(program->id);
slouken@5201
  1197
slouken@5201
  1198
    /* Set the current program */
slouken@7780
  1199
    data->current_program = program;
slouken@5201
  1200
slouken@5201
  1201
    /* Activate an orthographic projection */
slime73@9604
  1202
    if (GLES2_SetOrthographicProjection(renderer) < 0) {
slouken@5201
  1203
        goto fault;
slime73@9604
  1204
    }
slouken@5201
  1205
slouken@5201
  1206
    /* Clean up and return */
slouken@5201
  1207
    return 0;
slouken@5201
  1208
fault:
slime73@9604
  1209
    if (vertex && vertex->references <= 0) {
slouken@5201
  1210
        GLES2_EvictShader(renderer, vertex);
slime73@9604
  1211
    }
slime73@9604
  1212
    if (fragment && fragment->references <= 0) {
slouken@5201
  1213
        GLES2_EvictShader(renderer, fragment);
slime73@9604
  1214
    }
slouken@7780
  1215
    data->current_program = NULL;
slouken@5201
  1216
    return -1;
slouken@5201
  1217
}
slouken@5201
  1218
slouken@5201
  1219
static int
slouken@5201
  1220
GLES2_SetOrthographicProjection(SDL_Renderer *renderer)
slouken@5201
  1221
{
slouken@7780
  1222
    GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
slouken@5201
  1223
    GLfloat projection[4][4];
slouken@5201
  1224
slouken@7239
  1225
    if (!renderer->viewport.w || !renderer->viewport.h) {
slouken@7239
  1226
        return 0;
slouken@7239
  1227
    }
slouken@7239
  1228
slouken@5201
  1229
    /* Prepare an orthographic projection */
slouken@5297
  1230
    projection[0][0] = 2.0f / renderer->viewport.w;
slouken@5201
  1231
    projection[0][1] = 0.0f;
slouken@5201
  1232
    projection[0][2] = 0.0f;
slouken@5201
  1233
    projection[0][3] = 0.0f;
slouken@5201
  1234
    projection[1][0] = 0.0f;
slouken@6341
  1235
    if (renderer->target) {
slouken@6341
  1236
        projection[1][1] = 2.0f / renderer->viewport.h;
slouken@6341
  1237
    } else {
slouken@6341
  1238
        projection[1][1] = -2.0f / renderer->viewport.h;
slouken@6341
  1239
    }
slouken@5201
  1240
    projection[1][2] = 0.0f;
slouken@5201
  1241
    projection[1][3] = 0.0f;
slouken@5201
  1242
    projection[2][0] = 0.0f;
slouken@5201
  1243
    projection[2][1] = 0.0f;
slouken@6341
  1244
    projection[2][2] = 0.0f;
slouken@5201
  1245
    projection[2][3] = 0.0f;
slouken@5201
  1246
    projection[3][0] = -1.0f;
slouken@6341
  1247
    if (renderer->target) {
slouken@6341
  1248
        projection[3][1] = -1.0f;
slouken@6341
  1249
    } else {
slouken@6341
  1250
        projection[3][1] = 1.0f;
slouken@6341
  1251
    }
slouken@5201
  1252
    projection[3][2] = 0.0f;
slouken@5201
  1253
    projection[3][3] = 1.0f;
slouken@5201
  1254
slouken@5201
  1255
    /* Set the projection matrix */
icculus@7784
  1256
    if (SDL_memcmp(data->current_program->projection, projection, sizeof (projection)) != 0) {
icculus@7784
  1257
        const GLuint locProjection = data->current_program->uniform_locations[GLES2_UNIFORM_PROJECTION];
icculus@7784
  1258
        data->glUniformMatrix4fv(locProjection, 1, GL_FALSE, (GLfloat *)projection);
icculus@7784
  1259
        SDL_memcpy(data->current_program->projection, projection, sizeof (projection));
icculus@7784
  1260
    }
icculus@7784
  1261
slouken@5201
  1262
    return 0;
slouken@5201
  1263
}
slouken@5201
  1264
slouken@5201
  1265
/*************************************************************************************************
slouken@5201
  1266
 * Rendering functions                                                                           *
slouken@5201
  1267
 *************************************************************************************************/
slouken@5201
  1268
slouken@5224
  1269
static const float inv255f = 1.0f / 255.0f;
slouken@5224
  1270
slouken@5201
  1271
static int GLES2_RenderClear(SDL_Renderer *renderer);
slouken@6528
  1272
static int GLES2_RenderDrawPoints(SDL_Renderer *renderer, const SDL_FPoint *points, int count);
slouken@6528
  1273
static int GLES2_RenderDrawLines(SDL_Renderer *renderer, const SDL_FPoint *points, int count);
slouken@6528
  1274
static int GLES2_RenderFillRects(SDL_Renderer *renderer, const SDL_FRect *rects, int count);
slouken@5201
  1275
static int GLES2_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *srcrect,
slouken@6528
  1276
                            const SDL_FRect *dstrect);
gabomdq@6320
  1277
static int GLES2_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@6528
  1278
                         const SDL_Rect * srcrect, const SDL_FRect * dstrect,
slouken@6528
  1279
                         const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip);
slouken@7141
  1280
static int GLES2_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
slouken@7141
  1281
                    Uint32 pixel_format, void * pixels, int pitch);
slouken@5201
  1282
static void GLES2_RenderPresent(SDL_Renderer *renderer);
slouken@5201
  1283
slouken@7785
  1284
static SDL_bool
slouken@7785
  1285
CompareColors(Uint8 r1, Uint8 g1, Uint8 b1, Uint8 a1,
slouken@7785
  1286
              Uint8 r2, Uint8 g2, Uint8 b2, Uint8 a2)
slouken@7785
  1287
{
slouken@7785
  1288
    Uint32 Pixel1, Pixel2;
slouken@7785
  1289
    RGBA8888_FROM_RGBA(Pixel1, r1, g1, b1, a1);
slouken@7785
  1290
    RGBA8888_FROM_RGBA(Pixel2, r2, g2, b2, a2);
slouken@7785
  1291
    return (Pixel1 == Pixel2);
slouken@7785
  1292
}
slouken@5333
  1293
slouken@5201
  1294
static int
slouken@5333
  1295
GLES2_RenderClear(SDL_Renderer * renderer)
slouken@5201
  1296
{
slouken@8192
  1297
    Uint8 r, g, b, a;
slouken@8192
  1298
slouken@7780
  1299
    GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
slouken@6188
  1300
slouken@5201
  1301
    GLES2_ActivateRenderer(renderer);
slouken@6232
  1302
slouken@7785
  1303
    if (!CompareColors(data->clear_r, data->clear_g, data->clear_b, data->clear_a,
slouken@7785
  1304
                        renderer->r, renderer->g, renderer->b, renderer->a)) {
slouken@8192
  1305
slouken@8192
  1306
       /* Select the color to clear with */
slouken@8192
  1307
       g = renderer->g;
slouken@8192
  1308
       a = renderer->a;
slouken@8192
  1309
   
slouken@8192
  1310
       if (renderer->target &&
slouken@8192
  1311
            (renderer->target->format == SDL_PIXELFORMAT_ARGB8888 ||
slouken@8192
  1312
             renderer->target->format == SDL_PIXELFORMAT_RGB888)) {
slouken@8192
  1313
           r = renderer->b;
slouken@8192
  1314
           b = renderer->r;
slouken@8192
  1315
        } else {
slouken@8192
  1316
           r = renderer->r;
slouken@8192
  1317
           b = renderer->b;
slouken@8192
  1318
        }
slouken@8192
  1319
slouken@8192
  1320
        data->glClearColor((GLfloat) r * inv255f,
slouken@8192
  1321
                     (GLfloat) g * inv255f,
slouken@8192
  1322
                     (GLfloat) b * inv255f,
slouken@8192
  1323
                     (GLfloat) a * inv255f);
icculus@7784
  1324
        data->clear_r = renderer->r;
icculus@7784
  1325
        data->clear_g = renderer->g;
icculus@7784
  1326
        data->clear_b = renderer->b;
icculus@7784
  1327
        data->clear_a = renderer->a;
icculus@7784
  1328
    }
slouken@5333
  1329
slouken@7780
  1330
    data->glClear(GL_COLOR_BUFFER_BIT);
slouken@5333
  1331
slouken@5201
  1332
    return 0;
slouken@5201
  1333
}
slouken@5201
  1334
slouken@5201
  1335
static void
slouken@7780
  1336
GLES2_SetBlendMode(GLES2_DriverContext *data, int blendMode)
slouken@5201
  1337
{
slouken@7780
  1338
    if (blendMode != data->current.blendMode) {
slouken@5355
  1339
        switch (blendMode) {
slouken@5355
  1340
        default:
slouken@5355
  1341
        case SDL_BLENDMODE_NONE:
slouken@7780
  1342
            data->glDisable(GL_BLEND);
slouken@5355
  1343
            break;
slouken@5355
  1344
        case SDL_BLENDMODE_BLEND:
slouken@7780
  1345
            data->glEnable(GL_BLEND);
slouken@7780
  1346
            data->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
slouken@5355
  1347
            break;
slouken@5355
  1348
        case SDL_BLENDMODE_ADD:
slouken@7780
  1349
            data->glEnable(GL_BLEND);
slouken@7780
  1350
            data->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE);
slouken@5355
  1351
            break;
slouken@5355
  1352
        case SDL_BLENDMODE_MOD:
slouken@7780
  1353
            data->glEnable(GL_BLEND);
slouken@7780
  1354
            data->glBlendFuncSeparate(GL_ZERO, GL_SRC_COLOR, GL_ZERO, GL_ONE);
slouken@5355
  1355
            break;
slouken@5355
  1356
        }
slouken@7780
  1357
        data->current.blendMode = blendMode;
slouken@5201
  1358
    }
slouken@5201
  1359
}
slouken@5201
  1360
slouken@5355
  1361
static void
slouken@7780
  1362
GLES2_SetTexCoords(GLES2_DriverContext * data, SDL_bool enabled)
slouken@5355
  1363
{
slouken@7780
  1364
    if (enabled != data->current.tex_coords) {
slouken@5355
  1365
        if (enabled) {
slouken@7780
  1366
            data->glEnableVertexAttribArray(GLES2_ATTRIBUTE_TEXCOORD);
slouken@5355
  1367
        } else {
slouken@7780
  1368
            data->glDisableVertexAttribArray(GLES2_ATTRIBUTE_TEXCOORD);
slouken@5355
  1369
        }
slouken@7780
  1370
        data->current.tex_coords = enabled;
slouken@5355
  1371
    }
slouken@5355
  1372
}
slouken@5355
  1373
slouken@5355
  1374
static int
slouken@5355
  1375
GLES2_SetDrawingState(SDL_Renderer * renderer)
slouken@5355
  1376
{
slouken@7780
  1377
    GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
icculus@7784
  1378
    const int blendMode = renderer->blendMode;
icculus@7784
  1379
    GLES2_ProgramCacheEntry *program;
icculus@7784
  1380
    Uint8 r, g, b, a;
slouken@5355
  1381
slouken@5355
  1382
    GLES2_ActivateRenderer(renderer);
slouken@5355
  1383
slouken@7780
  1384
    GLES2_SetBlendMode(data, blendMode);
slouken@5355
  1385
slouken@7780
  1386
    GLES2_SetTexCoords(data, SDL_FALSE);
slouken@5355
  1387
slouken@5355
  1388
    /* Activate an appropriate shader and set the projection matrix */
icculus@7784
  1389
    if (GLES2_SelectProgram(renderer, GLES2_IMAGESOURCE_SOLID, blendMode) < 0) {
slouken@5355
  1390
        return -1;
icculus@7784
  1391
    }
slouken@5355
  1392
slouken@5355
  1393
    /* Select the color to draw with */
icculus@7784
  1394
    g = renderer->g;
icculus@7784
  1395
    a = renderer->a;
icculus@7784
  1396
slouken@6341
  1397
    if (renderer->target &&
icculus@7784
  1398
         (renderer->target->format == SDL_PIXELFORMAT_ARGB8888 ||
slouken@6341
  1399
         renderer->target->format == SDL_PIXELFORMAT_RGB888)) {
icculus@7784
  1400
        r = renderer->b;
icculus@7784
  1401
        b = renderer->r;
icculus@7784
  1402
     } else {
icculus@7784
  1403
        r = renderer->r;
icculus@7784
  1404
        b = renderer->b;
icculus@7784
  1405
     }
icculus@7784
  1406
icculus@7784
  1407
    program = data->current_program;
slouken@7785
  1408
    if (!CompareColors(program->color_r, program->color_g, program->color_b, program->color_a, r, g, b, a)) {
icculus@7784
  1409
        /* Select the color to draw with */
icculus@7784
  1410
        data->glUniform4f(program->uniform_locations[GLES2_UNIFORM_COLOR], r * inv255f, g * inv255f, b * inv255f, a * inv255f);
icculus@7784
  1411
        program->color_r = r;
icculus@7784
  1412
        program->color_g = g;
icculus@7784
  1413
        program->color_b = b;
icculus@7784
  1414
        program->color_a = a;
slouken@6341
  1415
    }
icculus@7784
  1416
slouken@5355
  1417
    return 0;
slouken@5355
  1418
}
slouken@5355
  1419
slouken@5201
  1420
static int
icculus@9278
  1421
GLES2_UpdateVertexBuffer(SDL_Renderer *renderer, GLES2_Attribute attr,
icculus@9278
  1422
                         const void *vertexData, size_t dataSizeInBytes)
icculus@9278
  1423
{
icculus@9278
  1424
    GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
icculus@9299
  1425
icculus@9299
  1426
#if !SDL_GLES2_USE_VBOS
icculus@9278
  1427
    data->glVertexAttribPointer(attr, attr == GLES2_ATTRIBUTE_ANGLE ? 1 : 2, GL_FLOAT, GL_FALSE, 0, vertexData);
icculus@9278
  1428
#else
slime73@9604
  1429
    if (!data->vertex_buffers[attr]) {
icculus@9278
  1430
        data->glGenBuffers(1, &data->vertex_buffers[attr]);
slime73@9604
  1431
    }
icculus@9278
  1432
icculus@9278
  1433
    data->glBindBuffer(GL_ARRAY_BUFFER, data->vertex_buffers[attr]);
icculus@9278
  1434
icculus@9278
  1435
    if (data->vertex_buffer_size[attr] < dataSizeInBytes) {
icculus@9278
  1436
        data->glBufferData(GL_ARRAY_BUFFER, dataSizeInBytes, vertexData, GL_STREAM_DRAW);
icculus@9278
  1437
        data->vertex_buffer_size[attr] = dataSizeInBytes;
icculus@9278
  1438
    } else {
icculus@9278
  1439
        data->glBufferSubData(GL_ARRAY_BUFFER, 0, dataSizeInBytes, vertexData);
icculus@9278
  1440
    }
icculus@9278
  1441
icculus@9278
  1442
    data->glVertexAttribPointer(attr, attr == GLES2_ATTRIBUTE_ANGLE ? 1 : 2, GL_FLOAT, GL_FALSE, 0, 0);
icculus@9278
  1443
#endif
icculus@9299
  1444
icculus@9278
  1445
    return 0;
icculus@9278
  1446
}
icculus@9278
  1447
icculus@9278
  1448
static int
slouken@6528
  1449
GLES2_RenderDrawPoints(SDL_Renderer *renderer, const SDL_FPoint *points, int count)
slouken@5201
  1450
{
slouken@7780
  1451
    GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
slouken@5201
  1452
    GLfloat *vertices;
slouken@5201
  1453
    int idx;
slouken@5201
  1454
slouken@5355
  1455
    if (GLES2_SetDrawingState(renderer) < 0) {
slouken@5201
  1456
        return -1;
slouken@5355
  1457
    }
slouken@5201
  1458
slouken@5201
  1459
    /* Emit the specified vertices as points */
slouken@5201
  1460
    vertices = SDL_stack_alloc(GLfloat, count * 2);
icculus@7037
  1461
    for (idx = 0; idx < count; ++idx) {
slouken@6528
  1462
        GLfloat x = points[idx].x + 0.5f;
slouken@6528
  1463
        GLfloat y = points[idx].y + 0.5f;
slouken@5201
  1464
slouken@5201
  1465
        vertices[idx * 2] = x;
slouken@5201
  1466
        vertices[(idx * 2) + 1] = y;
slouken@5201
  1467
    }
icculus@9278
  1468
    /*data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);*/
icculus@9278
  1469
    GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_POSITION, vertices, count * 2 * sizeof(GLfloat));
slouken@7780
  1470
    data->glDrawArrays(GL_POINTS, 0, count);
slouken@5201
  1471
    SDL_stack_free(vertices);
slouken@5201
  1472
    return 0;
slouken@5201
  1473
}
slouken@5201
  1474
slouken@5201
  1475
static int
slouken@6528
  1476
GLES2_RenderDrawLines(SDL_Renderer *renderer, const SDL_FPoint *points, int count)
slouken@5201
  1477
{
slouken@7780
  1478
    GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
slouken@5201
  1479
    GLfloat *vertices;
slouken@5201
  1480
    int idx;
slouken@5201
  1481
slouken@5355
  1482
    if (GLES2_SetDrawingState(renderer) < 0) {
slouken@5201
  1483
        return -1;
slouken@5355
  1484
    }
slouken@5201
  1485
slouken@5201
  1486
    /* Emit a line strip including the specified vertices */
slouken@5201
  1487
    vertices = SDL_stack_alloc(GLfloat, count * 2);
icculus@7037
  1488
    for (idx = 0; idx < count; ++idx) {
slouken@6528
  1489
        GLfloat x = points[idx].x + 0.5f;
slouken@6528
  1490
        GLfloat y = points[idx].y + 0.5f;
slouken@5201
  1491
slouken@5201
  1492
        vertices[idx * 2] = x;
slouken@5201
  1493
        vertices[(idx * 2) + 1] = y;
slouken@5201
  1494
    }
icculus@9278
  1495
    /*data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);*/
icculus@9278
  1496
    GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_POSITION, vertices, count * 2 * sizeof(GLfloat));
slouken@7780
  1497
    data->glDrawArrays(GL_LINE_STRIP, 0, count);
slouken@6076
  1498
slouken@6076
  1499
    /* We need to close the endpoint of the line */
slouken@6076
  1500
    if (count == 2 ||
slouken@6076
  1501
        points[0].x != points[count-1].x || points[0].y != points[count-1].y) {
slouken@7780
  1502
        data->glDrawArrays(GL_POINTS, count-1, 1);
slouken@6076
  1503
    }
slouken@5201
  1504
    SDL_stack_free(vertices);
slouken@7780
  1505
slouken@7780
  1506
    return GL_CheckError("", renderer);
slouken@5201
  1507
}
slouken@5201
  1508
slouken@5201
  1509
static int
slouken@6528
  1510
GLES2_RenderFillRects(SDL_Renderer *renderer, const SDL_FRect *rects, int count)
slouken@5201
  1511
{
slouken@7780
  1512
    GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
slouken@5201
  1513
    GLfloat vertices[8];
slouken@5201
  1514
    int idx;
slouken@5201
  1515
slouken@5355
  1516
    if (GLES2_SetDrawingState(renderer) < 0) {
slouken@5201
  1517
        return -1;
slouken@5355
  1518
    }
slouken@5201
  1519
slouken@5201
  1520
    /* Emit a line loop for each rectangle */
slouken@5297
  1521
    for (idx = 0; idx < count; ++idx) {
slouken@6528
  1522
        const SDL_FRect *rect = &rects[idx];
slouken@5297
  1523
slouken@6528
  1524
        GLfloat xMin = rect->x;
slouken@6528
  1525
        GLfloat xMax = (rect->x + rect->w);
slouken@6528
  1526
        GLfloat yMin = rect->y;
slouken@6528
  1527
        GLfloat yMax = (rect->y + rect->h);
slouken@5201
  1528
slouken@5201
  1529
        vertices[0] = xMin;
slouken@5201
  1530
        vertices[1] = yMin;
slouken@5201
  1531
        vertices[2] = xMax;
slouken@5201
  1532
        vertices[3] = yMin;
slouken@5201
  1533
        vertices[4] = xMin;
slouken@5201
  1534
        vertices[5] = yMax;
slouken@5201
  1535
        vertices[6] = xMax;
slouken@5201
  1536
        vertices[7] = yMax;
icculus@9278
  1537
        /*data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);*/
icculus@9278
  1538
        GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_POSITION, vertices, 8 * sizeof(GLfloat));
slouken@7780
  1539
        data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
slouken@5201
  1540
    }
slouken@7780
  1541
    return GL_CheckError("", renderer);
slouken@5201
  1542
}
slouken@5201
  1543
slouken@5201
  1544
static int
slouken@9046
  1545
GLES2_SetupCopy(SDL_Renderer *renderer, SDL_Texture *texture)
slouken@5201
  1546
{
slouken@7780
  1547
    GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
slouken@5201
  1548
    GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
gabomdq@7691
  1549
    GLES2_ImageSource sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
slouken@5201
  1550
    SDL_BlendMode blendMode;
icculus@7784
  1551
    GLES2_ProgramCacheEntry *program;
icculus@7784
  1552
    Uint8 r, g, b, a;
slouken@5201
  1553
slouken@5201
  1554
    /* Activate an appropriate shader and set the projection matrix */
slouken@5201
  1555
    blendMode = texture->blendMode;
slouken@6246
  1556
    if (renderer->target) {
slouken@6232
  1557
        /* Check if we need to do color mapping between the source and render target textures */
slouken@6246
  1558
        if (renderer->target->format != texture->format) {
slime73@9604
  1559
            switch (texture->format) {
slouken@8904
  1560
            case SDL_PIXELFORMAT_ARGB8888:
slime73@9604
  1561
                switch (renderer->target->format) {
slime73@9604
  1562
                case SDL_PIXELFORMAT_ABGR8888:
slime73@9604
  1563
                case SDL_PIXELFORMAT_BGR888:
slime73@9604
  1564
                    sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
slime73@9604
  1565
                    break;
slime73@9604
  1566
                case SDL_PIXELFORMAT_RGB888:
slime73@9604
  1567
                    sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
slime73@9604
  1568
                    break;
slouken@8904
  1569
                }
slouken@8904
  1570
                break;
slouken@6232
  1571
            case SDL_PIXELFORMAT_ABGR8888:
slime73@9604
  1572
                switch (renderer->target->format) {
slime73@9604
  1573
                case SDL_PIXELFORMAT_ARGB8888:
slime73@9604
  1574
                case SDL_PIXELFORMAT_RGB888:
slime73@9604
  1575
                    sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
slime73@9604
  1576
                    break;
slime73@9604
  1577
                case SDL_PIXELFORMAT_BGR888:
slime73@9604
  1578
                    sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
slime73@9604
  1579
                    break;
slouken@6232
  1580
                }
slouken@6232
  1581
                break;
slouken@8904
  1582
            case SDL_PIXELFORMAT_RGB888:
slime73@9604
  1583
                switch (renderer->target->format) {
slime73@9604
  1584
                case SDL_PIXELFORMAT_ABGR8888:
slime73@9604
  1585
                    sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
slime73@9604
  1586
                    break;
slime73@9604
  1587
                case SDL_PIXELFORMAT_ARGB8888:
slime73@9604
  1588
                    sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR;
slime73@9604
  1589
                    break;
slime73@9604
  1590
                case SDL_PIXELFORMAT_BGR888:
slime73@9604
  1591
                    sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
slime73@9604
  1592
                    break;
slouken@6232
  1593
                }
slouken@6232
  1594
                break;
slouken@6232
  1595
            case SDL_PIXELFORMAT_BGR888:
slime73@9604
  1596
                switch (renderer->target->format) {
slime73@9604
  1597
                case SDL_PIXELFORMAT_ABGR8888:
slime73@9604
  1598
                    sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR;
slime73@9604
  1599
                    break;
slime73@9604
  1600
                case SDL_PIXELFORMAT_ARGB8888:
slime73@9604
  1601
                    sourceType = GLES2_IMAGESOURCE_TEXTURE_RGB;
slime73@9604
  1602
                    break;
slime73@9604
  1603
                case SDL_PIXELFORMAT_RGB888:
slime73@9604
  1604
                    sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
slime73@9604
  1605
                    break;
slouken@6232
  1606
                }
slouken@6232
  1607
                break;
slouken@9046
  1608
            case SDL_PIXELFORMAT_IYUV:
slouken@9046
  1609
            case SDL_PIXELFORMAT_YV12:
slouken@9046
  1610
                sourceType = GLES2_IMAGESOURCE_TEXTURE_YUV;
slouken@9046
  1611
                break;
slouken@9046
  1612
            case SDL_PIXELFORMAT_NV12:
slouken@9046
  1613
                sourceType = GLES2_IMAGESOURCE_TEXTURE_NV12;
slouken@9046
  1614
                break;
slouken@9046
  1615
            case SDL_PIXELFORMAT_NV21:
slouken@9046
  1616
                sourceType = GLES2_IMAGESOURCE_TEXTURE_NV21;
slouken@9046
  1617
                break;
slouken@9046
  1618
            default:
slouken@9046
  1619
                return SDL_SetError("Unsupported texture format");
slouken@6232
  1620
            }
slime73@9604
  1621
        } else {
slime73@9604
  1622
            sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;   /* Texture formats match, use the non color mapping shader (even if the formats are not ABGR) */
slouken@6232
  1623
        }
slouken@9046
  1624
    } else {
slime73@9604
  1625
        switch (texture->format) {
slouken@8904
  1626
            case SDL_PIXELFORMAT_ARGB8888:
slouken@8904
  1627
                sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
slouken@8904
  1628
                break;
slouken@6232
  1629
            case SDL_PIXELFORMAT_ABGR8888:
slouken@6232
  1630
                sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
slouken@6232
  1631
                break;
slouken@8904
  1632
            case SDL_PIXELFORMAT_RGB888:
slouken@8904
  1633
                sourceType = GLES2_IMAGESOURCE_TEXTURE_RGB;
slouken@6232
  1634
                break;
slouken@6232
  1635
            case SDL_PIXELFORMAT_BGR888:
slouken@6232
  1636
                sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR;
slouken@6232
  1637
                break;
slouken@8835
  1638
            case SDL_PIXELFORMAT_IYUV:
slouken@8835
  1639
            case SDL_PIXELFORMAT_YV12:
slouken@8835
  1640
                sourceType = GLES2_IMAGESOURCE_TEXTURE_YUV;
slouken@8835
  1641
                break;
slouken@9046
  1642
            case SDL_PIXELFORMAT_NV12:
slouken@9046
  1643
                sourceType = GLES2_IMAGESOURCE_TEXTURE_NV12;
slouken@9046
  1644
                break;
slouken@9046
  1645
            case SDL_PIXELFORMAT_NV21:
slouken@9046
  1646
                sourceType = GLES2_IMAGESOURCE_TEXTURE_NV21;
slouken@9046
  1647
                break;
slouken@6928
  1648
            default:
slouken@9046
  1649
                return SDL_SetError("Unsupported texture format");
slouken@6232
  1650
        }
slouken@6113
  1651
    }
icculus@7784
  1652
icculus@7784
  1653
    if (GLES2_SelectProgram(renderer, sourceType, blendMode) < 0) {
slouken@5201
  1654
        return -1;
icculus@7784
  1655
    }
slouken@5201
  1656
slouken@5201
  1657
    /* Select the target texture */
slouken@8835
  1658
    if (tdata->yuv) {
slouken@8835
  1659
        data->glActiveTexture(GL_TEXTURE2);
slouken@8835
  1660
        data->glBindTexture(tdata->texture_type, tdata->texture_v);
slouken@8835
  1661
slouken@8835
  1662
        data->glActiveTexture(GL_TEXTURE1);
slouken@8835
  1663
        data->glBindTexture(tdata->texture_type, tdata->texture_u);
slouken@8835
  1664
slouken@8835
  1665
        data->glActiveTexture(GL_TEXTURE0);
slouken@8835
  1666
    }
slouken@9046
  1667
    if (tdata->nv12) {
slouken@9046
  1668
        data->glActiveTexture(GL_TEXTURE1);
slouken@9046
  1669
        data->glBindTexture(tdata->texture_type, tdata->texture_u);
slouken@9046
  1670
slouken@9046
  1671
        data->glActiveTexture(GL_TEXTURE0);
slouken@9046
  1672
    }
slouken@7780
  1673
    data->glBindTexture(tdata->texture_type, tdata->texture);
gabomdq@6320
  1674
gabomdq@6320
  1675
    /* Configure color modulation */
icculus@7784
  1676
    g = texture->g;
icculus@7784
  1677
    a = texture->a;
icculus@7784
  1678
slouken@6341
  1679
    if (renderer->target &&
slouken@6341
  1680
        (renderer->target->format == SDL_PIXELFORMAT_ARGB8888 ||
slouken@6341
  1681
         renderer->target->format == SDL_PIXELFORMAT_RGB888)) {
icculus@7784
  1682
        r = texture->b;
icculus@7784
  1683
        b = texture->r;
slouken@6341
  1684
    } else {
icculus@7784
  1685
        r = texture->r;
icculus@7784
  1686
        b = texture->b;
icculus@7784
  1687
    }
icculus@7784
  1688
icculus@7784
  1689
    program = data->current_program;
icculus@7784
  1690
slouken@7785
  1691
    if (!CompareColors(program->modulation_r, program->modulation_g, program->modulation_b, program->modulation_a, r, g, b, a)) {
icculus@7784
  1692
        data->glUniform4f(program->uniform_locations[GLES2_UNIFORM_MODULATION], r * inv255f, g * inv255f, b * inv255f, a * inv255f);
icculus@7784
  1693
        program->modulation_r = r;
icculus@7784
  1694
        program->modulation_g = g;
icculus@7784
  1695
        program->modulation_b = b;
icculus@7784
  1696
        program->modulation_a = a;
slouken@6341
  1697
    }
gabomdq@6320
  1698
gabomdq@6320
  1699
    /* Configure texture blending */
slouken@7780
  1700
    GLES2_SetBlendMode(data, blendMode);
gabomdq@6320
  1701
slouken@7780
  1702
    GLES2_SetTexCoords(data, SDL_TRUE);
slouken@9046
  1703
    return 0;
slouken@9046
  1704
}
slouken@9046
  1705
slouken@9046
  1706
static int
slouken@9046
  1707
GLES2_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *srcrect,
slouken@9046
  1708
                 const SDL_FRect *dstrect)
slouken@9046
  1709
{
slouken@9046
  1710
    GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
slouken@9046
  1711
    GLfloat vertices[8];
slouken@9046
  1712
    GLfloat texCoords[8];
slouken@9046
  1713
slouken@9046
  1714
    GLES2_ActivateRenderer(renderer);
slouken@9046
  1715
slouken@9046
  1716
    if (GLES2_SetupCopy(renderer, texture) < 0) {
slouken@9046
  1717
        return -1;
slouken@9046
  1718
    }
gabomdq@6320
  1719
gabomdq@6320
  1720
    /* Emit the textured quad */
slouken@6528
  1721
    vertices[0] = dstrect->x;
slouken@6528
  1722
    vertices[1] = dstrect->y;
slouken@6528
  1723
    vertices[2] = (dstrect->x + dstrect->w);
slouken@6528
  1724
    vertices[3] = dstrect->y;
slouken@6528
  1725
    vertices[4] = dstrect->x;
slouken@6528
  1726
    vertices[5] = (dstrect->y + dstrect->h);
slouken@6528
  1727
    vertices[6] = (dstrect->x + dstrect->w);
slouken@6528
  1728
    vertices[7] = (dstrect->y + dstrect->h);
icculus@9278
  1729
    /*data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);*/
icculus@9278
  1730
    GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_POSITION, vertices, 8 * sizeof(GLfloat));
gabomdq@6320
  1731
    texCoords[0] = srcrect->x / (GLfloat)texture->w;
gabomdq@6320
  1732
    texCoords[1] = srcrect->y / (GLfloat)texture->h;
gabomdq@6320
  1733
    texCoords[2] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
gabomdq@6320
  1734
    texCoords[3] = srcrect->y / (GLfloat)texture->h;
gabomdq@6320
  1735
    texCoords[4] = srcrect->x / (GLfloat)texture->w;
gabomdq@6320
  1736
    texCoords[5] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
gabomdq@6320
  1737
    texCoords[6] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
gabomdq@6320
  1738
    texCoords[7] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
icculus@9278
  1739
    /*data->glVertexAttribPointer(GLES2_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, texCoords);*/
icculus@9278
  1740
    GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_TEXCOORD, texCoords, 8 * sizeof(GLfloat));
slouken@7780
  1741
    data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
slouken@7780
  1742
slouken@7780
  1743
    return GL_CheckError("", renderer);
gabomdq@6320
  1744
}
gabomdq@6320
  1745
gabomdq@6320
  1746
static int
gabomdq@6320
  1747
GLES2_RenderCopyEx(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *srcrect,
slouken@6528
  1748
                 const SDL_FRect *dstrect, const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
gabomdq@6320
  1749
{
slouken@7780
  1750
    GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
gabomdq@6320
  1751
    GLfloat vertices[8];
gabomdq@6320
  1752
    GLfloat texCoords[8];
gabomdq@6320
  1753
    GLfloat translate[8];
gabomdq@6320
  1754
    GLfloat fAngle[4];
gabomdq@6320
  1755
    GLfloat tmp;
gabomdq@6320
  1756
gabomdq@6320
  1757
    GLES2_ActivateRenderer(renderer);
slouken@7191
  1758
slouken@9046
  1759
    if (GLES2_SetupCopy(renderer, texture) < 0) {
slouken@9046
  1760
        return -1;
slouken@9046
  1761
    }
slouken@9046
  1762
slouken@7780
  1763
    data->glEnableVertexAttribArray(GLES2_ATTRIBUTE_CENTER);
slouken@7780
  1764
    data->glEnableVertexAttribArray(GLES2_ATTRIBUTE_ANGLE);
slouken@6825
  1765
    fAngle[0] = fAngle[1] = fAngle[2] = fAngle[3] = (GLfloat)(360.0f - angle);
gabomdq@6320
  1766
    /* Calculate the center of rotation */
slouken@6528
  1767
    translate[0] = translate[2] = translate[4] = translate[6] = (center->x + dstrect->x);
slouken@6528
  1768
    translate[1] = translate[3] = translate[5] = translate[7] = (center->y + dstrect->y);
gabomdq@6320
  1769
slouken@5201
  1770
    /* Emit the textured quad */
slouken@6528
  1771
    vertices[0] = dstrect->x;
slouken@6528
  1772
    vertices[1] = dstrect->y;
slouken@6528
  1773
    vertices[2] = (dstrect->x + dstrect->w);
slouken@6528
  1774
    vertices[3] = dstrect->y;
slouken@6528
  1775
    vertices[4] = dstrect->x;
slouken@6528
  1776
    vertices[5] = (dstrect->y + dstrect->h);
slouken@6528
  1777
    vertices[6] = (dstrect->x + dstrect->w);
slouken@6528
  1778
    vertices[7] = (dstrect->y + dstrect->h);
gabomdq@6320
  1779
    if (flip & SDL_FLIP_HORIZONTAL) {
gabomdq@6320
  1780
        tmp = vertices[0];
gabomdq@6320
  1781
        vertices[0] = vertices[4] = vertices[2];
gabomdq@6320
  1782
        vertices[2] = vertices[6] = tmp;
gabomdq@6320
  1783
    }
gabomdq@6320
  1784
    if (flip & SDL_FLIP_VERTICAL) {
gabomdq@6320
  1785
        tmp = vertices[1];
gabomdq@6320
  1786
        vertices[1] = vertices[3] = vertices[5];
gabomdq@6320
  1787
        vertices[5] = vertices[7] = tmp;
gabomdq@6320
  1788
    }
slouken@7191
  1789
icculus@9278
  1790
    /*data->glVertexAttribPointer(GLES2_ATTRIBUTE_ANGLE, 1, GL_FLOAT, GL_FALSE, 0, &fAngle);
slouken@7780
  1791
    data->glVertexAttribPointer(GLES2_ATTRIBUTE_CENTER, 2, GL_FLOAT, GL_FALSE, 0, translate);
icculus@9278
  1792
    data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);*/
icculus@9278
  1793
icculus@9278
  1794
    GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_ANGLE, fAngle, 4 * sizeof(GLfloat));
icculus@9278
  1795
    GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_CENTER, translate, 8 * sizeof(GLfloat));
icculus@9278
  1796
    GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_POSITION, vertices, 8 * sizeof(GLfloat));
slouken@6232
  1797
slouken@5201
  1798
    texCoords[0] = srcrect->x / (GLfloat)texture->w;
slouken@5201
  1799
    texCoords[1] = srcrect->y / (GLfloat)texture->h;
slouken@5201
  1800
    texCoords[2] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
slouken@5201
  1801
    texCoords[3] = srcrect->y / (GLfloat)texture->h;
slouken@5201
  1802
    texCoords[4] = srcrect->x / (GLfloat)texture->w;
slouken@5201
  1803
    texCoords[5] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
slouken@5201
  1804
    texCoords[6] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
slouken@5201
  1805
    texCoords[7] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
icculus@9278
  1806
    /*data->glVertexAttribPointer(GLES2_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, texCoords);*/
icculus@9278
  1807
    GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_TEXCOORD, texCoords, 8 * sizeof(GLfloat));
slouken@7780
  1808
    data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
slouken@7780
  1809
    data->glDisableVertexAttribArray(GLES2_ATTRIBUTE_CENTER);
slouken@7780
  1810
    data->glDisableVertexAttribArray(GLES2_ATTRIBUTE_ANGLE);
slouken@7780
  1811
slouken@7780
  1812
    return GL_CheckError("", renderer);
slouken@5201
  1813
}
slouken@5201
  1814
slouken@6042
  1815
static int
slouken@6042
  1816
GLES2_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
slouken@6042
  1817
                    Uint32 pixel_format, void * pixels, int pitch)
slouken@6042
  1818
{
slouken@7780
  1819
    GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
slouken@6042
  1820
    Uint32 temp_format = SDL_PIXELFORMAT_ABGR8888;
slouken@6042
  1821
    void *temp_pixels;
slouken@6042
  1822
    int temp_pitch;
slouken@6042
  1823
    Uint8 *src, *dst, *tmp;
slouken@6042
  1824
    int w, h, length, rows;
slouken@6042
  1825
    int status;
slouken@6042
  1826
slouken@6042
  1827
    GLES2_ActivateRenderer(renderer);
slouken@6042
  1828
slouken@6042
  1829
    temp_pitch = rect->w * SDL_BYTESPERPIXEL(temp_format);
slouken@6042
  1830
    temp_pixels = SDL_malloc(rect->h * temp_pitch);
slouken@6042
  1831
    if (!temp_pixels) {
icculus@7037
  1832
        return SDL_OutOfMemory();
slouken@6042
  1833
    }
slouken@6042
  1834
slouken@7420
  1835
    SDL_GetRendererOutputSize(renderer, &w, &h);
slouken@6042
  1836
slouken@10405
  1837
    data->glReadPixels(rect->x, renderer->target ? rect->y : (h-rect->y)-rect->h,
slouken@10405
  1838
                       rect->w, rect->h, GL_RGBA, GL_UNSIGNED_BYTE, temp_pixels);
slouken@7780
  1839
    if (GL_CheckError("glReadPixels()", renderer) < 0) {
slouken@7780
  1840
        return -1;
slouken@7780
  1841
    }
slouken@6042
  1842
slouken@10405
  1843
    /* Flip the rows to be top-down if necessary */
slouken@10405
  1844
    if (!renderer->target) {
slouken@10405
  1845
        length = rect->w * SDL_BYTESPERPIXEL(temp_format);
slouken@10405
  1846
        src = (Uint8*)temp_pixels + (rect->h-1)*temp_pitch;
slouken@10405
  1847
        dst = (Uint8*)temp_pixels;
slouken@10405
  1848
        tmp = SDL_stack_alloc(Uint8, length);
slouken@10405
  1849
        rows = rect->h / 2;
slouken@10405
  1850
        while (rows--) {
slouken@10405
  1851
            SDL_memcpy(tmp, dst, length);
slouken@10405
  1852
            SDL_memcpy(dst, src, length);
slouken@10405
  1853
            SDL_memcpy(src, tmp, length);
slouken@10405
  1854
            dst += temp_pitch;
slouken@10405
  1855
            src -= temp_pitch;
slouken@10405
  1856
        }
slouken@10405
  1857
        SDL_stack_free(tmp);
slouken@6042
  1858
    }
slouken@6042
  1859
slouken@6042
  1860
    status = SDL_ConvertPixels(rect->w, rect->h,
slouken@6042
  1861
                               temp_format, temp_pixels, temp_pitch,
slouken@6042
  1862
                               pixel_format, pixels, pitch);
slouken@6042
  1863
    SDL_free(temp_pixels);
slouken@6042
  1864
slouken@6042
  1865
    return status;
slouken@6042
  1866
}
slouken@6042
  1867
slouken@5201
  1868
static void
slouken@5201
  1869
GLES2_RenderPresent(SDL_Renderer *renderer)
slouken@5201
  1870
{
slouken@5201
  1871
    GLES2_ActivateRenderer(renderer);
slouken@5201
  1872
slouken@5201
  1873
    /* Tell the video driver to swap buffers */
slouken@5201
  1874
    SDL_GL_SwapWindow(renderer->window);
slouken@5201
  1875
}
slouken@5201
  1876
gabomdq@6414
  1877
gabomdq@6414
  1878
/*************************************************************************************************
gabomdq@6414
  1879
 * Bind/unbinding of textures
gabomdq@6414
  1880
 *************************************************************************************************/
gabomdq@6414
  1881
static int GLES2_BindTexture (SDL_Renderer * renderer, SDL_Texture *texture, float *texw, float *texh);
gabomdq@6414
  1882
static int GLES2_UnbindTexture (SDL_Renderer * renderer, SDL_Texture *texture);
gabomdq@6414
  1883
slouken@7780
  1884
static int GLES2_BindTexture (SDL_Renderer * renderer, SDL_Texture *texture, float *texw, float *texh)
slouken@7780
  1885
{
gabomdq@6414
  1886
    GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
gabomdq@6414
  1887
    GLES2_TextureData *texturedata = (GLES2_TextureData *)texture->driverdata;
gabomdq@6414
  1888
    GLES2_ActivateRenderer(renderer);
gabomdq@6414
  1889
gabomdq@6414
  1890
    data->glBindTexture(texturedata->texture_type, texturedata->texture);
gabomdq@6414
  1891
slime73@9604
  1892
    if (texw) {
slime73@9604
  1893
        *texw = 1.0;
slime73@9604
  1894
    }
slime73@9604
  1895
    if (texh) {
slime73@9604
  1896
        *texh = 1.0;
slime73@9604
  1897
    }
gabomdq@6414
  1898
gabomdq@6414
  1899
    return 0;
gabomdq@6414
  1900
}
gabomdq@6414
  1901
slouken@7780
  1902
static int GLES2_UnbindTexture (SDL_Renderer * renderer, SDL_Texture *texture)
slouken@7780
  1903
{
gabomdq@6414
  1904
    GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
gabomdq@6414
  1905
    GLES2_TextureData *texturedata = (GLES2_TextureData *)texture->driverdata;
gabomdq@6414
  1906
    GLES2_ActivateRenderer(renderer);
gabomdq@6414
  1907
icculus@7075
  1908
    data->glBindTexture(texturedata->texture_type, 0);
gabomdq@6414
  1909
gabomdq@6414
  1910
    return 0;
gabomdq@6414
  1911
}
gabomdq@6414
  1912
gabomdq@6414
  1913
slouken@5201
  1914
/*************************************************************************************************
slouken@5201
  1915
 * Renderer instantiation                                                                        *
slouken@5201
  1916
 *************************************************************************************************/
slouken@5201
  1917
slouken@5201
  1918
#define GL_NVIDIA_PLATFORM_BINARY_NV 0x890B
slouken@5201
  1919
slouken@5355
  1920
static void
slouken@5355
  1921
GLES2_ResetState(SDL_Renderer *renderer)
slouken@5355
  1922
{
slouken@7780
  1923
    GLES2_DriverContext *data = (GLES2_DriverContext *) renderer->driverdata;
slouken@5355
  1924
slouken@7780
  1925
    if (SDL_CurrentContext == data->context) {
slouken@5355
  1926
        GLES2_UpdateViewport(renderer);
slouken@5355
  1927
    } else {
slouken@5355
  1928
        GLES2_ActivateRenderer(renderer);
slouken@5355
  1929
    }
slouken@5355
  1930
slouken@7780
  1931
    data->current.blendMode = -1;
slouken@7780
  1932
    data->current.tex_coords = SDL_FALSE;
slouken@5355
  1933
icculus@7784
  1934
    data->glActiveTexture(GL_TEXTURE0);
icculus@7784
  1935
    data->glPixelStorei(GL_PACK_ALIGNMENT, 1);
icculus@7784
  1936
    data->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
icculus@7784
  1937
icculus@7784
  1938
    data->glClearColor((GLfloat) data->clear_r * inv255f,
icculus@7784
  1939
                        (GLfloat) data->clear_g * inv255f,
icculus@7784
  1940
                        (GLfloat) data->clear_b * inv255f,
icculus@7784
  1941
                        (GLfloat) data->clear_a * inv255f);
icculus@7784
  1942
slouken@7780
  1943
    data->glEnableVertexAttribArray(GLES2_ATTRIBUTE_POSITION);
slouken@7780
  1944
    data->glDisableVertexAttribArray(GLES2_ATTRIBUTE_TEXCOORD);
slouken@7780
  1945
slouken@7780
  1946
    GL_CheckError("", renderer);
slouken@5355
  1947
}
slouken@5355
  1948
slouken@5201
  1949
static SDL_Renderer *
slouken@5201
  1950
GLES2_CreateRenderer(SDL_Window *window, Uint32 flags)
slouken@5201
  1951
{
slouken@5201
  1952
    SDL_Renderer *renderer;
slouken@7780
  1953
    GLES2_DriverContext *data;
slouken@5201
  1954
    GLint nFormats;
slouken@5201
  1955
#ifndef ZUNE_HD
slouken@5201
  1956
    GLboolean hasCompiler;
slouken@5201
  1957
#endif
slouken@8906
  1958
    Uint32 window_flags;
slouken@6271
  1959
    GLint window_framebuffer;
slouken@7770
  1960
    GLint value;
slime73@9958
  1961
    int profile_mask = 0, major = 0, minor = 0;
slouken@8906
  1962
    SDL_bool changed_window = SDL_FALSE;
slouken@6232
  1963
gabomdq@8257
  1964
    SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profile_mask);
gabomdq@8257
  1965
    SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major);
gabomdq@8257
  1966
    SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor);
slouken@6232
  1967
slouken@8906
  1968
    window_flags = SDL_GetWindowFlags(window);
slouken@8906
  1969
    if (!(window_flags & SDL_WINDOW_OPENGL) ||
gabomdq@8257
  1970
        profile_mask != SDL_GL_CONTEXT_PROFILE_ES || major != RENDERER_CONTEXT_MAJOR || minor != RENDERER_CONTEXT_MINOR) {
slouken@8906
  1971
slouken@8906
  1972
        changed_window = SDL_TRUE;
gabomdq@8264
  1973
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
gabomdq@8264
  1974
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, RENDERER_CONTEXT_MAJOR);
gabomdq@8264
  1975
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, RENDERER_CONTEXT_MINOR);
gabomdq@8264
  1976
slouken@8906
  1977
        if (SDL_RecreateWindow(window, window_flags | SDL_WINDOW_OPENGL) < 0) {
slouken@8906
  1978
            goto error;
slouken@6188
  1979
        }
slouken@6188
  1980
    }
slouken@5201
  1981
slouken@5201
  1982
    /* Create the renderer struct */
slouken@5201
  1983
    renderer = (SDL_Renderer *)SDL_calloc(1, sizeof(SDL_Renderer));
slouken@5209
  1984
    if (!renderer) {
slouken@5209
  1985
        SDL_OutOfMemory();
slouken@8906
  1986
        goto error;
slouken@5209
  1987
    }
slouken@5209
  1988
slouken@7780
  1989
    data = (GLES2_DriverContext *)SDL_calloc(1, sizeof(GLES2_DriverContext));
slouken@7780
  1990
    if (!data) {
slouken@5209
  1991
        GLES2_DestroyRenderer(renderer);
slouken@5201
  1992
        SDL_OutOfMemory();
slouken@8906
  1993
        goto error;
slouken@5201
  1994
    }
slouken@5201
  1995
    renderer->info = GLES2_RenderDriver.info;
slouken@8590
  1996
    renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
slouken@7780
  1997
    renderer->driverdata = data;
slouken@6171
  1998
    renderer->window = window;
slouken@5201
  1999
slouken@5209
  2000
    /* Create an OpenGL ES 2.0 context */
slouken@7780
  2001
    data->context = SDL_GL_CreateContext(window);
slouken@8906
  2002
    if (!data->context) {
slouken@5209
  2003
        GLES2_DestroyRenderer(renderer);
slouken@8906
  2004
        goto error;
slouken@5201
  2005
    }
slouken@7780
  2006
    if (SDL_GL_MakeCurrent(window, data->context) < 0) {
slouken@5209
  2007
        GLES2_DestroyRenderer(renderer);
slouken@8906
  2008
        goto error;
slouken@5202
  2009
    }
slouken@5202
  2010
slouken@7780
  2011
    if (GLES2_LoadFunctions(data) < 0) {
slouken@6188
  2012
        GLES2_DestroyRenderer(renderer);
slouken@8906
  2013
        goto error;
slouken@6188
  2014
    }
slouken@6188
  2015
dludwig@8546
  2016
#if __WINRT__
dludwig@8546
  2017
    /* DLudwig, 2013-11-29: ANGLE for WinRT doesn't seem to work unless VSync
dludwig@8546
  2018
     * is turned on.  Not doing so will freeze the screen's contents to that
dludwig@8546
  2019
     * of the first drawn frame.
dludwig@8546
  2020
     */
dludwig@8546
  2021
    flags |= SDL_RENDERER_PRESENTVSYNC;
dludwig@8546
  2022
#endif
dludwig@8546
  2023
slouken@5202
  2024
    if (flags & SDL_RENDERER_PRESENTVSYNC) {
slouken@5202
  2025
        SDL_GL_SetSwapInterval(1);
slouken@5202
  2026
    } else {
slouken@5202
  2027
        SDL_GL_SetSwapInterval(0);
slouken@5202
  2028
    }
slouken@5202
  2029
    if (SDL_GL_GetSwapInterval() > 0) {
slouken@5202
  2030
        renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
slouken@5202
  2031
    }
slouken@5201
  2032
slouken@7780
  2033
    /* Check for debug output support */
slouken@7780
  2034
    if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_FLAGS, &value) == 0 &&
slouken@7780
  2035
        (value & SDL_GL_CONTEXT_DEBUG_FLAG)) {
slouken@7780
  2036
        data->debug_enabled = SDL_TRUE;
slouken@7780
  2037
    }
slouken@7780
  2038
slouken@7770
  2039
    value = 0;
slouken@7780
  2040
    data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
slouken@7770
  2041
    renderer->info.max_texture_width = value;
slouken@7770
  2042
    value = 0;
slouken@7780
  2043
    data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
slouken@7770
  2044
    renderer->info.max_texture_height = value;
slouken@7770
  2045
slouken@5201
  2046
    /* Determine supported shader formats */
slouken@5201
  2047
    /* HACK: glGetInteger is broken on the Zune HD's compositor, so we just hardcode this */
slouken@5201
  2048
#ifdef ZUNE_HD
slouken@5201
  2049
    nFormats = 1;
slouken@5201
  2050
#else /* !ZUNE_HD */
slouken@7780
  2051
    data->glGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &nFormats);
slouken@7780
  2052
    data->glGetBooleanv(GL_SHADER_COMPILER, &hasCompiler);
slime73@9604
  2053
    if (hasCompiler) {
slouken@5201
  2054
        ++nFormats;
slime73@9604
  2055
    }
slouken@5201
  2056
#endif /* ZUNE_HD */
slouken@7780
  2057
    data->shader_formats = (GLenum *)SDL_calloc(nFormats, sizeof(GLenum));
slime73@9604
  2058
    if (!data->shader_formats) {
slouken@5209
  2059
        GLES2_DestroyRenderer(renderer);
slouken@5201
  2060
        SDL_OutOfMemory();
slouken@8906
  2061
        goto error;
slouken@5201
  2062
    }
slouken@7780
  2063
    data->shader_format_count = nFormats;
slouken@5201
  2064
#ifdef ZUNE_HD
slouken@7780
  2065
    data->shader_formats[0] = GL_NVIDIA_PLATFORM_BINARY_NV;
slouken@5201
  2066
#else /* !ZUNE_HD */
slouken@7780
  2067
    data->glGetIntegerv(GL_SHADER_BINARY_FORMATS, (GLint *)data->shader_formats);
slime73@9604
  2068
    if (hasCompiler) {
slouken@7780
  2069
        data->shader_formats[nFormats - 1] = (GLenum)-1;
slime73@9604
  2070
    }
slouken@5201
  2071
#endif /* ZUNE_HD */
slouken@5201
  2072
slouken@7780
  2073
    data->framebuffers = NULL;
slouken@7780
  2074
    data->glGetIntegerv(GL_FRAMEBUFFER_BINDING, &window_framebuffer);
slouken@7780
  2075
    data->window_framebuffer = (GLuint)window_framebuffer;
slouken@6232
  2076
slouken@5201
  2077
    /* Populate the function pointers for the module */
slouken@5201
  2078
    renderer->WindowEvent         = &GLES2_WindowEvent;
slime73@9530
  2079
    renderer->GetOutputSize       = &GLES2_GetOutputSize;
slouken@5201
  2080
    renderer->CreateTexture       = &GLES2_CreateTexture;
slouken@5201
  2081
    renderer->UpdateTexture       = &GLES2_UpdateTexture;
slouken@8835
  2082
    renderer->UpdateTextureYUV    = &GLES2_UpdateTextureYUV;
slouken@5201
  2083
    renderer->LockTexture         = &GLES2_LockTexture;
slouken@5201
  2084
    renderer->UnlockTexture       = &GLES2_UnlockTexture;
slouken@6247
  2085
    renderer->SetRenderTarget     = &GLES2_SetRenderTarget;
slouken@5297
  2086
    renderer->UpdateViewport      = &GLES2_UpdateViewport;
slouken@7141
  2087
    renderer->UpdateClipRect      = &GLES2_UpdateClipRect;
slouken@5201
  2088
    renderer->RenderClear         = &GLES2_RenderClear;
slouken@5201
  2089
    renderer->RenderDrawPoints    = &GLES2_RenderDrawPoints;
slouken@5201
  2090
    renderer->RenderDrawLines     = &GLES2_RenderDrawLines;
slouken@5201
  2091
    renderer->RenderFillRects     = &GLES2_RenderFillRects;
slouken@5201
  2092
    renderer->RenderCopy          = &GLES2_RenderCopy;
slouken@7141
  2093
    renderer->RenderCopyEx        = &GLES2_RenderCopyEx;
slouken@6042
  2094
    renderer->RenderReadPixels    = &GLES2_RenderReadPixels;
slouken@5201
  2095
    renderer->RenderPresent       = &GLES2_RenderPresent;
slouken@5201
  2096
    renderer->DestroyTexture      = &GLES2_DestroyTexture;
slouken@5201
  2097
    renderer->DestroyRenderer     = &GLES2_DestroyRenderer;
gabomdq@6414
  2098
    renderer->GL_BindTexture      = &GLES2_BindTexture;
gabomdq@6414
  2099
    renderer->GL_UnbindTexture    = &GLES2_UnbindTexture;
slouken@5355
  2100
slouken@8835
  2101
    renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;
slouken@8835
  2102
    renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
slouken@9046
  2103
    renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_NV12;
slouken@9046
  2104
    renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_NV21;
slouken@8835
  2105
slouken@5355
  2106
    GLES2_ResetState(renderer);
slouken@5355
  2107
slouken@5201
  2108
    return renderer;
slouken@8906
  2109
slouken@8906
  2110
error:
slouken@8906
  2111
    if (changed_window) {
slouken@8906
  2112
        /* Uh oh, better try to put it back... */
slouken@8906
  2113
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profile_mask);
slouken@8906
  2114
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major);
slouken@8906
  2115
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minor);
slouken@8906
  2116
        SDL_RecreateWindow(window, window_flags);
slouken@8906
  2117
    }
slouken@8906
  2118
    return NULL;
slouken@5201
  2119
}
slouken@5201
  2120
slouken@5226
  2121
#endif /* SDL_VIDEO_RENDER_OGL_ES2 && !SDL_RENDER_DISABLED */
slouken@5201
  2122
slouken@5201
  2123
/* vi: set ts=4 sw=4 expandtab: */