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