src/render/opengl/SDL_render_gl.c
author Ryan C. Gordon <icculus@icculus.org>
Sun, 22 Mar 2020 14:32:47 -0400
changeset 13664 1c73cc1e4a3a
parent 13536 4ba421b1e88f
child 13696 ea20a7434b98
permissions -rw-r--r--
opengl: Don't enable/disable texturing except when actually rendering.

Otherwise our cached state goes out of sync when updating a texture. Since
these state changes aren't necessary, they were removed instead of updating
the cached state.

Fixes Bugzilla #4998.
slouken@1918
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@13422
     3
  Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
slouken@1918
     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@1918
     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@1918
    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@1918
    20
*/
icculus@8093
    21
#include "../../SDL_internal.h"
slouken@1918
    22
slouken@5226
    23
#if SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED
slouken@1920
    24
slouken@5233
    25
#include "SDL_hints.h"
slouken@5233
    26
#include "SDL_log.h"
icculus@8650
    27
#include "SDL_assert.h"
slouken@1920
    28
#include "SDL_opengl.h"
slouken@5154
    29
#include "../SDL_sysrender.h"
slouken@5228
    30
#include "SDL_shaders_gl.h"
slouken@1918
    31
slouken@2246
    32
#ifdef __MACOSX__
slouken@2246
    33
#include <OpenGL/OpenGL.h>
slouken@2246
    34
#endif
slouken@2246
    35
gabomdq@8264
    36
/* To prevent unnecessary window recreation, 
gabomdq@8264
    37
 * these should match the defaults selected in SDL_GL_ResetAttributes 
gabomdq@8264
    38
 */
gabomdq@8264
    39
gabomdq@8257
    40
#define RENDERER_CONTEXT_MAJOR 2
gabomdq@8264
    41
#define RENDERER_CONTEXT_MINOR 1
slouken@2778
    42
slouken@1918
    43
/* OpenGL renderer implementation */
slouken@1918
    44
slouken@2230
    45
/* Details on optimizing the texture path on Mac OS X:
slouken@5203
    46
   http://developer.apple.com/library/mac/#documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_texturedata/opengl_texturedata.html
slouken@2230
    47
*/
slouken@2230
    48
slouken@5154
    49
/* Used to re-create the window with OpenGL capability */
slouken@5154
    50
extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags);
icculus@2835
    51
slouken@1985
    52
static const float inv255f = 1.0f / 255.0f;
slouken@1985
    53
slouken@6232
    54
typedef struct GL_FBOList GL_FBOList;
slouken@6232
    55
slouken@6232
    56
struct GL_FBOList
slouken@6232
    57
{
slouken@6232
    58
    Uint32 w, h;
slouken@6232
    59
    GLuint FBO;
slouken@6232
    60
    GL_FBOList *next;
slouken@6232
    61
};
slouken@6232
    62
slouken@1918
    63
typedef struct
slouken@1918
    64
{
icculus@12282
    65
    SDL_bool viewport_dirty;
icculus@12237
    66
    SDL_Rect viewport;
icculus@12237
    67
    SDL_Texture *texture;
icculus@12282
    68
    SDL_Texture *target;
icculus@12282
    69
    int drawablew;
icculus@12282
    70
    int drawableh;
icculus@12237
    71
    SDL_BlendMode blend;
icculus@12237
    72
    GL_Shader shader;
icculus@12282
    73
    SDL_bool cliprect_enabled_dirty;
icculus@12237
    74
    SDL_bool cliprect_enabled;
icculus@12282
    75
    SDL_bool cliprect_dirty;
icculus@12237
    76
    SDL_Rect cliprect;
icculus@12237
    77
    SDL_bool texturing;
icculus@12237
    78
    Uint32 color;
icculus@12237
    79
    Uint32 clear_color;
icculus@12237
    80
} GL_DrawStateCache;
icculus@12237
    81
icculus@12237
    82
typedef struct
icculus@12237
    83
{
slouken@1918
    84
    SDL_GLContext context;
slouken@7194
    85
slouken@7198
    86
    SDL_bool debug_enabled;
slouken@7194
    87
    SDL_bool GL_ARB_debug_output_supported;
slouken@7194
    88
    int errors;
slouken@7194
    89
    char **error_messages;
slouken@7194
    90
    GLDEBUGPROCARB next_error_callback;
slouken@7194
    91
    GLvoid *next_error_userparam;
slouken@7194
    92
icculus@12212
    93
    GLenum textype;
icculus@12212
    94
slouken@9063
    95
    SDL_bool GL_ARB_texture_non_power_of_two_supported;
slouken@2233
    96
    SDL_bool GL_ARB_texture_rectangle_supported;
slouken@6232
    97
    SDL_bool GL_EXT_framebuffer_object_supported;
slouken@6232
    98
    GL_FBOList *framebuffers;
slouken@1927
    99
slouken@1927
   100
    /* OpenGL functions */
slouken@1927
   101
#define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
slouken@5204
   102
#include "SDL_glfuncs.h"
slouken@1927
   103
#undef SDL_PROC
slouken@1974
   104
slouken@5228
   105
    /* Multitexture support */
slouken@5228
   106
    SDL_bool GL_ARB_multitexture_supported;
slouken@5228
   107
    PFNGLACTIVETEXTUREARBPROC glActiveTextureARB;
slouken@5351
   108
    GLint num_texture_units;
slouken@7191
   109
slouken@6232
   110
    PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT;
slouken@6232
   111
    PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT;
slouken@6232
   112
    PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT;
slouken@6232
   113
    PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT;
slouken@6232
   114
    PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT;
slouken@5228
   115
slouken@5228
   116
    /* Shader support */
slouken@5228
   117
    GL_ShaderContext *shaders;
slouken@5228
   118
icculus@12237
   119
    GL_DrawStateCache drawstate;
slouken@1918
   120
} GL_RenderData;
slouken@1918
   121
slouken@1918
   122
typedef struct
slouken@1918
   123
{
slouken@1918
   124
    GLuint texture;
slouken@1918
   125
    GLfloat texw;
slouken@1918
   126
    GLfloat texh;
slouken@1920
   127
    GLenum format;
slouken@1920
   128
    GLenum formattype;
slouken@1918
   129
    void *pixels;
slouken@1918
   130
    int pitch;
slouken@5227
   131
    SDL_Rect locked_rect;
slouken@5264
   132
slouken@9046
   133
    /* YUV texture support */
slouken@5264
   134
    SDL_bool yuv;
slouken@9046
   135
    SDL_bool nv12;
slouken@5264
   136
    GLuint utexture;
slouken@5264
   137
    GLuint vtexture;
slouken@7191
   138
slouken@6232
   139
    GL_FBOList *fbo;
slouken@1918
   140
} GL_TextureData;
slouken@1918
   141
slouken@7194
   142
SDL_FORCE_INLINE const char*
slouken@6494
   143
GL_TranslateError (GLenum error)
slouken@1924
   144
{
slouken@6494
   145
#define GL_ERROR_TRANSLATE(e) case e: return #e;
slouken@6494
   146
    switch (error) {
slouken@6494
   147
    GL_ERROR_TRANSLATE(GL_INVALID_ENUM)
slouken@6494
   148
    GL_ERROR_TRANSLATE(GL_INVALID_VALUE)
slouken@6494
   149
    GL_ERROR_TRANSLATE(GL_INVALID_OPERATION)
slouken@6494
   150
    GL_ERROR_TRANSLATE(GL_OUT_OF_MEMORY)
slouken@6494
   151
    GL_ERROR_TRANSLATE(GL_NO_ERROR)
slouken@6494
   152
    GL_ERROR_TRANSLATE(GL_STACK_OVERFLOW)
slouken@6494
   153
    GL_ERROR_TRANSLATE(GL_STACK_UNDERFLOW)
slouken@6494
   154
    GL_ERROR_TRANSLATE(GL_TABLE_TOO_LARGE)
slouken@6494
   155
    default:
slouken@6494
   156
        return "UNKNOWN";
slouken@6494
   157
}
slouken@6494
   158
#undef GL_ERROR_TRANSLATE
slouken@6494
   159
}
slouken@1924
   160
slouken@7194
   161
SDL_FORCE_INLINE void
slouken@7194
   162
GL_ClearErrors(SDL_Renderer *renderer)
slouken@7194
   163
{
slouken@7194
   164
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@7194
   165
slouken@7198
   166
    if (!data->debug_enabled)
slouken@7198
   167
    {
slouken@7198
   168
        return;
slouken@7198
   169
    }
slouken@7194
   170
    if (data->GL_ARB_debug_output_supported) {
slouken@7194
   171
        if (data->errors) {
slouken@7194
   172
            int i;
slouken@7194
   173
            for (i = 0; i < data->errors; ++i) {
slouken@7194
   174
                SDL_free(data->error_messages[i]);
slouken@7194
   175
            }
slouken@7194
   176
            SDL_free(data->error_messages);
slouken@7194
   177
slouken@7194
   178
            data->errors = 0;
slouken@7194
   179
            data->error_messages = NULL;
slouken@7194
   180
        }
icculus@12887
   181
    } else if (data->glGetError != NULL) {
slouken@7194
   182
        while (data->glGetError() != GL_NO_ERROR) {
sylvain@13201
   183
            /* continue; */
slouken@7194
   184
        }
slouken@7194
   185
    }
slouken@7194
   186
}
slouken@7194
   187
slouken@7194
   188
SDL_FORCE_INLINE int
slouken@7194
   189
GL_CheckAllErrors (const char *prefix, SDL_Renderer *renderer, const char *file, int line, const char *function)
slouken@6494
   190
{
slouken@6494
   191
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@6494
   192
    int ret = 0;
slouken@7194
   193
slouken@7198
   194
    if (!data->debug_enabled)
slouken@7198
   195
    {
slouken@7198
   196
        return 0;
slouken@7198
   197
    }
slouken@7194
   198
    if (data->GL_ARB_debug_output_supported) {
slouken@7194
   199
        if (data->errors) {
slouken@7194
   200
            int i;
slouken@7194
   201
            for (i = 0; i < data->errors; ++i) {
slouken@7194
   202
                SDL_SetError("%s: %s (%d): %s %s", prefix, file, line, function, data->error_messages[i]);
slouken@7194
   203
                ret = -1;
slouken@6494
   204
            }
slouken@7194
   205
            GL_ClearErrors(renderer);
slouken@7194
   206
        }
slouken@7194
   207
    } else {
slouken@7194
   208
        /* check gl errors (can return multiple errors) */
slouken@7194
   209
        for (;;) {
slouken@7194
   210
            GLenum error = data->glGetError();
slouken@7194
   211
            if (error != GL_NO_ERROR) {
slouken@7194
   212
                if (prefix == NULL || prefix[0] == '\0') {
slouken@7194
   213
                    prefix = "generic";
slouken@7194
   214
                }
slouken@7194
   215
                SDL_SetError("%s: %s (%d): %s %s (0x%X)", prefix, file, line, function, GL_TranslateError(error), error);
slouken@7194
   216
                ret = -1;
slouken@7194
   217
            } else {
slouken@7194
   218
                break;
slouken@7194
   219
            }
slouken@6494
   220
        }
slouken@1924
   221
    }
slouken@6494
   222
    return ret;
slouken@1924
   223
}
slouken@1924
   224
icculus@6499
   225
#if 0
icculus@6499
   226
#define GL_CheckError(prefix, renderer)
icculus@6499
   227
#else
slouken@11839
   228
#define GL_CheckError(prefix, renderer) GL_CheckAllErrors(prefix, renderer, SDL_FILE, SDL_LINE, SDL_FUNCTION)
slouken@6494
   229
#endif
slouken@6494
   230
slouken@1927
   231
static int
slouken@1927
   232
GL_LoadFunctions(GL_RenderData * data)
slouken@1927
   233
{
slouken@1927
   234
#ifdef __SDL_NOGETPROCADDR__
slouken@1927
   235
#define SDL_PROC(ret,func,params) data->func=func;
slouken@1927
   236
#else
icculus@12887
   237
    int retval = 0;
slouken@1927
   238
#define SDL_PROC(ret,func,params) \
slouken@1927
   239
    do { \
sezero@11872
   240
        data->func = SDL_GL_GetProcAddress(#func); \
slouken@1927
   241
        if ( ! data->func ) { \
icculus@12887
   242
            retval = SDL_SetError("Couldn't load GL function %s: %s", #func, SDL_GetError()); \
slouken@1927
   243
        } \
slouken@1927
   244
    } while ( 0 );
slouken@1927
   245
#endif /* __SDL_NOGETPROCADDR__ */
slouken@1927
   246
slouken@5204
   247
#include "SDL_glfuncs.h"
slouken@1927
   248
#undef SDL_PROC
icculus@12887
   249
    return retval;
slouken@1927
   250
}
slouken@1927
   251
slouken@5297
   252
static int
slouken@5297
   253
GL_ActivateRenderer(SDL_Renderer * renderer)
slouken@5297
   254
{
slouken@5297
   255
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@5297
   256
icculus@12212
   257
    if (SDL_GL_GetCurrentContext() != data->context) {
slouken@5297
   258
        if (SDL_GL_MakeCurrent(renderer->window, data->context) < 0) {
slouken@5297
   259
            return -1;
slouken@5297
   260
        }
slouken@5297
   261
    }
icculus@7486
   262
icculus@7486
   263
    GL_ClearErrors(renderer);
icculus@7486
   264
slouken@5297
   265
    return 0;
slouken@5297
   266
}
slouken@5297
   267
slouken@7197
   268
static void APIENTRY
jorgen@8811
   269
GL_HandleDebugMessage(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char *message, const void *userParam)
slouken@7194
   270
{
slouken@7194
   271
    SDL_Renderer *renderer = (SDL_Renderer *) userParam;
slouken@7194
   272
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@6232
   273
slouken@7194
   274
    if (type == GL_DEBUG_TYPE_ERROR_ARB) {
slouken@7194
   275
        /* Record this error */
philipp@9336
   276
        int errors = data->errors + 1;
philipp@9336
   277
        char **error_messages = SDL_realloc(data->error_messages, errors * sizeof(*data->error_messages));
philipp@9334
   278
        if (error_messages) {
philipp@9336
   279
            data->errors = errors;
philipp@9334
   280
            data->error_messages = error_messages;
slouken@7194
   281
            data->error_messages[data->errors-1] = SDL_strdup(message);
slouken@7194
   282
        }
slouken@7194
   283
    }
slouken@7194
   284
slouken@7194
   285
    /* If there's another error callback, pass it along, otherwise log it */
slouken@7194
   286
    if (data->next_error_callback) {
slouken@7194
   287
        data->next_error_callback(source, type, id, severity, length, message, data->next_error_userparam);
slouken@7194
   288
    } else {
slouken@7194
   289
        if (type == GL_DEBUG_TYPE_ERROR_ARB) {
slouken@7194
   290
            SDL_LogError(SDL_LOG_CATEGORY_RENDER, "%s", message);
slouken@7194
   291
        } else {
slouken@7194
   292
            SDL_LogDebug(SDL_LOG_CATEGORY_RENDER, "%s", message);
slouken@7194
   293
        }
slouken@7194
   294
    }
slouken@7194
   295
}
slouken@7194
   296
slouken@7194
   297
static GL_FBOList *
slouken@6232
   298
GL_GetFBO(GL_RenderData *data, Uint32 w, Uint32 h)
slouken@6232
   299
{
slouken@6232
   300
    GL_FBOList *result = data->framebuffers;
slouken@6232
   301
slouken@6232
   302
    while (result && ((result->w != w) || (result->h != h))) {
slouken@6232
   303
        result = result->next;
slouken@6232
   304
    }
slouken@6232
   305
slouken@6232
   306
    if (!result) {
slouken@6232
   307
        result = SDL_malloc(sizeof(GL_FBOList));
slouken@6232
   308
        if (result) {
slouken@6232
   309
            result->w = w;
slouken@6232
   310
            result->h = h;
slouken@6232
   311
            data->glGenFramebuffersEXT(1, &result->FBO);
slouken@6232
   312
            result->next = data->framebuffers;
slouken@6232
   313
            data->framebuffers = result;
slouken@6232
   314
        }
slouken@6232
   315
    }
slouken@6232
   316
    return result;
slouken@6232
   317
}
slouken@6232
   318
urkle@7746
   319
static int
urkle@7746
   320
GL_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
urkle@7746
   321
{
urkle@7746
   322
    SDL_GL_GetDrawableSize(renderer->window, w, h);
urkle@7746
   323
    return 0;
urkle@7746
   324
}
urkle@7746
   325
slouken@11282
   326
static GLenum GetBlendFunc(SDL_BlendFactor factor)
slouken@11282
   327
{
slouken@11282
   328
    switch (factor) {
slouken@11282
   329
    case SDL_BLENDFACTOR_ZERO:
slouken@11282
   330
        return GL_ZERO;
slouken@11282
   331
    case SDL_BLENDFACTOR_ONE:
slouken@11282
   332
        return GL_ONE;
slouken@11282
   333
    case SDL_BLENDFACTOR_SRC_COLOR:
slouken@11282
   334
        return GL_SRC_COLOR;
slouken@11282
   335
    case SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR:
slouken@11282
   336
        return GL_ONE_MINUS_SRC_COLOR;
slouken@11282
   337
    case SDL_BLENDFACTOR_SRC_ALPHA:
slouken@11282
   338
        return GL_SRC_ALPHA;
slouken@11282
   339
    case SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA:
slouken@11282
   340
        return GL_ONE_MINUS_SRC_ALPHA;
slouken@11282
   341
    case SDL_BLENDFACTOR_DST_COLOR:
slouken@11282
   342
        return GL_DST_COLOR;
slouken@11282
   343
    case SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR:
slouken@11282
   344
        return GL_ONE_MINUS_DST_COLOR;
slouken@11282
   345
    case SDL_BLENDFACTOR_DST_ALPHA:
slouken@11282
   346
        return GL_DST_ALPHA;
slouken@11282
   347
    case SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA:
slouken@11282
   348
        return GL_ONE_MINUS_DST_ALPHA;
slouken@11282
   349
    default:
slouken@11282
   350
        return GL_INVALID_ENUM;
slouken@11282
   351
    }
slouken@11282
   352
}
slouken@11282
   353
slouken@11282
   354
static GLenum GetBlendEquation(SDL_BlendOperation operation)
slouken@11282
   355
{
slouken@11282
   356
    switch (operation) {
slouken@11282
   357
    case SDL_BLENDOPERATION_ADD:
slouken@11282
   358
        return GL_FUNC_ADD;
slouken@11282
   359
    case SDL_BLENDOPERATION_SUBTRACT:
slouken@11282
   360
        return GL_FUNC_SUBTRACT;
slouken@11282
   361
    case SDL_BLENDOPERATION_REV_SUBTRACT:
slouken@11282
   362
        return GL_FUNC_REVERSE_SUBTRACT;
slouken@11282
   363
    default:
slouken@11282
   364
        return GL_INVALID_ENUM;
slouken@11282
   365
    }
slouken@11282
   366
}
slouken@11282
   367
slouken@11282
   368
static SDL_bool
slouken@11282
   369
GL_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
slouken@11282
   370
{
slouken@11282
   371
    SDL_BlendFactor srcColorFactor = SDL_GetBlendModeSrcColorFactor(blendMode);
slouken@11282
   372
    SDL_BlendFactor srcAlphaFactor = SDL_GetBlendModeSrcAlphaFactor(blendMode);
slouken@11282
   373
    SDL_BlendOperation colorOperation = SDL_GetBlendModeColorOperation(blendMode);
slouken@11282
   374
    SDL_BlendFactor dstColorFactor = SDL_GetBlendModeDstColorFactor(blendMode);
slouken@11282
   375
    SDL_BlendFactor dstAlphaFactor = SDL_GetBlendModeDstAlphaFactor(blendMode);
slouken@11282
   376
    SDL_BlendOperation alphaOperation = SDL_GetBlendModeAlphaOperation(blendMode);
slouken@11282
   377
slouken@11282
   378
    if (GetBlendFunc(srcColorFactor) == GL_INVALID_ENUM ||
slouken@11282
   379
        GetBlendFunc(srcAlphaFactor) == GL_INVALID_ENUM ||
slouken@11282
   380
        GetBlendEquation(colorOperation) == GL_INVALID_ENUM ||
slouken@11282
   381
        GetBlendFunc(dstColorFactor) == GL_INVALID_ENUM ||
slouken@11282
   382
        GetBlendFunc(dstAlphaFactor) == GL_INVALID_ENUM ||
slouken@11282
   383
        GetBlendEquation(alphaOperation) == GL_INVALID_ENUM) {
slouken@11282
   384
        return SDL_FALSE;
slouken@11282
   385
    }
slouken@11282
   386
    if (colorOperation != alphaOperation) {
slouken@11282
   387
        return SDL_FALSE;
slouken@11282
   388
    }
slouken@11282
   389
    return SDL_TRUE;
slouken@11282
   390
}
slouken@11282
   391
slouken@7194
   392
SDL_FORCE_INLINE int
slouken@1922
   393
power_of_2(int input)
slouken@1922
   394
{
slouken@1922
   395
    int value = 1;
slouken@1922
   396
slouken@1922
   397
    while (value < input) {
slouken@1922
   398
        value <<= 1;
slouken@1922
   399
    }
slouken@1922
   400
    return value;
slouken@1922
   401
}
slouken@1922
   402
slouken@7194
   403
SDL_FORCE_INLINE SDL_bool
slouken@3433
   404
convert_format(GL_RenderData *renderdata, Uint32 pixel_format,
slouken@3433
   405
               GLint* internalFormat, GLenum* format, GLenum* type)
slouken@3433
   406
{
slouken@3433
   407
    switch (pixel_format) {
slouken@3433
   408
    case SDL_PIXELFORMAT_ARGB8888:
slouken@12735
   409
    case SDL_PIXELFORMAT_RGB888:
slouken@3433
   410
        *internalFormat = GL_RGBA8;
slouken@3433
   411
        *format = GL_BGRA;
slouken@5156
   412
        *type = GL_UNSIGNED_INT_8_8_8_8_REV;
slouken@3433
   413
        break;
slouken@12735
   414
    case SDL_PIXELFORMAT_ABGR8888:
slouken@12735
   415
    case SDL_PIXELFORMAT_BGR888:
slouken@12735
   416
        *internalFormat = GL_RGBA8;
slouken@12735
   417
        *format = GL_RGBA;
slouken@12735
   418
        *type = GL_UNSIGNED_INT_8_8_8_8_REV;
slouken@12735
   419
        break;
slouken@5264
   420
    case SDL_PIXELFORMAT_YV12:
slouken@5264
   421
    case SDL_PIXELFORMAT_IYUV:
slouken@9046
   422
    case SDL_PIXELFORMAT_NV12:
slouken@9046
   423
    case SDL_PIXELFORMAT_NV21:
slouken@5264
   424
        *internalFormat = GL_LUMINANCE;
slouken@5264
   425
        *format = GL_LUMINANCE;
slouken@5264
   426
        *type = GL_UNSIGNED_BYTE;
slouken@5264
   427
        break;
slouken@7814
   428
#ifdef __MACOSX__
slouken@7814
   429
    case SDL_PIXELFORMAT_UYVY:
slouken@9046
   430
        *internalFormat = GL_RGB8;
slouken@9046
   431
        *format = GL_YCBCR_422_APPLE;
slouken@9046
   432
        *type = GL_UNSIGNED_SHORT_8_8_APPLE;
slouken@9046
   433
        break;
slouken@7814
   434
#endif
slouken@3433
   435
    default:
slouken@3433
   436
        return SDL_FALSE;
slouken@3433
   437
    }
slouken@3433
   438
    return SDL_TRUE;
slouken@3433
   439
}
icculus@2835
   440
slouken@1918
   441
static int
slouken@1918
   442
GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@1918
   443
{
slouken@1918
   444
    GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
icculus@12212
   445
    const GLenum textype = renderdata->textype;
slouken@1918
   446
    GL_TextureData *data;
slouken@1920
   447
    GLint internalFormat;
slouken@1920
   448
    GLenum format, type;
slouken@1922
   449
    int texture_w, texture_h;
slouken@5503
   450
    GLenum scaleMode;
slouken@1918
   451
slouken@5147
   452
    GL_ActivateRenderer(renderer);
slouken@5147
   453
icculus@12592
   454
    renderdata->drawstate.texture = NULL;  /* we trash this state. */
icculus@12592
   455
slouken@10401
   456
    if (texture->access == SDL_TEXTUREACCESS_TARGET &&
slouken@10401
   457
        !renderdata->GL_EXT_framebuffer_object_supported) {
slouken@10401
   458
        return SDL_SetError("Render targets not supported by OpenGL");
slouken@10401
   459
    }
slouken@10401
   460
slouken@3433
   461
    if (!convert_format(renderdata, texture->format, &internalFormat,
slouken@3433
   462
                        &format, &type)) {
icculus@7037
   463
        return SDL_SetError("Texture format %s not supported by OpenGL",
icculus@7037
   464
                            SDL_GetPixelFormatName(texture->format));
slouken@1920
   465
    }
slouken@1920
   466
slouken@1920
   467
    data = (GL_TextureData *) SDL_calloc(1, sizeof(*data));
slouken@1918
   468
    if (!data) {
icculus@7037
   469
        return SDL_OutOfMemory();
slouken@1918
   470
    }
slouken@1918
   471
slouken@2222
   472
    if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
slouken@5264
   473
        size_t size;
slouken@5156
   474
        data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);
slouken@5264
   475
        size = texture->h * data->pitch;
slouken@5264
   476
        if (texture->format == SDL_PIXELFORMAT_YV12 ||
slouken@5264
   477
            texture->format == SDL_PIXELFORMAT_IYUV) {
slouken@5264
   478
            /* Need to add size for the U and V planes */
slouken@11574
   479
            size += 2 * ((texture->h + 1) / 2) * ((data->pitch + 1) / 2);
slouken@5264
   480
        }
slouken@9046
   481
        if (texture->format == SDL_PIXELFORMAT_NV12 ||
slouken@9046
   482
            texture->format == SDL_PIXELFORMAT_NV21) {
slouken@9046
   483
            /* Need to add size for the U/V plane */
slouken@11574
   484
            size += 2 * ((texture->h + 1) / 2) * ((data->pitch + 1) / 2);
slouken@9046
   485
        }
slouken@5402
   486
        data->pixels = SDL_calloc(1, size);
slouken@2222
   487
        if (!data->pixels) {
slouken@2222
   488
            SDL_free(data);
icculus@7037
   489
            return SDL_OutOfMemory();
slouken@2222
   490
        }
slouken@2222
   491
    }
slouken@2222
   492
slouken@6232
   493
    if (texture->access == SDL_TEXTUREACCESS_TARGET) {
slouken@6232
   494
        data->fbo = GL_GetFBO(renderdata, texture->w, texture->h);
slouken@6232
   495
    } else {
slouken@6232
   496
        data->fbo = NULL;
slouken@6232
   497
    }
slouken@1918
   498
slouken@6494
   499
    GL_CheckError("", renderer);
slouken@1927
   500
    renderdata->glGenTextures(1, &data->texture);
slouken@9063
   501
    if (GL_CheckError("glGenTextures()", renderer) < 0) {
slouken@9011
   502
        if (data->pixels) {
slouken@9011
   503
            SDL_free(data->pixels);
slouken@9011
   504
        }
slouken@7624
   505
        SDL_free(data);
slouken@7624
   506
        return -1;
slouken@7624
   507
    }
slouken@7779
   508
    texture->driverdata = data;
slouken@7779
   509
slouken@9063
   510
    if (renderdata->GL_ARB_texture_non_power_of_two_supported) {
slouken@9063
   511
        texture_w = texture->w;
slouken@9063
   512
        texture_h = texture->h;
slouken@9063
   513
        data->texw = 1.0f;
slouken@9063
   514
        data->texh = 1.0f;
slouken@9063
   515
    } else if (renderdata->GL_ARB_texture_rectangle_supported) {
slouken@1926
   516
        texture_w = texture->w;
slouken@1926
   517
        texture_h = texture->h;
icculus@2835
   518
        data->texw = (GLfloat) texture_w;
icculus@2835
   519
        data->texh = (GLfloat) texture_h;
slouken@1926
   520
    } else {
slouken@1926
   521
        texture_w = power_of_2(texture->w);
slouken@1926
   522
        texture_h = power_of_2(texture->h);
icculus@2835
   523
        data->texw = (GLfloat) (texture->w) / texture_w;
slouken@1926
   524
        data->texh = (GLfloat) texture->h / texture_h;
slouken@1926
   525
    }
icculus@2835
   526
slouken@1920
   527
    data->format = format;
slouken@1920
   528
    data->formattype = type;
slouken@11958
   529
    scaleMode = (texture->scaleMode == SDL_ScaleModeNearest) ? GL_NEAREST : GL_LINEAR;
icculus@12212
   530
    renderdata->glEnable(textype);
icculus@12212
   531
    renderdata->glBindTexture(textype, data->texture);
icculus@12212
   532
    renderdata->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, scaleMode);
icculus@12212
   533
    renderdata->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, scaleMode);
slouken@6207
   534
    /* According to the spec, CLAMP_TO_EDGE is the default for TEXTURE_RECTANGLE
slouken@6207
   535
       and setting it causes an INVALID_ENUM error in the latest NVidia drivers.
slouken@6207
   536
    */
icculus@12212
   537
    if (textype != GL_TEXTURE_RECTANGLE_ARB) {
icculus@12212
   538
        renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_S,
slouken@6207
   539
                                    GL_CLAMP_TO_EDGE);
icculus@12212
   540
        renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_T,
slouken@6207
   541
                                    GL_CLAMP_TO_EDGE);
slouken@6207
   542
    }
slouken@2840
   543
#ifdef __MACOSX__
slouken@2230
   544
#ifndef GL_TEXTURE_STORAGE_HINT_APPLE
slouken@2230
   545
#define GL_TEXTURE_STORAGE_HINT_APPLE       0x85BC
slouken@2230
   546
#endif
slouken@2230
   547
#ifndef STORAGE_CACHED_APPLE
slouken@2230
   548
#define STORAGE_CACHED_APPLE                0x85BE
slouken@2230
   549
#endif
slouken@2230
   550
#ifndef STORAGE_SHARED_APPLE
slouken@2230
   551
#define STORAGE_SHARED_APPLE                0x85BF
slouken@2230
   552
#endif
slouken@2230
   553
    if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
icculus@12212
   554
        renderdata->glTexParameteri(textype, GL_TEXTURE_STORAGE_HINT_APPLE,
slouken@2230
   555
                                    GL_STORAGE_SHARED_APPLE);
slouken@2230
   556
    } else {
icculus@12212
   557
        renderdata->glTexParameteri(textype, GL_TEXTURE_STORAGE_HINT_APPLE,
slouken@2230
   558
                                    GL_STORAGE_CACHED_APPLE);
slouken@2230
   559
    }
bob@2295
   560
    if (texture->access == SDL_TEXTUREACCESS_STREAMING
slouken@5397
   561
        && texture->format == SDL_PIXELFORMAT_ARGB8888
slouken@5397
   562
        && (texture->w % 8) == 0) {
slouken@2230
   563
        renderdata->glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
slouken@5397
   564
        renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
slouken@5397
   565
        renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH,
slouken@5397
   566
                          (data->pitch / SDL_BYTESPERPIXEL(texture->format)));
icculus@12212
   567
        renderdata->glTexImage2D(textype, 0, internalFormat, texture_w,
slouken@2230
   568
                                 texture_h, 0, format, type, data->pixels);
slouken@5397
   569
        renderdata->glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
slouken@5156
   570
    }
slouken@5156
   571
    else
slouken@2809
   572
#endif
slouken@2230
   573
    {
icculus@12212
   574
        renderdata->glTexImage2D(textype, 0, internalFormat, texture_w,
slouken@2230
   575
                                 texture_h, 0, format, type, NULL);
slouken@2230
   576
    }
icculus@12212
   577
    renderdata->glDisable(textype);
slouken@7194
   578
    if (GL_CheckError("glTexImage2D()", renderer) < 0) {
slouken@1924
   579
        return -1;
slouken@1924
   580
    }
slouken@5264
   581
slouken@5264
   582
    if (texture->format == SDL_PIXELFORMAT_YV12 ||
slouken@5264
   583
        texture->format == SDL_PIXELFORMAT_IYUV) {
slouken@5264
   584
        data->yuv = SDL_TRUE;
slouken@5264
   585
slouken@5264
   586
        renderdata->glGenTextures(1, &data->utexture);
slouken@5264
   587
        renderdata->glGenTextures(1, &data->vtexture);
slouken@5264
   588
icculus@12212
   589
        renderdata->glBindTexture(textype, data->utexture);
icculus@12212
   590
        renderdata->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER,
slouken@5503
   591
                                    scaleMode);
icculus@12212
   592
        renderdata->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER,
slouken@5503
   593
                                    scaleMode);
icculus@12212
   594
        renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_S,
slouken@5264
   595
                                    GL_CLAMP_TO_EDGE);
icculus@12212
   596
        renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_T,
slouken@5264
   597
                                    GL_CLAMP_TO_EDGE);
icculus@12212
   598
        renderdata->glTexImage2D(textype, 0, internalFormat, (texture_w+1)/2,
slouken@11574
   599
                                 (texture_h+1)/2, 0, format, type, NULL);
slouken@5264
   600
icculus@12212
   601
        renderdata->glBindTexture(textype, data->vtexture);
icculus@12212
   602
        renderdata->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER,
slouken@5503
   603
                                    scaleMode);
icculus@12212
   604
        renderdata->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER,
slouken@5503
   605
                                    scaleMode);
icculus@12212
   606
        renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_S,
slouken@5264
   607
                                    GL_CLAMP_TO_EDGE);
icculus@12212
   608
        renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_T,
slouken@5264
   609
                                    GL_CLAMP_TO_EDGE);
icculus@12212
   610
        renderdata->glTexImage2D(textype, 0, internalFormat, (texture_w+1)/2,
slouken@11574
   611
                                 (texture_h+1)/2, 0, format, type, NULL);
slouken@5264
   612
    }
slouken@6494
   613
slouken@9046
   614
    if (texture->format == SDL_PIXELFORMAT_NV12 ||
slouken@9046
   615
        texture->format == SDL_PIXELFORMAT_NV21) {
slouken@9046
   616
        data->nv12 = SDL_TRUE;
slouken@9046
   617
slouken@9046
   618
        renderdata->glGenTextures(1, &data->utexture);
icculus@12212
   619
        renderdata->glBindTexture(textype, data->utexture);
icculus@12212
   620
        renderdata->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER,
slouken@9046
   621
                                    scaleMode);
icculus@12212
   622
        renderdata->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER,
slouken@9046
   623
                                    scaleMode);
icculus@12212
   624
        renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_S,
slouken@9046
   625
                                    GL_CLAMP_TO_EDGE);
icculus@12212
   626
        renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_T,
slouken@9046
   627
                                    GL_CLAMP_TO_EDGE);
icculus@12212
   628
        renderdata->glTexImage2D(textype, 0, GL_LUMINANCE_ALPHA, (texture_w+1)/2,
slouken@11574
   629
                                 (texture_h+1)/2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL);
slouken@9046
   630
    }
slouken@9046
   631
slouken@7194
   632
    return GL_CheckError("", renderer);
slouken@1918
   633
}
slouken@1918
   634
slouken@1918
   635
static int
slouken@1918
   636
GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@1918
   637
                 const SDL_Rect * rect, const void *pixels, int pitch)
slouken@1918
   638
{
slouken@1927
   639
    GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
icculus@12212
   640
    const GLenum textype = renderdata->textype;
slouken@1918
   641
    GL_TextureData *data = (GL_TextureData *) texture->driverdata;
icculus@8650
   642
    const int texturebpp = SDL_BYTESPERPIXEL(texture->format);
icculus@8650
   643
icculus@8650
   644
    SDL_assert(texturebpp != 0);  /* otherwise, division by zero later. */
slouken@1918
   645
slouken@5147
   646
    GL_ActivateRenderer(renderer);
slouken@5147
   647
icculus@12592
   648
    renderdata->drawstate.texture = NULL;  /* we trash this state. */
icculus@12592
   649
icculus@12212
   650
    renderdata->glBindTexture(textype, data->texture);
slouken@5227
   651
    renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
icculus@8650
   652
    renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, (pitch / texturebpp));
icculus@12212
   653
    renderdata->glTexSubImage2D(textype, 0, rect->x, rect->y, rect->w,
slouken@1927
   654
                                rect->h, data->format, data->formattype,
slouken@1927
   655
                                pixels);
slouken@5264
   656
    if (data->yuv) {
slouken@11574
   657
        renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, ((pitch + 1) / 2));
slouken@5265
   658
slouken@5264
   659
        /* Skip to the correct offset into the next texture */
slouken@6135
   660
        pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
slouken@5264
   661
        if (texture->format == SDL_PIXELFORMAT_YV12) {
icculus@12212
   662
            renderdata->glBindTexture(textype, data->vtexture);
slouken@5264
   663
        } else {
icculus@12212
   664
            renderdata->glBindTexture(textype, data->utexture);
slouken@5264
   665
        }
icculus@12212
   666
        renderdata->glTexSubImage2D(textype, 0, rect->x/2, rect->y/2,
slouken@11574
   667
                                    (rect->w+1)/2, (rect->h+1)/2,
slouken@5264
   668
                                    data->format, data->formattype, pixels);
slouken@5264
   669
slouken@5264
   670
        /* Skip to the correct offset into the next texture */
slouken@11574
   671
        pixels = (const void*)((const Uint8*)pixels + ((rect->h + 1) / 2) * ((pitch + 1) / 2));
slouken@5264
   672
        if (texture->format == SDL_PIXELFORMAT_YV12) {
icculus@12212
   673
            renderdata->glBindTexture(textype, data->utexture);
slouken@5264
   674
        } else {
icculus@12212
   675
            renderdata->glBindTexture(textype, data->vtexture);
slouken@5264
   676
        }
icculus@12212
   677
        renderdata->glTexSubImage2D(textype, 0, rect->x/2, rect->y/2,
slouken@11574
   678
                                    (rect->w+1)/2, (rect->h+1)/2,
slouken@5264
   679
                                    data->format, data->formattype, pixels);
slouken@5264
   680
    }
slouken@9046
   681
slouken@9046
   682
    if (data->nv12) {
slouken@11574
   683
        renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, ((pitch + 1) / 2));
slouken@9046
   684
slouken@9046
   685
        /* Skip to the correct offset into the next texture */
slouken@9046
   686
        pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
icculus@12212
   687
        renderdata->glBindTexture(textype, data->utexture);
icculus@12212
   688
        renderdata->glTexSubImage2D(textype, 0, rect->x/2, rect->y/2,
slouken@11574
   689
                                    (rect->w + 1)/2, (rect->h + 1)/2,
slouken@9046
   690
                                    GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, pixels);
slouken@9046
   691
    }
slouken@7779
   692
slouken@7194
   693
    return GL_CheckError("glTexSubImage2D()", renderer);
slouken@1918
   694
}
slouken@1918
   695
slouken@1918
   696
static int
slouken@7759
   697
GL_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@7759
   698
                    const SDL_Rect * rect,
slouken@7759
   699
                    const Uint8 *Yplane, int Ypitch,
slouken@7759
   700
                    const Uint8 *Uplane, int Upitch,
slouken@7759
   701
                    const Uint8 *Vplane, int Vpitch)
slouken@7759
   702
{
slouken@7759
   703
    GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
icculus@12212
   704
    const GLenum textype = renderdata->textype;
slouken@7759
   705
    GL_TextureData *data = (GL_TextureData *) texture->driverdata;
slouken@7759
   706
slouken@7759
   707
    GL_ActivateRenderer(renderer);
slouken@7759
   708
icculus@12592
   709
    renderdata->drawstate.texture = NULL;  /* we trash this state. */
icculus@12592
   710
icculus@12212
   711
    renderdata->glBindTexture(textype, data->texture);
slouken@7759
   712
    renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
slouken@7759
   713
    renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, Ypitch);
icculus@12212
   714
    renderdata->glTexSubImage2D(textype, 0, rect->x, rect->y, rect->w,
slouken@7759
   715
                                rect->h, data->format, data->formattype,
slouken@7759
   716
                                Yplane);
slouken@7759
   717
slouken@7759
   718
    renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, Upitch);
icculus@12212
   719
    renderdata->glBindTexture(textype, data->utexture);
icculus@12212
   720
    renderdata->glTexSubImage2D(textype, 0, rect->x/2, rect->y/2,
slouken@11574
   721
                                (rect->w + 1)/2, (rect->h + 1)/2,
slouken@7759
   722
                                data->format, data->formattype, Uplane);
slouken@7759
   723
slouken@7759
   724
    renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, Vpitch);
icculus@12212
   725
    renderdata->glBindTexture(textype, data->vtexture);
icculus@12212
   726
    renderdata->glTexSubImage2D(textype, 0, rect->x/2, rect->y/2,
slouken@11574
   727
                                (rect->w + 1)/2, (rect->h + 1)/2,
slouken@7759
   728
                                data->format, data->formattype, Vplane);
slouken@7779
   729
slouken@7759
   730
    return GL_CheckError("glTexSubImage2D()", renderer);
slouken@7759
   731
}
slouken@7759
   732
slouken@7759
   733
static int
slouken@1918
   734
GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@5156
   735
               const SDL_Rect * rect, void **pixels, int *pitch)
slouken@1918
   736
{
slouken@1918
   737
    GL_TextureData *data = (GL_TextureData *) texture->driverdata;
slouken@1918
   738
slouken@5227
   739
    data->locked_rect = *rect;
slouken@7191
   740
    *pixels =
slouken@1920
   741
        (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
slouken@5156
   742
                  rect->x * SDL_BYTESPERPIXEL(texture->format));
slouken@1920
   743
    *pitch = data->pitch;
slouken@1918
   744
    return 0;
slouken@1918
   745
}
slouken@1918
   746
slouken@1918
   747
static void
slouken@1918
   748
GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@1918
   749
{
slouken@5156
   750
    GL_TextureData *data = (GL_TextureData *) texture->driverdata;
slouken@5227
   751
    const SDL_Rect *rect;
slouken@5227
   752
    void *pixels;
slouken@1918
   753
slouken@5227
   754
    rect = &data->locked_rect;
slouken@7191
   755
    pixels =
slouken@5227
   756
        (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
slouken@5227
   757
                  rect->x * SDL_BYTESPERPIXEL(texture->format));
slouken@5227
   758
    GL_UpdateTexture(renderer, texture, rect, pixels, data->pitch);
slouken@1918
   759
}
slouken@1918
   760
slouken@13376
   761
static void
slouken@13376
   762
GL_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture, SDL_ScaleMode scaleMode)
slouken@13376
   763
{
slouken@13376
   764
    GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
slouken@13376
   765
    const GLenum textype = renderdata->textype;
slouken@13376
   766
    GL_TextureData *data = (GL_TextureData *) texture->driverdata;
slouken@13376
   767
    GLenum glScaleMode = (scaleMode == SDL_ScaleModeNearest) ? GL_NEAREST : GL_LINEAR;
slouken@13376
   768
slouken@13376
   769
    renderdata->glBindTexture(textype, data->texture);
slouken@13376
   770
    renderdata->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, glScaleMode);
slouken@13376
   771
    renderdata->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, glScaleMode);
slouken@13376
   772
slouken@13376
   773
    if (texture->format == SDL_PIXELFORMAT_YV12 ||
slouken@13376
   774
        texture->format == SDL_PIXELFORMAT_IYUV) {
slouken@13376
   775
        renderdata->glBindTexture(textype, data->utexture);
slouken@13376
   776
        renderdata->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, glScaleMode);
slouken@13376
   777
        renderdata->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, glScaleMode);
slouken@13376
   778
slouken@13376
   779
        renderdata->glBindTexture(textype, data->vtexture);
slouken@13376
   780
        renderdata->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, glScaleMode);
slouken@13376
   781
        renderdata->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, glScaleMode);
slouken@13376
   782
    }
slouken@13376
   783
slouken@13376
   784
    if (texture->format == SDL_PIXELFORMAT_NV12 ||
slouken@13376
   785
        texture->format == SDL_PIXELFORMAT_NV21) {
slouken@13376
   786
        renderdata->glBindTexture(textype, data->utexture);
slouken@13376
   787
        renderdata->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, glScaleMode);
slouken@13376
   788
        renderdata->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, glScaleMode);
slouken@13376
   789
    }
slouken@13376
   790
}
slouken@13376
   791
slouken@5297
   792
static int
slouken@6247
   793
GL_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@6246
   794
{
slouken@7191
   795
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@6246
   796
    GL_TextureData *texturedata;
slouken@6246
   797
    GLenum status;
slouken@6246
   798
slouken@6246
   799
    GL_ActivateRenderer(renderer);
slouken@7191
   800
slouken@10401
   801
    if (!data->GL_EXT_framebuffer_object_supported) {
slouken@10401
   802
        return SDL_SetError("Render targets not supported by OpenGL");
slouken@10401
   803
    }
slouken@10401
   804
sylvain@12621
   805
    data->drawstate.viewport_dirty = SDL_TRUE;
sylvain@12621
   806
slouken@6246
   807
    if (texture == NULL) {
slouken@6246
   808
        data->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
slouken@6246
   809
        return 0;
slouken@6246
   810
    }
slouken@6246
   811
slouken@6246
   812
    texturedata = (GL_TextureData *) texture->driverdata;
slouken@6246
   813
    data->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, texturedata->fbo->FBO);
slouken@6246
   814
    /* TODO: check if texture pixel format allows this operation */
icculus@12212
   815
    data->glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, data->textype, texturedata->texture, 0);
slouken@6246
   816
    /* Check FBO status */
slouken@6246
   817
    status = data->glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
slouken@6246
   818
    if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
icculus@7037
   819
        return SDL_SetError("glFramebufferTexture2DEXT() failed");
slouken@6246
   820
    }
slouken@6246
   821
    return 0;
slouken@6246
   822
}
slouken@6246
   823
icculus@12212
   824
/* !!! FIXME: all these Queue* calls set up the vertex buffer the way the immediate mode
icculus@12212
   825
   !!! FIXME:  renderer wants it, but this might want to operate differently if we move to
icculus@12212
   826
   !!! FIXME:  VBOs at some point. */
slouken@6246
   827
static int
icculus@12215
   828
GL_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd)
icculus@12215
   829
{
icculus@12215
   830
    return 0;  /* nothing to do in this backend. */
icculus@12215
   831
}
icculus@12215
   832
icculus@12215
   833
static int
icculus@12212
   834
GL_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
slouken@5224
   835
{
icculus@12215
   836
    GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, count * 2 * sizeof (GLfloat), 0, &cmd->data.draw.first);
slouken@12665
   837
    int i;
slouken@5224
   838
icculus@12212
   839
    if (!verts) {
icculus@12212
   840
        return -1;
slouken@7995
   841
    }
slouken@5224
   842
icculus@12212
   843
    cmd->data.draw.count = count;
icculus@12212
   844
    for (i = 0; i < count; i++) {
icculus@12212
   845
        *(verts++) = 0.5f + points[i].x;
icculus@12212
   846
        *(verts++) = 0.5f + points[i].y;
slouken@10408
   847
    }
slouken@10408
   848
slouken@3596
   849
    return 0;
slouken@3596
   850
}
slouken@3596
   851
slouken@3596
   852
static int
icculus@12212
   853
GL_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects, int count)
slouken@2884
   854
{
icculus@12215
   855
    GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, count * 4 * sizeof (GLfloat), 0, &cmd->data.draw.first);
slouken@12665
   856
    int i;
icculus@12212
   857
icculus@12212
   858
    if (!verts) {
icculus@12212
   859
        return -1;
icculus@12212
   860
    }
slouken@2884
   861
icculus@12212
   862
    cmd->data.draw.count = count;
icculus@12212
   863
    for (i = 0; i < count; i++) {
icculus@12212
   864
        const SDL_FRect *rect = &rects[i];
icculus@12212
   865
        *(verts++) = rect->x;
icculus@12212
   866
        *(verts++) = rect->y;
icculus@12212
   867
        *(verts++) = rect->x + rect->w;
icculus@12212
   868
        *(verts++) = rect->y + rect->h;
slouken@7908
   869
    }
slouken@2901
   870
slouken@2901
   871
    return 0;
slouken@2901
   872
}
slouken@2901
   873
slouken@2901
   874
static int
icculus@12212
   875
GL_QueueCopy(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
icculus@12212
   876
             const SDL_Rect * srcrect, const SDL_FRect * dstrect)
slouken@2925
   877
{
slouken@9046
   878
    GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
slouken@9046
   879
    GLfloat minx, miny, maxx, maxy;
slouken@9046
   880
    GLfloat minu, maxu, minv, maxv;
icculus@12215
   881
    GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, 8 * sizeof (GLfloat), 0, &cmd->data.draw.first);
slouken@9046
   882
icculus@12212
   883
    if (!verts) {
slouken@9046
   884
        return -1;
slouken@9046
   885
    }
slouken@5355
   886
icculus@12212
   887
    cmd->data.draw.count = 1;
icculus@12212
   888
slouken@1918
   889
    minx = dstrect->x;
slouken@1918
   890
    miny = dstrect->y;
slouken@1918
   891
    maxx = dstrect->x + dstrect->w;
slouken@1918
   892
    maxy = dstrect->y + dstrect->h;
slouken@1918
   893
slouken@1918
   894
    minu = (GLfloat) srcrect->x / texture->w;
slouken@1920
   895
    minu *= texturedata->texw;
slouken@1918
   896
    maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
slouken@1920
   897
    maxu *= texturedata->texw;
slouken@1918
   898
    minv = (GLfloat) srcrect->y / texture->h;
slouken@1920
   899
    minv *= texturedata->texh;
slouken@1918
   900
    maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
slouken@1920
   901
    maxv *= texturedata->texh;
slouken@1918
   902
icculus@12212
   903
    cmd->data.draw.count = 1;
icculus@12212
   904
    *(verts++) = minx;
icculus@12212
   905
    *(verts++) = miny;
icculus@12212
   906
    *(verts++) = maxx;
icculus@12212
   907
    *(verts++) = maxy;
icculus@12212
   908
    *(verts++) = minu;
icculus@12212
   909
    *(verts++) = maxu;
icculus@12212
   910
    *(verts++) = minv;
icculus@12212
   911
    *(verts++) = maxv;
icculus@12212
   912
    return 0;
slouken@1918
   913
}
slouken@1918
   914
slouken@3431
   915
static int
icculus@12212
   916
GL_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
icculus@12212
   917
               const SDL_Rect * srcrect, const SDL_FRect * dstrect,
icculus@12212
   918
               const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
gabomdq@6320
   919
{
gabomdq@6320
   920
    GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
gabomdq@6320
   921
    GLfloat minx, miny, maxx, maxy;
gabomdq@6320
   922
    GLfloat centerx, centery;
gabomdq@6320
   923
    GLfloat minu, maxu, minv, maxv;
icculus@12215
   924
    GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, 11 * sizeof (GLfloat), 0, &cmd->data.draw.first);
slouken@7194
   925
icculus@12212
   926
    if (!verts) {
slouken@9046
   927
        return -1;
gabomdq@6320
   928
    }
gabomdq@6320
   929
slouken@6528
   930
    centerx = center->x;
slouken@6528
   931
    centery = center->y;
gabomdq@6320
   932
slouken@7989
   933
    if (flip & SDL_FLIP_HORIZONTAL) {
slouken@7989
   934
        minx =  dstrect->w - centerx;
slouken@7976
   935
        maxx = -centerx;
slouken@7989
   936
    }
slouken@7989
   937
    else {
gabomdq@6320
   938
        minx = -centerx;
slouken@7989
   939
        maxx =  dstrect->w - centerx;
slouken@7989
   940
    }
slouken@7989
   941
slouken@7989
   942
    if (flip & SDL_FLIP_VERTICAL) {
slouken@7989
   943
        miny =  dstrect->h - centery;
slouken@7989
   944
        maxy = -centery;
slouken@7989
   945
    }
slouken@7989
   946
    else {
gabomdq@6320
   947
        miny = -centery;
slouken@7989
   948
        maxy =  dstrect->h - centery;
gabomdq@6320
   949
    }
gabomdq@6320
   950
gabomdq@6320
   951
    minu = (GLfloat) srcrect->x / texture->w;
gabomdq@6320
   952
    minu *= texturedata->texw;
gabomdq@6320
   953
    maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
gabomdq@6320
   954
    maxu *= texturedata->texw;
gabomdq@6320
   955
    minv = (GLfloat) srcrect->y / texture->h;
gabomdq@6320
   956
    minv *= texturedata->texh;
gabomdq@6320
   957
    maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
gabomdq@6320
   958
    maxv *= texturedata->texh;
gabomdq@6320
   959
icculus@12212
   960
    cmd->data.draw.count = 1;
icculus@12212
   961
    *(verts++) = minx;
icculus@12212
   962
    *(verts++) = miny;
icculus@12212
   963
    *(verts++) = maxx;
icculus@12212
   964
    *(verts++) = maxy;
icculus@12212
   965
    *(verts++) = minu;
icculus@12212
   966
    *(verts++) = maxu;
icculus@12212
   967
    *(verts++) = minv;
icculus@12212
   968
    *(verts++) = maxv;
icculus@12212
   969
    *(verts++) = (GLfloat) dstrect->x + centerx;
icculus@12212
   970
    *(verts++) = (GLfloat) dstrect->y + centery;
icculus@12212
   971
    *(verts++) = (GLfloat) angle;
icculus@12212
   972
    return 0;
icculus@12212
   973
}
icculus@12212
   974
icculus@12212
   975
static void
icculus@12237
   976
SetDrawState(GL_RenderData *data, const SDL_RenderCommand *cmd, const GL_Shader shader)
icculus@12212
   977
{
icculus@12212
   978
    const SDL_BlendMode blend = cmd->data.draw.blend;
icculus@12212
   979
icculus@12282
   980
    if (data->drawstate.viewport_dirty) {
icculus@12282
   981
        const SDL_bool istarget = data->drawstate.target != NULL;
icculus@12282
   982
        const SDL_Rect *viewport = &data->drawstate.viewport;
icculus@12282
   983
        data->glMatrixMode(GL_PROJECTION);
icculus@12282
   984
        data->glLoadIdentity();
icculus@12282
   985
        data->glViewport(viewport->x,
icculus@12282
   986
                         istarget ? viewport->y : (data->drawstate.drawableh - viewport->y - viewport->h),
icculus@12282
   987
                         viewport->w, viewport->h);
icculus@12282
   988
        if (viewport->w && viewport->h) {
icculus@12282
   989
            data->glOrtho((GLdouble) 0, (GLdouble) viewport->w,
icculus@12282
   990
                          (GLdouble) istarget ? 0 : viewport->h,
icculus@12282
   991
                          (GLdouble) istarget ? viewport->h : 0,
icculus@12282
   992
                          0.0, 1.0);
icculus@12282
   993
        }
icculus@12282
   994
        data->glMatrixMode(GL_MODELVIEW);
icculus@12282
   995
        data->drawstate.viewport_dirty = SDL_FALSE;
icculus@12282
   996
    }
icculus@12282
   997
icculus@12282
   998
    if (data->drawstate.cliprect_enabled_dirty) {
icculus@12282
   999
        if (!data->drawstate.cliprect_enabled) {
icculus@12282
  1000
            data->glDisable(GL_SCISSOR_TEST);
icculus@12282
  1001
        } else {
icculus@12282
  1002
            data->glEnable(GL_SCISSOR_TEST);
icculus@12282
  1003
        }
icculus@12282
  1004
        data->drawstate.cliprect_enabled_dirty = SDL_FALSE;
icculus@12282
  1005
    }
icculus@12282
  1006
icculus@12282
  1007
    if (data->drawstate.cliprect_enabled && data->drawstate.cliprect_dirty) {
icculus@12282
  1008
        const SDL_Rect *viewport = &data->drawstate.viewport;
icculus@12282
  1009
        const SDL_Rect *rect = &data->drawstate.cliprect;
icculus@12282
  1010
        data->glScissor(viewport->x + rect->x,
icculus@12282
  1011
                        data->drawstate.target ? viewport->y + rect->y : data->drawstate.drawableh - viewport->y - rect->y - rect->h,
icculus@12282
  1012
                        rect->w, rect->h);
icculus@12282
  1013
        data->drawstate.cliprect_dirty = SDL_FALSE;
icculus@12282
  1014
    }
icculus@12282
  1015
icculus@12237
  1016
    if (blend != data->drawstate.blend) {
icculus@12212
  1017
        if (blend == SDL_BLENDMODE_NONE) {
icculus@12212
  1018
            data->glDisable(GL_BLEND);
icculus@12212
  1019
        } else {
icculus@12212
  1020
            data->glEnable(GL_BLEND);
icculus@12212
  1021
            data->glBlendFuncSeparate(GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blend)),
icculus@12212
  1022
                                      GetBlendFunc(SDL_GetBlendModeDstColorFactor(blend)),
icculus@12212
  1023
                                      GetBlendFunc(SDL_GetBlendModeSrcAlphaFactor(blend)),
icculus@12212
  1024
                                      GetBlendFunc(SDL_GetBlendModeDstAlphaFactor(blend)));
icculus@12212
  1025
            data->glBlendEquation(GetBlendEquation(SDL_GetBlendModeColorOperation(blend)));
icculus@12212
  1026
        }
icculus@12237
  1027
        data->drawstate.blend = blend;
icculus@12212
  1028
    }
icculus@12212
  1029
icculus@12237
  1030
    if (data->shaders && (shader != data->drawstate.shader)) {
icculus@12212
  1031
        GL_SelectShader(data->shaders, shader);
icculus@12237
  1032
        data->drawstate.shader = shader;
icculus@12212
  1033
    }
icculus@12212
  1034
icculus@12237
  1035
    if ((cmd->data.draw.texture != NULL) != data->drawstate.texturing) {
icculus@12212
  1036
        if (cmd->data.draw.texture == NULL) {
icculus@12212
  1037
            data->glDisable(data->textype);
icculus@12237
  1038
            data->drawstate.texturing = SDL_FALSE;
icculus@12212
  1039
        } else {
icculus@12212
  1040
            data->glEnable(data->textype);
icculus@12237
  1041
            data->drawstate.texturing = SDL_TRUE;
icculus@12212
  1042
        }
icculus@12212
  1043
    }
icculus@12212
  1044
}
icculus@12212
  1045
icculus@12212
  1046
static void
icculus@12237
  1047
SetCopyState(GL_RenderData *data, const SDL_RenderCommand *cmd)
icculus@12212
  1048
{
icculus@12212
  1049
    SDL_Texture *texture = cmd->data.draw.texture;
icculus@12212
  1050
    const GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
slouken@12735
  1051
    GL_Shader shader;
slouken@12735
  1052
slouken@12735
  1053
    if (texture->format == SDL_PIXELFORMAT_ABGR8888 || texture->format == SDL_PIXELFORMAT_ARGB8888) {
slouken@12735
  1054
        shader = SHADER_RGBA;
slouken@12735
  1055
    } else {
slouken@12735
  1056
        shader = SHADER_RGB;
slouken@12735
  1057
    }
icculus@12212
  1058
icculus@12212
  1059
    if (data->shaders) {
icculus@12212
  1060
        if (texturedata->yuv || texturedata->nv12) {
icculus@12212
  1061
            switch (SDL_GetYUVConversionModeForResolution(texture->w, texture->h)) {
icculus@12212
  1062
                case SDL_YUV_CONVERSION_JPEG:
icculus@12212
  1063
                    if (texturedata->yuv) {
icculus@12212
  1064
                        shader = SHADER_YUV_JPEG;
icculus@12212
  1065
                    } else if (texture->format == SDL_PIXELFORMAT_NV12) {
icculus@12212
  1066
                        shader = SHADER_NV12_JPEG;
icculus@12212
  1067
                    } else {
icculus@12212
  1068
                        shader = SHADER_NV21_JPEG;
icculus@12212
  1069
                    }
icculus@12212
  1070
                    break;
icculus@12212
  1071
                case SDL_YUV_CONVERSION_BT601:
icculus@12212
  1072
                    if (texturedata->yuv) {
icculus@12212
  1073
                        shader = SHADER_YUV_BT601;
icculus@12212
  1074
                    } else if (texture->format == SDL_PIXELFORMAT_NV12) {
icculus@12212
  1075
                        shader = SHADER_NV12_BT601;
icculus@12212
  1076
                    } else {
icculus@12212
  1077
                        shader = SHADER_NV21_BT601;
icculus@12212
  1078
                    }
icculus@12212
  1079
                    break;
icculus@12212
  1080
                case SDL_YUV_CONVERSION_BT709:
icculus@12212
  1081
                    if (texturedata->yuv) {
icculus@12212
  1082
                        shader = SHADER_YUV_BT709;
icculus@12212
  1083
                    } else if (texture->format == SDL_PIXELFORMAT_NV12) {
icculus@12212
  1084
                        shader = SHADER_NV12_BT709;
icculus@12212
  1085
                    } else {
icculus@12212
  1086
                        shader = SHADER_NV21_BT709;
icculus@12212
  1087
                    }
icculus@12212
  1088
                    break;
icculus@12212
  1089
                default:
icculus@12212
  1090
                    SDL_assert(!"unsupported YUV conversion mode");
icculus@12212
  1091
                    break;
icculus@12212
  1092
            }
icculus@12212
  1093
        }
icculus@12212
  1094
    }
icculus@12212
  1095
icculus@12237
  1096
    SetDrawState(data, cmd, shader);
icculus@12212
  1097
icculus@12237
  1098
    if (texture != data->drawstate.texture) {
icculus@12212
  1099
        const GLenum textype = data->textype;
icculus@12212
  1100
        if (texturedata->yuv) {
icculus@12212
  1101
            data->glActiveTextureARB(GL_TEXTURE2_ARB);
icculus@12212
  1102
            data->glBindTexture(textype, texturedata->vtexture);
icculus@12212
  1103
icculus@12212
  1104
            data->glActiveTextureARB(GL_TEXTURE1_ARB);
icculus@12212
  1105
            data->glBindTexture(textype, texturedata->utexture);
icculus@12212
  1106
        }
icculus@12212
  1107
        if (texturedata->nv12) {
icculus@12212
  1108
            data->glActiveTextureARB(GL_TEXTURE1_ARB);
icculus@12212
  1109
            data->glBindTexture(textype, texturedata->utexture);
icculus@12212
  1110
        }
icculus@12212
  1111
        data->glActiveTextureARB(GL_TEXTURE0_ARB);
icculus@12212
  1112
        data->glBindTexture(textype, texturedata->texture);
icculus@12212
  1113
icculus@12237
  1114
        data->drawstate.texture = texture;
icculus@12212
  1115
    }
icculus@12212
  1116
}
icculus@12212
  1117
icculus@12212
  1118
static int
icculus@12212
  1119
GL_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
icculus@12212
  1120
{
icculus@12212
  1121
    /* !!! FIXME: it'd be nice to use a vertex buffer instead of immediate mode... */
icculus@12212
  1122
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
icculus@12212
  1123
    size_t i;
icculus@12212
  1124
icculus@12212
  1125
    if (GL_ActivateRenderer(renderer) < 0) {
icculus@12212
  1126
        return -1;
icculus@12212
  1127
    }
icculus@12212
  1128
icculus@12282
  1129
    data->drawstate.target = renderer->target;
icculus@12282
  1130
    if (!data->drawstate.target) {
icculus@12282
  1131
        SDL_GL_GetDrawableSize(renderer->window, &data->drawstate.drawablew, &data->drawstate.drawableh);
icculus@12212
  1132
    }
icculus@12212
  1133
icculus@12282
  1134
icculus@12212
  1135
    while (cmd) {
icculus@12212
  1136
        switch (cmd->command) {
icculus@12215
  1137
            case SDL_RENDERCMD_SETDRAWCOLOR: {
icculus@12237
  1138
                const Uint8 r = cmd->data.color.r;
icculus@12237
  1139
                const Uint8 g = cmd->data.color.g;
icculus@12237
  1140
                const Uint8 b = cmd->data.color.b;
icculus@12237
  1141
                const Uint8 a = cmd->data.color.a;
icculus@12237
  1142
                const Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b);
icculus@12237
  1143
                if (color != data->drawstate.color) {
icculus@12237
  1144
                    data->glColor4f((GLfloat) r * inv255f,
icculus@12237
  1145
                                    (GLfloat) g * inv255f,
icculus@12237
  1146
                                    (GLfloat) b * inv255f,
icculus@12237
  1147
                                    (GLfloat) a * inv255f);
icculus@12237
  1148
                    data->drawstate.color = color;
icculus@12237
  1149
                }
icculus@12215
  1150
                break;
icculus@12215
  1151
            }
icculus@12215
  1152
icculus@12212
  1153
            case SDL_RENDERCMD_SETVIEWPORT: {
icculus@12237
  1154
                SDL_Rect *viewport = &data->drawstate.viewport;
icculus@12237
  1155
                if (SDL_memcmp(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect)) != 0) {
icculus@12237
  1156
                    SDL_memcpy(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect));
icculus@12282
  1157
                    data->drawstate.viewport_dirty = SDL_TRUE;
icculus@12212
  1158
                }
icculus@12212
  1159
                break;
icculus@12212
  1160
            }
icculus@12212
  1161
icculus@12212
  1162
            case SDL_RENDERCMD_SETCLIPRECT: {
icculus@12212
  1163
                const SDL_Rect *rect = &cmd->data.cliprect.rect;
icculus@12237
  1164
                if (data->drawstate.cliprect_enabled != cmd->data.cliprect.enabled) {
icculus@12237
  1165
                    data->drawstate.cliprect_enabled = cmd->data.cliprect.enabled;
icculus@12282
  1166
                    data->drawstate.cliprect_enabled_dirty = SDL_TRUE;
icculus@12282
  1167
                }
icculus@12282
  1168
                if (SDL_memcmp(&data->drawstate.cliprect, rect, sizeof (SDL_Rect)) != 0) {
icculus@12282
  1169
                    SDL_memcpy(&data->drawstate.cliprect, rect, sizeof (SDL_Rect));
icculus@12282
  1170
                    data->drawstate.cliprect_dirty = SDL_TRUE;
icculus@12212
  1171
                }
icculus@12212
  1172
                break;
icculus@12212
  1173
            }
icculus@12212
  1174
icculus@12212
  1175
            case SDL_RENDERCMD_CLEAR: {
icculus@12237
  1176
                const Uint8 r = cmd->data.color.r;
icculus@12237
  1177
                const Uint8 g = cmd->data.color.g;
icculus@12237
  1178
                const Uint8 b = cmd->data.color.b;
icculus@12237
  1179
                const Uint8 a = cmd->data.color.a;
icculus@12237
  1180
                const Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b);
icculus@12237
  1181
                if (color != data->drawstate.clear_color) {
icculus@12237
  1182
                    const GLfloat fr = ((GLfloat) r) * inv255f;
icculus@12237
  1183
                    const GLfloat fg = ((GLfloat) g) * inv255f;
icculus@12237
  1184
                    const GLfloat fb = ((GLfloat) b) * inv255f;
icculus@12237
  1185
                    const GLfloat fa = ((GLfloat) a) * inv255f;
icculus@12237
  1186
                    data->glClearColor(fr, fg, fb, fa);
icculus@12237
  1187
                    data->drawstate.clear_color = color;
icculus@12237
  1188
                }
icculus@12212
  1189
slime73@13037
  1190
                if (data->drawstate.cliprect_enabled || data->drawstate.cliprect_enabled_dirty) {
icculus@12212
  1191
                    data->glDisable(GL_SCISSOR_TEST);
slime73@13037
  1192
                    data->drawstate.cliprect_enabled_dirty = data->drawstate.cliprect_enabled;
icculus@12212
  1193
                }
icculus@12212
  1194
icculus@12212
  1195
                data->glClear(GL_COLOR_BUFFER_BIT);
icculus@12212
  1196
icculus@12212
  1197
                break;
icculus@12212
  1198
            }
icculus@12212
  1199
icculus@12212
  1200
            case SDL_RENDERCMD_DRAW_POINTS: {
icculus@12212
  1201
                const size_t count = cmd->data.draw.count;
icculus@12212
  1202
                const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
icculus@12237
  1203
                SetDrawState(data, cmd, SHADER_SOLID);
icculus@12212
  1204
                data->glBegin(GL_POINTS);
icculus@12212
  1205
                for (i = 0; i < count; i++, verts += 2) {
icculus@12212
  1206
                    data->glVertex2f(verts[0], verts[1]);
icculus@12212
  1207
                }
icculus@12212
  1208
                data->glEnd();
icculus@12212
  1209
                break;
icculus@12212
  1210
            }
icculus@12212
  1211
icculus@12212
  1212
            case SDL_RENDERCMD_DRAW_LINES: {
icculus@12212
  1213
                const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
icculus@12237
  1214
                const size_t count = cmd->data.draw.count;
icculus@12237
  1215
                SetDrawState(data, cmd, SHADER_SOLID);
icculus@13536
  1216
                if (count > 2 && (verts[0] == verts[(count-1)*2]) && (verts[1] == verts[(count*2)-1])) {
icculus@13536
  1217
                    data->glBegin(GL_LINE_LOOP);
icculus@13536
  1218
                    /* GL_LINE_LOOP takes care of the final segment */
icculus@13536
  1219
                    for (i = 1; i < count; ++i, verts += 2) {
icculus@13536
  1220
                        data->glVertex2f(verts[0], verts[1]);
icculus@13536
  1221
                    }
icculus@13536
  1222
                    data->glEnd();
icculus@13536
  1223
                } else {
icculus@13536
  1224
                    #if defined(__MACOSX__) || defined(__WIN32__)
icculus@13536
  1225
                    #else
icculus@13536
  1226
                    int x1, y1, x2, y2;
icculus@13536
  1227
                    #endif
icculus@13536
  1228
icculus@13536
  1229
                    data->glBegin(GL_LINE_STRIP);
icculus@13536
  1230
                    for (i = 0; i < count; ++i, verts += 2) {
icculus@13536
  1231
                        data->glVertex2f(verts[0], verts[1]);
icculus@13536
  1232
                    }
icculus@13536
  1233
                    data->glEnd();
icculus@13536
  1234
                    verts -= 2 * count;
icculus@13536
  1235
icculus@13536
  1236
                    /* The line is half open, so we need one more point to complete it.
icculus@13536
  1237
                     * http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node47.html
icculus@13536
  1238
                     * If we have to, we can use vertical line and horizontal line textures
icculus@13536
  1239
                     * for vertical and horizontal lines, and then create custom textures
icculus@13536
  1240
                     * for diagonal lines and software render those.  It's terrible, but at
icculus@13536
  1241
                     * least it would be pixel perfect.
icculus@13536
  1242
                     */
icculus@13536
  1243
icculus@13536
  1244
                    data->glBegin(GL_POINTS);
icculus@13536
  1245
                    #if defined(__MACOSX__) || defined(__WIN32__)
icculus@13536
  1246
                    /* Mac OS X and Windows seem to always leave the last point open */
icculus@13536
  1247
                    data->glVertex2f(verts[(count-1)*2], verts[(count*2)-1]);
icculus@13536
  1248
                    #else
icculus@13536
  1249
                    /* Linux seems to leave the right-most or bottom-most point open */
icculus@13536
  1250
                    x1 = verts[0];
icculus@13536
  1251
                    y1 = verts[1];
icculus@13536
  1252
                    x2 = verts[(count-1)*2];
icculus@13536
  1253
                    y2 = verts[(count*2)-1];
icculus@13536
  1254
icculus@13536
  1255
                    if (x1 > x2) {
icculus@13536
  1256
                        data->glVertex2f(x1, y1);
icculus@13536
  1257
                    } else if (x2 > x1) {
icculus@13536
  1258
                        data->glVertex2f(x2, y2);
icculus@13536
  1259
                    }
icculus@13536
  1260
                    if (y1 > y2) {
icculus@13536
  1261
                        data->glVertex2f(x1, y1);
icculus@13536
  1262
                    } else if (y2 > y1) {
icculus@13536
  1263
                        data->glVertex2f(x2, y2);
icculus@13536
  1264
                    }
icculus@13536
  1265
                    #endif
icculus@13536
  1266
                    data->glEnd();
icculus@12212
  1267
                }
icculus@12212
  1268
                break;
icculus@12212
  1269
            }
icculus@12212
  1270
icculus@12212
  1271
            case SDL_RENDERCMD_FILL_RECTS: {
icculus@12212
  1272
                const size_t count = cmd->data.draw.count;
icculus@12212
  1273
                const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
icculus@12237
  1274
                SetDrawState(data, cmd, SHADER_SOLID);
icculus@12212
  1275
                for (i = 0; i < count; ++i, verts += 4) {
icculus@12212
  1276
                    data->glRectf(verts[0], verts[1], verts[2], verts[3]);
icculus@12212
  1277
                }
icculus@12212
  1278
                break;
icculus@12212
  1279
            }
icculus@12212
  1280
icculus@12212
  1281
            case SDL_RENDERCMD_COPY: {
icculus@12212
  1282
                const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
icculus@12212
  1283
                const GLfloat minx = verts[0];
icculus@12212
  1284
                const GLfloat miny = verts[1];
icculus@12212
  1285
                const GLfloat maxx = verts[2];
icculus@12212
  1286
                const GLfloat maxy = verts[3];
icculus@12212
  1287
                const GLfloat minu = verts[4];
icculus@12212
  1288
                const GLfloat maxu = verts[5];
icculus@12212
  1289
                const GLfloat minv = verts[6];
icculus@12212
  1290
                const GLfloat maxv = verts[7];
icculus@12237
  1291
                SetCopyState(data, cmd);
icculus@12212
  1292
                data->glBegin(GL_TRIANGLE_STRIP);
icculus@12212
  1293
                data->glTexCoord2f(minu, minv);
icculus@12212
  1294
                data->glVertex2f(minx, miny);
icculus@12212
  1295
                data->glTexCoord2f(maxu, minv);
icculus@12212
  1296
                data->glVertex2f(maxx, miny);
icculus@12212
  1297
                data->glTexCoord2f(minu, maxv);
icculus@12212
  1298
                data->glVertex2f(minx, maxy);
icculus@12212
  1299
                data->glTexCoord2f(maxu, maxv);
icculus@12212
  1300
                data->glVertex2f(maxx, maxy);
icculus@12212
  1301
                data->glEnd();
icculus@12212
  1302
                break;
icculus@12212
  1303
            }
icculus@12212
  1304
icculus@12212
  1305
            case SDL_RENDERCMD_COPY_EX: {
icculus@12212
  1306
                const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
icculus@12212
  1307
                const GLfloat minx = verts[0];
icculus@12212
  1308
                const GLfloat miny = verts[1];
icculus@12212
  1309
                const GLfloat maxx = verts[2];
icculus@12212
  1310
                const GLfloat maxy = verts[3];
icculus@12212
  1311
                const GLfloat minu = verts[4];
icculus@12212
  1312
                const GLfloat maxu = verts[5];
icculus@12212
  1313
                const GLfloat minv = verts[6];
icculus@12212
  1314
                const GLfloat maxv = verts[7];
icculus@12212
  1315
                const GLfloat translatex = verts[8];
icculus@12212
  1316
                const GLfloat translatey = verts[9];
icculus@12212
  1317
                const GLdouble angle = verts[10];
icculus@12237
  1318
                SetCopyState(data, cmd);
icculus@12212
  1319
icculus@12212
  1320
                /* Translate to flip, rotate, translate to position */
icculus@12212
  1321
                data->glPushMatrix();
icculus@12212
  1322
                data->glTranslatef(translatex, translatey, 0.0f);
icculus@12212
  1323
                data->glRotated(angle, 0.0, 0.0, 1.0);
icculus@12212
  1324
                data->glBegin(GL_TRIANGLE_STRIP);
icculus@12212
  1325
                data->glTexCoord2f(minu, minv);
icculus@12212
  1326
                data->glVertex2f(minx, miny);
icculus@12212
  1327
                data->glTexCoord2f(maxu, minv);
icculus@12212
  1328
                data->glVertex2f(maxx, miny);
icculus@12212
  1329
                data->glTexCoord2f(minu, maxv);
icculus@12212
  1330
                data->glVertex2f(minx, maxy);
icculus@12212
  1331
                data->glTexCoord2f(maxu, maxv);
icculus@12212
  1332
                data->glVertex2f(maxx, maxy);
icculus@12212
  1333
                data->glEnd();
icculus@12212
  1334
                data->glPopMatrix();
icculus@12212
  1335
                break;
icculus@12212
  1336
            }
icculus@12212
  1337
icculus@12212
  1338
            case SDL_RENDERCMD_NO_OP:
icculus@12212
  1339
                break;
icculus@12212
  1340
        }
icculus@12212
  1341
icculus@12212
  1342
        cmd = cmd->next;
icculus@12212
  1343
    }
gabomdq@6320
  1344
slouken@7194
  1345
    return GL_CheckError("", renderer);
gabomdq@6320
  1346
}
gabomdq@6320
  1347
gabomdq@6320
  1348
static int
slouken@3431
  1349
GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
slouken@3435
  1350
                    Uint32 pixel_format, void * pixels, int pitch)
slouken@3431
  1351
{
slouken@3433
  1352
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
philipp@10456
  1353
    Uint32 temp_format = renderer->target ? renderer->target->format : SDL_PIXELFORMAT_ARGB8888;
slouken@5465
  1354
    void *temp_pixels;
slouken@5465
  1355
    int temp_pitch;
slouken@3433
  1356
    GLint internalFormat;
slouken@3433
  1357
    GLenum format, type;
slouken@3435
  1358
    Uint8 *src, *dst, *tmp;
slouken@5154
  1359
    int w, h, length, rows;
slouken@5465
  1360
    int status;
slouken@3433
  1361
slouken@5147
  1362
    GL_ActivateRenderer(renderer);
slouken@5147
  1363
icculus@10650
  1364
    if (!convert_format(data, temp_format, &internalFormat, &format, &type)) {
icculus@10650
  1365
        return SDL_SetError("Texture format %s not supported by OpenGL",
icculus@10650
  1366
                            SDL_GetPixelFormatName(temp_format));
icculus@10650
  1367
    }
icculus@10650
  1368
icculus@10650
  1369
    if (!rect->w || !rect->h) {
icculus@10650
  1370
        return 0;  /* nothing to do. */
icculus@10650
  1371
    }
icculus@10650
  1372
slouken@5465
  1373
    temp_pitch = rect->w * SDL_BYTESPERPIXEL(temp_format);
slouken@5465
  1374
    temp_pixels = SDL_malloc(rect->h * temp_pitch);
slouken@5465
  1375
    if (!temp_pixels) {
icculus@7037
  1376
        return SDL_OutOfMemory();
slouken@3433
  1377
    }
slouken@3433
  1378
slouken@7420
  1379
    SDL_GetRendererOutputSize(renderer, &w, &h);
slouken@5154
  1380
slouken@3446
  1381
    data->glPixelStorei(GL_PACK_ALIGNMENT, 1);
slouken@3446
  1382
    data->glPixelStorei(GL_PACK_ROW_LENGTH,
slouken@5465
  1383
                        (temp_pitch / SDL_BYTESPERPIXEL(temp_format)));
slouken@3433
  1384
slouken@10405
  1385
    data->glReadPixels(rect->x, renderer->target ? rect->y : (h-rect->y)-rect->h,
slouken@10405
  1386
                       rect->w, rect->h, format, type, temp_pixels);
slouken@3435
  1387
slouken@7779
  1388
    if (GL_CheckError("glReadPixels()", renderer) < 0) {
slouken@9115
  1389
        SDL_free(temp_pixels);
slouken@7779
  1390
        return -1;
slouken@7779
  1391
    }
slouken@6494
  1392
slouken@10405
  1393
    /* Flip the rows to be top-down if necessary */
slouken@10405
  1394
    if (!renderer->target) {
icculus@12349
  1395
        SDL_bool isstack;
slouken@10405
  1396
        length = rect->w * SDL_BYTESPERPIXEL(temp_format);
slouken@10405
  1397
        src = (Uint8*)temp_pixels + (rect->h-1)*temp_pitch;
slouken@10405
  1398
        dst = (Uint8*)temp_pixels;
icculus@12349
  1399
        tmp = SDL_small_alloc(Uint8, length, &isstack);
slouken@10405
  1400
        rows = rect->h / 2;
slouken@10405
  1401
        while (rows--) {
slouken@10405
  1402
            SDL_memcpy(tmp, dst, length);
slouken@10405
  1403
            SDL_memcpy(dst, src, length);
slouken@10405
  1404
            SDL_memcpy(src, tmp, length);
slouken@10405
  1405
            dst += temp_pitch;
slouken@10405
  1406
            src -= temp_pitch;
slouken@10405
  1407
        }
icculus@12349
  1408
        SDL_small_free(tmp, isstack);
slouken@3435
  1409
    }
slouken@3440
  1410
slouken@5465
  1411
    status = SDL_ConvertPixels(rect->w, rect->h,
slouken@5465
  1412
                               temp_format, temp_pixels, temp_pitch,
slouken@5465
  1413
                               pixel_format, pixels, pitch);
slouken@5465
  1414
    SDL_free(temp_pixels);
slouken@5465
  1415
slouken@5465
  1416
    return status;
slouken@3431
  1417
}
slouken@3431
  1418
slouken@1918
  1419
static void
slouken@1918
  1420
GL_RenderPresent(SDL_Renderer * renderer)
slouken@1918
  1421
{
slouken@5147
  1422
    GL_ActivateRenderer(renderer);
slouken@5147
  1423
slouken@1918
  1424
    SDL_GL_SwapWindow(renderer->window);
slouken@1918
  1425
}
slouken@1918
  1426
slouken@1918
  1427
static void
slouken@1918
  1428
GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@1918
  1429
{
slouken@1927
  1430
    GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
slouken@1918
  1431
    GL_TextureData *data = (GL_TextureData *) texture->driverdata;
slouken@1918
  1432
slouken@5147
  1433
    GL_ActivateRenderer(renderer);
slouken@5147
  1434
slime73@12483
  1435
    if (renderdata->drawstate.texture == texture) {
slime73@12483
  1436
        renderdata->drawstate.texture = NULL;
slime73@12483
  1437
    }
slime73@12483
  1438
    if (renderdata->drawstate.target == texture) {
slime73@12483
  1439
        renderdata->drawstate.target = NULL;
slime73@12483
  1440
    }
slime73@12483
  1441
slouken@1918
  1442
    if (!data) {
slouken@1918
  1443
        return;
slouken@1918
  1444
    }
slouken@1918
  1445
    if (data->texture) {
slouken@1927
  1446
        renderdata->glDeleteTextures(1, &data->texture);
slouken@1918
  1447
    }
slouken@5264
  1448
    if (data->yuv) {
slouken@5264
  1449
        renderdata->glDeleteTextures(1, &data->utexture);
slouken@5264
  1450
        renderdata->glDeleteTextures(1, &data->vtexture);
slouken@5264
  1451
    }
slouken@7719
  1452
    SDL_free(data->pixels);
slouken@1918
  1453
    SDL_free(data);
slouken@1918
  1454
    texture->driverdata = NULL;
slouken@1918
  1455
}
slouken@1918
  1456
slouken@1975
  1457
static void
slouken@1918
  1458
GL_DestroyRenderer(SDL_Renderer * renderer)
slouken@1918
  1459
{
slouken@1918
  1460
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
slouken@1918
  1461
slouken@1918
  1462
    if (data) {
icculus@11013
  1463
        if (data->context != NULL) {
icculus@11013
  1464
            /* make sure we delete the right resources! */
icculus@11013
  1465
            GL_ActivateRenderer(renderer);
icculus@11013
  1466
        }
icculus@11013
  1467
slouken@7194
  1468
        GL_ClearErrors(renderer);
slouken@7194
  1469
        if (data->GL_ARB_debug_output_supported) {
sezero@11872
  1470
            PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARBFunc = (PFNGLDEBUGMESSAGECALLBACKARBPROC) SDL_GL_GetProcAddress("glDebugMessageCallbackARB");
slouken@7194
  1471
slouken@7194
  1472
            /* Uh oh, we don't have a safe way of removing ourselves from the callback chain, if it changed after we set our callback. */
slouken@7194
  1473
            /* For now, just always replace the callback with the original one */
slouken@7194
  1474
            glDebugMessageCallbackARBFunc(data->next_error_callback, data->next_error_userparam);
slouken@7194
  1475
        }
icculus@5566
  1476
        if (data->shaders) {
icculus@5566
  1477
            GL_DestroyShaderContext(data->shaders);
icculus@5566
  1478
        }
slouken@1920
  1479
        if (data->context) {
slouken@6232
  1480
            while (data->framebuffers) {
slouken@6232
  1481
                GL_FBOList *nextnode = data->framebuffers->next;
slouken@6232
  1482
                /* delete the framebuffer object */
slouken@6232
  1483
                data->glDeleteFramebuffersEXT(1, &data->framebuffers->FBO);
slouken@6494
  1484
                GL_CheckError("", renderer);
slouken@6232
  1485
                SDL_free(data->framebuffers);
slouken@6232
  1486
                data->framebuffers = nextnode;
jorgen@7091
  1487
            }
slouken@1920
  1488
            SDL_GL_DeleteContext(data->context);
slouken@1918
  1489
        }
slouken@1918
  1490
        SDL_free(data);
slouken@1918
  1491
    }
slouken@1918
  1492
    SDL_free(renderer);
slouken@1918
  1493
}
slouken@1918
  1494
slouken@7194
  1495
static int
slouken@7194
  1496
GL_BindTexture (SDL_Renderer * renderer, SDL_Texture *texture, float *texw, float *texh)
slouken@7194
  1497
{
gabomdq@6414
  1498
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
gabomdq@6414
  1499
    GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
icculus@12212
  1500
    const GLenum textype = data->textype;
icculus@12212
  1501
gabomdq@6414
  1502
    GL_ActivateRenderer(renderer);
gabomdq@6414
  1503
icculus@12212
  1504
    data->glEnable(textype);
gabomdq@6414
  1505
    if (texturedata->yuv) {
gabomdq@6414
  1506
        data->glActiveTextureARB(GL_TEXTURE2_ARB);
icculus@12212
  1507
        data->glBindTexture(textype, texturedata->vtexture);
gabomdq@6414
  1508
gabomdq@6414
  1509
        data->glActiveTextureARB(GL_TEXTURE1_ARB);
icculus@12212
  1510
        data->glBindTexture(textype, texturedata->utexture);
gabomdq@6414
  1511
gabomdq@6414
  1512
        data->glActiveTextureARB(GL_TEXTURE0_ARB);
gabomdq@6414
  1513
    }
icculus@12212
  1514
    data->glBindTexture(textype, texturedata->texture);
gabomdq@6414
  1515
icculus@12592
  1516
    data->drawstate.texturing = SDL_TRUE;
icculus@12592
  1517
    data->drawstate.texture = texture;
icculus@12592
  1518
gabomdq@6414
  1519
    if(texw) *texw = (float)texturedata->texw;
gabomdq@6414
  1520
    if(texh) *texh = (float)texturedata->texh;
gabomdq@6414
  1521
gabomdq@6414
  1522
    return 0;
gabomdq@6414
  1523
}
gabomdq@6414
  1524
slouken@7194
  1525
static int
slouken@7194
  1526
GL_UnbindTexture (SDL_Renderer * renderer, SDL_Texture *texture)
slouken@7194
  1527
{
gabomdq@6414
  1528
    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
gabomdq@6414
  1529
    GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
icculus@12212
  1530
    const GLenum textype = data->textype;
icculus@12212
  1531
gabomdq@6414
  1532
    GL_ActivateRenderer(renderer);
gabomdq@6414
  1533
gabomdq@6414
  1534
    if (texturedata->yuv) {
gabomdq@6414
  1535
        data->glActiveTextureARB(GL_TEXTURE2_ARB);
icculus@12212
  1536
        data->glDisable(textype);
gabomdq@6414
  1537
gabomdq@6414
  1538
        data->glActiveTextureARB(GL_TEXTURE1_ARB);
icculus@12212
  1539
        data->glDisable(textype);
gabomdq@6414
  1540
gabomdq@6414
  1541
        data->glActiveTextureARB(GL_TEXTURE0_ARB);
gabomdq@6414
  1542
    }
slouken@7191
  1543
icculus@12212
  1544
    data->glDisable(textype);
gabomdq@6414
  1545
icculus@12592
  1546
    data->drawstate.texturing = SDL_FALSE;
icculus@12592
  1547
    data->drawstate.texture = NULL;
icculus@12592
  1548
gabomdq@6414
  1549
    return 0;
gabomdq@6414
  1550
}
gabomdq@6414
  1551
icculus@12218
  1552
icculus@12218
  1553
SDL_Renderer *
icculus@12218
  1554
GL_CreateRenderer(SDL_Window * window, Uint32 flags)
icculus@12218
  1555
{
icculus@12218
  1556
    SDL_Renderer *renderer;
icculus@12218
  1557
    GL_RenderData *data;
icculus@12218
  1558
    GLint value;
icculus@12218
  1559
    Uint32 window_flags;
icculus@12218
  1560
    int profile_mask = 0, major = 0, minor = 0;
icculus@12218
  1561
    SDL_bool changed_window = SDL_FALSE;
icculus@12218
  1562
icculus@12218
  1563
    SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profile_mask);
icculus@12218
  1564
    SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major);
icculus@12218
  1565
    SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor);
sylvain@12621
  1566
icculus@12218
  1567
    window_flags = SDL_GetWindowFlags(window);
icculus@12218
  1568
    if (!(window_flags & SDL_WINDOW_OPENGL) ||
icculus@12218
  1569
        profile_mask == SDL_GL_CONTEXT_PROFILE_ES || major != RENDERER_CONTEXT_MAJOR || minor != RENDERER_CONTEXT_MINOR) {
icculus@12218
  1570
icculus@12218
  1571
        changed_window = SDL_TRUE;
icculus@12218
  1572
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0);
icculus@12218
  1573
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, RENDERER_CONTEXT_MAJOR);
icculus@12218
  1574
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, RENDERER_CONTEXT_MINOR);
icculus@12218
  1575
icculus@12218
  1576
        if (SDL_RecreateWindow(window, window_flags | SDL_WINDOW_OPENGL) < 0) {
icculus@12218
  1577
            goto error;
icculus@12218
  1578
        }
icculus@12218
  1579
    }
icculus@12218
  1580
icculus@12218
  1581
    renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
icculus@12218
  1582
    if (!renderer) {
icculus@12218
  1583
        SDL_OutOfMemory();
icculus@12218
  1584
        goto error;
icculus@12218
  1585
    }
icculus@12218
  1586
icculus@12218
  1587
    data = (GL_RenderData *) SDL_calloc(1, sizeof(*data));
icculus@12218
  1588
    if (!data) {
icculus@12381
  1589
        SDL_free(renderer);
icculus@12218
  1590
        SDL_OutOfMemory();
icculus@12218
  1591
        goto error;
icculus@12218
  1592
    }
icculus@12218
  1593
icculus@12218
  1594
    renderer->GetOutputSize = GL_GetOutputSize;
icculus@12218
  1595
    renderer->SupportsBlendMode = GL_SupportsBlendMode;
icculus@12218
  1596
    renderer->CreateTexture = GL_CreateTexture;
icculus@12218
  1597
    renderer->UpdateTexture = GL_UpdateTexture;
icculus@12218
  1598
    renderer->UpdateTextureYUV = GL_UpdateTextureYUV;
icculus@12218
  1599
    renderer->LockTexture = GL_LockTexture;
icculus@12218
  1600
    renderer->UnlockTexture = GL_UnlockTexture;
slouken@13376
  1601
    renderer->SetTextureScaleMode = GL_SetTextureScaleMode;
icculus@12218
  1602
    renderer->SetRenderTarget = GL_SetRenderTarget;
icculus@12218
  1603
    renderer->QueueSetViewport = GL_QueueSetViewport;
icculus@12218
  1604
    renderer->QueueSetDrawColor = GL_QueueSetViewport;  /* SetViewport and SetDrawColor are (currently) no-ops. */
icculus@12218
  1605
    renderer->QueueDrawPoints = GL_QueueDrawPoints;
icculus@13536
  1606
    renderer->QueueDrawLines = GL_QueueDrawPoints;  /* lines and points queue vertices the same way. */
icculus@12218
  1607
    renderer->QueueFillRects = GL_QueueFillRects;
icculus@12218
  1608
    renderer->QueueCopy = GL_QueueCopy;
icculus@12218
  1609
    renderer->QueueCopyEx = GL_QueueCopyEx;
icculus@12218
  1610
    renderer->RunCommandQueue = GL_RunCommandQueue;
icculus@12218
  1611
    renderer->RenderReadPixels = GL_RenderReadPixels;
icculus@12218
  1612
    renderer->RenderPresent = GL_RenderPresent;
icculus@12218
  1613
    renderer->DestroyTexture = GL_DestroyTexture;
icculus@12218
  1614
    renderer->DestroyRenderer = GL_DestroyRenderer;
icculus@12218
  1615
    renderer->GL_BindTexture = GL_BindTexture;
icculus@12218
  1616
    renderer->GL_UnbindTexture = GL_UnbindTexture;
icculus@12218
  1617
    renderer->info = GL_RenderDriver.info;
icculus@12218
  1618
    renderer->info.flags = SDL_RENDERER_ACCELERATED;
icculus@12218
  1619
    renderer->driverdata = data;
icculus@12218
  1620
    renderer->window = window;
icculus@12218
  1621
icculus@12218
  1622
    data->context = SDL_GL_CreateContext(window);
icculus@12218
  1623
    if (!data->context) {
icculus@12381
  1624
        SDL_free(renderer);
icculus@12381
  1625
        SDL_free(data);
icculus@12218
  1626
        goto error;
icculus@12218
  1627
    }
icculus@12218
  1628
    if (SDL_GL_MakeCurrent(window, data->context) < 0) {
icculus@12381
  1629
        SDL_GL_DeleteContext(data->context);
icculus@12381
  1630
        SDL_free(renderer);
icculus@12381
  1631
        SDL_free(data);
icculus@12218
  1632
        goto error;
icculus@12218
  1633
    }
icculus@12218
  1634
icculus@12218
  1635
    if (GL_LoadFunctions(data) < 0) {
icculus@12381
  1636
        SDL_GL_DeleteContext(data->context);
icculus@12381
  1637
        SDL_free(renderer);
icculus@12381
  1638
        SDL_free(data);
icculus@12218
  1639
        goto error;
icculus@12218
  1640
    }
icculus@12218
  1641
icculus@12218
  1642
#ifdef __MACOSX__
icculus@12218
  1643
    /* Enable multi-threaded rendering */
icculus@12218
  1644
    /* Disabled until Ryan finishes his VBO/PBO code...
icculus@12218
  1645
       CGLEnable(CGLGetCurrentContext(), kCGLCEMPEngine);
icculus@12218
  1646
     */
icculus@12218
  1647
#endif
icculus@12218
  1648
icculus@12218
  1649
    if (flags & SDL_RENDERER_PRESENTVSYNC) {
icculus@12218
  1650
        SDL_GL_SetSwapInterval(1);
icculus@12218
  1651
    } else {
icculus@12218
  1652
        SDL_GL_SetSwapInterval(0);
icculus@12218
  1653
    }
icculus@12218
  1654
    if (SDL_GL_GetSwapInterval() > 0) {
icculus@12218
  1655
        renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
icculus@12218
  1656
    }
icculus@12218
  1657
icculus@12218
  1658
    /* Check for debug output support */
icculus@12218
  1659
    if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_FLAGS, &value) == 0 &&
icculus@12218
  1660
        (value & SDL_GL_CONTEXT_DEBUG_FLAG)) {
icculus@12218
  1661
        data->debug_enabled = SDL_TRUE;
icculus@12218
  1662
    }
icculus@12218
  1663
    if (data->debug_enabled && SDL_GL_ExtensionSupported("GL_ARB_debug_output")) {
icculus@12218
  1664
        PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARBFunc = (PFNGLDEBUGMESSAGECALLBACKARBPROC) SDL_GL_GetProcAddress("glDebugMessageCallbackARB");
icculus@12218
  1665
icculus@12218
  1666
        data->GL_ARB_debug_output_supported = SDL_TRUE;
icculus@12218
  1667
        data->glGetPointerv(GL_DEBUG_CALLBACK_FUNCTION_ARB, (GLvoid **)(char *)&data->next_error_callback);
icculus@12218
  1668
        data->glGetPointerv(GL_DEBUG_CALLBACK_USER_PARAM_ARB, &data->next_error_userparam);
icculus@12218
  1669
        glDebugMessageCallbackARBFunc(GL_HandleDebugMessage, renderer);
icculus@12218
  1670
icculus@12218
  1671
        /* Make sure our callback is called when errors actually happen */
icculus@12218
  1672
        data->glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
icculus@12218
  1673
    }
icculus@12218
  1674
icculus@12218
  1675
    data->textype = GL_TEXTURE_2D;
icculus@12218
  1676
    if (SDL_GL_ExtensionSupported("GL_ARB_texture_non_power_of_two")) {
icculus@12218
  1677
        data->GL_ARB_texture_non_power_of_two_supported = SDL_TRUE;
icculus@12218
  1678
    } else if (SDL_GL_ExtensionSupported("GL_ARB_texture_rectangle") ||
icculus@12218
  1679
               SDL_GL_ExtensionSupported("GL_EXT_texture_rectangle")) {
icculus@12218
  1680
        data->GL_ARB_texture_rectangle_supported = SDL_TRUE;
icculus@12218
  1681
        data->textype = GL_TEXTURE_RECTANGLE_ARB;
icculus@12218
  1682
    }
icculus@12218
  1683
    if (data->GL_ARB_texture_rectangle_supported) {
icculus@12218
  1684
        data->glGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB, &value);
icculus@12218
  1685
        renderer->info.max_texture_width = value;
icculus@12218
  1686
        renderer->info.max_texture_height = value;
icculus@12218
  1687
    } else {
icculus@12218
  1688
        data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
icculus@12218
  1689
        renderer->info.max_texture_width = value;
icculus@12218
  1690
        renderer->info.max_texture_height = value;
icculus@12218
  1691
    }
icculus@12218
  1692
icculus@12218
  1693
    /* Check for multitexture support */
icculus@12218
  1694
    if (SDL_GL_ExtensionSupported("GL_ARB_multitexture")) {
icculus@12218
  1695
        data->glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC) SDL_GL_GetProcAddress("glActiveTextureARB");
icculus@12218
  1696
        if (data->glActiveTextureARB) {
icculus@12218
  1697
            data->GL_ARB_multitexture_supported = SDL_TRUE;
icculus@12218
  1698
            data->glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &data->num_texture_units);
icculus@12218
  1699
        }
icculus@12218
  1700
    }
icculus@12218
  1701
icculus@12218
  1702
    /* Check for shader support */
icculus@12218
  1703
    if (SDL_GetHintBoolean(SDL_HINT_RENDER_OPENGL_SHADERS, SDL_TRUE)) {
icculus@12218
  1704
        data->shaders = GL_CreateShaderContext();
icculus@12218
  1705
    }
icculus@12218
  1706
    SDL_LogInfo(SDL_LOG_CATEGORY_RENDER, "OpenGL shaders: %s",
icculus@12218
  1707
                data->shaders ? "ENABLED" : "DISABLED");
icculus@12218
  1708
icculus@12218
  1709
    /* We support YV12 textures using 3 textures and a shader */
icculus@12218
  1710
    if (data->shaders && data->num_texture_units >= 3) {
icculus@12218
  1711
        renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;
icculus@12218
  1712
        renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
icculus@12218
  1713
        renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_NV12;
icculus@12218
  1714
        renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_NV21;
icculus@12218
  1715
    }
icculus@12218
  1716
icculus@12218
  1717
#ifdef __MACOSX__
icculus@12218
  1718
    renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_UYVY;
icculus@12218
  1719
#endif
icculus@12218
  1720
icculus@12218
  1721
    if (SDL_GL_ExtensionSupported("GL_EXT_framebuffer_object")) {
icculus@12218
  1722
        data->GL_EXT_framebuffer_object_supported = SDL_TRUE;
icculus@12218
  1723
        data->glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC)
icculus@12218
  1724
            SDL_GL_GetProcAddress("glGenFramebuffersEXT");
icculus@12218
  1725
        data->glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC)
icculus@12218
  1726
            SDL_GL_GetProcAddress("glDeleteFramebuffersEXT");
icculus@12218
  1727
        data->glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)
icculus@12218
  1728
            SDL_GL_GetProcAddress("glFramebufferTexture2DEXT");
icculus@12218
  1729
        data->glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)
icculus@12218
  1730
            SDL_GL_GetProcAddress("glBindFramebufferEXT");
icculus@12218
  1731
        data->glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)
icculus@12218
  1732
            SDL_GL_GetProcAddress("glCheckFramebufferStatusEXT");
icculus@12218
  1733
        renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE;
icculus@12218
  1734
    }
icculus@12218
  1735
    data->framebuffers = NULL;
icculus@12218
  1736
icculus@12218
  1737
    /* Set up parameters for rendering */
icculus@12237
  1738
    data->glMatrixMode(GL_MODELVIEW);
icculus@12237
  1739
    data->glLoadIdentity();
icculus@12218
  1740
    data->glDisable(GL_DEPTH_TEST);
icculus@12218
  1741
    data->glDisable(GL_CULL_FACE);
icculus@12237
  1742
    data->glDisable(GL_SCISSOR_TEST);
icculus@12237
  1743
    data->glDisable(data->textype);
icculus@12237
  1744
    data->glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
icculus@12237
  1745
    data->glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
icculus@12218
  1746
    /* This ended up causing video discrepancies between OpenGL and Direct3D */
icculus@12218
  1747
    /* data->glEnable(GL_LINE_SMOOTH); */
icculus@12218
  1748
slouken@12417
  1749
    data->drawstate.blend = SDL_BLENDMODE_INVALID;
icculus@12237
  1750
    data->drawstate.shader = SHADER_INVALID;
icculus@12237
  1751
    data->drawstate.color = 0xFFFFFFFF;
icculus@12237
  1752
    data->drawstate.clear_color = 0xFFFFFFFF;
icculus@12237
  1753
icculus@12218
  1754
    return renderer;
icculus@12218
  1755
icculus@12218
  1756
error:
icculus@12218
  1757
    if (changed_window) {
icculus@12218
  1758
        /* Uh oh, better try to put it back... */
icculus@12218
  1759
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profile_mask);
icculus@12218
  1760
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major);
icculus@12218
  1761
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minor);
icculus@12218
  1762
        SDL_RecreateWindow(window, window_flags);
icculus@12218
  1763
    }
icculus@12218
  1764
    return NULL;
icculus@12218
  1765
}
icculus@12218
  1766
icculus@12218
  1767
icculus@12218
  1768
SDL_RenderDriver GL_RenderDriver = {
icculus@12218
  1769
    GL_CreateRenderer,
icculus@12218
  1770
    {
icculus@12218
  1771
     "opengl",
icculus@12218
  1772
     (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
slouken@12735
  1773
     4,
slouken@12735
  1774
     {
slouken@12735
  1775
         SDL_PIXELFORMAT_ARGB8888,
slouken@12735
  1776
         SDL_PIXELFORMAT_ABGR8888,
slouken@12735
  1777
         SDL_PIXELFORMAT_RGB888,
slouken@12735
  1778
         SDL_PIXELFORMAT_BGR888
slouken@12735
  1779
     },
icculus@12218
  1780
     0,
icculus@12218
  1781
     0}
icculus@12218
  1782
};
icculus@12218
  1783
icculus@12218
  1784
slouken@5226
  1785
#endif /* SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED */
slouken@1918
  1786
slouken@1918
  1787
/* vi: set ts=4 sw=4 expandtab: */