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