src/render/opengles2/SDL_render_gles2.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 08 Jan 2012 02:23:37 -0500
changeset 6188 e82023802002
parent 6178 1fc633857667
child 6190 519380462400
permissions -rwxr-xr-x
Fixed bug 1242 - PATCH: Improve support for OpenGL ES under X11

Scott Percival 2011-07-03 06:41:51 PDT

This submission is aimed at making life easier for OpenGL ES capable devices
running a X11 stack (e.g. Maemo, Meego, TrimSlice, other ARM SoC boards not
running Android). SDL's Pandora support already has the neccesary GLES-to-X11
glue code, however it's all ghetto'd off in Makefile.pandora and not very
flexible.

The patch:
- adds an awesome --enable-video-opengles option to configure
- re-modifies the opengles and opengles2 SDL_renderers to use function pointers
- no idea why this was removed?
- for SDL_Renderers, links in libGLESv1_CM, libGLES_CM (for PowerVR fans) or
libGLESv2 at runtime
- links in libEGL.so at runtime - the old code made an assumption that
eglFunctions could be pulled from the active GLES library, PowerVR for one
doesn't let you do that with their libGLESv2
- allows you to pick which of GLES v1 or v2 to load via
SDL_GL_CONTEXT_MAJOR_VERSION

So far I've tested this on a Nokia N900 (OMAP 3430/SGX 530 running Maemo 5) and
a Toshiba AC100 (Tegra 2 running Ubuntu 10.10). I haven't tested it on... well,
everything that isn't those two, such as a Pandora, iOS or Android device. The
Pandora specific code should be kept intact (fingers crossed), and nothing
painfully drastic has been added to the SDL_renderers. The library loading
sequence in SDL_x11opengles has been updated to accomodate both NVIDIA's
propensity to let developers get away with murder and PowerVR's alternative of
punishing every missed step.

The test apps work okay with GLES or GLES2 as the renderer. For some reason
alpha blending doesn't seem to work on the Tegra 2; last week NVIDIA pushed out
a new set of X11 GLES drivers, so I'll try and investigate once I upgrade
those. Also, this patch adds things to configure.in, include/SDL_config.h.in
and test/configure.in. I didn't know what the policy was re. committing
generated spaghetti from autotools, so ./autogen.sh has to be run again. Sorry.

I think that's about everything, let me know if there's anything I've
overlooked.
slouken@5201
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@6138
     3
  Copyright (C) 1997-2012 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
*/
slouken@5201
    21
#include "SDL_config.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@5201
    28
#include "SDL_shaders_gles2.h"
slouken@5201
    29
slouken@6188
    30
/* Used to re-create the window with OpenGL capability */
slouken@6188
    31
extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags);
slouken@6188
    32
slouken@5201
    33
/*************************************************************************************************
slouken@5201
    34
 * Bootstrap data                                                                                *
slouken@5201
    35
 *************************************************************************************************/
slouken@5201
    36
slouken@5201
    37
static SDL_Renderer *GLES2_CreateRenderer(SDL_Window *window, Uint32 flags);
slouken@5201
    38
slouken@5201
    39
SDL_RenderDriver GLES2_RenderDriver = {
slouken@5201
    40
    GLES2_CreateRenderer,
slouken@5201
    41
    {
slouken@5201
    42
        "opengles2",
slouken@5201
    43
        (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC),
slouken@6113
    44
        4,
slouken@6113
    45
        {SDL_PIXELFORMAT_ABGR8888,
slouken@6113
    46
        SDL_PIXELFORMAT_ARGB8888,
slouken@6113
    47
        SDL_PIXELFORMAT_RGB888,
slouken@6113
    48
        SDL_PIXELFORMAT_BGR888},
slouken@5201
    49
        0,
slouken@5201
    50
        0
slouken@5201
    51
    }
slouken@5201
    52
};
slouken@5201
    53
slouken@5201
    54
/*************************************************************************************************
slouken@5201
    55
 * Context structures                                                                            *
slouken@5201
    56
 *************************************************************************************************/
slouken@5201
    57
slouken@5201
    58
typedef struct GLES2_TextureData
slouken@5201
    59
{
slouken@5201
    60
    GLenum texture;
slouken@5201
    61
    GLenum texture_type;
slouken@5201
    62
    GLenum pixel_format;
slouken@5201
    63
    GLenum pixel_type;
slouken@5201
    64
    void *pixel_data;
slouken@5201
    65
    size_t pitch;
slouken@5201
    66
} GLES2_TextureData;
slouken@5201
    67
slouken@5201
    68
typedef struct GLES2_ShaderCacheEntry
slouken@5201
    69
{
slouken@5201
    70
    GLuint id;
slouken@5201
    71
    GLES2_ShaderType type;
slouken@5201
    72
    const GLES2_ShaderInstance *instance;
slouken@5201
    73
    int references;
slouken@5201
    74
    struct GLES2_ShaderCacheEntry *prev;
slouken@5201
    75
    struct GLES2_ShaderCacheEntry *next;
slouken@5201
    76
} GLES2_ShaderCacheEntry;
slouken@5201
    77
slouken@5201
    78
typedef struct GLES2_ShaderCache
slouken@5201
    79
{
slouken@5201
    80
    int count;
slouken@5201
    81
    GLES2_ShaderCacheEntry *head;
slouken@5201
    82
} GLES2_ShaderCache;
slouken@5201
    83
slouken@5201
    84
typedef struct GLES2_ProgramCacheEntry
slouken@5201
    85
{
slouken@5201
    86
    GLuint id;
slouken@5201
    87
    SDL_BlendMode blend_mode;
slouken@5201
    88
    GLES2_ShaderCacheEntry *vertex_shader;
slouken@5201
    89
    GLES2_ShaderCacheEntry *fragment_shader;
slouken@5201
    90
    GLuint uniform_locations[16];
slouken@5201
    91
    struct GLES2_ProgramCacheEntry *prev;
slouken@5201
    92
    struct GLES2_ProgramCacheEntry *next;
slouken@5201
    93
} GLES2_ProgramCacheEntry;
slouken@5201
    94
slouken@5201
    95
typedef struct GLES2_ProgramCache
slouken@5201
    96
{
slouken@5201
    97
    int count;
slouken@5201
    98
    GLES2_ProgramCacheEntry *head;
slouken@5201
    99
    GLES2_ProgramCacheEntry *tail;
slouken@5201
   100
} GLES2_ProgramCache;
slouken@5201
   101
slouken@5201
   102
typedef enum
slouken@5201
   103
{
slouken@5201
   104
    GLES2_ATTRIBUTE_POSITION = 0,
slouken@5201
   105
    GLES2_ATTRIBUTE_TEXCOORD = 1
slouken@5201
   106
} GLES2_Attribute;
slouken@5201
   107
slouken@5201
   108
typedef enum
slouken@5201
   109
{
slouken@5201
   110
    GLES2_UNIFORM_PROJECTION,
slouken@5201
   111
    GLES2_UNIFORM_TEXTURE,
slouken@5201
   112
    GLES2_UNIFORM_MODULATION,
slouken@5201
   113
    GLES2_UNIFORM_COLOR,
slouken@5201
   114
    GLES2_UNIFORM_COLORTABLE
slouken@5201
   115
} GLES2_Uniform;
slouken@5201
   116
slouken@5201
   117
typedef enum
slouken@5201
   118
{
slouken@5201
   119
    GLES2_IMAGESOURCE_SOLID,
slouken@6113
   120
    GLES2_IMAGESOURCE_TEXTURE_ABGR,
slouken@6113
   121
    GLES2_IMAGESOURCE_TEXTURE_ARGB,
slouken@6113
   122
    GLES2_IMAGESOURCE_TEXTURE_RGB,
slouken@6113
   123
    GLES2_IMAGESOURCE_TEXTURE_BGR
slouken@5201
   124
} GLES2_ImageSource;
slouken@5201
   125
slouken@5201
   126
typedef struct GLES2_DriverContext
slouken@5201
   127
{
slouken@5201
   128
    SDL_GLContext *context;
slouken@5355
   129
    struct {
slouken@5355
   130
        int blendMode;
slouken@5355
   131
        SDL_bool tex_coords;
slouken@5355
   132
    } current;
slouken@5355
   133
slouken@6188
   134
#define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
slouken@6188
   135
#include "SDL_gles2funcs.h"
slouken@6188
   136
#undef SDL_PROC
slouken@6188
   137
slouken@5201
   138
    int shader_format_count;
slouken@5201
   139
    GLenum *shader_formats;
slouken@5201
   140
    GLES2_ShaderCache shader_cache;
slouken@5201
   141
    GLES2_ProgramCache program_cache;
slouken@5201
   142
    GLES2_ProgramCacheEntry *current_program;
slouken@5201
   143
} GLES2_DriverContext;
slouken@5201
   144
slouken@5201
   145
#define GLES2_MAX_CACHED_PROGRAMS 8
slouken@5201
   146
slouken@5201
   147
/*************************************************************************************************
slouken@5201
   148
 * Renderer state APIs                                                                           *
slouken@5201
   149
 *************************************************************************************************/
slouken@5201
   150
slouken@5224
   151
static int GLES2_ActivateRenderer(SDL_Renderer *renderer);
slouken@5201
   152
static void GLES2_WindowEvent(SDL_Renderer * renderer,
slouken@5201
   153
                              const SDL_WindowEvent *event);
slouken@5297
   154
static int GLES2_UpdateViewport(SDL_Renderer * renderer);
slouken@5201
   155
static void GLES2_DestroyRenderer(SDL_Renderer *renderer);
slouken@5201
   156
slouken@5201
   157
static SDL_GLContext SDL_CurrentContext = NULL;
slouken@5201
   158
slouken@6188
   159
static int GLES2_LoadFunctions(GLES2_DriverContext * data)
slouken@6188
   160
{
slouken@6188
   161
#ifdef __SDL_NOGETPROCADDR__
slouken@6188
   162
#define SDL_PROC(ret,func,params) data->func=func;
slouken@6188
   163
#else
slouken@6188
   164
#define SDL_PROC(ret,func,params) \
slouken@6188
   165
    do { \
slouken@6188
   166
        data->func = SDL_GL_GetProcAddress(#func); \
slouken@6188
   167
        if ( ! data->func ) { \
slouken@6188
   168
            SDL_SetError("Couldn't load GLES2 function %s: %s\n", #func, SDL_GetError()); \
slouken@6188
   169
            return -1; \
slouken@6188
   170
        } \
slouken@6188
   171
    } while ( 0 );  
slouken@6188
   172
#endif /* _SDL_NOGETPROCADDR_ */
slouken@6188
   173
slouken@6188
   174
#include "SDL_gles2funcs.h"
slouken@6188
   175
#undef SDL_PROC
slouken@6188
   176
    return 0;
slouken@6188
   177
}
slouken@6188
   178
slouken@5201
   179
static int
slouken@5201
   180
GLES2_ActivateRenderer(SDL_Renderer * renderer)
slouken@5201
   181
{
slouken@5201
   182
    GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
slouken@5201
   183
slouken@5201
   184
    if (SDL_CurrentContext != rdata->context) {
slouken@5201
   185
        /* Null out the current program to ensure we set it again */
slouken@5201
   186
        rdata->current_program = NULL;
slouken@5201
   187
slouken@5297
   188
        if (SDL_GL_MakeCurrent(renderer->window, rdata->context) < 0) {
slouken@5201
   189
            return -1;
slouken@5201
   190
        }
slouken@5201
   191
        SDL_CurrentContext = rdata->context;
slouken@5201
   192
slouken@5297
   193
        GLES2_UpdateViewport(renderer);
slouken@5201
   194
    }
slouken@5201
   195
    return 0;
slouken@5201
   196
}
slouken@5201
   197
slouken@5201
   198
static void
slouken@5201
   199
GLES2_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
slouken@5201
   200
{
slouken@6188
   201
    GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
slouken@6188
   202
    
slouken@5276
   203
    if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) {
slouken@5201
   204
        /* Rebind the context to the window area */
slouken@5201
   205
        SDL_CurrentContext = NULL;
slouken@5201
   206
    }
slouken@6060
   207
slouken@6060
   208
    if (event->event == SDL_WINDOWEVENT_MINIMIZED) {
slouken@6060
   209
        /* According to Apple documentation, we need to finish drawing NOW! */
slouken@6188
   210
        rdata->glFinish();
slouken@6060
   211
    }
slouken@5201
   212
}
slouken@5201
   213
slouken@5297
   214
static int
slouken@5297
   215
GLES2_UpdateViewport(SDL_Renderer * renderer)
slouken@5224
   216
{
slouken@5297
   217
    GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
slouken@5224
   218
slouken@5297
   219
    if (SDL_CurrentContext != rdata->context) {
slouken@5297
   220
        /* We'll update the viewport after we rebind the context */
slouken@5297
   221
        return 0;
slouken@5297
   222
    }
slouken@5224
   223
slouken@6188
   224
    rdata->glViewport(renderer->viewport.x, renderer->viewport.y,
slouken@5297
   225
               renderer->viewport.w, renderer->viewport.h);
slouken@5297
   226
    return 0;
slouken@5224
   227
}
slouken@5224
   228
slouken@5224
   229
static void
slouken@5201
   230
GLES2_DestroyRenderer(SDL_Renderer *renderer)
slouken@5201
   231
{
slouken@5201
   232
    GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
slouken@5201
   233
slouken@5209
   234
    /* Deallocate everything */
slouken@5209
   235
    if (rdata) {
slouken@5209
   236
        GLES2_ActivateRenderer(renderer);
slouken@5201
   237
slouken@6178
   238
        {
slouken@6178
   239
            GLES2_ShaderCacheEntry *entry;
slouken@6178
   240
            GLES2_ShaderCacheEntry *next;
slouken@6178
   241
            entry = rdata->shader_cache.head;
slouken@6178
   242
            while (entry)
slouken@6178
   243
            {
slouken@6188
   244
                rdata->glDeleteShader(entry->id);
slouken@6052
   245
                next = entry->next;
slouken@6052
   246
                SDL_free(entry);
slouken@6052
   247
                entry = next;
slouken@6178
   248
            }
slouken@6178
   249
        }
slouken@6178
   250
        {
slouken@6178
   251
            GLES2_ProgramCacheEntry *entry;
slouken@6178
   252
            GLES2_ProgramCacheEntry *next;
slouken@6052
   253
            entry = rdata->program_cache.head;
slouken@6052
   254
            while (entry) {
slouken@6188
   255
                rdata->glDeleteProgram(entry->id);
slouken@6052
   256
                next = entry->next;
slouken@6052
   257
                SDL_free(entry);
slouken@6052
   258
                entry = next;
slouken@6052
   259
            }
slouken@6178
   260
        }
slouken@5209
   261
        if (rdata->context) {
slouken@5209
   262
            SDL_GL_DeleteContext(rdata->context);
slouken@5209
   263
        }
slouken@5209
   264
        if (rdata->shader_formats) {
slouken@5209
   265
            SDL_free(rdata->shader_formats);
slouken@5209
   266
        }
slouken@5209
   267
        SDL_free(rdata);
slouken@5201
   268
    }
slouken@5201
   269
    SDL_free(renderer);
slouken@5201
   270
}
slouken@5201
   271
slouken@5201
   272
/*************************************************************************************************
slouken@5201
   273
 * Texture APIs                                                                                  *
slouken@5201
   274
 *************************************************************************************************/
slouken@5201
   275
slouken@5201
   276
static int GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture);
slouken@5201
   277
static void GLES2_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture);
slouken@5201
   278
static int GLES2_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect,
slouken@5201
   279
                             void **pixels, int *pitch);
slouken@5201
   280
static void GLES2_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture);
slouken@5201
   281
static int GLES2_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect,
slouken@5201
   282
                               const void *pixels, int pitch);
slouken@5201
   283
slouken@5484
   284
static GLenum
slouken@5484
   285
GetScaleQuality(void)
slouken@5484
   286
{
slouken@5484
   287
    const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
slouken@5484
   288
slouken@5484
   289
    if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) {
slouken@5484
   290
        return GL_NEAREST;
slouken@5484
   291
    } else {
slouken@5484
   292
        return GL_LINEAR;
slouken@5484
   293
    }
slouken@5484
   294
}
slouken@5484
   295
slouken@5201
   296
static int
slouken@5201
   297
GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture)
slouken@5201
   298
{
slouken@6188
   299
    GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
slouken@5201
   300
    GLES2_TextureData *tdata;
slouken@5201
   301
    GLenum format;
slouken@5201
   302
    GLenum type;
slouken@5503
   303
    GLenum scaleMode;
slouken@5201
   304
slouken@5201
   305
    GLES2_ActivateRenderer(renderer);
slouken@5201
   306
slouken@5201
   307
    /* Determine the corresponding GLES texture format params */
slouken@5201
   308
    switch (texture->format)
slouken@5201
   309
    {
slouken@5201
   310
    case SDL_PIXELFORMAT_ABGR8888:
slouken@6113
   311
    case SDL_PIXELFORMAT_ARGB8888:
slouken@6113
   312
    case SDL_PIXELFORMAT_BGR888:
slouken@6113
   313
    case SDL_PIXELFORMAT_RGB888:
slouken@5201
   314
        format = GL_RGBA;
slouken@5201
   315
        type = GL_UNSIGNED_BYTE;
slouken@5201
   316
        break;
slouken@5201
   317
    default:
slouken@5201
   318
        SDL_SetError("Texture format not supported");
slouken@5201
   319
        return -1;
slouken@5201
   320
    }
slouken@5201
   321
slouken@5201
   322
    /* Allocate a texture struct */
slouken@5201
   323
    tdata = (GLES2_TextureData *)SDL_calloc(1, sizeof(GLES2_TextureData));
slouken@5201
   324
    if (!tdata)
slouken@5201
   325
    {
slouken@5201
   326
        SDL_OutOfMemory();
slouken@5201
   327
        return -1;
slouken@5201
   328
    }
slouken@5201
   329
    tdata->texture = 0;
slouken@5201
   330
    tdata->texture_type = GL_TEXTURE_2D;
slouken@5201
   331
    tdata->pixel_format = format;
slouken@5201
   332
    tdata->pixel_type = type;
slouken@5503
   333
    scaleMode = GetScaleQuality();
slouken@5201
   334
slouken@5201
   335
    /* Allocate a blob for image data */
slouken@5201
   336
    if (texture->access == SDL_TEXTUREACCESS_STREAMING)
slouken@5201
   337
    {
slouken@5201
   338
        tdata->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);
slouken@5402
   339
        tdata->pixel_data = SDL_calloc(1, tdata->pitch * texture->h);
slouken@5201
   340
        if (!tdata->pixel_data)
slouken@5201
   341
        {
slouken@5201
   342
            SDL_OutOfMemory();
slouken@5201
   343
            SDL_free(tdata);
slouken@5201
   344
            return -1;
slouken@5201
   345
        }
slouken@5201
   346
    }
slouken@5201
   347
slouken@5201
   348
    /* Allocate the texture */
slouken@6188
   349
    rdata->glGetError();
slouken@6188
   350
    rdata->glGenTextures(1, &tdata->texture);
slouken@6188
   351
    rdata->glActiveTexture(GL_TEXTURE0);
slouken@6188
   352
    rdata->glBindTexture(tdata->texture_type, tdata->texture);
slouken@6188
   353
    rdata->glTexParameteri(tdata->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode);
slouken@6188
   354
    rdata->glTexParameteri(tdata->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode);
slouken@6188
   355
    rdata->glTexParameteri(tdata->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
slouken@6188
   356
    rdata->glTexParameteri(tdata->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
slouken@6188
   357
    rdata->glTexImage2D(tdata->texture_type, 0, format, texture->w, texture->h, 0, format, type, NULL);
slouken@6188
   358
    if (rdata->glGetError() != GL_NO_ERROR)
slouken@5201
   359
    {
slouken@5201
   360
        SDL_SetError("Texture creation failed");
slouken@6188
   361
        rdata->glDeleteTextures(1, &tdata->texture);
slouken@5201
   362
        SDL_free(tdata);
slouken@5201
   363
        return -1;
slouken@5201
   364
    }
slouken@5201
   365
    texture->driverdata = tdata;
slouken@5201
   366
    return 0;
slouken@5201
   367
}
slouken@5201
   368
slouken@5201
   369
static void
slouken@5201
   370
GLES2_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture)
slouken@5201
   371
{
slouken@6188
   372
    GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
slouken@5201
   373
    GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
slouken@5201
   374
slouken@5201
   375
    GLES2_ActivateRenderer(renderer);
slouken@5201
   376
slouken@5201
   377
    /* Destroy the texture */
slouken@5201
   378
    if (tdata)
slouken@5201
   379
    {
slouken@6188
   380
        rdata->glDeleteTextures(1, &tdata->texture);
slouken@5201
   381
        SDL_free(tdata->pixel_data);
slouken@5201
   382
        SDL_free(tdata);
slouken@5201
   383
        texture->driverdata = NULL;
slouken@5201
   384
    }
slouken@5201
   385
}
slouken@5201
   386
slouken@5201
   387
static int
slouken@5201
   388
GLES2_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect,
slouken@5201
   389
                  void **pixels, int *pitch)
slouken@5201
   390
{
slouken@5201
   391
    GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
slouken@5201
   392
slouken@5201
   393
    /* Retrieve the buffer/pitch for the specified region */
slouken@5201
   394
    *pixels = (Uint8 *)tdata->pixel_data +
slouken@5201
   395
              (tdata->pitch * rect->y) +
slouken@5201
   396
              (rect->x * SDL_BYTESPERPIXEL(texture->format));
slouken@5201
   397
    *pitch = tdata->pitch;
slouken@5201
   398
slouken@5201
   399
    return 0;
slouken@5201
   400
}
slouken@5201
   401
slouken@5201
   402
static void
slouken@5201
   403
GLES2_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
slouken@5201
   404
{
slouken@5201
   405
    GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
slouken@5227
   406
    SDL_Rect rect;
slouken@5201
   407
slouken@5227
   408
    /* We do whole texture updates, at least for now */
slouken@5227
   409
    rect.x = 0;
slouken@5227
   410
    rect.y = 0;
slouken@5227
   411
    rect.w = texture->w;
slouken@5227
   412
    rect.h = texture->h;
slouken@5227
   413
    GLES2_UpdateTexture(renderer, texture, &rect, tdata->pixel_data, tdata->pitch);
slouken@5201
   414
}
slouken@5201
   415
slouken@5201
   416
static int
slouken@5201
   417
GLES2_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect,
slouken@5201
   418
                    const void *pixels, int pitch)
slouken@5201
   419
{
slouken@6188
   420
    GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
slouken@5201
   421
    GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
slouken@5201
   422
    Uint8 *blob = NULL;
slouken@5201
   423
    Uint8 *src;
slouken@5201
   424
    int srcPitch;
slouken@5201
   425
    int y;
slouken@5201
   426
slouken@5201
   427
    GLES2_ActivateRenderer(renderer);
slouken@6188
   428
    
slouken@5201
   429
    /* Bail out if we're supposed to update an empty rectangle */
slouken@5201
   430
    if (rect->w <= 0 || rect->h <= 0)
slouken@5201
   431
        return 0;
slouken@5201
   432
slouken@5201
   433
    /* Reformat the texture data into a tightly packed array */
slouken@5201
   434
    srcPitch = rect->w * SDL_BYTESPERPIXEL(texture->format);
slouken@5201
   435
    src = (Uint8 *)pixels;
slouken@5201
   436
    if (pitch != srcPitch)
slouken@5201
   437
    {
slouken@5201
   438
        blob = (Uint8 *)SDL_malloc(srcPitch * rect->h);
slouken@5201
   439
        if (!blob)
slouken@5201
   440
        {
slouken@5201
   441
            SDL_OutOfMemory();
slouken@5201
   442
            return -1;
slouken@5201
   443
        }
slouken@5201
   444
        src = blob;
slouken@5201
   445
        for (y = 0; y < rect->h; ++y)
slouken@5201
   446
        {
slouken@5201
   447
            SDL_memcpy(src, pixels, srcPitch);
slouken@5201
   448
            src += srcPitch;
slouken@5201
   449
            pixels = (Uint8 *)pixels + pitch;
slouken@5201
   450
        }
slouken@5201
   451
        src = blob;
slouken@5201
   452
    }
slouken@5201
   453
slouken@5201
   454
    /* Create a texture subimage with the supplied data */
slouken@6188
   455
    rdata->glGetError();
slouken@6188
   456
    rdata->glActiveTexture(GL_TEXTURE0);
slouken@6188
   457
    rdata->glBindTexture(tdata->texture_type, tdata->texture);
slouken@6188
   458
    rdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
slouken@6188
   459
    rdata->glTexSubImage2D(tdata->texture_type,
slouken@5201
   460
                    0,
slouken@5201
   461
                    rect->x,
slouken@5201
   462
                    rect->y,
slouken@5201
   463
                    rect->w,
slouken@5201
   464
                    rect->h,
slouken@5201
   465
                    tdata->pixel_format,
slouken@5201
   466
                    tdata->pixel_type,
slouken@5201
   467
                    src);
slouken@5227
   468
    if (blob) {
slouken@5227
   469
        SDL_free(blob);
slouken@5227
   470
    }
slouken@5214
   471
slouken@6188
   472
    if (rdata->glGetError() != GL_NO_ERROR)
slouken@5201
   473
    {
slouken@5201
   474
        SDL_SetError("Failed to update texture");
slouken@5201
   475
        return -1;
slouken@5201
   476
    }
slouken@5201
   477
    return 0;
slouken@5201
   478
}
slouken@5201
   479
slouken@5201
   480
/*************************************************************************************************
slouken@5201
   481
 * Shader management functions                                                                   *
slouken@5201
   482
 *************************************************************************************************/
slouken@5201
   483
slouken@5201
   484
static GLES2_ShaderCacheEntry *GLES2_CacheShader(SDL_Renderer *renderer, GLES2_ShaderType type,
slouken@5201
   485
                                                 SDL_BlendMode blendMode);
slouken@5201
   486
static void GLES2_EvictShader(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *entry);
slouken@5201
   487
static GLES2_ProgramCacheEntry *GLES2_CacheProgram(SDL_Renderer *renderer,
slouken@5201
   488
                                                   GLES2_ShaderCacheEntry *vertex,
slouken@5201
   489
                                                   GLES2_ShaderCacheEntry *fragment,
slouken@5201
   490
                                                   SDL_BlendMode blendMode);
slouken@5201
   491
static int GLES2_SelectProgram(SDL_Renderer *renderer, GLES2_ImageSource source,
slouken@5201
   492
                               SDL_BlendMode blendMode);
slouken@5201
   493
static int GLES2_SetOrthographicProjection(SDL_Renderer *renderer);
slouken@5201
   494
slouken@5201
   495
static GLES2_ProgramCacheEntry *
slouken@5201
   496
GLES2_CacheProgram(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *vertex,
slouken@5201
   497
                   GLES2_ShaderCacheEntry *fragment, SDL_BlendMode blendMode)
slouken@5201
   498
{
slouken@5201
   499
    GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
slouken@5201
   500
    GLES2_ProgramCacheEntry *entry;
slouken@5201
   501
    GLES2_ShaderCacheEntry *shaderEntry;
slouken@5201
   502
    GLint linkSuccessful;
slouken@5201
   503
slouken@5201
   504
    /* Check if we've already cached this program */
slouken@5201
   505
    entry = rdata->program_cache.head;
slouken@5201
   506
    while (entry)
slouken@5201
   507
    {
slouken@5201
   508
        if (entry->vertex_shader == vertex && entry->fragment_shader == fragment)
slouken@5201
   509
            break;
slouken@5201
   510
        entry = entry->next;
slouken@5201
   511
    }
slouken@5201
   512
    if (entry)
slouken@5201
   513
    {
slouken@6061
   514
        if (rdata->program_cache.head != entry)
slouken@5201
   515
        {
slouken@5201
   516
            if (entry->next)
slouken@5201
   517
                entry->next->prev = entry->prev;
slouken@5201
   518
            if (entry->prev)
slouken@5201
   519
                entry->prev->next = entry->next;
slouken@5201
   520
            entry->prev = NULL;
slouken@5201
   521
            entry->next = rdata->program_cache.head;
slouken@5201
   522
            rdata->program_cache.head->prev = entry;
slouken@5201
   523
            rdata->program_cache.head = entry;
slouken@5201
   524
        }
slouken@5201
   525
        return entry;
slouken@5201
   526
    }
slouken@5201
   527
slouken@5201
   528
    /* Create a program cache entry */
slouken@5201
   529
    entry = (GLES2_ProgramCacheEntry *)SDL_calloc(1, sizeof(GLES2_ProgramCacheEntry));
slouken@5201
   530
    if (!entry)
slouken@5201
   531
    {
slouken@5201
   532
        SDL_OutOfMemory();
slouken@5201
   533
        return NULL;
slouken@5201
   534
    }
slouken@5201
   535
    entry->vertex_shader = vertex;
slouken@5201
   536
    entry->fragment_shader = fragment;
slouken@5201
   537
    entry->blend_mode = blendMode;
slouken@5201
   538
    
slouken@5201
   539
    /* Create the program and link it */
slouken@6188
   540
    rdata->glGetError();
slouken@6188
   541
    entry->id = rdata->glCreateProgram();
slouken@6188
   542
    rdata->glAttachShader(entry->id, vertex->id);
slouken@6188
   543
    rdata->glAttachShader(entry->id, fragment->id);
slouken@6188
   544
    rdata->glBindAttribLocation(entry->id, GLES2_ATTRIBUTE_POSITION, "a_position");
slouken@6188
   545
    rdata->glBindAttribLocation(entry->id, GLES2_ATTRIBUTE_TEXCOORD, "a_texCoord");
slouken@6188
   546
    rdata->glLinkProgram(entry->id);
slouken@6188
   547
    rdata->glGetProgramiv(entry->id, GL_LINK_STATUS, &linkSuccessful);
slouken@6188
   548
    if (rdata->glGetError() != GL_NO_ERROR || !linkSuccessful)
slouken@5201
   549
    {
slouken@5201
   550
        SDL_SetError("Failed to link shader program");
slouken@6188
   551
        rdata->glDeleteProgram(entry->id);
slouken@5201
   552
        SDL_free(entry);
slouken@5201
   553
        return NULL;
slouken@5201
   554
    }
slouken@5201
   555
    
slouken@5201
   556
    /* Predetermine locations of uniform variables */
slouken@5201
   557
    entry->uniform_locations[GLES2_UNIFORM_PROJECTION] =
slouken@6188
   558
        rdata->glGetUniformLocation(entry->id, "u_projection");
slouken@5201
   559
    entry->uniform_locations[GLES2_UNIFORM_TEXTURE] =
slouken@6188
   560
        rdata->glGetUniformLocation(entry->id, "u_texture");
slouken@5201
   561
    entry->uniform_locations[GLES2_UNIFORM_MODULATION] =
slouken@6188
   562
        rdata->glGetUniformLocation(entry->id, "u_modulation");
slouken@5201
   563
    entry->uniform_locations[GLES2_UNIFORM_COLOR] =
slouken@6188
   564
        rdata->glGetUniformLocation(entry->id, "u_color");
slouken@5201
   565
    entry->uniform_locations[GLES2_UNIFORM_COLORTABLE] =
slouken@6188
   566
        rdata->glGetUniformLocation(entry->id, "u_colorTable");
slouken@5201
   567
slouken@5201
   568
    /* Cache the linked program */
slouken@5201
   569
    if (rdata->program_cache.head)
slouken@5201
   570
    {
slouken@5201
   571
        entry->next = rdata->program_cache.head;
slouken@5201
   572
        rdata->program_cache.head->prev = entry;
slouken@5201
   573
    }
slouken@5201
   574
    else
slouken@5201
   575
    {
slouken@5201
   576
        rdata->program_cache.tail = entry;
slouken@5201
   577
    }
slouken@5201
   578
    rdata->program_cache.head = entry;
slouken@5201
   579
    ++rdata->program_cache.count;
slouken@5201
   580
slouken@5201
   581
    /* Increment the refcount of the shaders we're using */
slouken@5201
   582
    ++vertex->references;
slouken@5201
   583
    ++fragment->references;
slouken@5201
   584
slouken@5201
   585
    /* Evict the last entry from the cache if we exceed the limit */
slouken@5201
   586
    if (rdata->program_cache.count > GLES2_MAX_CACHED_PROGRAMS)
slouken@5201
   587
    {
slouken@5201
   588
        shaderEntry = rdata->program_cache.tail->vertex_shader;
slouken@5201
   589
        if (--shaderEntry->references <= 0)
slouken@5201
   590
            GLES2_EvictShader(renderer, shaderEntry);
slouken@5201
   591
        shaderEntry = rdata->program_cache.tail->fragment_shader;
slouken@5201
   592
        if (--shaderEntry->references <= 0)
slouken@5201
   593
            GLES2_EvictShader(renderer, shaderEntry);
slouken@6188
   594
        rdata->glDeleteProgram(rdata->program_cache.tail->id);
slouken@5201
   595
        rdata->program_cache.tail = rdata->program_cache.tail->prev;
slouken@5201
   596
        SDL_free(rdata->program_cache.tail->next);
slouken@5201
   597
        rdata->program_cache.tail->next = NULL;
slouken@5201
   598
        --rdata->program_cache.count;
slouken@5201
   599
    }
slouken@5201
   600
    return entry;
slouken@5201
   601
}
slouken@5201
   602
slouken@5201
   603
static GLES2_ShaderCacheEntry *
slouken@5201
   604
GLES2_CacheShader(SDL_Renderer *renderer, GLES2_ShaderType type, SDL_BlendMode blendMode)
slouken@5201
   605
{
slouken@5201
   606
    GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
slouken@5201
   607
    const GLES2_Shader *shader;
slouken@5201
   608
    const GLES2_ShaderInstance *instance = NULL;
slouken@5201
   609
    GLES2_ShaderCacheEntry *entry = NULL;
slouken@5201
   610
    GLint compileSuccessful = GL_FALSE;
slouken@5201
   611
    int i, j;
slouken@5201
   612
slouken@5201
   613
    /* Find the corresponding shader */
slouken@5201
   614
    shader = GLES2_GetShader(type, blendMode);
slouken@5201
   615
    if (!shader)
slouken@5201
   616
    {
slouken@5201
   617
        SDL_SetError("No shader matching the requested characteristics was found");
slouken@5201
   618
        return NULL;
slouken@5201
   619
    }
slouken@5201
   620
    
slouken@5201
   621
    /* Find a matching shader instance that's supported on this hardware */
slouken@5206
   622
    for (i = 0; i < shader->instance_count && !instance; ++i)
slouken@5201
   623
    {
slouken@5206
   624
        for (j = 0; j < rdata->shader_format_count && !instance; ++j)
slouken@5201
   625
        {
slouken@5201
   626
            if (!shader->instances)
slouken@5201
   627
                continue;
slouken@5206
   628
            if (!shader->instances[i])
slouken@5206
   629
                continue;
slouken@5201
   630
            if (shader->instances[i]->format != rdata->shader_formats[j])
slouken@5201
   631
                continue;
slouken@5201
   632
            instance = shader->instances[i];
slouken@5201
   633
        }
slouken@5201
   634
    }
slouken@5201
   635
    if (!instance)
slouken@5201
   636
    {
slouken@5201
   637
        SDL_SetError("The specified shader cannot be loaded on the current platform");
slouken@5201
   638
        return NULL;
slouken@5201
   639
    }
slouken@5201
   640
slouken@5201
   641
    /* Check if we've already cached this shader */
slouken@5201
   642
    entry = rdata->shader_cache.head;
slouken@5201
   643
    while (entry)
slouken@5201
   644
    {
slouken@5201
   645
        if (entry->instance == instance)
slouken@5201
   646
            break;
slouken@5201
   647
        entry = entry->next;
slouken@5201
   648
    }
slouken@5201
   649
    if (entry)
slouken@5201
   650
        return entry;
slouken@5201
   651
slouken@5201
   652
    /* Create a shader cache entry */
slouken@5201
   653
    entry = (GLES2_ShaderCacheEntry *)SDL_calloc(1, sizeof(GLES2_ShaderCacheEntry));
slouken@5201
   654
    if (!entry)
slouken@5201
   655
    {
slouken@5201
   656
        SDL_OutOfMemory();
slouken@5201
   657
        return NULL;
slouken@5201
   658
    }
slouken@5201
   659
    entry->type = type;
slouken@5201
   660
    entry->instance = instance;
slouken@5201
   661
slouken@5201
   662
    /* Compile or load the selected shader instance */
slouken@6188
   663
    rdata->glGetError();
slouken@6188
   664
    entry->id = rdata->glCreateShader(instance->type);
slouken@5201
   665
    if (instance->format == (GLenum)-1)
slouken@5201
   666
    {
slouken@6188
   667
        rdata->glShaderSource(entry->id, 1, (const char **)&instance->data, NULL);
slouken@6188
   668
        rdata->glCompileShader(entry->id);
slouken@6188
   669
        rdata->glGetShaderiv(entry->id, GL_COMPILE_STATUS, &compileSuccessful);
slouken@5201
   670
    }
slouken@5201
   671
    else
slouken@5201
   672
    {
slouken@6188
   673
        rdata->glShaderBinary(1, &entry->id, instance->format, instance->data, instance->length);
slouken@5201
   674
        compileSuccessful = GL_TRUE;
slouken@5201
   675
    }
slouken@6188
   676
    if (rdata->glGetError() != GL_NO_ERROR || !compileSuccessful)
slouken@5201
   677
    {
slouken@5212
   678
        char *info = NULL;
slouken@6113
   679
        int length = 0;
slouken@5212
   680
slouken@6188
   681
        rdata->glGetShaderiv(entry->id, GL_INFO_LOG_LENGTH, &length);
slouken@5212
   682
        if (length > 0) {
slouken@5212
   683
            info = SDL_stack_alloc(char, length);
slouken@5212
   684
            if (info) {
slouken@6188
   685
                rdata->glGetShaderInfoLog(entry->id, length, &length, info);
slouken@5212
   686
            }
slouken@5212
   687
        }
slouken@5212
   688
        if (info) {
slouken@5212
   689
            SDL_SetError("Failed to load the shader: %s", info);
slouken@5212
   690
            SDL_stack_free(info);
slouken@5212
   691
        } else {
slouken@5212
   692
            SDL_SetError("Failed to load the shader");
slouken@5212
   693
        }
slouken@6188
   694
        rdata->glDeleteShader(entry->id);
slouken@5201
   695
        SDL_free(entry);
slouken@5201
   696
        return NULL;
slouken@5201
   697
    }
slouken@5201
   698
slouken@5201
   699
    /* Link the shader entry in at the front of the cache */
slouken@5201
   700
    if (rdata->shader_cache.head)
slouken@5201
   701
    {
slouken@5201
   702
        entry->next = rdata->shader_cache.head;
slouken@5201
   703
        rdata->shader_cache.head->prev = entry;
slouken@5201
   704
    }
slouken@5201
   705
    rdata->shader_cache.head = entry;
slouken@5201
   706
    ++rdata->shader_cache.count;
slouken@5201
   707
    return entry;
slouken@5201
   708
}
slouken@5201
   709
slouken@5201
   710
static void
slouken@5201
   711
GLES2_EvictShader(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *entry)
slouken@5201
   712
{
slouken@5201
   713
    GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
slouken@5201
   714
slouken@5201
   715
    /* Unlink the shader from the cache */
slouken@5201
   716
    if (entry->next)
slouken@5201
   717
        entry->next->prev = entry->prev;
slouken@5201
   718
    if (entry->prev)
slouken@5201
   719
        entry->prev->next = entry->next;
slouken@5201
   720
    if (rdata->shader_cache.head == entry)
slouken@5201
   721
        rdata->shader_cache.head = entry->next;
slouken@5201
   722
    --rdata->shader_cache.count;
slouken@5201
   723
slouken@5201
   724
    /* Deallocate the shader */
slouken@6188
   725
    rdata->glDeleteShader(entry->id);
slouken@5201
   726
    SDL_free(entry);
slouken@5201
   727
}
slouken@5201
   728
slouken@5201
   729
static int
slouken@5201
   730
GLES2_SelectProgram(SDL_Renderer *renderer, GLES2_ImageSource source, SDL_BlendMode blendMode)
slouken@5201
   731
{
slouken@5201
   732
    GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
slouken@5201
   733
    GLES2_ShaderCacheEntry *vertex = NULL;
slouken@5201
   734
    GLES2_ShaderCacheEntry *fragment = NULL;
slouken@5201
   735
    GLES2_ShaderType vtype, ftype;
slouken@5201
   736
    GLES2_ProgramCacheEntry *program;
slouken@5201
   737
slouken@5201
   738
    /* Select an appropriate shader pair for the specified modes */
slouken@5201
   739
    vtype = GLES2_SHADER_VERTEX_DEFAULT;
slouken@5201
   740
    switch (source)
slouken@5201
   741
    {
slouken@5201
   742
    case GLES2_IMAGESOURCE_SOLID:
slouken@5201
   743
        ftype = GLES2_SHADER_FRAGMENT_SOLID_SRC;
slouken@5201
   744
        break;
slouken@6113
   745
    case GLES2_IMAGESOURCE_TEXTURE_ABGR:
slouken@6113
   746
        ftype = GLES2_SHADER_FRAGMENT_TEXTURE_ABGR_SRC;
slouken@6113
   747
            break;
slouken@6113
   748
    case GLES2_IMAGESOURCE_TEXTURE_ARGB:
slouken@6113
   749
        ftype = GLES2_SHADER_FRAGMENT_TEXTURE_ARGB_SRC;
slouken@5201
   750
        break;
slouken@6113
   751
    case GLES2_IMAGESOURCE_TEXTURE_RGB:
slouken@6113
   752
        ftype = GLES2_SHADER_FRAGMENT_TEXTURE_RGB_SRC;
slouken@6113
   753
        break;
slouken@6113
   754
    case GLES2_IMAGESOURCE_TEXTURE_BGR:
slouken@6113
   755
        ftype = GLES2_SHADER_FRAGMENT_TEXTURE_BGR_SRC;
slouken@6113
   756
        break;
slouken@6113
   757
    default:
slouken@6113
   758
        goto fault;
slouken@5201
   759
    }
slouken@5201
   760
slouken@5201
   761
    /* Load the requested shaders */
slouken@5201
   762
    vertex = GLES2_CacheShader(renderer, vtype, blendMode);
slouken@5201
   763
    if (!vertex)
slouken@5201
   764
        goto fault;
slouken@5201
   765
    fragment = GLES2_CacheShader(renderer, ftype, blendMode);
slouken@5201
   766
    if (!fragment)
slouken@5201
   767
        goto fault;
slouken@5201
   768
slouken@5201
   769
    /* Check if we need to change programs at all */
slouken@5201
   770
    if (rdata->current_program &&
slouken@5201
   771
        rdata->current_program->vertex_shader == vertex &&
slouken@5201
   772
        rdata->current_program->fragment_shader == fragment)
slouken@5201
   773
        return 0;
slouken@5201
   774
slouken@5201
   775
    /* Generate a matching program */
slouken@5201
   776
    program = GLES2_CacheProgram(renderer, vertex, fragment, blendMode);
slouken@5201
   777
    if (!program)
slouken@5201
   778
        goto fault;
slouken@5201
   779
slouken@5201
   780
    /* Select that program in OpenGL */
slouken@6188
   781
    rdata->glGetError();
slouken@6188
   782
    rdata->glUseProgram(program->id);
slouken@6188
   783
    if (rdata->glGetError() != GL_NO_ERROR)
slouken@5201
   784
    {
slouken@5201
   785
        SDL_SetError("Failed to select program");
slouken@5201
   786
        goto fault;
slouken@5201
   787
    }
slouken@5201
   788
slouken@5201
   789
    /* Set the current program */
slouken@5201
   790
    rdata->current_program = program;
slouken@5201
   791
slouken@5201
   792
    /* Activate an orthographic projection */
slouken@5201
   793
    if (GLES2_SetOrthographicProjection(renderer) < 0)
slouken@5201
   794
        goto fault;
slouken@5201
   795
slouken@5201
   796
    /* Clean up and return */
slouken@5201
   797
    return 0;
slouken@5201
   798
fault:
slouken@5201
   799
    if (vertex && vertex->references <= 0)
slouken@5201
   800
        GLES2_EvictShader(renderer, vertex);
slouken@5201
   801
    if (fragment && fragment->references <= 0)
slouken@5201
   802
        GLES2_EvictShader(renderer, fragment);
slouken@5201
   803
    rdata->current_program = NULL;
slouken@5201
   804
    return -1;
slouken@5201
   805
}
slouken@5201
   806
slouken@5201
   807
static int
slouken@5201
   808
GLES2_SetOrthographicProjection(SDL_Renderer *renderer)
slouken@5201
   809
{
slouken@5201
   810
    GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
slouken@5201
   811
    GLfloat projection[4][4];
slouken@5201
   812
    GLuint locProjection;
slouken@5201
   813
slouken@5201
   814
    /* Prepare an orthographic projection */
slouken@5297
   815
    projection[0][0] = 2.0f / renderer->viewport.w;
slouken@5201
   816
    projection[0][1] = 0.0f;
slouken@5201
   817
    projection[0][2] = 0.0f;
slouken@5201
   818
    projection[0][3] = 0.0f;
slouken@5201
   819
    projection[1][0] = 0.0f;
slouken@5297
   820
    projection[1][1] = -2.0f / renderer->viewport.h;
slouken@5201
   821
    projection[1][2] = 0.0f;
slouken@5201
   822
    projection[1][3] = 0.0f;
slouken@5201
   823
    projection[2][0] = 0.0f;
slouken@5201
   824
    projection[2][1] = 0.0f;
slouken@5201
   825
    projection[2][2] = 1.0f;
slouken@5201
   826
    projection[2][3] = 0.0f;
slouken@5201
   827
    projection[3][0] = -1.0f;
slouken@5201
   828
    projection[3][1] = 1.0f;
slouken@5201
   829
    projection[3][2] = 0.0f;
slouken@5201
   830
    projection[3][3] = 1.0f;
slouken@5201
   831
slouken@5201
   832
    /* Set the projection matrix */
slouken@5201
   833
    locProjection = rdata->current_program->uniform_locations[GLES2_UNIFORM_PROJECTION];
slouken@6188
   834
    rdata->glGetError();
slouken@6188
   835
    rdata->glUniformMatrix4fv(locProjection, 1, GL_FALSE, (GLfloat *)projection);
slouken@6188
   836
    if (rdata->glGetError() != GL_NO_ERROR)
slouken@5201
   837
    {
slouken@5201
   838
        SDL_SetError("Failed to set orthographic projection");
slouken@5201
   839
        return -1;
slouken@5201
   840
    }
slouken@5201
   841
    return 0;
slouken@5201
   842
}
slouken@5201
   843
slouken@5201
   844
/*************************************************************************************************
slouken@5201
   845
 * Rendering functions                                                                           *
slouken@5201
   846
 *************************************************************************************************/
slouken@5201
   847
slouken@5224
   848
static const float inv255f = 1.0f / 255.0f;
slouken@5224
   849
slouken@5201
   850
static int GLES2_RenderClear(SDL_Renderer *renderer);
slouken@5201
   851
static int GLES2_RenderDrawPoints(SDL_Renderer *renderer, const SDL_Point *points, int count);
slouken@5201
   852
static int GLES2_RenderDrawLines(SDL_Renderer *renderer, const SDL_Point *points, int count);
slouken@5297
   853
static int GLES2_RenderFillRects(SDL_Renderer *renderer, const SDL_Rect *rects, int count);
slouken@5201
   854
static int GLES2_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *srcrect,
slouken@5201
   855
                            const SDL_Rect *dstrect);
slouken@6042
   856
static int GLES2_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
slouken@6042
   857
                    Uint32 pixel_format, void * pixels, int pitch);
slouken@5201
   858
static void GLES2_RenderPresent(SDL_Renderer *renderer);
slouken@5201
   859
slouken@5333
   860
slouken@5201
   861
static int
slouken@5333
   862
GLES2_RenderClear(SDL_Renderer * renderer)
slouken@5201
   863
{
slouken@6188
   864
    GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
slouken@6188
   865
slouken@5201
   866
    GLES2_ActivateRenderer(renderer);
slouken@6188
   867
    
slouken@6188
   868
    rdata->glClearColor((GLfloat) renderer->r * inv255f,
slouken@5333
   869
                 (GLfloat) renderer->g * inv255f,
slouken@5333
   870
                 (GLfloat) renderer->b * inv255f,
slouken@5333
   871
                 (GLfloat) renderer->a * inv255f);
slouken@5333
   872
slouken@6188
   873
    rdata->glClear(GL_COLOR_BUFFER_BIT);
slouken@5333
   874
slouken@5201
   875
    return 0;
slouken@5201
   876
}
slouken@5201
   877
slouken@5201
   878
static void
slouken@5355
   879
GLES2_SetBlendMode(GLES2_DriverContext *rdata, int blendMode)
slouken@5201
   880
{
slouken@5355
   881
    if (blendMode != rdata->current.blendMode) {
slouken@5355
   882
        switch (blendMode) {
slouken@5355
   883
        default:
slouken@5355
   884
        case SDL_BLENDMODE_NONE:
slouken@6188
   885
            rdata->glDisable(GL_BLEND);
slouken@5355
   886
            break;
slouken@5355
   887
        case SDL_BLENDMODE_BLEND:
slouken@6188
   888
            rdata->glEnable(GL_BLEND);
slouken@6188
   889
            rdata->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
slouken@5355
   890
            break;
slouken@5355
   891
        case SDL_BLENDMODE_ADD:
slouken@6188
   892
            rdata->glEnable(GL_BLEND);
slouken@6188
   893
            rdata->glBlendFunc(GL_SRC_ALPHA, GL_ONE);
slouken@5355
   894
            break;
slouken@5355
   895
        case SDL_BLENDMODE_MOD:
slouken@6188
   896
            rdata->glEnable(GL_BLEND);
slouken@6188
   897
            rdata->glBlendFunc(GL_ZERO, GL_SRC_COLOR);
slouken@5355
   898
            break;
slouken@5355
   899
        }
slouken@5355
   900
        rdata->current.blendMode = blendMode;
slouken@5201
   901
    }
slouken@5201
   902
}
slouken@5201
   903
slouken@5355
   904
static void
slouken@5355
   905
GLES2_SetTexCoords(GLES2_DriverContext * rdata, SDL_bool enabled)
slouken@5355
   906
{
slouken@5355
   907
    if (enabled != rdata->current.tex_coords) {
slouken@5355
   908
        if (enabled) {
slouken@6188
   909
            rdata->glEnableVertexAttribArray(GLES2_ATTRIBUTE_TEXCOORD);
slouken@5355
   910
        } else {
slouken@6188
   911
            rdata->glDisableVertexAttribArray(GLES2_ATTRIBUTE_TEXCOORD);
slouken@5355
   912
        }
slouken@5355
   913
        rdata->current.tex_coords = enabled;
slouken@5355
   914
    }
slouken@5355
   915
}
slouken@5355
   916
slouken@5355
   917
static int
slouken@5355
   918
GLES2_SetDrawingState(SDL_Renderer * renderer)
slouken@5355
   919
{
slouken@5355
   920
    GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
slouken@5355
   921
    int blendMode = renderer->blendMode;
slouken@5355
   922
    GLuint locColor;
slouken@5355
   923
slouken@6188
   924
    rdata->glGetError();
slouken@5355
   925
slouken@5355
   926
    GLES2_ActivateRenderer(renderer);
slouken@5355
   927
slouken@5355
   928
    GLES2_SetBlendMode(rdata, blendMode);
slouken@5355
   929
slouken@5355
   930
    GLES2_SetTexCoords(rdata, SDL_FALSE);
slouken@5355
   931
slouken@5355
   932
    /* Activate an appropriate shader and set the projection matrix */
slouken@5355
   933
    if (GLES2_SelectProgram(renderer, GLES2_IMAGESOURCE_SOLID, blendMode) < 0)
slouken@5355
   934
        return -1;
slouken@5355
   935
slouken@5355
   936
    /* Select the color to draw with */
slouken@5355
   937
    locColor = rdata->current_program->uniform_locations[GLES2_UNIFORM_COLOR];
slouken@6188
   938
    rdata->glUniform4f(locColor,
slouken@5355
   939
                renderer->r * inv255f,
slouken@5355
   940
                renderer->g * inv255f,
slouken@5355
   941
                renderer->b * inv255f,
slouken@5355
   942
                renderer->a * inv255f);
slouken@5355
   943
    return 0;
slouken@5355
   944
}
slouken@5355
   945
slouken@5201
   946
static int
slouken@5201
   947
GLES2_RenderDrawPoints(SDL_Renderer *renderer, const SDL_Point *points, int count)
slouken@5201
   948
{
slouken@6188
   949
    GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
slouken@5201
   950
    GLfloat *vertices;
slouken@5201
   951
    int idx;
slouken@5201
   952
slouken@5355
   953
    if (GLES2_SetDrawingState(renderer) < 0) {
slouken@5201
   954
        return -1;
slouken@5355
   955
    }
slouken@5201
   956
slouken@5201
   957
    /* Emit the specified vertices as points */
slouken@5201
   958
    vertices = SDL_stack_alloc(GLfloat, count * 2);
slouken@5201
   959
    for (idx = 0; idx < count; ++idx)
slouken@5201
   960
    {
slouken@5201
   961
        GLfloat x = (GLfloat)points[idx].x + 0.5f;
slouken@5201
   962
        GLfloat y = (GLfloat)points[idx].y + 0.5f;
slouken@5201
   963
slouken@5201
   964
        vertices[idx * 2] = x;
slouken@5201
   965
        vertices[(idx * 2) + 1] = y;
slouken@5201
   966
    }
slouken@6188
   967
    rdata->glGetError();
slouken@6188
   968
    rdata->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);
slouken@6188
   969
    rdata->glDrawArrays(GL_POINTS, 0, count);
slouken@5201
   970
    SDL_stack_free(vertices);
slouken@6188
   971
    if (rdata->glGetError() != GL_NO_ERROR)
slouken@5201
   972
    {
slouken@5201
   973
        SDL_SetError("Failed to render lines");
slouken@5201
   974
        return -1;
slouken@5201
   975
    }
slouken@5201
   976
    return 0;
slouken@5201
   977
}
slouken@5201
   978
slouken@5201
   979
static int
slouken@5201
   980
GLES2_RenderDrawLines(SDL_Renderer *renderer, const SDL_Point *points, int count)
slouken@5201
   981
{
slouken@6188
   982
    GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
slouken@5201
   983
    GLfloat *vertices;
slouken@5201
   984
    int idx;
slouken@5201
   985
slouken@5355
   986
    if (GLES2_SetDrawingState(renderer) < 0) {
slouken@5201
   987
        return -1;
slouken@5355
   988
    }
slouken@5201
   989
slouken@5201
   990
    /* Emit a line strip including the specified vertices */
slouken@5201
   991
    vertices = SDL_stack_alloc(GLfloat, count * 2);
slouken@5201
   992
    for (idx = 0; idx < count; ++idx)
slouken@5201
   993
    {
slouken@5201
   994
        GLfloat x = (GLfloat)points[idx].x + 0.5f;
slouken@5201
   995
        GLfloat y = (GLfloat)points[idx].y + 0.5f;
slouken@5201
   996
slouken@5201
   997
        vertices[idx * 2] = x;
slouken@5201
   998
        vertices[(idx * 2) + 1] = y;
slouken@5201
   999
    }
slouken@6188
  1000
    rdata->glGetError();
slouken@6188
  1001
    rdata->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);
slouken@6188
  1002
    rdata->glDrawArrays(GL_LINE_STRIP, 0, count);
slouken@6076
  1003
slouken@6076
  1004
    /* We need to close the endpoint of the line */
slouken@6076
  1005
    if (count == 2 ||
slouken@6076
  1006
        points[0].x != points[count-1].x || points[0].y != points[count-1].y) {
slouken@6188
  1007
        rdata->glDrawArrays(GL_POINTS, count-1, 1);
slouken@6076
  1008
    }
slouken@5201
  1009
    SDL_stack_free(vertices);
slouken@6188
  1010
    if (rdata->glGetError() != GL_NO_ERROR)
slouken@5201
  1011
    {
slouken@5201
  1012
        SDL_SetError("Failed to render lines");
slouken@5201
  1013
        return -1;
slouken@5201
  1014
    }
slouken@5201
  1015
    return 0;
slouken@5201
  1016
}
slouken@5201
  1017
slouken@5201
  1018
static int
slouken@5297
  1019
GLES2_RenderFillRects(SDL_Renderer *renderer, const SDL_Rect *rects, int count)
slouken@5201
  1020
{
slouken@6188
  1021
    GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
slouken@5201
  1022
    GLfloat vertices[8];
slouken@5201
  1023
    int idx;
slouken@5201
  1024
slouken@5355
  1025
    if (GLES2_SetDrawingState(renderer) < 0) {
slouken@5201
  1026
        return -1;
slouken@5355
  1027
    }
slouken@5201
  1028
slouken@5201
  1029
    /* Emit a line loop for each rectangle */
slouken@6188
  1030
    rdata->glGetError();
slouken@5297
  1031
    for (idx = 0; idx < count; ++idx) {
slouken@5297
  1032
        const SDL_Rect *rect = &rects[idx];
slouken@5297
  1033
slouken@5297
  1034
        GLfloat xMin = (GLfloat)rect->x;
slouken@5297
  1035
        GLfloat xMax = (GLfloat)(rect->x + rect->w);
slouken@5297
  1036
        GLfloat yMin = (GLfloat)rect->y;
slouken@5297
  1037
        GLfloat yMax = (GLfloat)(rect->y + rect->h);
slouken@5201
  1038
slouken@5201
  1039
        vertices[0] = xMin;
slouken@5201
  1040
        vertices[1] = yMin;
slouken@5201
  1041
        vertices[2] = xMax;
slouken@5201
  1042
        vertices[3] = yMin;
slouken@5201
  1043
        vertices[4] = xMin;
slouken@5201
  1044
        vertices[5] = yMax;
slouken@5201
  1045
        vertices[6] = xMax;
slouken@5201
  1046
        vertices[7] = yMax;
slouken@6188
  1047
        rdata->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);
slouken@6188
  1048
        rdata->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
slouken@5201
  1049
    }
slouken@6188
  1050
    if (rdata->glGetError() != GL_NO_ERROR)
slouken@5201
  1051
    {
slouken@5201
  1052
        SDL_SetError("Failed to render lines");
slouken@5201
  1053
        return -1;
slouken@5201
  1054
    }
slouken@5201
  1055
    return 0;
slouken@5201
  1056
}
slouken@5201
  1057
slouken@5201
  1058
static int
slouken@5201
  1059
GLES2_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *srcrect,
slouken@5201
  1060
                 const SDL_Rect *dstrect)
slouken@5201
  1061
{
slouken@5201
  1062
    GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
slouken@5201
  1063
    GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
slouken@5201
  1064
    GLES2_ImageSource sourceType;
slouken@5201
  1065
    SDL_BlendMode blendMode;
slouken@5201
  1066
    GLfloat vertices[8];
slouken@5201
  1067
    GLfloat texCoords[8];
slouken@5201
  1068
    GLuint locTexture;
slouken@5201
  1069
    GLuint locModulation;
slouken@5201
  1070
slouken@5201
  1071
    GLES2_ActivateRenderer(renderer);
slouken@5201
  1072
slouken@5201
  1073
    /* Activate an appropriate shader and set the projection matrix */
slouken@5201
  1074
    blendMode = texture->blendMode;
slouken@6113
  1075
    switch (texture->format)
slouken@6113
  1076
    {
slouken@6113
  1077
        case SDL_PIXELFORMAT_ABGR8888:
slouken@6113
  1078
            sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
slouken@6113
  1079
            break;
slouken@6113
  1080
        case SDL_PIXELFORMAT_ARGB8888:
slouken@6113
  1081
            sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
slouken@6113
  1082
            break;
slouken@6113
  1083
        case SDL_PIXELFORMAT_BGR888:
slouken@6113
  1084
            sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR;
slouken@6113
  1085
            break;
slouken@6113
  1086
        case SDL_PIXELFORMAT_RGB888:
slouken@6113
  1087
            sourceType = GLES2_IMAGESOURCE_TEXTURE_RGB;
slouken@6113
  1088
            break;
slouken@6113
  1089
    }
slouken@5201
  1090
    if (GLES2_SelectProgram(renderer, sourceType, blendMode) < 0)
slouken@5201
  1091
        return -1;
slouken@5201
  1092
slouken@5201
  1093
    /* Select the target texture */
slouken@5201
  1094
    locTexture = rdata->current_program->uniform_locations[GLES2_UNIFORM_TEXTURE];
slouken@6188
  1095
    rdata->glGetError();
slouken@6188
  1096
    rdata->glActiveTexture(GL_TEXTURE0);
slouken@6188
  1097
    rdata->glBindTexture(tdata->texture_type, tdata->texture);
slouken@6188
  1098
    rdata->glUniform1i(locTexture, 0);
slouken@5201
  1099
slouken@5201
  1100
    /* Configure color modulation */
slouken@5201
  1101
    locModulation = rdata->current_program->uniform_locations[GLES2_UNIFORM_MODULATION];
slouken@6188
  1102
    rdata->glUniform4f(locModulation,
slouken@5224
  1103
                texture->r * inv255f,
slouken@5224
  1104
                texture->g * inv255f,
slouken@5224
  1105
                texture->b * inv255f,
slouken@5355
  1106
                texture->a * inv255f);
slouken@5355
  1107
slouken@5355
  1108
    /* Configure texture blending */
slouken@5355
  1109
    GLES2_SetBlendMode(rdata, blendMode);
slouken@5355
  1110
slouken@5355
  1111
    GLES2_SetTexCoords(rdata, SDL_TRUE);
slouken@5201
  1112
slouken@5201
  1113
    /* Emit the textured quad */
slouken@5201
  1114
    vertices[0] = (GLfloat)dstrect->x;
slouken@5201
  1115
    vertices[1] = (GLfloat)dstrect->y;
slouken@5201
  1116
    vertices[2] = (GLfloat)(dstrect->x + dstrect->w);
slouken@5201
  1117
    vertices[3] = (GLfloat)dstrect->y;
slouken@5201
  1118
    vertices[4] = (GLfloat)dstrect->x;
slouken@5201
  1119
    vertices[5] = (GLfloat)(dstrect->y + dstrect->h);
slouken@5201
  1120
    vertices[6] = (GLfloat)(dstrect->x + dstrect->w);
slouken@5201
  1121
    vertices[7] = (GLfloat)(dstrect->y + dstrect->h);
slouken@6188
  1122
    rdata->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);
slouken@5201
  1123
    texCoords[0] = srcrect->x / (GLfloat)texture->w;
slouken@5201
  1124
    texCoords[1] = srcrect->y / (GLfloat)texture->h;
slouken@5201
  1125
    texCoords[2] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
slouken@5201
  1126
    texCoords[3] = srcrect->y / (GLfloat)texture->h;
slouken@5201
  1127
    texCoords[4] = srcrect->x / (GLfloat)texture->w;
slouken@5201
  1128
    texCoords[5] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
slouken@5201
  1129
    texCoords[6] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
slouken@5201
  1130
    texCoords[7] = (srcrect->y + srcrect->h) / (GLfloat)texture->h;
slouken@6188
  1131
    rdata->glVertexAttribPointer(GLES2_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, texCoords);
slouken@6188
  1132
    rdata->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
slouken@6188
  1133
    if (rdata->glGetError() != GL_NO_ERROR)
slouken@5201
  1134
    {
slouken@5201
  1135
        SDL_SetError("Failed to render texture");
slouken@5201
  1136
        return -1;
slouken@5201
  1137
    }
slouken@5201
  1138
    return 0;
slouken@5201
  1139
}
slouken@5201
  1140
slouken@6042
  1141
static int
slouken@6042
  1142
GLES2_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
slouken@6042
  1143
                    Uint32 pixel_format, void * pixels, int pitch)
slouken@6042
  1144
{
slouken@6188
  1145
    GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
slouken@6042
  1146
    SDL_Window *window = renderer->window;
slouken@6042
  1147
    Uint32 temp_format = SDL_PIXELFORMAT_ABGR8888;
slouken@6042
  1148
    void *temp_pixels;
slouken@6042
  1149
    int temp_pitch;
slouken@6042
  1150
    Uint8 *src, *dst, *tmp;
slouken@6042
  1151
    int w, h, length, rows;
slouken@6042
  1152
    int status;
slouken@6042
  1153
slouken@6042
  1154
    GLES2_ActivateRenderer(renderer);
slouken@6042
  1155
slouken@6042
  1156
    temp_pitch = rect->w * SDL_BYTESPERPIXEL(temp_format);
slouken@6042
  1157
    temp_pixels = SDL_malloc(rect->h * temp_pitch);
slouken@6042
  1158
    if (!temp_pixels) {
slouken@6042
  1159
        SDL_OutOfMemory();
slouken@6042
  1160
        return -1;
slouken@6042
  1161
    }
slouken@6042
  1162
slouken@6042
  1163
    SDL_GetWindowSize(window, &w, &h);
slouken@6042
  1164
slouken@6188
  1165
    rdata->glPixelStorei(GL_PACK_ALIGNMENT, 1);
slouken@6042
  1166
slouken@6188
  1167
    rdata->glReadPixels(rect->x, (h-rect->y)-rect->h, rect->w, rect->h,
slouken@6042
  1168
                       GL_RGBA, GL_UNSIGNED_BYTE, temp_pixels);
slouken@6042
  1169
slouken@6042
  1170
    /* Flip the rows to be top-down */
slouken@6042
  1171
    length = rect->w * SDL_BYTESPERPIXEL(temp_format);
slouken@6042
  1172
    src = (Uint8*)temp_pixels + (rect->h-1)*temp_pitch;
slouken@6042
  1173
    dst = (Uint8*)temp_pixels;
slouken@6042
  1174
    tmp = SDL_stack_alloc(Uint8, length);
slouken@6042
  1175
    rows = rect->h / 2;
slouken@6042
  1176
    while (rows--) {
slouken@6042
  1177
        SDL_memcpy(tmp, dst, length);
slouken@6042
  1178
        SDL_memcpy(dst, src, length);
slouken@6042
  1179
        SDL_memcpy(src, tmp, length);
slouken@6042
  1180
        dst += temp_pitch;
slouken@6042
  1181
        src -= temp_pitch;
slouken@6042
  1182
    }
slouken@6042
  1183
    SDL_stack_free(tmp);
slouken@6042
  1184
slouken@6042
  1185
    status = SDL_ConvertPixels(rect->w, rect->h,
slouken@6042
  1186
                               temp_format, temp_pixels, temp_pitch,
slouken@6042
  1187
                               pixel_format, pixels, pitch);
slouken@6042
  1188
    SDL_free(temp_pixels);
slouken@6042
  1189
slouken@6042
  1190
    return status;
slouken@6042
  1191
}
slouken@6042
  1192
slouken@5201
  1193
static void
slouken@5201
  1194
GLES2_RenderPresent(SDL_Renderer *renderer)
slouken@5201
  1195
{
slouken@5201
  1196
    GLES2_ActivateRenderer(renderer);
slouken@5201
  1197
slouken@5201
  1198
    /* Tell the video driver to swap buffers */
slouken@5201
  1199
    SDL_GL_SwapWindow(renderer->window);
slouken@5201
  1200
}
slouken@5201
  1201
slouken@5201
  1202
/*************************************************************************************************
slouken@5201
  1203
 * Renderer instantiation                                                                        *
slouken@5201
  1204
 *************************************************************************************************/
slouken@5201
  1205
slouken@5201
  1206
#define GL_NVIDIA_PLATFORM_BINARY_NV 0x890B
slouken@5201
  1207
slouken@5355
  1208
static void
slouken@5355
  1209
GLES2_ResetState(SDL_Renderer *renderer)
slouken@5355
  1210
{
slouken@5355
  1211
    GLES2_DriverContext *rdata = (GLES2_DriverContext *) renderer->driverdata;
slouken@5355
  1212
slouken@5355
  1213
    if (SDL_CurrentContext == rdata->context) {
slouken@5355
  1214
        GLES2_UpdateViewport(renderer);
slouken@5355
  1215
    } else {
slouken@5355
  1216
        GLES2_ActivateRenderer(renderer);
slouken@5355
  1217
    }
slouken@5355
  1218
slouken@5355
  1219
    rdata->current.blendMode = -1;
slouken@5355
  1220
    rdata->current.tex_coords = SDL_FALSE;
slouken@5355
  1221
slouken@6188
  1222
    rdata->glEnableVertexAttribArray(GLES2_ATTRIBUTE_POSITION);
slouken@6188
  1223
    rdata->glDisableVertexAttribArray(GLES2_ATTRIBUTE_TEXCOORD);
slouken@5355
  1224
}
slouken@5355
  1225
slouken@5201
  1226
static SDL_Renderer *
slouken@5201
  1227
GLES2_CreateRenderer(SDL_Window *window, Uint32 flags)
slouken@5201
  1228
{
slouken@5201
  1229
    SDL_Renderer *renderer;
slouken@5201
  1230
    GLES2_DriverContext *rdata;
slouken@5201
  1231
    GLint nFormats;
slouken@5201
  1232
#ifndef ZUNE_HD
slouken@5201
  1233
    GLboolean hasCompiler;
slouken@5201
  1234
#endif
slouken@6188
  1235
    Uint32 windowFlags;
slouken@6188
  1236
    
slouken@6188
  1237
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
slouken@6188
  1238
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
slouken@6188
  1239
    
slouken@6188
  1240
    windowFlags = SDL_GetWindowFlags(window);
slouken@6188
  1241
    if (!(windowFlags & SDL_WINDOW_OPENGL)) {
slouken@6188
  1242
        if (SDL_RecreateWindow(window, windowFlags | SDL_WINDOW_OPENGL) < 0) {
slouken@6188
  1243
            /* Uh oh, better try to put it back... */
slouken@6188
  1244
            SDL_RecreateWindow(window, windowFlags);
slouken@6188
  1245
            return NULL;
slouken@6188
  1246
        }
slouken@6188
  1247
    }
slouken@5201
  1248
slouken@5201
  1249
    /* Create the renderer struct */
slouken@5201
  1250
    renderer = (SDL_Renderer *)SDL_calloc(1, sizeof(SDL_Renderer));
slouken@5209
  1251
    if (!renderer) {
slouken@5209
  1252
        SDL_OutOfMemory();
slouken@5209
  1253
        return NULL;
slouken@5209
  1254
    }
slouken@5209
  1255
slouken@5201
  1256
    rdata = (GLES2_DriverContext *)SDL_calloc(1, sizeof(GLES2_DriverContext));
slouken@5209
  1257
    if (!rdata) {
slouken@5209
  1258
        GLES2_DestroyRenderer(renderer);
slouken@5201
  1259
        SDL_OutOfMemory();
slouken@5201
  1260
        return NULL;
slouken@5201
  1261
    }
slouken@5201
  1262
    renderer->info = GLES2_RenderDriver.info;
slouken@5297
  1263
    renderer->info.flags = SDL_RENDERER_ACCELERATED;
slouken@5201
  1264
    renderer->driverdata = rdata;
slouken@6171
  1265
    renderer->window = window;
slouken@5201
  1266
slouken@5209
  1267
    /* Create an OpenGL ES 2.0 context */
slouken@5201
  1268
    rdata->context = SDL_GL_CreateContext(window);
slouken@5201
  1269
    if (!rdata->context)
slouken@5201
  1270
    {
slouken@5209
  1271
        GLES2_DestroyRenderer(renderer);
slouken@5201
  1272
        return NULL;
slouken@5201
  1273
    }
slouken@5202
  1274
    if (SDL_GL_MakeCurrent(window, rdata->context) < 0) {
slouken@5209
  1275
        GLES2_DestroyRenderer(renderer);
slouken@5202
  1276
        return NULL;
slouken@5202
  1277
    }
slouken@5202
  1278
slouken@6188
  1279
    if (GLES2_LoadFunctions(rdata) < 0) {
slouken@6188
  1280
        GLES2_DestroyRenderer(renderer);
slouken@6188
  1281
        return NULL;
slouken@6188
  1282
    }
slouken@6188
  1283
slouken@5202
  1284
    if (flags & SDL_RENDERER_PRESENTVSYNC) {
slouken@5202
  1285
        SDL_GL_SetSwapInterval(1);
slouken@5202
  1286
    } else {
slouken@5202
  1287
        SDL_GL_SetSwapInterval(0);
slouken@5202
  1288
    }
slouken@5202
  1289
    if (SDL_GL_GetSwapInterval() > 0) {
slouken@5202
  1290
        renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
slouken@5202
  1291
    }
slouken@5201
  1292
slouken@5201
  1293
    /* Determine supported shader formats */
slouken@5201
  1294
    /* HACK: glGetInteger is broken on the Zune HD's compositor, so we just hardcode this */
slouken@6188
  1295
    rdata->glGetError();
slouken@5201
  1296
#ifdef ZUNE_HD
slouken@5201
  1297
    nFormats = 1;
slouken@5201
  1298
#else /* !ZUNE_HD */
slouken@6188
  1299
    rdata->glGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &nFormats);
slouken@6188
  1300
    rdata->glGetBooleanv(GL_SHADER_COMPILER, &hasCompiler);
slouken@5201
  1301
    if (hasCompiler)
slouken@5201
  1302
        ++nFormats;
slouken@5201
  1303
#endif /* ZUNE_HD */
slouken@5201
  1304
    rdata->shader_formats = (GLenum *)SDL_calloc(nFormats, sizeof(GLenum));
slouken@5201
  1305
    if (!rdata->shader_formats)
slouken@5201
  1306
    {
slouken@5209
  1307
        GLES2_DestroyRenderer(renderer);
slouken@5201
  1308
        SDL_OutOfMemory();
slouken@5201
  1309
        return NULL;
slouken@5201
  1310
    }
slouken@5201
  1311
    rdata->shader_format_count = nFormats;
slouken@5201
  1312
#ifdef ZUNE_HD
slouken@5201
  1313
    rdata->shader_formats[0] = GL_NVIDIA_PLATFORM_BINARY_NV;
slouken@5201
  1314
#else /* !ZUNE_HD */
slouken@6188
  1315
    rdata->glGetIntegerv(GL_SHADER_BINARY_FORMATS, (GLint *)rdata->shader_formats);
slouken@6188
  1316
    if (rdata->glGetError() != GL_NO_ERROR)
slouken@5201
  1317
    {
slouken@5209
  1318
        GLES2_DestroyRenderer(renderer);
slouken@5201
  1319
        SDL_SetError("Failed to query supported shader formats");
slouken@5201
  1320
        return NULL;
slouken@5201
  1321
    }
slouken@5201
  1322
    if (hasCompiler)
slouken@5201
  1323
        rdata->shader_formats[nFormats - 1] = (GLenum)-1;
slouken@5201
  1324
#endif /* ZUNE_HD */
slouken@5201
  1325
slouken@5201
  1326
    /* Populate the function pointers for the module */
slouken@5201
  1327
    renderer->WindowEvent         = &GLES2_WindowEvent;
slouken@5201
  1328
    renderer->CreateTexture       = &GLES2_CreateTexture;
slouken@5201
  1329
    renderer->UpdateTexture       = &GLES2_UpdateTexture;
slouken@5201
  1330
    renderer->LockTexture         = &GLES2_LockTexture;
slouken@5201
  1331
    renderer->UnlockTexture       = &GLES2_UnlockTexture;
slouken@5297
  1332
    renderer->UpdateViewport      = &GLES2_UpdateViewport;
slouken@5201
  1333
    renderer->RenderClear         = &GLES2_RenderClear;
slouken@5201
  1334
    renderer->RenderDrawPoints    = &GLES2_RenderDrawPoints;
slouken@5201
  1335
    renderer->RenderDrawLines     = &GLES2_RenderDrawLines;
slouken@5201
  1336
    renderer->RenderFillRects     = &GLES2_RenderFillRects;
slouken@5201
  1337
    renderer->RenderCopy          = &GLES2_RenderCopy;
slouken@6042
  1338
    renderer->RenderReadPixels    = &GLES2_RenderReadPixels;
slouken@5201
  1339
    renderer->RenderPresent       = &GLES2_RenderPresent;
slouken@5201
  1340
    renderer->DestroyTexture      = &GLES2_DestroyTexture;
slouken@5201
  1341
    renderer->DestroyRenderer     = &GLES2_DestroyRenderer;
slouken@5355
  1342
slouken@5355
  1343
    GLES2_ResetState(renderer);
slouken@5355
  1344
slouken@5201
  1345
    return renderer;
slouken@5201
  1346
}
slouken@5201
  1347
slouken@5226
  1348
#endif /* SDL_VIDEO_RENDER_OGL_ES2 && !SDL_RENDER_DISABLED */
slouken@5201
  1349
slouken@5201
  1350
/* vi: set ts=4 sw=4 expandtab: */