src/render/opengles2/SDL_render_gles2.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 21 Jun 2014 12:38:46 -0700
changeset 8890 d9a2fa86cd97
parent 8835 bc5ec1b6904c
child 8904 c38e754cafd3
permissions -rw-r--r--
Fixed bug 2595 - Padded, non-contiguous YUV does not display correctly using OpenGL ES 2.0 renderer

Alvin

The new OpenGL ES 2.0 YUV Texture support does not correctly display padded, non-contiguous YUV data.

I am using SDL2 60edb019f0fe (as provided by 'hg id --id') from Mercurial.

The YUV data I am using is provided by the FFMPEG family of libraries. According to FFMPEG's documentation, "The linesize [pitch] may be larger than the size of usable data -- there may be extra padding present for performance reasons."

The dimensions of the video file that I am using are 480x360. What I get from FFMPEG is a Ypitch of 512, and Upitch and Vpitch are both 256.

When I pack new Y, U and V buffers with only the "usable" data (Ypitch is 480 and Upitch and Vpitch are both 240), and use those new buffers, the image is display correctly.

It appears that the Ypitch, Upitch and Vpitch parameters are not being used by SDL_UpdateYUVTexture().

I use SDL_PIXELFORMAT_YV12 for my YUV texture, however, the same results are seen when I use SDL_PIXELFORMAT_IYUV.

Not sure if this is related or not, but when I render the YUV texture (padded and unpadded) to a RGB24 texture, the resulting image is greyscale (or could by just the Y channel).

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