src/render/direct3d/SDL_render_d3d.c
author Ryan C. Gordon <icculus@icculus.org>
Fri, 21 Jun 2019 15:07:39 -0400
changeset 12900 9d3f245739f8
parent 12898 89b3e1e9839c
permissions -rw-r--r--
direct3d: Use D3DPOOL_DEFAULT for vertex buffers after all, release correctly.

Fixes Bugzilla #4679.
Fixes Bugzilla #4537.
slouken@1895
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@12503
     3
  Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
slouken@1895
     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@1895
     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@1895
    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@1895
    20
*/
icculus@8093
    21
#include "../../SDL_internal.h"
slouken@1895
    22
slouken@8193
    23
#include "SDL_render.h"
slouken@8193
    24
#include "SDL_system.h"
slouken@8193
    25
slouken@5226
    26
#if SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED
slouken@5226
    27
slouken@5154
    28
#include "../../core/windows/SDL_windows.h"
slouken@5154
    29
slouken@5484
    30
#include "SDL_hints.h"
slouken@5154
    31
#include "SDL_loadso.h"
slouken@5154
    32
#include "SDL_syswm.h"
icculus@12279
    33
#include "SDL_log.h"
icculus@12279
    34
#include "SDL_assert.h"
slouken@5154
    35
#include "../SDL_sysrender.h"
slouken@8599
    36
#include "../SDL_d3dmath.h"
slouken@7762
    37
#include "../../video/windows/SDL_windowsvideo.h"
slouken@5154
    38
slouken@5154
    39
#if SDL_VIDEO_RENDER_D3D
slouken@5154
    40
#define D3D_DEBUG_INFO
slouken@5154
    41
#include <d3d9.h>
slouken@5154
    42
#endif
slouken@1895
    43
slouken@11702
    44
#include "SDL_shaders_d3d.h"
slouken@3556
    45
icculus@12278
    46
typedef struct
icculus@12278
    47
{
icculus@12278
    48
    SDL_Rect viewport;
icculus@12278
    49
    SDL_bool viewport_dirty;
icculus@12278
    50
    SDL_Texture *texture;
icculus@12278
    51
    SDL_BlendMode blend;
icculus@12278
    52
    SDL_bool cliprect_enabled;
icculus@12278
    53
    SDL_bool cliprect_enabled_dirty;
icculus@12278
    54
    SDL_Rect cliprect;
icculus@12278
    55
    SDL_bool cliprect_dirty;
icculus@12278
    56
    SDL_bool is_copy_ex;
icculus@12278
    57
    LPDIRECT3DPIXELSHADER9 shader;
icculus@12278
    58
} D3D_DrawStateCache;
icculus@12278
    59
slouken@3556
    60
slouken@1895
    61
/* Direct3D renderer implementation */
slouken@1895
    62
slouken@1895
    63
typedef struct
slouken@1895
    64
{
slouken@5154
    65
    void* d3dDLL;
slouken@2973
    66
    IDirect3D9 *d3d;
slouken@1895
    67
    IDirect3DDevice9 *device;
slouken@3527
    68
    UINT adapter;
slouken@1975
    69
    D3DPRESENT_PARAMETERS pparams;
slouken@5297
    70
    SDL_bool updateSize;
slouken@1900
    71
    SDL_bool beginScene;
slouken@7502
    72
    SDL_bool enableSeparateAlphaBlend;
slouken@7505
    73
    D3DTEXTUREFILTERTYPE scaleMode[8];
slouken@6232
    74
    IDirect3DSurface9 *defaultRenderTarget;
slouken@6232
    75
    IDirect3DSurface9 *currentRenderTarget;
gabomdq@6320
    76
    void* d3dxDLL;
slouken@11702
    77
    LPDIRECT3DPIXELSHADER9 shaders[NUM_SHADERS];
icculus@12279
    78
    LPDIRECT3DVERTEXBUFFER9 vertexBuffers[8];
icculus@12279
    79
    size_t vertexBufferSize[8];
icculus@12278
    80
    int currentVertexBuffer;
icculus@12278
    81
    SDL_bool reportedVboProblem;
icculus@12278
    82
    D3D_DrawStateCache drawstate;
slouken@1913
    83
} D3D_RenderData;
slouken@1895
    84
slouken@1895
    85
typedef struct
slouken@1895
    86
{
slouken@8822
    87
    SDL_bool dirty;
slouken@9074
    88
    int w, h;
slouken@9074
    89
    DWORD usage;
slouken@9074
    90
    Uint32 format;
slouken@11702
    91
    D3DFORMAT d3dfmt;
slouken@1903
    92
    IDirect3DTexture9 *texture;
slouken@8792
    93
    IDirect3DTexture9 *staging;
slouken@8792
    94
} D3D_TextureRep;
slouken@8792
    95
slouken@8792
    96
typedef struct
slouken@8792
    97
{
slouken@8792
    98
    D3D_TextureRep texture;
slouken@5484
    99
    D3DTEXTUREFILTERTYPE scaleMode;
slouken@7505
   100
slouken@7505
   101
    /* YV12 texture support */
slouken@7505
   102
    SDL_bool yuv;
slouken@8792
   103
    D3D_TextureRep utexture;
slouken@8792
   104
    D3D_TextureRep vtexture;
slouken@7505
   105
    Uint8 *pixels;
slouken@7505
   106
    int pitch;
slouken@7505
   107
    SDL_Rect locked_rect;
slouken@1913
   108
} D3D_TextureData;
slouken@1895
   109
slouken@1903
   110
typedef struct
slouken@1903
   111
{
slouken@1903
   112
    float x, y, z;
slouken@1987
   113
    DWORD color;
slouken@1904
   114
    float u, v;
slouken@1903
   115
} Vertex;
slouken@1903
   116
icculus@7037
   117
static int
slouken@1900
   118
D3D_SetError(const char *prefix, HRESULT result)
slouken@1900
   119
{
slouken@1900
   120
    const char *error;
slouken@1900
   121
slouken@1900
   122
    switch (result) {
slouken@1900
   123
    case D3DERR_WRONGTEXTUREFORMAT:
slouken@1900
   124
        error = "WRONGTEXTUREFORMAT";
slouken@1900
   125
        break;
slouken@1900
   126
    case D3DERR_UNSUPPORTEDCOLOROPERATION:
slouken@1900
   127
        error = "UNSUPPORTEDCOLOROPERATION";
slouken@1900
   128
        break;
slouken@1900
   129
    case D3DERR_UNSUPPORTEDCOLORARG:
slouken@1900
   130
        error = "UNSUPPORTEDCOLORARG";
slouken@1900
   131
        break;
slouken@1900
   132
    case D3DERR_UNSUPPORTEDALPHAOPERATION:
slouken@1900
   133
        error = "UNSUPPORTEDALPHAOPERATION";
slouken@1900
   134
        break;
slouken@1900
   135
    case D3DERR_UNSUPPORTEDALPHAARG:
slouken@1900
   136
        error = "UNSUPPORTEDALPHAARG";
slouken@1900
   137
        break;
slouken@1900
   138
    case D3DERR_TOOMANYOPERATIONS:
slouken@1900
   139
        error = "TOOMANYOPERATIONS";
slouken@1900
   140
        break;
slouken@1900
   141
    case D3DERR_CONFLICTINGTEXTUREFILTER:
slouken@1900
   142
        error = "CONFLICTINGTEXTUREFILTER";
slouken@1900
   143
        break;
slouken@1900
   144
    case D3DERR_UNSUPPORTEDFACTORVALUE:
slouken@1900
   145
        error = "UNSUPPORTEDFACTORVALUE";
slouken@1900
   146
        break;
slouken@1900
   147
    case D3DERR_CONFLICTINGRENDERSTATE:
slouken@1900
   148
        error = "CONFLICTINGRENDERSTATE";
slouken@1900
   149
        break;
slouken@1900
   150
    case D3DERR_UNSUPPORTEDTEXTUREFILTER:
slouken@1900
   151
        error = "UNSUPPORTEDTEXTUREFILTER";
slouken@1900
   152
        break;
slouken@1900
   153
    case D3DERR_CONFLICTINGTEXTUREPALETTE:
slouken@1900
   154
        error = "CONFLICTINGTEXTUREPALETTE";
slouken@1900
   155
        break;
slouken@1900
   156
    case D3DERR_DRIVERINTERNALERROR:
slouken@1900
   157
        error = "DRIVERINTERNALERROR";
slouken@1900
   158
        break;
slouken@1900
   159
    case D3DERR_NOTFOUND:
slouken@1900
   160
        error = "NOTFOUND";
slouken@1900
   161
        break;
slouken@1900
   162
    case D3DERR_MOREDATA:
slouken@1900
   163
        error = "MOREDATA";
slouken@1900
   164
        break;
slouken@1900
   165
    case D3DERR_DEVICELOST:
slouken@1900
   166
        error = "DEVICELOST";
slouken@1900
   167
        break;
slouken@1900
   168
    case D3DERR_DEVICENOTRESET:
slouken@1900
   169
        error = "DEVICENOTRESET";
slouken@1900
   170
        break;
slouken@1900
   171
    case D3DERR_NOTAVAILABLE:
slouken@1900
   172
        error = "NOTAVAILABLE";
slouken@1900
   173
        break;
slouken@1900
   174
    case D3DERR_OUTOFVIDEOMEMORY:
slouken@1900
   175
        error = "OUTOFVIDEOMEMORY";
slouken@1900
   176
        break;
slouken@1900
   177
    case D3DERR_INVALIDDEVICE:
slouken@1900
   178
        error = "INVALIDDEVICE";
slouken@1900
   179
        break;
slouken@1900
   180
    case D3DERR_INVALIDCALL:
slouken@1900
   181
        error = "INVALIDCALL";
slouken@1900
   182
        break;
slouken@1900
   183
    case D3DERR_DRIVERINVALIDCALL:
slouken@1900
   184
        error = "DRIVERINVALIDCALL";
slouken@1900
   185
        break;
slouken@1900
   186
    case D3DERR_WASSTILLDRAWING:
slouken@1900
   187
        error = "WASSTILLDRAWING";
slouken@1900
   188
        break;
slouken@1900
   189
    default:
slouken@1900
   190
        error = "UNKNOWN";
slouken@1900
   191
        break;
slouken@1900
   192
    }
icculus@7037
   193
    return SDL_SetError("%s: %s", prefix, error);
slouken@1900
   194
}
slouken@1900
   195
slouken@1903
   196
static D3DFORMAT
slouken@1903
   197
PixelFormatToD3DFMT(Uint32 format)
slouken@1895
   198
{
slouken@1903
   199
    switch (format) {
slouken@1965
   200
    case SDL_PIXELFORMAT_RGB565:
slouken@1903
   201
        return D3DFMT_R5G6B5;
slouken@1965
   202
    case SDL_PIXELFORMAT_RGB888:
slouken@1903
   203
        return D3DFMT_X8R8G8B8;
slouken@1965
   204
    case SDL_PIXELFORMAT_ARGB8888:
slouken@1903
   205
        return D3DFMT_A8R8G8B8;
slouken@7505
   206
    case SDL_PIXELFORMAT_YV12:
slouken@7505
   207
    case SDL_PIXELFORMAT_IYUV:
slouken@11702
   208
    case SDL_PIXELFORMAT_NV12:
slouken@11702
   209
    case SDL_PIXELFORMAT_NV21:
slouken@7505
   210
        return D3DFMT_L8;
slouken@1903
   211
    default:
slouken@1903
   212
        return D3DFMT_UNKNOWN;
slouken@1903
   213
    }
slouken@1895
   214
}
slouken@1895
   215
slouken@5156
   216
static Uint32
slouken@5156
   217
D3DFMTToPixelFormat(D3DFORMAT format)
slouken@2973
   218
{
slouken@5156
   219
    switch (format) {
slouken@5156
   220
    case D3DFMT_R5G6B5:
slouken@5156
   221
        return SDL_PIXELFORMAT_RGB565;
slouken@5156
   222
    case D3DFMT_X8R8G8B8:
slouken@5156
   223
        return SDL_PIXELFORMAT_RGB888;
slouken@5156
   224
    case D3DFMT_A8R8G8B8:
slouken@5156
   225
        return SDL_PIXELFORMAT_ARGB8888;
slouken@5156
   226
    default:
slouken@5156
   227
        return SDL_PIXELFORMAT_UNKNOWN;
slouken@2973
   228
    }
slouken@1895
   229
}
slouken@1895
   230
slouken@7648
   231
static void
slouken@7648
   232
D3D_InitRenderState(D3D_RenderData *data)
slouken@7648
   233
{
slouken@7651
   234
    D3DMATRIX matrix;
slouken@7651
   235
slouken@7651
   236
    IDirect3DDevice9 *device = data->device;
icculus@12278
   237
    IDirect3DDevice9_SetFVF(device, D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);
slouken@7648
   238
    IDirect3DDevice9_SetVertexShader(device, NULL);
slouken@7648
   239
    IDirect3DDevice9_SetRenderState(device, D3DRS_ZENABLE, D3DZB_FALSE);
slouken@7648
   240
    IDirect3DDevice9_SetRenderState(device, D3DRS_CULLMODE, D3DCULL_NONE);
slouken@7648
   241
    IDirect3DDevice9_SetRenderState(device, D3DRS_LIGHTING, FALSE);
slouken@7648
   242
slouken@7648
   243
    /* Enable color modulation by diffuse color */
slouken@7648
   244
    IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLOROP,
slouken@7648
   245
                                          D3DTOP_MODULATE);
slouken@7648
   246
    IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLORARG1,
slouken@7648
   247
                                          D3DTA_TEXTURE);
slouken@7648
   248
    IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLORARG2,
slouken@7648
   249
                                          D3DTA_DIFFUSE);
slouken@7648
   250
slouken@7648
   251
    /* Enable alpha modulation by diffuse alpha */
slouken@7648
   252
    IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAOP,
slouken@7648
   253
                                          D3DTOP_MODULATE);
slouken@7648
   254
    IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAARG1,
slouken@7648
   255
                                          D3DTA_TEXTURE);
slouken@7648
   256
    IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAARG2,
slouken@7648
   257
                                          D3DTA_DIFFUSE);
slouken@7648
   258
slouken@7648
   259
    /* Enable separate alpha blend function, if possible */
slouken@7648
   260
    if (data->enableSeparateAlphaBlend) {
slouken@7648
   261
        IDirect3DDevice9_SetRenderState(device, D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
slouken@7648
   262
    }
slouken@7648
   263
slouken@7648
   264
    /* Disable second texture stage, since we're done */
slouken@7648
   265
    IDirect3DDevice9_SetTextureStageState(device, 1, D3DTSS_COLOROP,
slouken@7648
   266
                                          D3DTOP_DISABLE);
slouken@7648
   267
    IDirect3DDevice9_SetTextureStageState(device, 1, D3DTSS_ALPHAOP,
slouken@7648
   268
                                          D3DTOP_DISABLE);
slouken@7648
   269
slouken@7648
   270
    /* Set an identity world and view matrix */
icculus@12278
   271
    SDL_zero(matrix);
slouken@7648
   272
    matrix.m[0][0] = 1.0f;
slouken@7648
   273
    matrix.m[1][1] = 1.0f;
slouken@7648
   274
    matrix.m[2][2] = 1.0f;
slouken@7648
   275
    matrix.m[3][3] = 1.0f;
slouken@7648
   276
    IDirect3DDevice9_SetTransform(device, D3DTS_WORLD, &matrix);
slouken@7648
   277
    IDirect3DDevice9_SetTransform(device, D3DTS_VIEW, &matrix);
slouken@7648
   278
slouken@7648
   279
    /* Reset our current scale mode */
slouken@7648
   280
    SDL_memset(data->scaleMode, 0xFF, sizeof(data->scaleMode));
slouken@7648
   281
slouken@7648
   282
    /* Start the render with beginScene */
slouken@7648
   283
    data->beginScene = SDL_TRUE;
slouken@7648
   284
}
slouken@7648
   285
icculus@12279
   286
static int D3D_Reset(SDL_Renderer * renderer);
slouken@5297
   287
slouken@5297
   288
static int
slouken@5297
   289
D3D_ActivateRenderer(SDL_Renderer * renderer)
slouken@5297
   290
{
slouken@5297
   291
    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
slouken@5297
   292
    HRESULT result;
slouken@5297
   293
slouken@5297
   294
    if (data->updateSize) {
slouken@5297
   295
        SDL_Window *window = renderer->window;
slouken@5297
   296
        int w, h;
slouken@8823
   297
        Uint32 window_flags = SDL_GetWindowFlags(window);
slouken@5297
   298
slouken@5297
   299
        SDL_GetWindowSize(window, &w, &h);
slouken@5297
   300
        data->pparams.BackBufferWidth = w;
slouken@5297
   301
        data->pparams.BackBufferHeight = h;
slouken@8823
   302
        if (window_flags & SDL_WINDOW_FULLSCREEN && (window_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
slouken@8823
   303
            SDL_DisplayMode fullscreen_mode;
slouken@8823
   304
            SDL_GetWindowDisplayMode(window, &fullscreen_mode);
slouken@8823
   305
            data->pparams.Windowed = FALSE;
slouken@8823
   306
            data->pparams.BackBufferFormat = PixelFormatToD3DFMT(fullscreen_mode.format);
slouken@8823
   307
            data->pparams.FullScreen_RefreshRateInHz = fullscreen_mode.refresh_rate;
slouken@5297
   308
        } else {
slouken@8823
   309
            data->pparams.Windowed = TRUE;
slouken@5297
   310
            data->pparams.BackBufferFormat = D3DFMT_UNKNOWN;
slouken@8823
   311
            data->pparams.FullScreen_RefreshRateInHz = 0;
slouken@5297
   312
        }
slouken@5297
   313
        if (D3D_Reset(renderer) < 0) {
slouken@5297
   314
            return -1;
slouken@5297
   315
        }
slouken@5297
   316
slouken@5297
   317
        data->updateSize = SDL_FALSE;
slouken@5297
   318
    }
slouken@5297
   319
    if (data->beginScene) {
slouken@5297
   320
        result = IDirect3DDevice9_BeginScene(data->device);
slouken@5297
   321
        if (result == D3DERR_DEVICELOST) {
slouken@5297
   322
            if (D3D_Reset(renderer) < 0) {
slouken@5297
   323
                return -1;
slouken@5297
   324
            }
slouken@5297
   325
            result = IDirect3DDevice9_BeginScene(data->device);
slouken@5297
   326
        }
slouken@5297
   327
        if (FAILED(result)) {
icculus@7037
   328
            return D3D_SetError("BeginScene()", result);
slouken@5297
   329
        }
slouken@5297
   330
        data->beginScene = SDL_FALSE;
slouken@5297
   331
    }
slouken@5297
   332
    return 0;
slouken@5297
   333
}
slouken@5297
   334
slouken@5297
   335
static void
slouken@5297
   336
D3D_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
slouken@1975
   337
{
slouken@1975
   338
    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
slouken@1975
   339
slouken@5297
   340
    if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) {
slouken@5297
   341
        data->updateSize = SDL_TRUE;
slouken@1975
   342
    }
slouken@1975
   343
}
slouken@1975
   344
slouken@11282
   345
static D3DBLEND GetBlendFunc(SDL_BlendFactor factor)
slouken@11282
   346
{
slouken@11282
   347
    switch (factor) {
slouken@11282
   348
    case SDL_BLENDFACTOR_ZERO:
slouken@11282
   349
        return D3DBLEND_ZERO;
slouken@11282
   350
    case SDL_BLENDFACTOR_ONE:
slouken@11282
   351
        return D3DBLEND_ONE;
slouken@11282
   352
    case SDL_BLENDFACTOR_SRC_COLOR:
slouken@11282
   353
        return D3DBLEND_SRCCOLOR;
slouken@11282
   354
    case SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR:
slouken@11282
   355
        return D3DBLEND_INVSRCCOLOR;
slouken@11282
   356
    case SDL_BLENDFACTOR_SRC_ALPHA:
slouken@11282
   357
        return D3DBLEND_SRCALPHA;
slouken@11282
   358
    case SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA:
slouken@11282
   359
        return D3DBLEND_INVSRCALPHA;
slouken@11282
   360
    case SDL_BLENDFACTOR_DST_COLOR:
slouken@11282
   361
        return D3DBLEND_DESTCOLOR;
slouken@11282
   362
    case SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR:
slouken@11282
   363
        return D3DBLEND_INVDESTCOLOR;
slouken@11282
   364
    case SDL_BLENDFACTOR_DST_ALPHA:
slouken@11282
   365
        return D3DBLEND_DESTALPHA;
slouken@11282
   366
    case SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA:
slouken@11282
   367
        return D3DBLEND_INVDESTALPHA;
slouken@11282
   368
    default:
slouken@11282
   369
        return (D3DBLEND)0;
slouken@11282
   370
    }
slouken@11282
   371
}
slouken@11282
   372
slouken@11282
   373
static SDL_bool
slouken@11282
   374
D3D_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
slouken@11282
   375
{
slouken@11282
   376
    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
slouken@11282
   377
    SDL_BlendFactor srcColorFactor = SDL_GetBlendModeSrcColorFactor(blendMode);
slouken@11282
   378
    SDL_BlendFactor srcAlphaFactor = SDL_GetBlendModeSrcAlphaFactor(blendMode);
slouken@11282
   379
    SDL_BlendOperation colorOperation = SDL_GetBlendModeColorOperation(blendMode);
slouken@11282
   380
    SDL_BlendFactor dstColorFactor = SDL_GetBlendModeDstColorFactor(blendMode);
slouken@11282
   381
    SDL_BlendFactor dstAlphaFactor = SDL_GetBlendModeDstAlphaFactor(blendMode);
slouken@11282
   382
    SDL_BlendOperation alphaOperation = SDL_GetBlendModeAlphaOperation(blendMode);
slouken@11282
   383
slouken@11282
   384
    if (!GetBlendFunc(srcColorFactor) || !GetBlendFunc(srcAlphaFactor) ||
slouken@11282
   385
        !GetBlendFunc(dstColorFactor) || !GetBlendFunc(dstAlphaFactor)) {
slouken@11282
   386
        return SDL_FALSE;
slouken@11282
   387
    }
slouken@11282
   388
    if ((srcColorFactor != srcAlphaFactor || dstColorFactor != dstAlphaFactor) && !data->enableSeparateAlphaBlend) {
slouken@11282
   389
        return SDL_FALSE;
slouken@11282
   390
    }
slouken@11282
   391
    if (colorOperation != SDL_BLENDOPERATION_ADD || alphaOperation != SDL_BLENDOPERATION_ADD) {
slouken@11282
   392
        return SDL_FALSE;
slouken@11282
   393
    }
slouken@11282
   394
    return SDL_TRUE;
slouken@11282
   395
}
slouken@11282
   396
slouken@1975
   397
static int
slouken@11702
   398
D3D_CreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWORD usage, Uint32 format, D3DFORMAT d3dfmt, int w, int h)
slouken@1895
   399
{
slouken@1903
   400
    HRESULT result;
slouken@1895
   401
slouken@8822
   402
    texture->dirty = SDL_FALSE;
slouken@9074
   403
    texture->w = w;
slouken@9074
   404
    texture->h = h;
slouken@9074
   405
    texture->usage = usage;
slouken@9074
   406
    texture->format = format;
slouken@11702
   407
    texture->d3dfmt = d3dfmt;
slouken@8822
   408
slouken@8792
   409
    result = IDirect3DDevice9_CreateTexture(device, w, h, 1, usage,
slouken@8792
   410
        PixelFormatToD3DFMT(format),
slouken@8792
   411
        D3DPOOL_DEFAULT, &texture->texture, NULL);
slouken@8792
   412
    if (FAILED(result)) {
slouken@8792
   413
        return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
slouken@5173
   414
    }
slouken@9074
   415
    return 0;
slouken@9074
   416
}
slouken@2973
   417
slouken@9074
   418
slouken@9074
   419
static int
slouken@9074
   420
D3D_CreateStagingTexture(IDirect3DDevice9 *device, D3D_TextureRep *texture)
slouken@9074
   421
{
slouken@9074
   422
    HRESULT result;
slouken@9074
   423
slouken@9074
   424
    if (texture->staging == NULL) {
slouken@9702
   425
        result = IDirect3DDevice9_CreateTexture(device, texture->w, texture->h, 1, 0,
slouken@11702
   426
            texture->d3dfmt, D3DPOOL_SYSTEMMEM, &texture->staging, NULL);
slouken@7505
   427
        if (FAILED(result)) {
slouken@8792
   428
            return D3D_SetError("CreateTexture(D3DPOOL_SYSTEMMEM)", result);
slouken@7505
   429
        }
slouken@7505
   430
    }
slouken@7505
   431
    return 0;
slouken@7505
   432
}
slouken@7505
   433
slouken@7505
   434
static int
slouken@11702
   435
D3D_RecreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture)
slouken@8822
   436
{
slouken@8822
   437
    if (texture->texture) {
slouken@8822
   438
        IDirect3DTexture9_Release(texture->texture);
slouken@8822
   439
        texture->texture = NULL;
slouken@8792
   440
    }
slouken@9074
   441
    if (texture->staging) {
slouken@9074
   442
        IDirect3DTexture9_AddDirtyRect(texture->staging, NULL);
slouken@9074
   443
        texture->dirty = SDL_TRUE;
slouken@9074
   444
    }
slouken@8792
   445
    return 0;
slouken@8792
   446
}
slouken@8792
   447
slouken@8792
   448
static int
slouken@11702
   449
D3D_UpdateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, int x, int y, int w, int h, const void *pixels, int pitch)
slouken@7505
   450
{
slouken@7505
   451
    RECT d3drect;
slouken@7505
   452
    D3DLOCKED_RECT locked;
slouken@7505
   453
    const Uint8 *src;
slouken@7505
   454
    Uint8 *dst;
slouken@7505
   455
    int row, length;
slouken@7505
   456
    HRESULT result;
slouken@7505
   457
slouken@9074
   458
    if (D3D_CreateStagingTexture(device, texture) < 0) {
slouken@9074
   459
        return -1;
slouken@9074
   460
    }
slouken@9074
   461
slouken@8792
   462
    d3drect.left = x;
slouken@8792
   463
    d3drect.right = x + w;
slouken@8792
   464
    d3drect.top = y;
slouken@8792
   465
    d3drect.bottom = y + h;
slouken@9074
   466
    
slouken@8792
   467
    result = IDirect3DTexture9_LockRect(texture->staging, 0, &locked, &d3drect, 0);
slouken@7505
   468
    if (FAILED(result)) {
slouken@7505
   469
        return D3D_SetError("LockRect()", result);
slouken@7505
   470
    }
slouken@7505
   471
slouken@7505
   472
    src = (const Uint8 *)pixels;
slouken@11702
   473
    dst = (Uint8 *)locked.pBits;
slouken@11702
   474
    length = w * SDL_BYTESPERPIXEL(texture->format);
slouken@7505
   475
    if (length == pitch && length == locked.Pitch) {
slouken@7505
   476
        SDL_memcpy(dst, src, length*h);
slouken@7505
   477
    } else {
slouken@8255
   478
        if (length > pitch) {
slouken@8255
   479
            length = pitch;
slouken@8255
   480
        }
slouken@8255
   481
        if (length > locked.Pitch) {
slouken@8255
   482
            length = locked.Pitch;
slouken@8255
   483
        }
slouken@7505
   484
        for (row = 0; row < h; ++row) {
slouken@7505
   485
            SDL_memcpy(dst, src, length);
slouken@7505
   486
            src += pitch;
slouken@7505
   487
            dst += locked.Pitch;
slouken@7505
   488
        }
slouken@7505
   489
    }
slouken@8822
   490
    result = IDirect3DTexture9_UnlockRect(texture->staging, 0);
slouken@8822
   491
    if (FAILED(result)) {
slouken@8822
   492
        return D3D_SetError("UnlockRect()", result);
slouken@8822
   493
    }
slouken@8822
   494
    texture->dirty = SDL_TRUE;
slouken@7505
   495
slouken@1895
   496
    return 0;
slouken@1895
   497
}
slouken@1895
   498
slouken@8792
   499
static void
slouken@8792
   500
D3D_DestroyTextureRep(D3D_TextureRep *texture)
slouken@8792
   501
{
slouken@8792
   502
    if (texture->texture) {
slouken@8792
   503
        IDirect3DTexture9_Release(texture->texture);
slouken@8792
   504
        texture->texture = NULL;
slouken@8792
   505
    }
slouken@8792
   506
    if (texture->staging) {
slouken@8792
   507
        IDirect3DTexture9_Release(texture->staging);
slouken@8792
   508
        texture->staging = NULL;
slouken@8792
   509
    }
slouken@8792
   510
}
slouken@8792
   511
slouken@8792
   512
static int
slouken@8792
   513
D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@8792
   514
{
slouken@8792
   515
    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
slouken@8792
   516
    D3D_TextureData *texturedata;
slouken@8792
   517
    DWORD usage;
slouken@8792
   518
slouken@8792
   519
    texturedata = (D3D_TextureData *) SDL_calloc(1, sizeof(*texturedata));
slouken@8792
   520
    if (!texturedata) {
slouken@8792
   521
        return SDL_OutOfMemory();
slouken@8792
   522
    }
slouken@11958
   523
    texturedata->scaleMode = (texture->scaleMode == SDL_ScaleModeNearest) ? D3DTEXF_POINT : D3DTEXF_LINEAR;
slouken@8792
   524
slouken@8792
   525
    texture->driverdata = texturedata;
slouken@8792
   526
slouken@8792
   527
    if (texture->access == SDL_TEXTUREACCESS_TARGET) {
slouken@8792
   528
        usage = D3DUSAGE_RENDERTARGET;
slouken@8792
   529
    } else {
slouken@8792
   530
        usage = 0;
slouken@8792
   531
    }
slouken@8792
   532
slouken@11702
   533
    if (D3D_CreateTextureRep(data->device, &texturedata->texture, usage, texture->format, PixelFormatToD3DFMT(texture->format), texture->w, texture->h) < 0) {
slouken@8792
   534
        return -1;
slouken@8792
   535
    }
slouken@8792
   536
slouken@8792
   537
    if (texture->format == SDL_PIXELFORMAT_YV12 ||
slouken@8792
   538
        texture->format == SDL_PIXELFORMAT_IYUV) {
slouken@8792
   539
        texturedata->yuv = SDL_TRUE;
slouken@8792
   540
slouken@11702
   541
        if (D3D_CreateTextureRep(data->device, &texturedata->utexture, usage, texture->format, PixelFormatToD3DFMT(texture->format), (texture->w + 1) / 2, (texture->h + 1) / 2) < 0) {
slouken@8792
   542
            return -1;
slouken@8792
   543
        }
slouken@8792
   544
slouken@11702
   545
        if (D3D_CreateTextureRep(data->device, &texturedata->vtexture, usage, texture->format, PixelFormatToD3DFMT(texture->format), (texture->w + 1) / 2, (texture->h + 1) / 2) < 0) {
slouken@8792
   546
            return -1;
slouken@8792
   547
        }
slouken@8792
   548
    }
slouken@8792
   549
    return 0;
slouken@8792
   550
}
slouken@8792
   551
slouken@8792
   552
static int
slouken@8792
   553
D3D_RecreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@8792
   554
{
slouken@8792
   555
    D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
slouken@8792
   556
    D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
slouken@8792
   557
dludwig@10183
   558
    if (!texturedata) {
dludwig@10183
   559
        return 0;
dludwig@10183
   560
    }
dludwig@10183
   561
slouken@11702
   562
    if (D3D_RecreateTextureRep(data->device, &texturedata->texture) < 0) {
slouken@8792
   563
        return -1;
slouken@8792
   564
    }
slouken@8792
   565
slouken@8792
   566
    if (texturedata->yuv) {
slouken@11702
   567
        if (D3D_RecreateTextureRep(data->device, &texturedata->utexture) < 0) {
slouken@8792
   568
            return -1;
slouken@8792
   569
        }
slouken@8792
   570
slouken@11702
   571
        if (D3D_RecreateTextureRep(data->device, &texturedata->vtexture) < 0) {
slouken@8792
   572
            return -1;
slouken@8792
   573
        }
slouken@8792
   574
    }
slouken@8792
   575
    return 0;
slouken@8792
   576
}
slouken@8792
   577
slouken@1895
   578
static int
slouken@1913
   579
D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@1913
   580
                  const SDL_Rect * rect, const void *pixels, int pitch)
slouken@1895
   581
{
slouken@8792
   582
    D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
slouken@8792
   583
    D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata;
slouken@2973
   584
slouken@8792
   585
    if (!texturedata) {
slouken@8208
   586
        SDL_SetError("Texture is not currently available");
slouken@8208
   587
        return -1;
slouken@8208
   588
    }
slouken@8208
   589
slouken@11702
   590
    if (D3D_UpdateTextureRep(data->device, &texturedata->texture, rect->x, rect->y, rect->w, rect->h, pixels, pitch) < 0) {
slouken@7505
   591
        return -1;
slouken@5156
   592
    }
slouken@2973
   593
slouken@8792
   594
    if (texturedata->yuv) {
slouken@7505
   595
        /* Skip to the correct offset into the next texture */
slouken@7505
   596
        pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
slouken@2973
   597
slouken@11702
   598
        if (D3D_UpdateTextureRep(data->device, texture->format == SDL_PIXELFORMAT_YV12 ? &texturedata->vtexture : &texturedata->utexture, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, pixels, (pitch + 1) / 2) < 0) {
slouken@7505
   599
            return -1;
slouken@7505
   600
        }
slouken@7505
   601
slouken@7505
   602
        /* Skip to the correct offset into the next texture */
slouken@11702
   603
        pixels = (const void*)((const Uint8*)pixels + ((rect->h + 1) / 2) * ((pitch + 1) / 2));
slouken@11702
   604
        if (D3D_UpdateTextureRep(data->device, texture->format == SDL_PIXELFORMAT_YV12 ? &texturedata->utexture : &texturedata->vtexture, rect->x / 2, (rect->y + 1) / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, pixels, (pitch + 1) / 2) < 0) {
slouken@7505
   605
            return -1;
slouken@5173
   606
        }
slouken@5156
   607
    }
slouken@5156
   608
    return 0;
slouken@1895
   609
}
slouken@1895
   610
slouken@1895
   611
static int
slouken@7761
   612
D3D_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@7761
   613
                     const SDL_Rect * rect,
slouken@7761
   614
                     const Uint8 *Yplane, int Ypitch,
slouken@7761
   615
                     const Uint8 *Uplane, int Upitch,
slouken@7761
   616
                     const Uint8 *Vplane, int Vpitch)
slouken@7761
   617
{
slouken@8792
   618
    D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
slouken@8792
   619
    D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata;
slouken@7761
   620
slouken@8792
   621
    if (!texturedata) {
slouken@8208
   622
        SDL_SetError("Texture is not currently available");
slouken@8208
   623
        return -1;
slouken@8208
   624
    }
slouken@8208
   625
slouken@11702
   626
    if (D3D_UpdateTextureRep(data->device, &texturedata->texture, rect->x, rect->y, rect->w, rect->h, Yplane, Ypitch) < 0) {
slouken@7877
   627
        return -1;
slouken@7877
   628
    }
slouken@11702
   629
    if (D3D_UpdateTextureRep(data->device, &texturedata->utexture, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, Uplane, Upitch) < 0) {
slouken@7877
   630
        return -1;
slouken@7877
   631
    }
slouken@11702
   632
    if (D3D_UpdateTextureRep(data->device, &texturedata->vtexture, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, Vplane, Vpitch) < 0) {
slouken@7877
   633
        return -1;
slouken@7877
   634
    }
slouken@7877
   635
    return 0;
slouken@7761
   636
}
slouken@7761
   637
slouken@7761
   638
static int
slouken@1913
   639
D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@5156
   640
                const SDL_Rect * rect, void **pixels, int *pitch)
slouken@1895
   641
{
slouken@9074
   642
    D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
slouken@8792
   643
    D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
slouken@9074
   644
    IDirect3DDevice9 *device = data->device;
slouken@1895
   645
slouken@8792
   646
    if (!texturedata) {
slouken@8208
   647
        SDL_SetError("Texture is not currently available");
slouken@8208
   648
        return -1;
slouken@8208
   649
    }
slouken@8208
   650
slouken@8792
   651
    texturedata->locked_rect = *rect;
slouken@8792
   652
slouken@8792
   653
    if (texturedata->yuv) {
gabomdq@7663
   654
        /* It's more efficient to upload directly... */
slouken@8792
   655
        if (!texturedata->pixels) {
slouken@8792
   656
            texturedata->pitch = texture->w;
slouken@8792
   657
            texturedata->pixels = (Uint8 *)SDL_malloc((texture->h * texturedata->pitch * 3) / 2);
slouken@8792
   658
            if (!texturedata->pixels) {
slouken@7505
   659
                return SDL_OutOfMemory();
slouken@7505
   660
            }
slouken@7505
   661
        }
slouken@7505
   662
        *pixels =
slouken@8792
   663
            (void *) ((Uint8 *) texturedata->pixels + rect->y * texturedata->pitch +
slouken@7505
   664
                      rect->x * SDL_BYTESPERPIXEL(texture->format));
slouken@8792
   665
        *pitch = texturedata->pitch;
slouken@7505
   666
    } else {
slouken@8792
   667
        RECT d3drect;
slouken@8792
   668
        D3DLOCKED_RECT locked;
slouken@8792
   669
        HRESULT result;
slouken@8792
   670
slouken@9074
   671
        if (D3D_CreateStagingTexture(device, &texturedata->texture) < 0) {
slouken@9074
   672
            return -1;
slouken@9074
   673
        }
slouken@9074
   674
slouken@7505
   675
        d3drect.left = rect->x;
slouken@7505
   676
        d3drect.right = rect->x + rect->w;
slouken@7505
   677
        d3drect.top = rect->y;
slouken@7505
   678
        d3drect.bottom = rect->y + rect->h;
slouken@1903
   679
slouken@8792
   680
        result = IDirect3DTexture9_LockRect(texturedata->texture.staging, 0, &locked, &d3drect, 0);
slouken@7505
   681
        if (FAILED(result)) {
slouken@7505
   682
            return D3D_SetError("LockRect()", result);
slouken@7505
   683
        }
slouken@7505
   684
        *pixels = locked.pBits;
slouken@7505
   685
        *pitch = locked.Pitch;
slouken@1903
   686
    }
slouken@5156
   687
    return 0;
slouken@1895
   688
}
slouken@1895
   689
slouken@1895
   690
static void
slouken@1913
   691
D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@1895
   692
{
icculus@12448
   693
    D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
slouken@8792
   694
    D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
slouken@1895
   695
slouken@8792
   696
    if (!texturedata) {
slouken@8208
   697
        return;
slouken@8208
   698
    }
slouken@8208
   699
slouken@8792
   700
    if (texturedata->yuv) {
slouken@8792
   701
        const SDL_Rect *rect = &texturedata->locked_rect;
slouken@7505
   702
        void *pixels =
slouken@8792
   703
            (void *) ((Uint8 *) texturedata->pixels + rect->y * texturedata->pitch +
slouken@7505
   704
                      rect->x * SDL_BYTESPERPIXEL(texture->format));
slouken@8792
   705
        D3D_UpdateTexture(renderer, texture, rect, pixels, texturedata->pitch);
slouken@7505
   706
    } else {
slouken@8792
   707
        IDirect3DTexture9_UnlockRect(texturedata->texture.staging, 0);
slouken@8822
   708
        texturedata->texture.dirty = SDL_TRUE;
icculus@12448
   709
        if (data->drawstate.texture == texture) {
icculus@12448
   710
            data->drawstate.texture = NULL;
icculus@12448
   711
        }
slouken@8822
   712
   }
slouken@1895
   713
}
slouken@1895
   714
slouken@5297
   715
static int
slouken@8228
   716
D3D_SetRenderTargetInternal(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@7141
   717
{
slouken@7141
   718
    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
slouken@7141
   719
    D3D_TextureData *texturedata;
slouken@9074
   720
    D3D_TextureRep *texturerep;
slouken@7141
   721
    HRESULT result;
slouken@9074
   722
    IDirect3DDevice9 *device = data->device;
slouken@7141
   723
slouken@7141
   724
    /* Release the previous render target if it wasn't the default one */
slouken@7141
   725
    if (data->currentRenderTarget != NULL) {
slouken@7141
   726
        IDirect3DSurface9_Release(data->currentRenderTarget);
slouken@7141
   727
        data->currentRenderTarget = NULL;
slouken@7141
   728
    }
slouken@7141
   729
slouken@7141
   730
    if (texture == NULL) {
slouken@7141
   731
        IDirect3DDevice9_SetRenderTarget(data->device, 0, data->defaultRenderTarget);
slouken@7141
   732
        return 0;
slouken@7141
   733
    }
slouken@7141
   734
slouken@8208
   735
    texturedata = (D3D_TextureData *)texture->driverdata;
slouken@8208
   736
    if (!texturedata) {
slouken@8208
   737
        SDL_SetError("Texture is not currently available");
slouken@8208
   738
        return -1;
slouken@8208
   739
    }
slouken@8208
   740
slouken@9074
   741
    /* Make sure the render target is updated if it was locked and written to */
slouken@9074
   742
    texturerep = &texturedata->texture;
slouken@9074
   743
    if (texturerep->dirty && texturerep->staging) {
slouken@9074
   744
        if (!texturerep->texture) {
slouken@9074
   745
            result = IDirect3DDevice9_CreateTexture(device, texturerep->w, texturerep->h, 1, texturerep->usage,
slouken@9074
   746
                PixelFormatToD3DFMT(texturerep->format), D3DPOOL_DEFAULT, &texturerep->texture, NULL);
slouken@9074
   747
            if (FAILED(result)) {
slouken@9074
   748
                return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
slouken@9074
   749
            }
slouken@9074
   750
        }
slouken@9074
   751
slouken@9074
   752
        result = IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)texturerep->staging, (IDirect3DBaseTexture9 *)texturerep->texture);
slouken@9074
   753
        if (FAILED(result)) {
slouken@9074
   754
            return D3D_SetError("UpdateTexture()", result);
slouken@9074
   755
        }
slouken@9074
   756
        texturerep->dirty = SDL_FALSE;
slouken@9074
   757
    }
slouken@9074
   758
slouken@8792
   759
    result = IDirect3DTexture9_GetSurfaceLevel(texturedata->texture.texture, 0, &data->currentRenderTarget);
slouken@7141
   760
    if(FAILED(result)) {
slouken@7141
   761
        return D3D_SetError("GetSurfaceLevel()", result);
slouken@7141
   762
    }
slouken@7141
   763
    result = IDirect3DDevice9_SetRenderTarget(data->device, 0, data->currentRenderTarget);
slouken@7141
   764
    if(FAILED(result)) {
slouken@7141
   765
        return D3D_SetError("SetRenderTarget()", result);
slouken@7141
   766
    }
slouken@7141
   767
slouken@7141
   768
    return 0;
slouken@7141
   769
}
slouken@7141
   770
slouken@7141
   771
static int
slouken@8228
   772
D3D_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@8228
   773
{
slouken@11739
   774
    if (D3D_ActivateRenderer(renderer) < 0) {
slouken@11739
   775
        return -1;
slouken@11739
   776
    }
slouken@8228
   777
slouken@8228
   778
    return D3D_SetRenderTargetInternal(renderer, texture);
slouken@8228
   779
}
slouken@8228
   780
icculus@12278
   781
slouken@8228
   782
static int
icculus@12278
   783
D3D_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd)
slouken@5224
   784
{
icculus@12278
   785
    return 0;  /* nothing to do in this backend. */
icculus@12278
   786
}
slouken@5224
   787
icculus@12278
   788
static int
icculus@12278
   789
D3D_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
icculus@12278
   790
{
icculus@12278
   791
    const DWORD color = D3DCOLOR_ARGB(cmd->data.draw.a, cmd->data.draw.r, cmd->data.draw.g, cmd->data.draw.b);
icculus@12278
   792
    const size_t vertslen = count * sizeof (Vertex);
icculus@12278
   793
    Vertex *verts = (Vertex *) SDL_AllocateRenderVertices(renderer, vertslen, 0, &cmd->data.draw.first);
slouken@12665
   794
    int i;
slouken@5224
   795
icculus@12278
   796
    if (!verts) {
icculus@12278
   797
        return -1;
icculus@12278
   798
    }
icculus@12278
   799
icculus@12278
   800
    SDL_memset(verts, '\0', vertslen);
icculus@12278
   801
    cmd->data.draw.count = count;
icculus@12278
   802
icculus@12278
   803
    for (i = 0; i < count; i++, verts++, points++) {
icculus@12278
   804
        verts->x = points->x;
icculus@12278
   805
        verts->y = points->y;
icculus@12278
   806
        verts->color = color;
slouken@7239
   807
    }
slouken@5297
   808
slouken@5297
   809
    return 0;
slouken@5297
   810
}
slouken@5297
   811
slouken@5297
   812
static int
icculus@12278
   813
D3D_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects, int count)
slouken@6246
   814
{
icculus@12278
   815
    const DWORD color = D3DCOLOR_ARGB(cmd->data.draw.a, cmd->data.draw.r, cmd->data.draw.g, cmd->data.draw.b);
icculus@12278
   816
    const size_t vertslen = count * sizeof (Vertex) * 4;
icculus@12278
   817
    Vertex *verts = (Vertex *) SDL_AllocateRenderVertices(renderer, vertslen, 0, &cmd->data.draw.first);
slouken@12665
   818
    int i;
slouken@6246
   819
icculus@12278
   820
    if (!verts) {
icculus@12278
   821
        return -1;
icculus@12278
   822
    }
jorgenpt@8728
   823
icculus@12278
   824
    SDL_memset(verts, '\0', vertslen);
icculus@12278
   825
    cmd->data.draw.count = count;
slouken@6246
   826
icculus@12278
   827
    for (i = 0; i < count; i++) {
icculus@12278
   828
        const SDL_FRect *rect = &rects[i];
icculus@12278
   829
        const float minx = rect->x;
icculus@12278
   830
        const float maxx = rect->x + rect->w;
icculus@12278
   831
        const float miny = rect->y;
icculus@12278
   832
        const float maxy = rect->y + rect->h;
icculus@12278
   833
icculus@12278
   834
        verts->x = minx;
icculus@12278
   835
        verts->y = miny;
icculus@12278
   836
        verts->color = color;
icculus@12278
   837
        verts++;
icculus@12278
   838
icculus@12278
   839
        verts->x = maxx;
icculus@12278
   840
        verts->y = miny;
icculus@12278
   841
        verts->color = color;
icculus@12278
   842
        verts++;
icculus@12278
   843
icculus@12278
   844
        verts->x = maxx;
icculus@12278
   845
        verts->y = maxy;
icculus@12278
   846
        verts->color = color;
icculus@12278
   847
        verts++;
icculus@12278
   848
icculus@12278
   849
        verts->x = minx;
icculus@12278
   850
        verts->y = maxy;
icculus@12278
   851
        verts->color = color;
icculus@12278
   852
        verts++;
slouken@6246
   853
    }
icculus@12278
   854
slouken@6246
   855
    return 0;
slouken@6246
   856
}
slouken@6246
   857
slouken@6246
   858
static int
icculus@12278
   859
D3D_QueueCopy(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
icculus@12278
   860
                          const SDL_Rect * srcrect, const SDL_FRect * dstrect)
slouken@5297
   861
{
icculus@12278
   862
    const DWORD color = D3DCOLOR_ARGB(cmd->data.draw.a, cmd->data.draw.r, cmd->data.draw.g, cmd->data.draw.b);
icculus@12278
   863
    float minx, miny, maxx, maxy;
icculus@12278
   864
    float minu, maxu, minv, maxv;
icculus@12278
   865
    const size_t vertslen = sizeof (Vertex) * 4;
icculus@12278
   866
    Vertex *verts = (Vertex *) SDL_AllocateRenderVertices(renderer, vertslen, 0, &cmd->data.draw.first);
slouken@5297
   867
icculus@12278
   868
    if (!verts) {
slouken@5297
   869
        return -1;
slouken@5224
   870
    }
slouken@5297
   871
icculus@12278
   872
    cmd->data.draw.count = 1;
slouken@5297
   873
icculus@12278
   874
    minx = dstrect->x - 0.5f;
icculus@12278
   875
    miny = dstrect->y - 0.5f;
icculus@12278
   876
    maxx = dstrect->x + dstrect->w - 0.5f;
icculus@12278
   877
    maxy = dstrect->y + dstrect->h - 0.5f;
icculus@12278
   878
icculus@12278
   879
    minu = (float) srcrect->x / texture->w;
icculus@12278
   880
    maxu = (float) (srcrect->x + srcrect->w) / texture->w;
icculus@12278
   881
    minv = (float) srcrect->y / texture->h;
icculus@12278
   882
    maxv = (float) (srcrect->y + srcrect->h) / texture->h;
icculus@12278
   883
icculus@12278
   884
    verts->x = minx;
icculus@12278
   885
    verts->y = miny;
icculus@12278
   886
    verts->z = 0.0f;
icculus@12278
   887
    verts->color = color;
icculus@12278
   888
    verts->u = minu;
icculus@12278
   889
    verts->v = minv;
icculus@12278
   890
    verts++;
icculus@12278
   891
icculus@12278
   892
    verts->x = maxx;
icculus@12278
   893
    verts->y = miny;
icculus@12278
   894
    verts->z = 0.0f;
icculus@12278
   895
    verts->color = color;
icculus@12278
   896
    verts->u = maxu;
icculus@12278
   897
    verts->v = minv;
icculus@12278
   898
    verts++;
icculus@12278
   899
icculus@12278
   900
    verts->x = maxx;
icculus@12278
   901
    verts->y = maxy;
icculus@12278
   902
    verts->z = 0.0f;
icculus@12278
   903
    verts->color = color;
icculus@12278
   904
    verts->u = maxu;
icculus@12278
   905
    verts->v = maxv;
icculus@12278
   906
    verts++;
icculus@12278
   907
icculus@12278
   908
    verts->x = minx;
icculus@12278
   909
    verts->y = maxy;
icculus@12278
   910
    verts->z = 0.0f;
icculus@12278
   911
    verts->color = color;
icculus@12278
   912
    verts->u = minu;
icculus@12278
   913
    verts->v = maxv;
icculus@12278
   914
    verts++;
icculus@12278
   915
icculus@12278
   916
    return 0;
icculus@12278
   917
}
icculus@12278
   918
icculus@12278
   919
static int
icculus@12278
   920
D3D_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
icculus@12278
   921
                        const SDL_Rect * srcquad, const SDL_FRect * dstrect,
icculus@12278
   922
                        const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
icculus@12278
   923
{
icculus@12278
   924
    const DWORD color = D3DCOLOR_ARGB(cmd->data.draw.a, cmd->data.draw.r, cmd->data.draw.g, cmd->data.draw.b);
icculus@12278
   925
    float minx, miny, maxx, maxy;
icculus@12278
   926
    float minu, maxu, minv, maxv;
icculus@12278
   927
    const size_t vertslen = sizeof (Vertex) * 5;
icculus@12278
   928
    Vertex *verts = (Vertex *) SDL_AllocateRenderVertices(renderer, vertslen, 0, &cmd->data.draw.first);
icculus@12278
   929
icculus@12278
   930
    if (!verts) {
icculus@12278
   931
        return -1;
slouken@7837
   932
    }
slouken@7837
   933
icculus@12278
   934
    cmd->data.draw.count = 1;
icculus@12278
   935
icculus@12278
   936
    minx = -center->x;
icculus@12278
   937
    maxx = dstrect->w - center->x;
icculus@12278
   938
    miny = -center->y;
icculus@12278
   939
    maxy = dstrect->h - center->y;
icculus@12278
   940
icculus@12278
   941
    if (flip & SDL_FLIP_HORIZONTAL) {
icculus@12278
   942
        minu = (float) (srcquad->x + srcquad->w) / texture->w;
icculus@12278
   943
        maxu = (float) srcquad->x / texture->w;
icculus@12278
   944
    } else {
icculus@12278
   945
        minu = (float) srcquad->x / texture->w;
icculus@12278
   946
        maxu = (float) (srcquad->x + srcquad->w) / texture->w;
slouken@10408
   947
    }
slouken@10408
   948
icculus@12278
   949
    if (flip & SDL_FLIP_VERTICAL) {
icculus@12278
   950
        minv = (float) (srcquad->y + srcquad->h) / texture->h;
icculus@12278
   951
        maxv = (float) srcquad->y / texture->h;
slouken@5299
   952
    } else {
icculus@12278
   953
        minv = (float) srcquad->y / texture->h;
icculus@12278
   954
        maxv = (float) (srcquad->y + srcquad->h) / texture->h;
slouken@5299
   955
    }
slouken@5297
   956
icculus@12278
   957
    verts->x = minx;
icculus@12278
   958
    verts->y = miny;
icculus@12278
   959
    verts->z = 0.0f;
icculus@12278
   960
    verts->color = color;
icculus@12278
   961
    verts->u = minu;
icculus@12278
   962
    verts->v = minv;
icculus@12278
   963
    verts++;
icculus@12278
   964
icculus@12278
   965
    verts->x = maxx;
icculus@12278
   966
    verts->y = miny;
icculus@12278
   967
    verts->z = 0.0f;
icculus@12278
   968
    verts->color = color;
icculus@12278
   969
    verts->u = maxu;
icculus@12278
   970
    verts->v = minv;
icculus@12278
   971
    verts++;
icculus@12278
   972
icculus@12278
   973
    verts->x = maxx;
icculus@12278
   974
    verts->y = maxy;
icculus@12278
   975
    verts->z = 0.0f;
icculus@12278
   976
    verts->color = color;
icculus@12278
   977
    verts->u = maxu;
icculus@12278
   978
    verts->v = maxv;
icculus@12278
   979
    verts++;
icculus@12278
   980
icculus@12278
   981
    verts->x = minx;
icculus@12278
   982
    verts->y = maxy;
icculus@12278
   983
    verts->z = 0.0f;
icculus@12278
   984
    verts->color = color;
icculus@12278
   985
    verts->u = minu;
icculus@12278
   986
    verts->v = maxv;
icculus@12278
   987
    verts++;
icculus@12278
   988
icculus@12278
   989
    verts->x = dstrect->x + center->x - 0.5f;  /* X translation */
icculus@12278
   990
    verts->y = dstrect->y + center->y - 0.5f;  /* Y translation */
icculus@12278
   991
    verts->z = (float)(M_PI * (float) angle / 180.0f);  /* rotation */
icculus@12278
   992
    verts->color = 0;
icculus@12278
   993
    verts->u = 0.0f;
icculus@12278
   994
    verts->v = 0.0f;
icculus@12278
   995
    verts++;
icculus@12278
   996
icculus@12278
   997
    return 0;
icculus@12278
   998
}
icculus@12278
   999
icculus@12278
  1000
static int
icculus@12446
  1001
UpdateDirtyTexture(IDirect3DDevice9 *device, D3D_TextureRep *texture)
icculus@12278
  1002
{
icculus@12278
  1003
    if (texture->dirty && texture->staging) {
icculus@12446
  1004
        HRESULT result;
icculus@12278
  1005
        if (!texture->texture) {
icculus@12278
  1006
            result = IDirect3DDevice9_CreateTexture(device, texture->w, texture->h, 1, texture->usage,
icculus@12278
  1007
                PixelFormatToD3DFMT(texture->format), D3DPOOL_DEFAULT, &texture->texture, NULL);
icculus@12278
  1008
            if (FAILED(result)) {
icculus@12278
  1009
                return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
icculus@12278
  1010
            }
icculus@12278
  1011
        }
icculus@12278
  1012
icculus@12278
  1013
        result = IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)texture->staging, (IDirect3DBaseTexture9 *)texture->texture);
icculus@12278
  1014
        if (FAILED(result)) {
icculus@12278
  1015
            return D3D_SetError("UpdateTexture()", result);
icculus@12278
  1016
        }
icculus@12278
  1017
        texture->dirty = SDL_FALSE;
slouken@10408
  1018
    }
icculus@12446
  1019
    return 0;
icculus@12446
  1020
}
icculus@12446
  1021
icculus@12446
  1022
static int
icculus@12446
  1023
BindTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWORD sampler)
icculus@12446
  1024
{
icculus@12446
  1025
    HRESULT result;
icculus@12446
  1026
    UpdateDirtyTexture(device, texture);
icculus@12278
  1027
    result = IDirect3DDevice9_SetTexture(device, sampler, (IDirect3DBaseTexture9 *)texture->texture);
slouken@5297
  1028
    if (FAILED(result)) {
icculus@12278
  1029
        return D3D_SetError("SetTexture()", result);
slouken@5297
  1030
    }
slouken@5297
  1031
    return 0;
slouken@5224
  1032
}
slouken@5224
  1033
slouken@5224
  1034
static void
icculus@12278
  1035
UpdateTextureScaleMode(D3D_RenderData *data, D3D_TextureData *texturedata, unsigned index)
slouken@7505
  1036
{
slouken@7505
  1037
    if (texturedata->scaleMode != data->scaleMode[index]) {
slouken@7505
  1038
        IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MINFILTER,
slouken@7505
  1039
                                         texturedata->scaleMode);
slouken@7505
  1040
        IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MAGFILTER,
slouken@7505
  1041
                                         texturedata->scaleMode);
slouken@11737
  1042
        IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_ADDRESSU,
slouken@11737
  1043
                                         D3DTADDRESS_CLAMP);
slouken@11737
  1044
        IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_ADDRESSV,
slouken@11737
  1045
                                         D3DTADDRESS_CLAMP);
slouken@7505
  1046
        data->scaleMode[index] = texturedata->scaleMode;
slouken@7505
  1047
    }
slouken@7505
  1048
}
slouken@7505
  1049
slouken@1895
  1050
static int
icculus@12278
  1051
SetupTextureState(D3D_RenderData *data, SDL_Texture * texture, LPDIRECT3DPIXELSHADER9 *shader)
slouken@11702
  1052
{
icculus@12278
  1053
    D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
slouken@11702
  1054
icculus@12278
  1055
    SDL_assert(*shader == NULL);
slouken@11702
  1056
slouken@11702
  1057
    if (!texturedata) {
slouken@11702
  1058
        SDL_SetError("Texture is not currently available");
slouken@11702
  1059
        return -1;
slouken@11702
  1060
    }
slouken@11702
  1061
icculus@12278
  1062
    UpdateTextureScaleMode(data, texturedata, 0);
slouken@11702
  1063
icculus@12278
  1064
    if (BindTextureRep(data->device, &texturedata->texture, 0) < 0) {
slouken@11702
  1065
        return -1;
slouken@11702
  1066
    }
slouken@11702
  1067
slouken@11702
  1068
    if (texturedata->yuv) {
slouken@11702
  1069
        switch (SDL_GetYUVConversionModeForResolution(texture->w, texture->h)) {
slouken@11702
  1070
        case SDL_YUV_CONVERSION_JPEG:
slouken@11702
  1071
            *shader = data->shaders[SHADER_YUV_JPEG];
slouken@11702
  1072
            break;
slouken@11702
  1073
        case SDL_YUV_CONVERSION_BT601:
slouken@11702
  1074
            *shader = data->shaders[SHADER_YUV_BT601];
slouken@11702
  1075
            break;
slouken@11702
  1076
        case SDL_YUV_CONVERSION_BT709:
slouken@11702
  1077
            *shader = data->shaders[SHADER_YUV_BT709];
slouken@11702
  1078
            break;
slouken@11702
  1079
        default:
slouken@11702
  1080
            return SDL_SetError("Unsupported YUV conversion mode");
slouken@11702
  1081
        }
slouken@11702
  1082
icculus@12278
  1083
        UpdateTextureScaleMode(data, texturedata, 1);
icculus@12278
  1084
        UpdateTextureScaleMode(data, texturedata, 2);
slouken@11702
  1085
icculus@12278
  1086
        if (BindTextureRep(data->device, &texturedata->utexture, 1) < 0) {
slouken@11702
  1087
            return -1;
slouken@11702
  1088
        }
icculus@12278
  1089
        if (BindTextureRep(data->device, &texturedata->vtexture, 2) < 0) {
slouken@11702
  1090
            return -1;
slouken@11702
  1091
        }
slouken@11702
  1092
    }
slouken@11702
  1093
    return 0;
slouken@11702
  1094
}
slouken@11702
  1095
slouken@11702
  1096
static int
icculus@12279
  1097
SetDrawState(D3D_RenderData *data, const SDL_RenderCommand *cmd)
icculus@12278
  1098
{
icculus@12278
  1099
    const SDL_bool was_copy_ex = data->drawstate.is_copy_ex;
icculus@12278
  1100
    const SDL_bool is_copy_ex = (cmd->command == SDL_RENDERCMD_COPY_EX);
icculus@12278
  1101
    SDL_Texture *texture = cmd->data.draw.texture;
icculus@12278
  1102
    const SDL_BlendMode blend = cmd->data.draw.blend;
icculus@12278
  1103
icculus@12278
  1104
    if (texture != data->drawstate.texture) {
icculus@12278
  1105
        D3D_TextureData *oldtexturedata = data->drawstate.texture ? (D3D_TextureData *) data->drawstate.texture->driverdata : NULL;
icculus@12278
  1106
        D3D_TextureData *newtexturedata = texture ? (D3D_TextureData *) texture->driverdata : NULL;
icculus@12278
  1107
        LPDIRECT3DPIXELSHADER9 shader = NULL;
icculus@12278
  1108
icculus@12278
  1109
        /* disable any enabled textures we aren't going to use, let SetupTextureState() do the rest. */
icculus@12278
  1110
        if (texture == NULL) {
icculus@12278
  1111
            IDirect3DDevice9_SetTexture(data->device, 0, NULL);
icculus@12278
  1112
        }
icculus@12278
  1113
        if ((!newtexturedata || !newtexturedata->yuv) && (oldtexturedata && oldtexturedata->yuv)) {
icculus@12278
  1114
            IDirect3DDevice9_SetTexture(data->device, 1, NULL);
icculus@12278
  1115
            IDirect3DDevice9_SetTexture(data->device, 2, NULL);
icculus@12278
  1116
        }
icculus@12279
  1117
        if (texture && SetupTextureState(data, texture, &shader) < 0) {
icculus@12278
  1118
            return -1;
icculus@12278
  1119
        }
icculus@12278
  1120
icculus@12279
  1121
        if (shader != data->drawstate.shader) {
icculus@12279
  1122
            const HRESULT result = IDirect3DDevice9_SetPixelShader(data->device, shader);
icculus@12279
  1123
            if (FAILED(result)) {
icculus@12278
  1124
                return D3D_SetError("IDirect3DDevice9_SetPixelShader()", result);
icculus@12278
  1125
            }
icculus@12278
  1126
            data->drawstate.shader = shader;
icculus@12278
  1127
        }
icculus@12278
  1128
icculus@12278
  1129
        data->drawstate.texture = texture;
aicommander@12898
  1130
    } else if (texture) {
aicommander@12898
  1131
        D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata;
aicommander@12898
  1132
        UpdateDirtyTexture(data->device, &texturedata->texture);
aicommander@12898
  1133
        if (texturedata->yuv) {
aicommander@12898
  1134
            UpdateDirtyTexture(data->device, &texturedata->utexture);
aicommander@12898
  1135
            UpdateDirtyTexture(data->device, &texturedata->vtexture);
aicommander@12898
  1136
        }
icculus@12278
  1137
    }
icculus@12278
  1138
icculus@12278
  1139
    if (blend != data->drawstate.blend) {
icculus@12278
  1140
        if (blend == SDL_BLENDMODE_NONE) {
icculus@12278
  1141
            IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, FALSE);
icculus@12278
  1142
        } else {
icculus@12278
  1143
            IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, TRUE);
icculus@12278
  1144
            IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
icculus@12279
  1145
                                            GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blend)));
icculus@12278
  1146
            IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
icculus@12279
  1147
                                            GetBlendFunc(SDL_GetBlendModeDstColorFactor(blend)));
icculus@12278
  1148
            if (data->enableSeparateAlphaBlend) {
icculus@12278
  1149
                IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA,
icculus@12279
  1150
                                                GetBlendFunc(SDL_GetBlendModeSrcAlphaFactor(blend)));
icculus@12278
  1151
                IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA,
icculus@12279
  1152
                                                GetBlendFunc(SDL_GetBlendModeDstAlphaFactor(blend)));
icculus@12278
  1153
            }
icculus@12278
  1154
        }
icculus@12278
  1155
icculus@12278
  1156
        data->drawstate.blend = blend;
icculus@12278
  1157
    }
icculus@12278
  1158
icculus@12278
  1159
    if (is_copy_ex != was_copy_ex) {
icculus@12278
  1160
        if (!is_copy_ex) {  /* SDL_RENDERCMD_COPY_EX will set this, we only want to reset it here if necessary. */
icculus@12278
  1161
            const Float4X4 d3dmatrix = MatrixIdentity();
icculus@12278
  1162
            IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*) &d3dmatrix);
icculus@12278
  1163
        }
icculus@12278
  1164
        data->drawstate.is_copy_ex = is_copy_ex;
icculus@12278
  1165
    }
icculus@12278
  1166
icculus@12278
  1167
    if (data->drawstate.viewport_dirty) {
icculus@12278
  1168
        const SDL_Rect *viewport = &data->drawstate.viewport;
icculus@12278
  1169
        const D3DVIEWPORT9 d3dviewport = { viewport->x, viewport->y, viewport->w, viewport->h, 0.0f, 1.0f };
icculus@12278
  1170
        IDirect3DDevice9_SetViewport(data->device, &d3dviewport);
icculus@12278
  1171
icculus@12278
  1172
        /* Set an orthographic projection matrix */
icculus@12278
  1173
        if (viewport->w && viewport->h) {
icculus@12278
  1174
            D3DMATRIX d3dmatrix;
icculus@12278
  1175
            SDL_zero(d3dmatrix);
icculus@12278
  1176
            d3dmatrix.m[0][0] = 2.0f / viewport->w;
icculus@12278
  1177
            d3dmatrix.m[1][1] = -2.0f / viewport->h;
icculus@12278
  1178
            d3dmatrix.m[2][2] = 1.0f;
icculus@12278
  1179
            d3dmatrix.m[3][0] = -1.0f;
icculus@12278
  1180
            d3dmatrix.m[3][1] = 1.0f;
icculus@12278
  1181
            d3dmatrix.m[3][3] = 1.0f;
icculus@12278
  1182
            IDirect3DDevice9_SetTransform(data->device, D3DTS_PROJECTION, &d3dmatrix);
icculus@12278
  1183
        }
icculus@12278
  1184
icculus@12278
  1185
        data->drawstate.viewport_dirty = SDL_FALSE;
icculus@12278
  1186
    }
icculus@12278
  1187
icculus@12278
  1188
    if (data->drawstate.cliprect_enabled_dirty) {
icculus@12278
  1189
        IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, data->drawstate.cliprect_enabled ? TRUE : FALSE);
icculus@12278
  1190
        data->drawstate.cliprect_enabled_dirty = SDL_FALSE;
icculus@12278
  1191
    }
icculus@12278
  1192
icculus@12278
  1193
    if (data->drawstate.cliprect_dirty) {
icculus@12278
  1194
        const SDL_Rect *viewport = &data->drawstate.viewport;
icculus@12833
  1195
        const SDL_Rect *rect = &data->drawstate.cliprect;
icculus@12278
  1196
        const RECT d3drect = { viewport->x + rect->x, viewport->y + rect->y, viewport->x + rect->x + rect->w, viewport->y + rect->y + rect->h };
icculus@12278
  1197
        IDirect3DDevice9_SetScissorRect(data->device, &d3drect);
icculus@12278
  1198
        data->drawstate.cliprect_dirty = SDL_FALSE;
icculus@12278
  1199
    }
icculus@12278
  1200
icculus@12278
  1201
    return 0;
icculus@12278
  1202
}
icculus@12278
  1203
icculus@12278
  1204
static int
icculus@12278
  1205
D3D_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
slouken@1895
  1206
{
slouken@1913
  1207
    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
icculus@12278
  1208
    const int vboidx = data->currentVertexBuffer;
icculus@12278
  1209
    IDirect3DVertexBuffer9 *vbo = NULL;
icculus@12278
  1210
    const SDL_bool istarget = renderer->target != NULL;
icculus@12278
  1211
    size_t i;
slouken@1895
  1212
slouken@5297
  1213
    if (D3D_ActivateRenderer(renderer) < 0) {
slouken@5297
  1214
        return -1;
slouken@1900
  1215
    }
slouken@1903
  1216
icculus@12278
  1217
    /* upload the new VBO data for this set of commands. */
icculus@12281
  1218
    vbo = data->vertexBuffers[vboidx];
icculus@12281
  1219
    if (!vbo || (data->vertexBufferSize[vboidx] < vertsize)) {
icculus@12281
  1220
        const DWORD usage = D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY;
icculus@12281
  1221
        const DWORD fvf = D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1;
icculus@12281
  1222
        if (vbo) {
icculus@12281
  1223
            IDirect3DVertexBuffer9_Release(vbo);
icculus@12278
  1224
        }
slouken@1903
  1225
icculus@12900
  1226
        if (FAILED(IDirect3DDevice9_CreateVertexBuffer(data->device, (UINT) vertsize, usage, fvf, D3DPOOL_DEFAULT, &vbo, NULL))) {
icculus@12281
  1227
            vbo = NULL;
icculus@12281
  1228
        }
icculus@12281
  1229
        data->vertexBuffers[vboidx] = vbo;
icculus@12281
  1230
        data->vertexBufferSize[vboidx] = vbo ? vertsize : 0;
icculus@12281
  1231
    }
icculus@12281
  1232
icculus@12281
  1233
    if (vbo) {
icculus@12281
  1234
        void *ptr;
icculus@12827
  1235
        if (FAILED(IDirect3DVertexBuffer9_Lock(vbo, 0, (UINT) vertsize, &ptr, D3DLOCK_DISCARD))) {
icculus@12281
  1236
            vbo = NULL;  /* oh well, we'll do immediate mode drawing.  :(  */
icculus@12281
  1237
        } else {
icculus@12281
  1238
            SDL_memcpy(ptr, vertices, vertsize);
icculus@12281
  1239
            if (FAILED(IDirect3DVertexBuffer9_Unlock(vbo))) {
icculus@12278
  1240
                vbo = NULL;  /* oh well, we'll do immediate mode drawing.  :(  */
icculus@12278
  1241
            }
slouken@3556
  1242
        }
slouken@3556
  1243
    }
icculus@12278
  1244
icculus@12281
  1245
    /* cycle through a few VBOs so D3D has some time with the data before we replace it. */
icculus@12281
  1246
    if (vbo) {
icculus@12281
  1247
        data->currentVertexBuffer++;
icculus@12281
  1248
        if (data->currentVertexBuffer >= SDL_arraysize(data->vertexBuffers)) {
icculus@12281
  1249
            data->currentVertexBuffer = 0;
icculus@12281
  1250
        }
icculus@12281
  1251
    } else if (!data->reportedVboProblem) {
icculus@12278
  1252
        SDL_LogError(SDL_LOG_CATEGORY_RENDER, "SDL failed to get a vertex buffer for this Direct3D 9 rendering batch!");
icculus@12278
  1253
        SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Dropping back to a slower method.");
icculus@12278
  1254
        SDL_LogError(SDL_LOG_CATEGORY_RENDER, "This might be a brief hiccup, but if performance is bad, this is probably why.");
icculus@12278
  1255
        SDL_LogError(SDL_LOG_CATEGORY_RENDER, "This error will not be logged again for this renderer.");
icculus@12278
  1256
        data->reportedVboProblem = SDL_TRUE;
slouken@1903
  1257
    }
icculus@12278
  1258
icculus@12280
  1259
    IDirect3DDevice9_SetStreamSource(data->device, 0, vbo, 0, sizeof (Vertex));
icculus@12280
  1260
icculus@12278
  1261
    while (cmd) {
icculus@12278
  1262
        switch (cmd->command) {
icculus@12278
  1263
            case SDL_RENDERCMD_SETDRAWCOLOR: {
icculus@12278
  1264
                /* currently this is sent with each vertex, but if we move to
icculus@12278
  1265
                   shaders, we can put this in a uniform here and reduce vertex
icculus@12278
  1266
                   buffer bandwidth */
icculus@12278
  1267
                break;
icculus@12278
  1268
            }
icculus@12278
  1269
icculus@12278
  1270
            case SDL_RENDERCMD_SETVIEWPORT: {
icculus@12278
  1271
                SDL_Rect *viewport = &data->drawstate.viewport;
icculus@12278
  1272
                if (SDL_memcmp(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect)) != 0) {
icculus@12278
  1273
                    SDL_memcpy(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect));
icculus@12278
  1274
                    data->drawstate.viewport_dirty = SDL_TRUE;
icculus@12278
  1275
                }
icculus@12278
  1276
                break;
icculus@12278
  1277
            }
icculus@12278
  1278
icculus@12278
  1279
            case SDL_RENDERCMD_SETCLIPRECT: {
icculus@12278
  1280
                const SDL_Rect *rect = &cmd->data.cliprect.rect;
icculus@12278
  1281
                if (data->drawstate.cliprect_enabled != cmd->data.cliprect.enabled) {
icculus@12278
  1282
                    data->drawstate.cliprect_enabled = cmd->data.cliprect.enabled;
icculus@12279
  1283
                    data->drawstate.cliprect_enabled_dirty = SDL_TRUE;
icculus@12278
  1284
                }
icculus@12278
  1285
icculus@12278
  1286
                if (SDL_memcmp(&data->drawstate.cliprect, rect, sizeof (SDL_Rect)) != 0) {
icculus@12278
  1287
                    SDL_memcpy(&data->drawstate.cliprect, rect, sizeof (SDL_Rect));
icculus@12278
  1288
                    data->drawstate.cliprect_dirty = SDL_TRUE;
icculus@12278
  1289
                }
icculus@12278
  1290
                break;
icculus@12278
  1291
            }
icculus@12278
  1292
icculus@12278
  1293
            case SDL_RENDERCMD_CLEAR: {
icculus@12278
  1294
                const DWORD color = D3DCOLOR_ARGB(cmd->data.color.a, cmd->data.color.r, cmd->data.color.g, cmd->data.color.b);
icculus@12278
  1295
                const SDL_Rect *viewport = &data->drawstate.viewport;
icculus@12278
  1296
                const int backw = istarget ? renderer->target->w : data->pparams.BackBufferWidth;
icculus@12279
  1297
                const int backh = istarget ? renderer->target->h : data->pparams.BackBufferHeight;
icculus@12278
  1298
icculus@12279
  1299
                if (data->drawstate.cliprect_enabled) {
icculus@12278
  1300
                    IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, FALSE);
icculus@12278
  1301
                    data->drawstate.cliprect_enabled_dirty = SDL_TRUE;
icculus@12278
  1302
                }
icculus@12278
  1303
icculus@12278
  1304
                /* Don't reset the viewport if we don't have to! */
icculus@12279
  1305
                if (!viewport->x && !viewport->y && (viewport->w == backw) && (viewport->h == backh)) {
icculus@12279
  1306
                    IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
icculus@12278
  1307
                } else {
icculus@12278
  1308
                    /* Clear is defined to clear the entire render target */
icculus@12278
  1309
                    const D3DVIEWPORT9 wholeviewport = { 0, 0, backw, backh, 0.0f, 1.0f };
icculus@12278
  1310
                    IDirect3DDevice9_SetViewport(data->device, &wholeviewport);
icculus@12278
  1311
                    data->drawstate.viewport_dirty = SDL_TRUE;
icculus@12278
  1312
                    IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
icculus@12278
  1313
                }
icculus@12278
  1314
icculus@12278
  1315
                break;
icculus@12278
  1316
            }
icculus@12278
  1317
icculus@12278
  1318
            case SDL_RENDERCMD_DRAW_POINTS: {
icculus@12278
  1319
                const size_t count = cmd->data.draw.count;
icculus@12278
  1320
                const size_t first = cmd->data.draw.first;
icculus@12278
  1321
                SetDrawState(data, cmd);
icculus@12278
  1322
                if (vbo) {
icculus@12827
  1323
                    IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_POINTLIST, (UINT) (first / sizeof (Vertex)), (UINT) count);
icculus@12278
  1324
                } else {
icculus@12278
  1325
                    const Vertex *verts = (Vertex *) (((Uint8 *) vertices) + first);
icculus@12827
  1326
                    IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, (UINT) count, verts, sizeof (Vertex));
icculus@12278
  1327
                }
icculus@12278
  1328
                break;
icculus@12278
  1329
            }
icculus@12278
  1330
icculus@12278
  1331
            case SDL_RENDERCMD_DRAW_LINES: {
icculus@12278
  1332
                const size_t count = cmd->data.draw.count;
icculus@12278
  1333
                const size_t first = cmd->data.draw.first;
icculus@12279
  1334
                const Vertex *verts = (Vertex *) (((Uint8 *) vertices) + first);
icculus@12278
  1335
icculus@12278
  1336
                /* DirectX 9 has the same line rasterization semantics as GDI,
icculus@12278
  1337
                   so we need to close the endpoint of the line with a second draw call. */
icculus@12278
  1338
                const SDL_bool close_endpoint = ((count == 2) || (verts[0].x != verts[count-1].x) || (verts[0].y != verts[count-1].y));
icculus@12278
  1339
icculus@12278
  1340
                SetDrawState(data, cmd);
icculus@12278
  1341
icculus@12278
  1342
                if (vbo) {
icculus@12827
  1343
                    IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_LINESTRIP, (UINT) (first / sizeof (Vertex)), (UINT) (count - 1));
icculus@12278
  1344
                    if (close_endpoint) {
icculus@12827
  1345
                        IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_POINTLIST, (UINT) ((first / sizeof (Vertex)) + (count - 1)), 1);
icculus@12278
  1346
                    }
icculus@12278
  1347
                } else {
icculus@12827
  1348
                    IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_LINESTRIP, (UINT) (count - 1), verts, sizeof (Vertex));
icculus@12278
  1349
                    if (close_endpoint) {
icculus@12278
  1350
                        IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, 1, &verts[count-1], sizeof (Vertex));
icculus@12278
  1351
                    }
icculus@12278
  1352
                }
icculus@12278
  1353
                break;
icculus@12278
  1354
            }
icculus@12278
  1355
icculus@12278
  1356
            case SDL_RENDERCMD_FILL_RECTS: {
icculus@12278
  1357
                const size_t count = cmd->data.draw.count;
icculus@12278
  1358
                const size_t first = cmd->data.draw.first;
icculus@12278
  1359
                SetDrawState(data, cmd);
icculus@12278
  1360
                if (vbo) {
icculus@12278
  1361
                    size_t offset = 0;
icculus@12278
  1362
                    for (i = 0; i < count; ++i, offset += 4) {
icculus@12827
  1363
                        IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_TRIANGLEFAN, (UINT) ((first / sizeof (Vertex)) + offset), 2);
icculus@12278
  1364
                    }
icculus@12278
  1365
                } else {
icculus@12278
  1366
                    const Vertex *verts = (Vertex *) (((Uint8 *) vertices) + first);
icculus@12278
  1367
                    for (i = 0; i < count; ++i, verts += 4) {
icculus@12278
  1368
                        IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2, verts, sizeof (Vertex));
icculus@12278
  1369
                    }
icculus@12278
  1370
                }
icculus@12278
  1371
                break;
icculus@12278
  1372
            }
icculus@12278
  1373
icculus@12278
  1374
            case SDL_RENDERCMD_COPY: {
icculus@12278
  1375
                const size_t count = cmd->data.draw.count;
icculus@12278
  1376
                const size_t first = cmd->data.draw.first;
icculus@12278
  1377
                SetDrawState(data, cmd);
icculus@12278
  1378
                if (vbo) {
icculus@12278
  1379
                    size_t offset = 0;
icculus@12278
  1380
                    for (i = 0; i < count; ++i, offset += 4) {
icculus@12827
  1381
                        IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_TRIANGLEFAN, (UINT) ((first / sizeof (Vertex)) + offset), 2);
icculus@12278
  1382
                    }
icculus@12278
  1383
                } else {
icculus@12278
  1384
                    const Vertex *verts = (Vertex *) (((Uint8 *) vertices) + first);
icculus@12278
  1385
                    for (i = 0; i < count; ++i, verts += 4) {
icculus@12278
  1386
                        IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2, verts, sizeof (Vertex));
icculus@12278
  1387
                    }
icculus@12278
  1388
                }
icculus@12278
  1389
                break;
icculus@12278
  1390
            }
icculus@12278
  1391
icculus@12278
  1392
            case SDL_RENDERCMD_COPY_EX: {
icculus@12279
  1393
                const size_t first = cmd->data.draw.first;
icculus@12278
  1394
                const Vertex *verts = (Vertex *) (((Uint8 *) vertices) + first);
icculus@12278
  1395
                const Vertex *transvert = verts + 4;
icculus@12278
  1396
                const float translatex = transvert->x;
icculus@12278
  1397
                const float translatey = transvert->y;
icculus@12278
  1398
                const float rotation = transvert->z;
icculus@12278
  1399
                const Float4X4 d3dmatrix = MatrixMultiply(MatrixRotationZ(rotation), MatrixTranslation(translatex, translatey, 0));
icculus@12278
  1400
                SetDrawState(data, cmd);
icculus@12278
  1401
icculus@12278
  1402
                IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)&d3dmatrix);
icculus@12278
  1403
icculus@12278
  1404
                if (vbo) {
icculus@12827
  1405
                    IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_TRIANGLEFAN, (UINT) (first / sizeof (Vertex)), 2);
icculus@12278
  1406
                } else {
icculus@12278
  1407
                    IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2, verts, sizeof (Vertex));
icculus@12278
  1408
                }
icculus@12278
  1409
                break;
icculus@12278
  1410
            }
icculus@12278
  1411
icculus@12278
  1412
            case SDL_RENDERCMD_NO_OP:
icculus@12278
  1413
                break;
icculus@12278
  1414
        }
icculus@12278
  1415
icculus@12278
  1416
        cmd = cmd->next;
slouken@3556
  1417
    }
icculus@12278
  1418
icculus@12278
  1419
    return 0;
slouken@1895
  1420
}
slouken@1895
  1421
gabomdq@6320
  1422
gabomdq@6320
  1423
static int
slouken@3427
  1424
D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
slouken@3480
  1425
                     Uint32 format, void * pixels, int pitch)
slouken@3427
  1426
{
slouken@3549
  1427
    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
slouken@3549
  1428
    D3DSURFACE_DESC desc;
slouken@3549
  1429
    LPDIRECT3DSURFACE9 backBuffer;
slouken@3549
  1430
    LPDIRECT3DSURFACE9 surface;
slouken@3549
  1431
    RECT d3drect;
slouken@3549
  1432
    D3DLOCKED_RECT locked;
slouken@3549
  1433
    HRESULT result;
slouken@3427
  1434
slouken@9085
  1435
    if (data->currentRenderTarget) {
slouken@9085
  1436
        backBuffer = data->currentRenderTarget;
slouken@9085
  1437
    } else {
slouken@9085
  1438
        backBuffer = data->defaultRenderTarget;
slouken@3549
  1439
    }
slouken@3427
  1440
slouken@3549
  1441
    result = IDirect3DSurface9_GetDesc(backBuffer, &desc);
slouken@3549
  1442
    if (FAILED(result)) {
slouken@3549
  1443
        IDirect3DSurface9_Release(backBuffer);
icculus@7037
  1444
        return D3D_SetError("GetDesc()", result);
slouken@3549
  1445
    }
slouken@3427
  1446
slouken@3549
  1447
    result = IDirect3DDevice9_CreateOffscreenPlainSurface(data->device, desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surface, NULL);
slouken@3549
  1448
    if (FAILED(result)) {
slouken@3549
  1449
        IDirect3DSurface9_Release(backBuffer);
icculus@7037
  1450
        return D3D_SetError("CreateOffscreenPlainSurface()", result);
slouken@3549
  1451
    }
slouken@3427
  1452
slouken@3549
  1453
    result = IDirect3DDevice9_GetRenderTargetData(data->device, backBuffer, surface);
slouken@3549
  1454
    if (FAILED(result)) {
slouken@3549
  1455
        IDirect3DSurface9_Release(surface);
slouken@3549
  1456
        IDirect3DSurface9_Release(backBuffer);
icculus@7037
  1457
        return D3D_SetError("GetRenderTargetData()", result);
slouken@3549
  1458
    }
slouken@3427
  1459
slouken@3549
  1460
    d3drect.left = rect->x;
slouken@3549
  1461
    d3drect.right = rect->x + rect->w;
slouken@3549
  1462
    d3drect.top = rect->y;
slouken@3549
  1463
    d3drect.bottom = rect->y + rect->h;
slouken@3427
  1464
slouken@3549
  1465
    result = IDirect3DSurface9_LockRect(surface, &locked, &d3drect, D3DLOCK_READONLY);
slouken@3549
  1466
    if (FAILED(result)) {
slouken@3549
  1467
        IDirect3DSurface9_Release(surface);
slouken@3549
  1468
        IDirect3DSurface9_Release(backBuffer);
icculus@7037
  1469
        return D3D_SetError("LockRect()", result);
slouken@3549
  1470
    }
slouken@3427
  1471
slouken@3549
  1472
    SDL_ConvertPixels(rect->w, rect->h,
slouken@5156
  1473
                      D3DFMTToPixelFormat(desc.Format), locked.pBits, locked.Pitch,
slouken@3549
  1474
                      format, pixels, pitch);
slouken@3549
  1475
slouken@3549
  1476
    IDirect3DSurface9_UnlockRect(surface);
slouken@3549
  1477
slouken@3549
  1478
    IDirect3DSurface9_Release(surface);
slouken@3549
  1479
slouken@3549
  1480
    return 0;
slouken@3427
  1481
}
slouken@3427
  1482
slouken@1895
  1483
static void
slouken@1913
  1484
D3D_RenderPresent(SDL_Renderer * renderer)
slouken@1895
  1485
{
slouken@1913
  1486
    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
slouken@1900
  1487
    HRESULT result;
slouken@1900
  1488
slouken@1900
  1489
    if (!data->beginScene) {
slouken@1900
  1490
        IDirect3DDevice9_EndScene(data->device);
slouken@1900
  1491
        data->beginScene = SDL_TRUE;
slouken@1900
  1492
    }
slouken@1900
  1493
slouken@1975
  1494
    result = IDirect3DDevice9_TestCooperativeLevel(data->device);
slouken@1975
  1495
    if (result == D3DERR_DEVICELOST) {
slouken@1975
  1496
        /* We'll reset later */
slouken@1975
  1497
        return;
slouken@1975
  1498
    }
slouken@1975
  1499
    if (result == D3DERR_DEVICENOTRESET) {
slouken@1975
  1500
        D3D_Reset(renderer);
slouken@1975
  1501
    }
slouken@1900
  1502
    result = IDirect3DDevice9_Present(data->device, NULL, NULL, NULL, NULL);
slouken@1900
  1503
    if (FAILED(result)) {
slouken@1900
  1504
        D3D_SetError("Present()", result);
slouken@1900
  1505
    }
slouken@1895
  1506
}
slouken@1895
  1507
slouken@1895
  1508
static void
slouken@1913
  1509
D3D_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@1895
  1510
{
icculus@12832
  1511
    D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata;
slouken@1913
  1512
    D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
slouken@1895
  1513
icculus@12832
  1514
    if (renderdata->drawstate.texture == texture) {
icculus@12832
  1515
        renderdata->drawstate.texture = NULL;
icculus@12832
  1516
    }
icculus@12832
  1517
slouken@1895
  1518
    if (!data) {
slouken@1895
  1519
        return;
slouken@1895
  1520
    }
icculus@12833
  1521
slouken@8792
  1522
    D3D_DestroyTextureRep(&data->texture);
slouken@8792
  1523
    D3D_DestroyTextureRep(&data->utexture);
slouken@8792
  1524
    D3D_DestroyTextureRep(&data->vtexture);
slouken@7719
  1525
    SDL_free(data->pixels);
slouken@1895
  1526
    SDL_free(data);
slouken@1895
  1527
    texture->driverdata = NULL;
slouken@1895
  1528
}
slouken@1895
  1529
slouken@1975
  1530
static void
slouken@1913
  1531
D3D_DestroyRenderer(SDL_Renderer * renderer)
slouken@1895
  1532
{
slouken@1913
  1533
    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
slouken@1895
  1534
slouken@1895
  1535
    if (data) {
slouken@11702
  1536
        int i;
slouken@11702
  1537
slouken@7191
  1538
        /* Release the render target */
slouken@6895
  1539
        if (data->defaultRenderTarget) {
slouken@6895
  1540
            IDirect3DSurface9_Release(data->defaultRenderTarget);
slouken@6895
  1541
            data->defaultRenderTarget = NULL;
slouken@6895
  1542
        }
slouken@6232
  1543
        if (data->currentRenderTarget != NULL) {
slouken@6232
  1544
            IDirect3DSurface9_Release(data->currentRenderTarget);
slouken@6232
  1545
            data->currentRenderTarget = NULL;
slouken@6232
  1546
        }
slouken@11702
  1547
        for (i = 0; i < SDL_arraysize(data->shaders); ++i) {
slouken@11702
  1548
            if (data->shaders[i]) {
slouken@11702
  1549
                IDirect3DPixelShader9_Release(data->shaders[i]);
slouken@11702
  1550
                data->shaders[i] = NULL;
slouken@11702
  1551
            }
icculus@7658
  1552
        }
icculus@12900
  1553
        /* Release all vertex buffers */
icculus@12900
  1554
        for (i = 0; i < SDL_arraysize(data->vertexBuffers); ++i) {
icculus@12900
  1555
            if (data->vertexBuffers[i]) {
icculus@12900
  1556
                IDirect3DVertexBuffer9_Release(data->vertexBuffers[i]);
icculus@12900
  1557
            }
icculus@12900
  1558
            data->vertexBuffers[i] = NULL;
icculus@12900
  1559
        }
slouken@1900
  1560
        if (data->device) {
slouken@1900
  1561
            IDirect3DDevice9_Release(data->device);
slouken@11702
  1562
            data->device = NULL;
slouken@1900
  1563
        }
slouken@5154
  1564
        if (data->d3d) {
slouken@5154
  1565
            IDirect3D9_Release(data->d3d);
slouken@5154
  1566
            SDL_UnloadObject(data->d3dDLL);
slouken@5154
  1567
        }
slouken@1895
  1568
        SDL_free(data);
slouken@1895
  1569
    }
slouken@1895
  1570
    SDL_free(renderer);
slouken@1895
  1571
}
icculus@12278
  1572
icculus@12279
  1573
static int
icculus@12279
  1574
D3D_Reset(SDL_Renderer * renderer)
icculus@12279
  1575
{
icculus@12279
  1576
    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
icculus@12448
  1577
    const Float4X4 d3dmatrix = MatrixIdentity();
icculus@12279
  1578
    HRESULT result;
icculus@12279
  1579
    SDL_Texture *texture;
icculus@12445
  1580
    int i;
icculus@12279
  1581
icculus@12279
  1582
    /* Release the default render target before reset */
icculus@12279
  1583
    if (data->defaultRenderTarget) {
icculus@12279
  1584
        IDirect3DSurface9_Release(data->defaultRenderTarget);
icculus@12279
  1585
        data->defaultRenderTarget = NULL;
icculus@12279
  1586
    }
icculus@12279
  1587
    if (data->currentRenderTarget != NULL) {
icculus@12279
  1588
        IDirect3DSurface9_Release(data->currentRenderTarget);
icculus@12279
  1589
        data->currentRenderTarget = NULL;
icculus@12279
  1590
    }
icculus@12279
  1591
icculus@12279
  1592
    /* Release application render targets */
icculus@12279
  1593
    for (texture = renderer->textures; texture; texture = texture->next) {
icculus@12279
  1594
        if (texture->access == SDL_TEXTUREACCESS_TARGET) {
icculus@12279
  1595
            D3D_DestroyTexture(renderer, texture);
icculus@12279
  1596
        } else {
icculus@12279
  1597
            D3D_RecreateTexture(renderer, texture);
icculus@12279
  1598
        }
icculus@12279
  1599
    }
icculus@12279
  1600
icculus@12900
  1601
    /* Release all vertex buffers */
icculus@12444
  1602
    for (i = 0; i < SDL_arraysize(data->vertexBuffers); ++i) {
icculus@12444
  1603
        if (data->vertexBuffers[i]) {
icculus@12444
  1604
            IDirect3DVertexBuffer9_Release(data->vertexBuffers[i]);
icculus@12444
  1605
        }
icculus@12444
  1606
        data->vertexBuffers[i] = NULL;
icculus@12444
  1607
    }
icculus@12444
  1608
icculus@12279
  1609
    result = IDirect3DDevice9_Reset(data->device, &data->pparams);
icculus@12279
  1610
    if (FAILED(result)) {
icculus@12279
  1611
        if (result == D3DERR_DEVICELOST) {
icculus@12279
  1612
            /* Don't worry about it, we'll reset later... */
icculus@12279
  1613
            return 0;
icculus@12279
  1614
        } else {
icculus@12279
  1615
            return D3D_SetError("Reset()", result);
icculus@12279
  1616
        }
icculus@12279
  1617
    }
icculus@12279
  1618
icculus@12279
  1619
    /* Allocate application render targets */
icculus@12279
  1620
    for (texture = renderer->textures; texture; texture = texture->next) {
icculus@12279
  1621
        if (texture->access == SDL_TEXTUREACCESS_TARGET) {
icculus@12279
  1622
            D3D_CreateTexture(renderer, texture);
icculus@12279
  1623
        }
icculus@12279
  1624
    }
icculus@12279
  1625
icculus@12279
  1626
    IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget);
icculus@12279
  1627
    D3D_InitRenderState(data);
icculus@12279
  1628
    D3D_SetRenderTargetInternal(renderer, renderer->target);
icculus@12279
  1629
    data->drawstate.viewport_dirty = SDL_TRUE;
icculus@12448
  1630
    data->drawstate.cliprect_dirty = SDL_TRUE;
icculus@12448
  1631
    data->drawstate.cliprect_enabled_dirty = SDL_TRUE;
icculus@12448
  1632
    data->drawstate.texture = NULL;
icculus@12448
  1633
    data->drawstate.shader = NULL;
icculus@12448
  1634
    data->drawstate.blend = SDL_BLENDMODE_INVALID;
icculus@12448
  1635
    data->drawstate.is_copy_ex = SDL_FALSE;
icculus@12448
  1636
    IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)&d3dmatrix);
icculus@12279
  1637
icculus@12279
  1638
    /* Let the application know that render targets were reset */
icculus@12279
  1639
    {
icculus@12279
  1640
        SDL_Event event;
icculus@12279
  1641
        event.type = SDL_RENDER_TARGETS_RESET;
icculus@12279
  1642
        SDL_PushEvent(&event);
icculus@12279
  1643
    }
icculus@12279
  1644
icculus@12279
  1645
    return 0;
icculus@12279
  1646
}
icculus@12279
  1647
icculus@12278
  1648
SDL_Renderer *
icculus@12278
  1649
D3D_CreateRenderer(SDL_Window * window, Uint32 flags)
icculus@12278
  1650
{
icculus@12278
  1651
    SDL_Renderer *renderer;
icculus@12278
  1652
    D3D_RenderData *data;
icculus@12278
  1653
    SDL_SysWMinfo windowinfo;
icculus@12278
  1654
    HRESULT result;
icculus@12278
  1655
    D3DPRESENT_PARAMETERS pparams;
icculus@12278
  1656
    IDirect3DSwapChain9 *chain;
icculus@12278
  1657
    D3DCAPS9 caps;
icculus@12278
  1658
    DWORD device_flags;
icculus@12278
  1659
    Uint32 window_flags;
icculus@12278
  1660
    int w, h;
icculus@12278
  1661
    SDL_DisplayMode fullscreen_mode;
icculus@12278
  1662
    int displayIndex;
icculus@12278
  1663
icculus@12278
  1664
    renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
icculus@12278
  1665
    if (!renderer) {
icculus@12278
  1666
        SDL_OutOfMemory();
icculus@12278
  1667
        return NULL;
icculus@12278
  1668
    }
icculus@12278
  1669
icculus@12278
  1670
    data = (D3D_RenderData *) SDL_calloc(1, sizeof(*data));
icculus@12278
  1671
    if (!data) {
icculus@12278
  1672
        SDL_free(renderer);
icculus@12278
  1673
        SDL_OutOfMemory();
icculus@12278
  1674
        return NULL;
icculus@12278
  1675
    }
icculus@12278
  1676
icculus@12278
  1677
    if (!D3D_LoadDLL(&data->d3dDLL, &data->d3d)) {
icculus@12278
  1678
        SDL_free(renderer);
icculus@12278
  1679
        SDL_free(data);
icculus@12278
  1680
        SDL_SetError("Unable to create Direct3D interface");
icculus@12278
  1681
        return NULL;
icculus@12278
  1682
    }
icculus@12278
  1683
icculus@12278
  1684
    renderer->WindowEvent = D3D_WindowEvent;
icculus@12278
  1685
    renderer->SupportsBlendMode = D3D_SupportsBlendMode;
icculus@12278
  1686
    renderer->CreateTexture = D3D_CreateTexture;
icculus@12278
  1687
    renderer->UpdateTexture = D3D_UpdateTexture;
icculus@12278
  1688
    renderer->UpdateTextureYUV = D3D_UpdateTextureYUV;
icculus@12278
  1689
    renderer->LockTexture = D3D_LockTexture;
icculus@12278
  1690
    renderer->UnlockTexture = D3D_UnlockTexture;
icculus@12278
  1691
    renderer->SetRenderTarget = D3D_SetRenderTarget;
icculus@12278
  1692
    renderer->QueueSetViewport = D3D_QueueSetViewport;
icculus@12278
  1693
    renderer->QueueSetDrawColor = D3D_QueueSetViewport;  /* SetViewport and SetDrawColor are (currently) no-ops. */
icculus@12278
  1694
    renderer->QueueDrawPoints = D3D_QueueDrawPoints;
icculus@12278
  1695
    renderer->QueueDrawLines = D3D_QueueDrawPoints;  /* lines and points queue vertices the same way. */
icculus@12278
  1696
    renderer->QueueFillRects = D3D_QueueFillRects;
icculus@12278
  1697
    renderer->QueueCopy = D3D_QueueCopy;
icculus@12278
  1698
    renderer->QueueCopyEx = D3D_QueueCopyEx;
icculus@12278
  1699
    renderer->RunCommandQueue = D3D_RunCommandQueue;
icculus@12278
  1700
    renderer->RenderReadPixels = D3D_RenderReadPixels;
icculus@12278
  1701
    renderer->RenderPresent = D3D_RenderPresent;
icculus@12278
  1702
    renderer->DestroyTexture = D3D_DestroyTexture;
icculus@12278
  1703
    renderer->DestroyRenderer = D3D_DestroyRenderer;
icculus@12278
  1704
    renderer->info = D3D_RenderDriver.info;
icculus@12278
  1705
    renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
icculus@12278
  1706
    renderer->driverdata = data;
icculus@12278
  1707
icculus@12278
  1708
    SDL_VERSION(&windowinfo.version);
icculus@12278
  1709
    SDL_GetWindowWMInfo(window, &windowinfo);
icculus@12278
  1710
icculus@12278
  1711
    window_flags = SDL_GetWindowFlags(window);
icculus@12278
  1712
    SDL_GetWindowSize(window, &w, &h);
icculus@12278
  1713
    SDL_GetWindowDisplayMode(window, &fullscreen_mode);
icculus@12278
  1714
icculus@12278
  1715
    SDL_zero(pparams);
icculus@12278
  1716
    pparams.hDeviceWindow = windowinfo.info.win.window;
icculus@12278
  1717
    pparams.BackBufferWidth = w;
icculus@12278
  1718
    pparams.BackBufferHeight = h;
icculus@12278
  1719
    pparams.BackBufferCount = 1;
icculus@12278
  1720
    pparams.SwapEffect = D3DSWAPEFFECT_DISCARD;
icculus@12278
  1721
icculus@12278
  1722
    if (window_flags & SDL_WINDOW_FULLSCREEN && (window_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
icculus@12278
  1723
        pparams.Windowed = FALSE;
icculus@12278
  1724
        pparams.BackBufferFormat = PixelFormatToD3DFMT(fullscreen_mode.format);
icculus@12278
  1725
        pparams.FullScreen_RefreshRateInHz = fullscreen_mode.refresh_rate;
icculus@12278
  1726
    } else {
icculus@12278
  1727
        pparams.Windowed = TRUE;
icculus@12278
  1728
        pparams.BackBufferFormat = D3DFMT_UNKNOWN;
icculus@12278
  1729
        pparams.FullScreen_RefreshRateInHz = 0;
icculus@12278
  1730
    }
icculus@12278
  1731
    if (flags & SDL_RENDERER_PRESENTVSYNC) {
icculus@12278
  1732
        pparams.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
icculus@12278
  1733
    } else {
icculus@12278
  1734
        pparams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
icculus@12278
  1735
    }
icculus@12278
  1736
icculus@12278
  1737
    /* Get the adapter for the display that the window is on */
icculus@12278
  1738
    displayIndex = SDL_GetWindowDisplayIndex(window);
icculus@12278
  1739
    data->adapter = SDL_Direct3D9GetAdapterIndex(displayIndex);
icculus@12278
  1740
icculus@12278
  1741
    IDirect3D9_GetDeviceCaps(data->d3d, data->adapter, D3DDEVTYPE_HAL, &caps);
icculus@12278
  1742
icculus@12278
  1743
    device_flags = D3DCREATE_FPU_PRESERVE;
icculus@12278
  1744
    if (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) {
icculus@12278
  1745
        device_flags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
icculus@12278
  1746
    } else {
icculus@12278
  1747
        device_flags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
icculus@12278
  1748
    }
icculus@12278
  1749
icculus@12278
  1750
    if (SDL_GetHintBoolean(SDL_HINT_RENDER_DIRECT3D_THREADSAFE, SDL_FALSE)) {
icculus@12278
  1751
        device_flags |= D3DCREATE_MULTITHREADED;
icculus@12278
  1752
    }
icculus@12278
  1753
icculus@12278
  1754
    result = IDirect3D9_CreateDevice(data->d3d, data->adapter,
icculus@12278
  1755
                                     D3DDEVTYPE_HAL,
icculus@12278
  1756
                                     pparams.hDeviceWindow,
icculus@12278
  1757
                                     device_flags,
icculus@12278
  1758
                                     &pparams, &data->device);
icculus@12278
  1759
    if (FAILED(result)) {
icculus@12278
  1760
        D3D_DestroyRenderer(renderer);
icculus@12278
  1761
        D3D_SetError("CreateDevice()", result);
icculus@12278
  1762
        return NULL;
icculus@12278
  1763
    }
icculus@12278
  1764
icculus@12278
  1765
    /* Get presentation parameters to fill info */
icculus@12278
  1766
    result = IDirect3DDevice9_GetSwapChain(data->device, 0, &chain);
icculus@12278
  1767
    if (FAILED(result)) {
icculus@12278
  1768
        D3D_DestroyRenderer(renderer);
icculus@12278
  1769
        D3D_SetError("GetSwapChain()", result);
icculus@12278
  1770
        return NULL;
icculus@12278
  1771
    }
icculus@12278
  1772
    result = IDirect3DSwapChain9_GetPresentParameters(chain, &pparams);
icculus@12278
  1773
    if (FAILED(result)) {
icculus@12278
  1774
        IDirect3DSwapChain9_Release(chain);
icculus@12278
  1775
        D3D_DestroyRenderer(renderer);
icculus@12278
  1776
        D3D_SetError("GetPresentParameters()", result);
icculus@12278
  1777
        return NULL;
icculus@12278
  1778
    }
icculus@12278
  1779
    IDirect3DSwapChain9_Release(chain);
icculus@12278
  1780
    if (pparams.PresentationInterval == D3DPRESENT_INTERVAL_ONE) {
icculus@12278
  1781
        renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
icculus@12278
  1782
    }
icculus@12278
  1783
    data->pparams = pparams;
icculus@12278
  1784
icculus@12278
  1785
    IDirect3DDevice9_GetDeviceCaps(data->device, &caps);
icculus@12278
  1786
    renderer->info.max_texture_width = caps.MaxTextureWidth;
icculus@12278
  1787
    renderer->info.max_texture_height = caps.MaxTextureHeight;
icculus@12278
  1788
    if (caps.NumSimultaneousRTs >= 2) {
icculus@12278
  1789
        renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE;
icculus@12278
  1790
    }
icculus@12278
  1791
icculus@12278
  1792
    if (caps.PrimitiveMiscCaps & D3DPMISCCAPS_SEPARATEALPHABLEND) {
icculus@12278
  1793
        data->enableSeparateAlphaBlend = SDL_TRUE;
icculus@12278
  1794
    }
icculus@12278
  1795
icculus@12278
  1796
    /* Store the default render target */
icculus@12278
  1797
    IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget);
icculus@12278
  1798
    data->currentRenderTarget = NULL;
icculus@12278
  1799
icculus@12278
  1800
    /* Set up parameters for rendering */
icculus@12278
  1801
    D3D_InitRenderState(data);
icculus@12278
  1802
icculus@12278
  1803
    if (caps.MaxSimultaneousTextures >= 3) {
icculus@12278
  1804
        int i;
icculus@12278
  1805
        for (i = 0; i < SDL_arraysize(data->shaders); ++i) {
icculus@12278
  1806
            result = D3D9_CreatePixelShader(data->device, (D3D9_Shader)i, &data->shaders[i]);
icculus@12278
  1807
            if (FAILED(result)) {
icculus@12278
  1808
                D3D_SetError("CreatePixelShader()", result);
icculus@12278
  1809
            }
icculus@12278
  1810
        }
icculus@12278
  1811
        if (data->shaders[SHADER_YUV_JPEG] && data->shaders[SHADER_YUV_BT601] && data->shaders[SHADER_YUV_BT709]) {
icculus@12278
  1812
            renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;
icculus@12278
  1813
            renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
icculus@12278
  1814
        }
icculus@12278
  1815
    }
icculus@12278
  1816
slouken@12417
  1817
    data->drawstate.blend = SDL_BLENDMODE_INVALID;
icculus@12278
  1818
icculus@12278
  1819
    return renderer;
icculus@12278
  1820
}
icculus@12278
  1821
icculus@12278
  1822
SDL_RenderDriver D3D_RenderDriver = {
icculus@12278
  1823
    D3D_CreateRenderer,
icculus@12278
  1824
    {
icculus@12278
  1825
     "direct3d",
icculus@12278
  1826
     (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
icculus@12278
  1827
     1,
icculus@12278
  1828
     {SDL_PIXELFORMAT_ARGB8888},
icculus@12278
  1829
     0,
icculus@12278
  1830
     0}
icculus@12278
  1831
};
icculus@8130
  1832
#endif /* SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED */
slouken@1895
  1833
icculus@8131
  1834
#ifdef __WIN32__
icculus@8131
  1835
/* This function needs to always exist on Windows, for the Dynamic API. */
slouken@7763
  1836
IDirect3DDevice9 *
slouken@7765
  1837
SDL_RenderGetD3D9Device(SDL_Renderer * renderer)
slouken@7763
  1838
{
icculus@8130
  1839
    IDirect3DDevice9 *device = NULL;
icculus@8130
  1840
icculus@8130
  1841
#if SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED
slouken@7877
  1842
    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
slouken@7763
  1843
philipp@8778
  1844
    /* Make sure that this is a D3D renderer */
slouken@7877
  1845
    if (renderer->DestroyRenderer != D3D_DestroyRenderer) {
slouken@7877
  1846
        SDL_SetError("Renderer is not a D3D renderer");
slouken@7877
  1847
        return NULL;
slouken@7877
  1848
    }
slouken@7766
  1849
slouken@7877
  1850
    device = data->device;
slouken@7877
  1851
    if (device) {
slouken@8207
  1852
        IDirect3DDevice9_AddRef(device);
slouken@7877
  1853
    }
icculus@8130
  1854
#endif /* SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED */
icculus@8130
  1855
slouken@7877
  1856
    return device;
slouken@7763
  1857
}
slouken@8193
  1858
#endif /* __WIN32__ */
slouken@7763
  1859
slouken@1895
  1860
/* vi: set ts=4 sw=4 expandtab: */