src/render/direct3d/SDL_render_d3d.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 10 Mar 2014 17:19:19 -0700
changeset 8599 532cd234e923
parent 8590 6e6bd53feff0
child 8728 c7174f961388
permissions -rw-r--r--
Fixed D3D9 initialization on Windows 8, which doesn't have D3DX
slouken@1895
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@8149
     3
  Copyright (C) 1997-2014 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"
slouken@5154
    33
#include "../SDL_sysrender.h"
slouken@8599
    34
#include "../SDL_d3dmath.h"
slouken@7762
    35
#include "../../video/windows/SDL_windowsvideo.h"
slouken@5154
    36
slouken@5154
    37
#if SDL_VIDEO_RENDER_D3D
slouken@5154
    38
#define D3D_DEBUG_INFO
slouken@5154
    39
#include <d3d9.h>
slouken@5154
    40
#endif
slouken@1895
    41
gabomdq@6320
    42
slouken@3556
    43
#ifdef ASSEMBLE_SHADER
slouken@7191
    44
/**************************************************************************
slouken@7191
    45
 * ID3DXBuffer:
slouken@7191
    46
 * ------------
slouken@7191
    47
 * The buffer object is used by D3DX to return arbitrary size data.
slouken@7191
    48
 *
slouken@7191
    49
 * GetBufferPointer -
slouken@7191
    50
 *    Returns a pointer to the beginning of the buffer.
slouken@7191
    51
 *
slouken@7191
    52
 * GetBufferSize -
slouken@7191
    53
 *    Returns the size of the buffer, in bytes.
slouken@7191
    54
 **************************************************************************/
slouken@3556
    55
slouken@3556
    56
typedef interface ID3DXBuffer ID3DXBuffer;
slouken@3556
    57
typedef interface ID3DXBuffer *LPD3DXBUFFER;
slouken@3556
    58
slouken@7191
    59
/* {8BA5FB08-5195-40e2-AC58-0D989C3A0102} */
slouken@7191
    60
DEFINE_GUID(IID_ID3DXBuffer,
slouken@3556
    61
0x8ba5fb08, 0x5195, 0x40e2, 0xac, 0x58, 0xd, 0x98, 0x9c, 0x3a, 0x1, 0x2);
slouken@3556
    62
slouken@3556
    63
#undef INTERFACE
slouken@3556
    64
#define INTERFACE ID3DXBuffer
slouken@3556
    65
slouken@3556
    66
typedef interface ID3DXBuffer {
slouken@3556
    67
    const struct ID3DXBufferVtbl FAR* lpVtbl;
slouken@3556
    68
} ID3DXBuffer;
slouken@3556
    69
typedef const struct ID3DXBufferVtbl ID3DXBufferVtbl;
slouken@3556
    70
const struct ID3DXBufferVtbl
slouken@3556
    71
{
slouken@7191
    72
    /* IUnknown */
slouken@3556
    73
    STDMETHOD(QueryInterface)(THIS_ REFIID iid, LPVOID *ppv) PURE;
slouken@3556
    74
    STDMETHOD_(ULONG, AddRef)(THIS) PURE;
slouken@3556
    75
    STDMETHOD_(ULONG, Release)(THIS) PURE;
slouken@3556
    76
slouken@7191
    77
    /* ID3DXBuffer */
slouken@3556
    78
    STDMETHOD_(LPVOID, GetBufferPointer)(THIS) PURE;
slouken@3556
    79
    STDMETHOD_(DWORD, GetBufferSize)(THIS) PURE;
slouken@3556
    80
};
slouken@3556
    81
slouken@3556
    82
HRESULT WINAPI
slouken@3556
    83
    D3DXAssembleShader(
slouken@3556
    84
        LPCSTR                          pSrcData,
slouken@3556
    85
        UINT                            SrcDataLen,
slouken@3556
    86
        CONST LPVOID*                   pDefines,
slouken@3556
    87
        LPVOID                          pInclude,
slouken@3556
    88
        DWORD                           Flags,
slouken@3556
    89
        LPD3DXBUFFER*                   ppShader,
slouken@3556
    90
        LPD3DXBUFFER*                   ppErrorMsgs);
slouken@3556
    91
slouken@7505
    92
static void PrintShaderData(LPDWORD shader_data, DWORD shader_size)
slouken@7505
    93
{
slouken@7505
    94
    OutputDebugStringA("const DWORD shader_data[] = {\n\t");
slouken@7505
    95
    {
slouken@7505
    96
        SDL_bool newline = SDL_FALSE;
slouken@7505
    97
        unsigned i;
slouken@7505
    98
        for (i = 0; i < shader_size / sizeof(DWORD); ++i) {
slouken@7505
    99
            char dword[11];
slouken@7505
   100
            if (i > 0) {
slouken@7505
   101
                if ((i%6) == 0) {
slouken@7505
   102
                    newline = SDL_TRUE;
slouken@7505
   103
                }
slouken@7505
   104
                if (newline) {
slouken@7505
   105
                    OutputDebugStringA(",\n    ");
slouken@7505
   106
                    newline = SDL_FALSE;
slouken@7505
   107
                } else {
slouken@7505
   108
                    OutputDebugStringA(", ");
slouken@7505
   109
                }
slouken@7505
   110
            }
slouken@7505
   111
            SDL_snprintf(dword, sizeof(dword), "0x%8.8x", shader_data[i]);
slouken@7505
   112
            OutputDebugStringA(dword);
slouken@7505
   113
        }
slouken@7505
   114
        OutputDebugStringA("\n};\n");
slouken@7505
   115
    }
slouken@7505
   116
}
slouken@7505
   117
slouken@3556
   118
#endif /* ASSEMBLE_SHADER */
slouken@3556
   119
slouken@3556
   120
slouken@1895
   121
/* Direct3D renderer implementation */
slouken@1895
   122
slouken@1913
   123
static SDL_Renderer *D3D_CreateRenderer(SDL_Window * window, Uint32 flags);
slouken@5297
   124
static void D3D_WindowEvent(SDL_Renderer * renderer,
slouken@5297
   125
                            const SDL_WindowEvent *event);
slouken@1913
   126
static int D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
slouken@1913
   127
static int D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@1913
   128
                             const SDL_Rect * rect, const void *pixels,
slouken@1913
   129
                             int pitch);
slouken@7761
   130
static int D3D_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@7761
   131
                                const SDL_Rect * rect,
slouken@7761
   132
                                const Uint8 *Yplane, int Ypitch,
slouken@7761
   133
                                const Uint8 *Uplane, int Upitch,
slouken@7761
   134
                                const Uint8 *Vplane, int Vpitch);
slouken@1913
   135
static int D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@5156
   136
                           const SDL_Rect * rect, void **pixels, int *pitch);
slouken@1913
   137
static void D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
slouken@8228
   138
static int D3D_SetRenderTargetInternal(SDL_Renderer * renderer, SDL_Texture * texture);
slouken@6247
   139
static int D3D_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture);
slouken@5297
   140
static int D3D_UpdateViewport(SDL_Renderer * renderer);
slouken@7141
   141
static int D3D_UpdateClipRect(SDL_Renderer * renderer);
slouken@5297
   142
static int D3D_RenderClear(SDL_Renderer * renderer);
slouken@3599
   143
static int D3D_RenderDrawPoints(SDL_Renderer * renderer,
slouken@6528
   144
                                const SDL_FPoint * points, int count);
slouken@3599
   145
static int D3D_RenderDrawLines(SDL_Renderer * renderer,
slouken@6528
   146
                               const SDL_FPoint * points, int count);
slouken@3599
   147
static int D3D_RenderFillRects(SDL_Renderer * renderer,
slouken@6528
   148
                               const SDL_FRect * rects, int count);
slouken@1913
   149
static int D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@6528
   150
                          const SDL_Rect * srcrect, const SDL_FRect * dstrect);
gabomdq@6320
   151
static int D3D_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@6528
   152
                          const SDL_Rect * srcrect, const SDL_FRect * dstrect,
slouken@6528
   153
                          const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip);
slouken@3427
   154
static int D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
slouken@3480
   155
                                Uint32 format, void * pixels, int pitch);
slouken@1913
   156
static void D3D_RenderPresent(SDL_Renderer * renderer);
slouken@1913
   157
static void D3D_DestroyTexture(SDL_Renderer * renderer,
slouken@1913
   158
                               SDL_Texture * texture);
slouken@1913
   159
static void D3D_DestroyRenderer(SDL_Renderer * renderer);
slouken@1895
   160
slouken@1895
   161
slouken@1913
   162
SDL_RenderDriver D3D_RenderDriver = {
slouken@1913
   163
    D3D_CreateRenderer,
slouken@1895
   164
    {
slouken@5186
   165
     "direct3d",
slouken@6237
   166
     (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
slouken@5156
   167
     1,
slouken@5156
   168
     {SDL_PIXELFORMAT_ARGB8888},
slouken@1895
   169
     0,
slouken@1895
   170
     0}
slouken@1895
   171
};
slouken@1895
   172
slouken@1895
   173
typedef struct
slouken@1895
   174
{
slouken@5154
   175
    void* d3dDLL;
slouken@2973
   176
    IDirect3D9 *d3d;
slouken@1895
   177
    IDirect3DDevice9 *device;
slouken@3527
   178
    UINT adapter;
slouken@1975
   179
    D3DPRESENT_PARAMETERS pparams;
slouken@5297
   180
    SDL_bool updateSize;
slouken@1900
   181
    SDL_bool beginScene;
slouken@7502
   182
    SDL_bool enableSeparateAlphaBlend;
slouken@7505
   183
    D3DTEXTUREFILTERTYPE scaleMode[8];
slouken@6232
   184
    IDirect3DSurface9 *defaultRenderTarget;
slouken@6232
   185
    IDirect3DSurface9 *currentRenderTarget;
gabomdq@6320
   186
    void* d3dxDLL;
slouken@7505
   187
    LPDIRECT3DPIXELSHADER9 ps_yuv;
slouken@1913
   188
} D3D_RenderData;
slouken@1895
   189
slouken@1895
   190
typedef struct
slouken@1895
   191
{
slouken@1903
   192
    IDirect3DTexture9 *texture;
slouken@5484
   193
    D3DTEXTUREFILTERTYPE scaleMode;
slouken@7505
   194
slouken@7505
   195
    /* YV12 texture support */
slouken@7505
   196
    SDL_bool yuv;
slouken@7505
   197
    IDirect3DTexture9 *utexture;
slouken@7505
   198
    IDirect3DTexture9 *vtexture;
slouken@7505
   199
    Uint8 *pixels;
slouken@7505
   200
    int pitch;
slouken@7505
   201
    SDL_Rect locked_rect;
slouken@1913
   202
} D3D_TextureData;
slouken@1895
   203
slouken@1903
   204
typedef struct
slouken@1903
   205
{
slouken@1903
   206
    float x, y, z;
slouken@1987
   207
    DWORD color;
slouken@1904
   208
    float u, v;
slouken@1903
   209
} Vertex;
slouken@1903
   210
icculus@7037
   211
static int
slouken@1900
   212
D3D_SetError(const char *prefix, HRESULT result)
slouken@1900
   213
{
slouken@1900
   214
    const char *error;
slouken@1900
   215
slouken@1900
   216
    switch (result) {
slouken@1900
   217
    case D3DERR_WRONGTEXTUREFORMAT:
slouken@1900
   218
        error = "WRONGTEXTUREFORMAT";
slouken@1900
   219
        break;
slouken@1900
   220
    case D3DERR_UNSUPPORTEDCOLOROPERATION:
slouken@1900
   221
        error = "UNSUPPORTEDCOLOROPERATION";
slouken@1900
   222
        break;
slouken@1900
   223
    case D3DERR_UNSUPPORTEDCOLORARG:
slouken@1900
   224
        error = "UNSUPPORTEDCOLORARG";
slouken@1900
   225
        break;
slouken@1900
   226
    case D3DERR_UNSUPPORTEDALPHAOPERATION:
slouken@1900
   227
        error = "UNSUPPORTEDALPHAOPERATION";
slouken@1900
   228
        break;
slouken@1900
   229
    case D3DERR_UNSUPPORTEDALPHAARG:
slouken@1900
   230
        error = "UNSUPPORTEDALPHAARG";
slouken@1900
   231
        break;
slouken@1900
   232
    case D3DERR_TOOMANYOPERATIONS:
slouken@1900
   233
        error = "TOOMANYOPERATIONS";
slouken@1900
   234
        break;
slouken@1900
   235
    case D3DERR_CONFLICTINGTEXTUREFILTER:
slouken@1900
   236
        error = "CONFLICTINGTEXTUREFILTER";
slouken@1900
   237
        break;
slouken@1900
   238
    case D3DERR_UNSUPPORTEDFACTORVALUE:
slouken@1900
   239
        error = "UNSUPPORTEDFACTORVALUE";
slouken@1900
   240
        break;
slouken@1900
   241
    case D3DERR_CONFLICTINGRENDERSTATE:
slouken@1900
   242
        error = "CONFLICTINGRENDERSTATE";
slouken@1900
   243
        break;
slouken@1900
   244
    case D3DERR_UNSUPPORTEDTEXTUREFILTER:
slouken@1900
   245
        error = "UNSUPPORTEDTEXTUREFILTER";
slouken@1900
   246
        break;
slouken@1900
   247
    case D3DERR_CONFLICTINGTEXTUREPALETTE:
slouken@1900
   248
        error = "CONFLICTINGTEXTUREPALETTE";
slouken@1900
   249
        break;
slouken@1900
   250
    case D3DERR_DRIVERINTERNALERROR:
slouken@1900
   251
        error = "DRIVERINTERNALERROR";
slouken@1900
   252
        break;
slouken@1900
   253
    case D3DERR_NOTFOUND:
slouken@1900
   254
        error = "NOTFOUND";
slouken@1900
   255
        break;
slouken@1900
   256
    case D3DERR_MOREDATA:
slouken@1900
   257
        error = "MOREDATA";
slouken@1900
   258
        break;
slouken@1900
   259
    case D3DERR_DEVICELOST:
slouken@1900
   260
        error = "DEVICELOST";
slouken@1900
   261
        break;
slouken@1900
   262
    case D3DERR_DEVICENOTRESET:
slouken@1900
   263
        error = "DEVICENOTRESET";
slouken@1900
   264
        break;
slouken@1900
   265
    case D3DERR_NOTAVAILABLE:
slouken@1900
   266
        error = "NOTAVAILABLE";
slouken@1900
   267
        break;
slouken@1900
   268
    case D3DERR_OUTOFVIDEOMEMORY:
slouken@1900
   269
        error = "OUTOFVIDEOMEMORY";
slouken@1900
   270
        break;
slouken@1900
   271
    case D3DERR_INVALIDDEVICE:
slouken@1900
   272
        error = "INVALIDDEVICE";
slouken@1900
   273
        break;
slouken@1900
   274
    case D3DERR_INVALIDCALL:
slouken@1900
   275
        error = "INVALIDCALL";
slouken@1900
   276
        break;
slouken@1900
   277
    case D3DERR_DRIVERINVALIDCALL:
slouken@1900
   278
        error = "DRIVERINVALIDCALL";
slouken@1900
   279
        break;
slouken@1900
   280
    case D3DERR_WASSTILLDRAWING:
slouken@1900
   281
        error = "WASSTILLDRAWING";
slouken@1900
   282
        break;
slouken@1900
   283
    default:
slouken@1900
   284
        error = "UNKNOWN";
slouken@1900
   285
        break;
slouken@1900
   286
    }
icculus@7037
   287
    return SDL_SetError("%s: %s", prefix, error);
slouken@1900
   288
}
slouken@1900
   289
slouken@1903
   290
static D3DFORMAT
slouken@1903
   291
PixelFormatToD3DFMT(Uint32 format)
slouken@1895
   292
{
slouken@1903
   293
    switch (format) {
slouken@1965
   294
    case SDL_PIXELFORMAT_RGB565:
slouken@1903
   295
        return D3DFMT_R5G6B5;
slouken@1965
   296
    case SDL_PIXELFORMAT_RGB888:
slouken@1903
   297
        return D3DFMT_X8R8G8B8;
slouken@1965
   298
    case SDL_PIXELFORMAT_ARGB8888:
slouken@1903
   299
        return D3DFMT_A8R8G8B8;
slouken@7505
   300
    case SDL_PIXELFORMAT_YV12:
slouken@7505
   301
    case SDL_PIXELFORMAT_IYUV:
slouken@7505
   302
        return D3DFMT_L8;
slouken@1903
   303
    default:
slouken@1903
   304
        return D3DFMT_UNKNOWN;
slouken@1903
   305
    }
slouken@1895
   306
}
slouken@1895
   307
slouken@5156
   308
static Uint32
slouken@5156
   309
D3DFMTToPixelFormat(D3DFORMAT format)
slouken@2973
   310
{
slouken@5156
   311
    switch (format) {
slouken@5156
   312
    case D3DFMT_R5G6B5:
slouken@5156
   313
        return SDL_PIXELFORMAT_RGB565;
slouken@5156
   314
    case D3DFMT_X8R8G8B8:
slouken@5156
   315
        return SDL_PIXELFORMAT_RGB888;
slouken@5156
   316
    case D3DFMT_A8R8G8B8:
slouken@5156
   317
        return SDL_PIXELFORMAT_ARGB8888;
slouken@5156
   318
    default:
slouken@5156
   319
        return SDL_PIXELFORMAT_UNKNOWN;
slouken@2973
   320
    }
slouken@1895
   321
}
slouken@1895
   322
slouken@7648
   323
static void
slouken@7648
   324
D3D_InitRenderState(D3D_RenderData *data)
slouken@7648
   325
{
slouken@7651
   326
    D3DMATRIX matrix;
slouken@7651
   327
slouken@7651
   328
    IDirect3DDevice9 *device = data->device;
slouken@7648
   329
slouken@7648
   330
    IDirect3DDevice9_SetVertexShader(device, NULL);
slouken@7648
   331
    IDirect3DDevice9_SetFVF(device, D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);
slouken@7648
   332
    IDirect3DDevice9_SetRenderState(device, D3DRS_ZENABLE, D3DZB_FALSE);
slouken@7648
   333
    IDirect3DDevice9_SetRenderState(device, D3DRS_CULLMODE, D3DCULL_NONE);
slouken@7648
   334
    IDirect3DDevice9_SetRenderState(device, D3DRS_LIGHTING, FALSE);
slouken@7648
   335
slouken@7648
   336
    /* Enable color modulation by diffuse color */
slouken@7648
   337
    IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLOROP,
slouken@7648
   338
                                          D3DTOP_MODULATE);
slouken@7648
   339
    IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLORARG1,
slouken@7648
   340
                                          D3DTA_TEXTURE);
slouken@7648
   341
    IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLORARG2,
slouken@7648
   342
                                          D3DTA_DIFFUSE);
slouken@7648
   343
slouken@7648
   344
    /* Enable alpha modulation by diffuse alpha */
slouken@7648
   345
    IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAOP,
slouken@7648
   346
                                          D3DTOP_MODULATE);
slouken@7648
   347
    IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAARG1,
slouken@7648
   348
                                          D3DTA_TEXTURE);
slouken@7648
   349
    IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAARG2,
slouken@7648
   350
                                          D3DTA_DIFFUSE);
slouken@7648
   351
slouken@7648
   352
    /* Enable separate alpha blend function, if possible */
slouken@7648
   353
    if (data->enableSeparateAlphaBlend) {
slouken@7648
   354
        IDirect3DDevice9_SetRenderState(device, D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
slouken@7648
   355
    }
slouken@7648
   356
slouken@7648
   357
    /* Disable second texture stage, since we're done */
slouken@7648
   358
    IDirect3DDevice9_SetTextureStageState(device, 1, D3DTSS_COLOROP,
slouken@7648
   359
                                          D3DTOP_DISABLE);
slouken@7648
   360
    IDirect3DDevice9_SetTextureStageState(device, 1, D3DTSS_ALPHAOP,
slouken@7648
   361
                                          D3DTOP_DISABLE);
slouken@7648
   362
slouken@7648
   363
    /* Set an identity world and view matrix */
slouken@7648
   364
    matrix.m[0][0] = 1.0f;
slouken@7648
   365
    matrix.m[0][1] = 0.0f;
slouken@7648
   366
    matrix.m[0][2] = 0.0f;
slouken@7648
   367
    matrix.m[0][3] = 0.0f;
slouken@7648
   368
    matrix.m[1][0] = 0.0f;
slouken@7648
   369
    matrix.m[1][1] = 1.0f;
slouken@7648
   370
    matrix.m[1][2] = 0.0f;
slouken@7648
   371
    matrix.m[1][3] = 0.0f;
slouken@7648
   372
    matrix.m[2][0] = 0.0f;
slouken@7648
   373
    matrix.m[2][1] = 0.0f;
slouken@7648
   374
    matrix.m[2][2] = 1.0f;
slouken@7648
   375
    matrix.m[2][3] = 0.0f;
slouken@7648
   376
    matrix.m[3][0] = 0.0f;
slouken@7648
   377
    matrix.m[3][1] = 0.0f;
slouken@7648
   378
    matrix.m[3][2] = 0.0f;
slouken@7648
   379
    matrix.m[3][3] = 1.0f;
slouken@7648
   380
    IDirect3DDevice9_SetTransform(device, D3DTS_WORLD, &matrix);
slouken@7648
   381
    IDirect3DDevice9_SetTransform(device, D3DTS_VIEW, &matrix);
slouken@7648
   382
slouken@7648
   383
    /* Reset our current scale mode */
slouken@7648
   384
    SDL_memset(data->scaleMode, 0xFF, sizeof(data->scaleMode));
slouken@7648
   385
slouken@7648
   386
    /* Start the render with beginScene */
slouken@7648
   387
    data->beginScene = SDL_TRUE;
slouken@7648
   388
}
slouken@7648
   389
slouken@5297
   390
static int
slouken@5297
   391
D3D_Reset(SDL_Renderer * renderer)
slouken@5297
   392
{
slouken@5297
   393
    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
slouken@5297
   394
    HRESULT result;
slouken@8207
   395
    SDL_Texture *texture;
slouken@5297
   396
slouken@6860
   397
    /* Release the default render target before reset */
slouken@6895
   398
    if (data->defaultRenderTarget) {
slouken@6895
   399
        IDirect3DSurface9_Release(data->defaultRenderTarget);
slouken@6895
   400
        data->defaultRenderTarget = NULL;
slouken@6895
   401
    }
slouken@8224
   402
    if (data->currentRenderTarget != NULL) {
slouken@8224
   403
        IDirect3DSurface9_Release(data->currentRenderTarget);
slouken@8224
   404
        data->currentRenderTarget = NULL;
slouken@8224
   405
    }
slouken@6860
   406
slouken@8207
   407
    /* Release application render targets */
slouken@8207
   408
    for (texture = renderer->textures; texture; texture = texture->next) {
slouken@8207
   409
        if (texture->access == SDL_TEXTUREACCESS_TARGET) {
slouken@8207
   410
            D3D_DestroyTexture(renderer, texture);
slouken@8207
   411
        }
slouken@8207
   412
    }
slouken@8207
   413
slouken@5297
   414
    result = IDirect3DDevice9_Reset(data->device, &data->pparams);
slouken@5297
   415
    if (FAILED(result)) {
slouken@5297
   416
        if (result == D3DERR_DEVICELOST) {
slouken@5297
   417
            /* Don't worry about it, we'll reset later... */
slouken@5297
   418
            return 0;
slouken@5297
   419
        } else {
icculus@7037
   420
            return D3D_SetError("Reset()", result);
slouken@5297
   421
        }
slouken@5297
   422
    }
slouken@7648
   423
slouken@8207
   424
    /* Allocate application render targets */
slouken@8207
   425
    for (texture = renderer->textures; texture; texture = texture->next) {
slouken@8207
   426
        if (texture->access == SDL_TEXTUREACCESS_TARGET) {
slouken@8207
   427
            D3D_CreateTexture(renderer, texture);
slouken@8207
   428
        }
slouken@8207
   429
    }
slouken@8207
   430
slouken@6860
   431
    IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget);
slouken@7648
   432
    D3D_InitRenderState(data);
slouken@8228
   433
    D3D_SetRenderTargetInternal(renderer, renderer->target);
slouken@7586
   434
    D3D_UpdateViewport(renderer);
slouken@8207
   435
slouken@8207
   436
    /* Let the application know that render targets were reset */
slouken@8207
   437
    {
slouken@8207
   438
        SDL_Event event;
slouken@8207
   439
        event.type = SDL_RENDER_TARGETS_RESET;
slouken@8207
   440
        SDL_PushEvent(&event);
slouken@8207
   441
    }
slouken@8207
   442
slouken@5297
   443
    return 0;
slouken@5297
   444
}
slouken@5297
   445
slouken@5297
   446
static int
slouken@5297
   447
D3D_ActivateRenderer(SDL_Renderer * renderer)
slouken@5297
   448
{
slouken@5297
   449
    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
slouken@5297
   450
    HRESULT result;
slouken@5297
   451
slouken@5297
   452
    if (data->updateSize) {
slouken@5297
   453
        SDL_Window *window = renderer->window;
slouken@5297
   454
        int w, h;
slouken@5297
   455
slouken@5297
   456
        SDL_GetWindowSize(window, &w, &h);
slouken@5297
   457
        data->pparams.BackBufferWidth = w;
slouken@5297
   458
        data->pparams.BackBufferHeight = h;
slouken@5297
   459
        if (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN) {
slouken@5297
   460
            data->pparams.BackBufferFormat =
slouken@5297
   461
                PixelFormatToD3DFMT(SDL_GetWindowPixelFormat(window));
slouken@5297
   462
        } else {
slouken@5297
   463
            data->pparams.BackBufferFormat = D3DFMT_UNKNOWN;
slouken@5297
   464
        }
slouken@5297
   465
        if (D3D_Reset(renderer) < 0) {
slouken@5297
   466
            return -1;
slouken@5297
   467
        }
slouken@5297
   468
slouken@5297
   469
        data->updateSize = SDL_FALSE;
slouken@5297
   470
    }
slouken@5297
   471
    if (data->beginScene) {
slouken@5297
   472
        result = IDirect3DDevice9_BeginScene(data->device);
slouken@5297
   473
        if (result == D3DERR_DEVICELOST) {
slouken@5297
   474
            if (D3D_Reset(renderer) < 0) {
slouken@5297
   475
                return -1;
slouken@5297
   476
            }
slouken@5297
   477
            result = IDirect3DDevice9_BeginScene(data->device);
slouken@5297
   478
        }
slouken@5297
   479
        if (FAILED(result)) {
icculus@7037
   480
            return D3D_SetError("BeginScene()", result);
slouken@5297
   481
        }
slouken@5297
   482
        data->beginScene = SDL_FALSE;
slouken@5297
   483
    }
slouken@5297
   484
    return 0;
slouken@5297
   485
}
slouken@5297
   486
slouken@1895
   487
SDL_Renderer *
slouken@1913
   488
D3D_CreateRenderer(SDL_Window * window, Uint32 flags)
slouken@1895
   489
{
slouken@1895
   490
    SDL_Renderer *renderer;
slouken@1913
   491
    D3D_RenderData *data;
slouken@5154
   492
    SDL_SysWMinfo windowinfo;
slouken@1900
   493
    HRESULT result;
slouken@7877
   494
    const char *hint;
slouken@1900
   495
    D3DPRESENT_PARAMETERS pparams;
slouken@1907
   496
    IDirect3DSwapChain9 *chain;
slouken@1925
   497
    D3DCAPS9 caps;
slouken@7877
   498
    DWORD device_flags;
slouken@5156
   499
    Uint32 window_flags;
slouken@5156
   500
    int w, h;
slouken@5156
   501
    SDL_DisplayMode fullscreen_mode;
slouken@7877
   502
    int displayIndex;
slouken@1895
   503
slouken@1920
   504
    renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
slouken@1895
   505
    if (!renderer) {
slouken@1895
   506
        SDL_OutOfMemory();
slouken@1895
   507
        return NULL;
slouken@1895
   508
    }
slouken@1895
   509
slouken@1920
   510
    data = (D3D_RenderData *) SDL_calloc(1, sizeof(*data));
slouken@1895
   511
    if (!data) {
slouken@5154
   512
        SDL_free(renderer);
slouken@1895
   513
        SDL_OutOfMemory();
slouken@1895
   514
        return NULL;
slouken@1895
   515
    }
slouken@1895
   516
slouken@8599
   517
    if (!D3D_LoadDLL(&data->d3dDLL, &data->d3d)) {
slouken@5154
   518
        SDL_free(renderer);
slouken@5154
   519
        SDL_free(data);
slouken@5154
   520
        SDL_SetError("Unable to create Direct3D interface");
slouken@5154
   521
        return NULL;
slouken@5154
   522
    }
slouken@5154
   523
slouken@5297
   524
    renderer->WindowEvent = D3D_WindowEvent;
slouken@1913
   525
    renderer->CreateTexture = D3D_CreateTexture;
slouken@1913
   526
    renderer->UpdateTexture = D3D_UpdateTexture;
slouken@7877
   527
    renderer->UpdateTextureYUV = D3D_UpdateTextureYUV;
slouken@1913
   528
    renderer->LockTexture = D3D_LockTexture;
slouken@1913
   529
    renderer->UnlockTexture = D3D_UnlockTexture;
slouken@6247
   530
    renderer->SetRenderTarget = D3D_SetRenderTarget;
slouken@5297
   531
    renderer->UpdateViewport = D3D_UpdateViewport;
slouken@7141
   532
    renderer->UpdateClipRect = D3D_UpdateClipRect;
slouken@5297
   533
    renderer->RenderClear = D3D_RenderClear;
slouken@3599
   534
    renderer->RenderDrawPoints = D3D_RenderDrawPoints;
slouken@3599
   535
    renderer->RenderDrawLines = D3D_RenderDrawLines;
slouken@3675
   536
    renderer->RenderFillRects = D3D_RenderFillRects;
slouken@1913
   537
    renderer->RenderCopy = D3D_RenderCopy;
gabomdq@6320
   538
    renderer->RenderCopyEx = D3D_RenderCopyEx;
slouken@3427
   539
    renderer->RenderReadPixels = D3D_RenderReadPixels;
slouken@1913
   540
    renderer->RenderPresent = D3D_RenderPresent;
slouken@1913
   541
    renderer->DestroyTexture = D3D_DestroyTexture;
slouken@1913
   542
    renderer->DestroyRenderer = D3D_DestroyRenderer;
slouken@1913
   543
    renderer->info = D3D_RenderDriver.info;
slouken@8590
   544
    renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
slouken@1895
   545
    renderer->driverdata = data;
slouken@1895
   546
slouken@5154
   547
    SDL_VERSION(&windowinfo.version);
slouken@5154
   548
    SDL_GetWindowWMInfo(window, &windowinfo);
slouken@5154
   549
slouken@5156
   550
    window_flags = SDL_GetWindowFlags(window);
slouken@5156
   551
    SDL_GetWindowSize(window, &w, &h);
slouken@5156
   552
    SDL_GetWindowDisplayMode(window, &fullscreen_mode);
slouken@5156
   553
slouken@1900
   554
    SDL_zero(pparams);
slouken@5154
   555
    pparams.hDeviceWindow = windowinfo.info.win.window;
slouken@5156
   556
    pparams.BackBufferWidth = w;
slouken@5156
   557
    pparams.BackBufferHeight = h;
slouken@5156
   558
    if (window_flags & SDL_WINDOW_FULLSCREEN) {
slouken@1903
   559
        pparams.BackBufferFormat =
slouken@5156
   560
            PixelFormatToD3DFMT(fullscreen_mode.format);
slouken@1903
   561
    } else {
slouken@1903
   562
        pparams.BackBufferFormat = D3DFMT_UNKNOWN;
slouken@1903
   563
    }
slouken@5142
   564
    pparams.BackBufferCount = 1;
slouken@5142
   565
    pparams.SwapEffect = D3DSWAPEFFECT_DISCARD;
slouken@5142
   566
slouken@5156
   567
    if (window_flags & SDL_WINDOW_FULLSCREEN) {
slouken@8207
   568
        if ((window_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP)  {
slouken@7191
   569
            pparams.Windowed = TRUE;
slouken@7191
   570
            pparams.FullScreen_RefreshRateInHz = 0;
slouken@7191
   571
        } else {
slouken@8207
   572
            pparams.Windowed = FALSE;
slouken@8207
   573
            pparams.FullScreen_RefreshRateInHz = fullscreen_mode.refresh_rate;
slouken@7191
   574
        }
slouken@1900
   575
    } else {
slouken@1900
   576
        pparams.Windowed = TRUE;
slouken@1903
   577
        pparams.FullScreen_RefreshRateInHz = 0;
slouken@1900
   578
    }
slouken@1965
   579
    if (flags & SDL_RENDERER_PRESENTVSYNC) {
slouken@1907
   580
        pparams.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
slouken@1907
   581
    } else {
slouken@1907
   582
        pparams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
slouken@1907
   583
    }
slouken@1900
   584
slouken@7742
   585
    /* Get the adapter for the display that the window is on */
slouken@8207
   586
    displayIndex = SDL_GetWindowDisplayIndex(window);
slouken@8207
   587
    data->adapter = SDL_Direct3D9GetAdapterIndex(displayIndex);
slouken@7742
   588
slouken@5154
   589
    IDirect3D9_GetDeviceCaps(data->d3d, data->adapter, D3DDEVTYPE_HAL, &caps);
slouken@3197
   590
slouken@7877
   591
    device_flags = D3DCREATE_FPU_PRESERVE;
slouken@7877
   592
    if (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) {
slouken@7877
   593
        device_flags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
slouken@7877
   594
    } else {
slouken@7877
   595
        device_flags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
slouken@7877
   596
    }
slouken@7764
   597
slouken@7877
   598
    hint = SDL_GetHint(SDL_HINT_RENDER_DIRECT3D_THREADSAFE);
slouken@7877
   599
    if (hint && SDL_atoi(hint)) {
slouken@7877
   600
        device_flags |= D3DCREATE_MULTITHREADED;
slouken@7877
   601
    }
slouken@7764
   602
slouken@5154
   603
    result = IDirect3D9_CreateDevice(data->d3d, data->adapter,
slouken@1900
   604
                                     D3DDEVTYPE_HAL,
slouken@5154
   605
                                     pparams.hDeviceWindow,
slouken@7764
   606
                                     device_flags,
slouken@1900
   607
                                     &pparams, &data->device);
slouken@1900
   608
    if (FAILED(result)) {
slouken@1913
   609
        D3D_DestroyRenderer(renderer);
slouken@1900
   610
        D3D_SetError("CreateDevice()", result);
slouken@1900
   611
        return NULL;
slouken@1900
   612
    }
slouken@1900
   613
slouken@1907
   614
    /* Get presentation parameters to fill info */
slouken@1907
   615
    result = IDirect3DDevice9_GetSwapChain(data->device, 0, &chain);
slouken@1907
   616
    if (FAILED(result)) {
slouken@1913
   617
        D3D_DestroyRenderer(renderer);
slouken@1907
   618
        D3D_SetError("GetSwapChain()", result);
slouken@1907
   619
        return NULL;
slouken@1907
   620
    }
slouken@1907
   621
    result = IDirect3DSwapChain9_GetPresentParameters(chain, &pparams);
slouken@1907
   622
    if (FAILED(result)) {
slouken@1907
   623
        IDirect3DSwapChain9_Release(chain);
slouken@1913
   624
        D3D_DestroyRenderer(renderer);
slouken@1907
   625
        D3D_SetError("GetPresentParameters()", result);
slouken@1907
   626
        return NULL;
slouken@1907
   627
    }
slouken@1907
   628
    IDirect3DSwapChain9_Release(chain);
slouken@1907
   629
    if (pparams.PresentationInterval == D3DPRESENT_INTERVAL_ONE) {
slouken@1965
   630
        renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
slouken@1907
   631
    }
slouken@1975
   632
    data->pparams = pparams;
slouken@1907
   633
slouken@1925
   634
    IDirect3DDevice9_GetDeviceCaps(data->device, &caps);
slouken@1925
   635
    renderer->info.max_texture_width = caps.MaxTextureWidth;
slouken@1925
   636
    renderer->info.max_texture_height = caps.MaxTextureHeight;
slouken@6246
   637
    if (caps.NumSimultaneousRTs >= 2) {
slouken@6246
   638
        renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE;
slouken@6246
   639
    }
slouken@1918
   640
slouken@7502
   641
    if (caps.PrimitiveMiscCaps & D3DPMISCCAPS_SEPARATEALPHABLEND) {
slouken@7502
   642
        data->enableSeparateAlphaBlend = SDL_TRUE;
slouken@7502
   643
    }
slouken@7502
   644
slouken@6232
   645
    /* Store the default render target */
slouken@6232
   646
    IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget );
slouken@6232
   647
    data->currentRenderTarget = NULL;
slouken@6232
   648
slouken@7648
   649
    /* Set up parameters for rendering */
slouken@7648
   650
    D3D_InitRenderState(data);
slouken@5297
   651
slouken@7505
   652
    if (caps.MaxSimultaneousTextures >= 3)
slouken@7505
   653
    {
slouken@7505
   654
#ifdef ASSEMBLE_SHADER
slouken@7505
   655
        /* This shader was created by running the following HLSL through the fxc compiler
slouken@7505
   656
           and then tuning the generated assembly.
slouken@7505
   657
slouken@7505
   658
           fxc /T fx_4_0 /O3 /Gfa /Fc yuv.fxc yuv.fx
slouken@7505
   659
slouken@7505
   660
           --- yuv.fx ---
slouken@7505
   661
           Texture2D g_txY;
slouken@7505
   662
           Texture2D g_txU;
slouken@7505
   663
           Texture2D g_txV;
slouken@7505
   664
slouken@7505
   665
           SamplerState samLinear
slouken@7505
   666
           {
slouken@7505
   667
               Filter = ANISOTROPIC;
slouken@7505
   668
               AddressU = Clamp;
slouken@7505
   669
               AddressV = Clamp;
slouken@7505
   670
               MaxAnisotropy = 1;
slouken@7505
   671
           };
slouken@7505
   672
slouken@7505
   673
           struct VS_OUTPUT
slouken@7505
   674
           {
slouken@7505
   675
                float2 TextureUV  : TEXCOORD0;
slouken@7505
   676
           };
slouken@7505
   677
slouken@7505
   678
           struct PS_OUTPUT
slouken@7505
   679
           {
slouken@7505
   680
                float4 RGBAColor : SV_Target;
slouken@7505
   681
           };
slouken@7505
   682
slouken@7505
   683
           PS_OUTPUT YUV420( VS_OUTPUT In ) 
slouken@7505
   684
           {
slouken@7505
   685
               const float3 offset = {-0.0625, -0.5, -0.5};
slouken@7505
   686
               const float3 Rcoeff = {1.164,  0.000,  1.596};
slouken@7505
   687
               const float3 Gcoeff = {1.164, -0.391, -0.813};
slouken@7505
   688
               const float3 Bcoeff = {1.164,  2.018,  0.000};
slouken@7505
   689
slouken@7505
   690
               PS_OUTPUT Output;
slouken@7505
   691
               float2 TextureUV = In.TextureUV;
slouken@7505
   692
slouken@7505
   693
               float3 yuv;
slouken@7505
   694
               yuv.x = g_txY.Sample( samLinear, TextureUV ).r;
slouken@7505
   695
               yuv.y = g_txU.Sample( samLinear, TextureUV ).r;
slouken@7505
   696
               yuv.z = g_txV.Sample( samLinear, TextureUV ).r;
slouken@7505
   697
slouken@7505
   698
               yuv += offset;
slouken@7505
   699
               Output.RGBAColor.r = dot(yuv, Rcoeff);
slouken@7505
   700
               Output.RGBAColor.g = dot(yuv, Gcoeff);
slouken@7505
   701
               Output.RGBAColor.b = dot(yuv, Bcoeff);
slouken@7505
   702
               Output.RGBAColor.a = 1.0f;
slouken@7505
   703
slouken@7505
   704
               return Output;
slouken@7505
   705
           }
slouken@7505
   706
slouken@7505
   707
           technique10 RenderYUV420
slouken@7505
   708
           {
slouken@7505
   709
               pass P0
slouken@7505
   710
               {
slouken@7505
   711
                    SetPixelShader( CompileShader( ps_4_0_level_9_0, YUV420() ) );
slouken@7505
   712
               }
slouken@7505
   713
           }
slouken@7505
   714
        */
slouken@7505
   715
        const char *shader_text =
slouken@7505
   716
            "ps_2_0\n"
slouken@7505
   717
            "def c0, -0.0625, -0.5, -0.5, 1\n"
slouken@7505
   718
            "def c1, 1.16400003, 0, 1.59599996, 0\n"
slouken@7505
   719
            "def c2, 1.16400003, -0.391000003, -0.813000023, 0\n"
slouken@7505
   720
            "def c3, 1.16400003, 2.01799989, 0, 0\n"
slouken@7505
   721
            "dcl t0.xy\n"
slouken@7505
   722
            "dcl v0.xyzw\n"
slouken@7505
   723
            "dcl_2d s0\n"
slouken@7505
   724
            "dcl_2d s1\n"
slouken@7505
   725
            "dcl_2d s2\n"
slouken@7505
   726
            "texld r0, t0, s0\n"
slouken@7505
   727
            "texld r1, t0, s1\n"
slouken@7505
   728
            "texld r2, t0, s2\n"
slouken@7505
   729
            "mov r0.y, r1.x\n"
slouken@7505
   730
            "mov r0.z, r2.x\n"
slouken@7505
   731
            "add r0.xyz, r0, c0\n"
slouken@7505
   732
            "dp3 r1.x, r0, c1\n"
slouken@7505
   733
            "dp3 r1.y, r0, c2\n"
slouken@7505
   734
            "dp2add r1.z, r0, c3, c3.z\n"   /* Logically this is "dp3 r1.z, r0, c3" but the optimizer did its magic */
slouken@7505
   735
            "mov r1.w, c0.w\n"
slouken@7505
   736
            "mul r0, r1, v0\n"              /* Not in the HLSL, multiply by vertex color */
slouken@7505
   737
            "mov oC0, r0\n"
slouken@7505
   738
        ;
slouken@7505
   739
        LPD3DXBUFFER pCode;
slouken@7505
   740
        LPD3DXBUFFER pErrorMsgs;
slouken@7505
   741
        LPDWORD shader_data = NULL;
slouken@7505
   742
        DWORD   shader_size = 0;
slouken@7505
   743
        result = D3DXAssembleShader(shader_text, SDL_strlen(shader_text), NULL, NULL, 0, &pCode, &pErrorMsgs);
slouken@7505
   744
        if (!FAILED(result)) {
slouken@7505
   745
            shader_data = (DWORD*)pCode->lpVtbl->GetBufferPointer(pCode);
slouken@7505
   746
            shader_size = pCode->lpVtbl->GetBufferSize(pCode);
slouken@7505
   747
            PrintShaderData(shader_data, shader_size);
slouken@7505
   748
        } else {
slouken@7505
   749
            const char *error = (const char *)pErrorMsgs->lpVtbl->GetBufferPointer(pErrorMsgs);
slouken@7505
   750
            SDL_SetError("Couldn't assemble shader: %s", error);
slouken@7505
   751
        }
slouken@7505
   752
#else
slouken@7505
   753
        const DWORD shader_data[] = {
slouken@7505
   754
            0xffff0200, 0x05000051, 0xa00f0000, 0xbd800000, 0xbf000000, 0xbf000000,
slouken@7505
   755
            0x3f800000, 0x05000051, 0xa00f0001, 0x3f94fdf4, 0x00000000, 0x3fcc49ba,
slouken@7505
   756
            0x00000000, 0x05000051, 0xa00f0002, 0x3f94fdf4, 0xbec83127, 0xbf5020c5,
slouken@7505
   757
            0x00000000, 0x05000051, 0xa00f0003, 0x3f94fdf4, 0x400126e9, 0x00000000,
slouken@7505
   758
            0x00000000, 0x0200001f, 0x80000000, 0xb0030000, 0x0200001f, 0x80000000,
slouken@7505
   759
            0x900f0000, 0x0200001f, 0x90000000, 0xa00f0800, 0x0200001f, 0x90000000,
slouken@7505
   760
            0xa00f0801, 0x0200001f, 0x90000000, 0xa00f0802, 0x03000042, 0x800f0000,
slouken@7505
   761
            0xb0e40000, 0xa0e40800, 0x03000042, 0x800f0001, 0xb0e40000, 0xa0e40801,
slouken@7505
   762
            0x03000042, 0x800f0002, 0xb0e40000, 0xa0e40802, 0x02000001, 0x80020000,
slouken@7505
   763
            0x80000001, 0x02000001, 0x80040000, 0x80000002, 0x03000002, 0x80070000,
slouken@7505
   764
            0x80e40000, 0xa0e40000, 0x03000008, 0x80010001, 0x80e40000, 0xa0e40001,
slouken@7505
   765
            0x03000008, 0x80020001, 0x80e40000, 0xa0e40002, 0x0400005a, 0x80040001,
slouken@7505
   766
            0x80e40000, 0xa0e40003, 0xa0aa0003, 0x02000001, 0x80080001, 0xa0ff0000,
slouken@7505
   767
            0x03000005, 0x800f0000, 0x80e40001, 0x90e40000, 0x02000001, 0x800f0800,
slouken@7505
   768
            0x80e40000, 0x0000ffff
slouken@7505
   769
        };
slouken@7505
   770
#endif
slouken@7547
   771
        if (shader_data != NULL) {
slouken@7505
   772
            result = IDirect3DDevice9_CreatePixelShader(data->device, shader_data, &data->ps_yuv);
slouken@7505
   773
            if (!FAILED(result)) {
slouken@7505
   774
                renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;
slouken@7505
   775
                renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
slouken@7505
   776
            } else {
slouken@7505
   777
                D3D_SetError("CreatePixelShader()", result);
slouken@7505
   778
            }
slouken@7505
   779
        }
slouken@7505
   780
    }
slouken@7505
   781
slouken@1895
   782
    return renderer;
slouken@1895
   783
}
slouken@1895
   784
slouken@5297
   785
static void
slouken@5297
   786
D3D_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
slouken@1975
   787
{
slouken@1975
   788
    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
slouken@1975
   789
slouken@5297
   790
    if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) {
slouken@5297
   791
        data->updateSize = SDL_TRUE;
slouken@1975
   792
    }
slouken@1975
   793
}
slouken@1975
   794
slouken@5484
   795
static D3DTEXTUREFILTERTYPE
slouken@5484
   796
GetScaleQuality(void)
slouken@5484
   797
{
slouken@5484
   798
    const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
slouken@5484
   799
slouken@5484
   800
    if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) {
slouken@5484
   801
        return D3DTEXF_POINT;
gabomdq@7678
   802
    } else /* if (*hint == '1' || SDL_strcasecmp(hint, "linear") == 0) */ {
slouken@5484
   803
        return D3DTEXF_LINEAR;
slouken@5484
   804
    }
slouken@5484
   805
}
slouken@5484
   806
slouken@1975
   807
static int
slouken@1913
   808
D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@1895
   809
{
icculus@6404
   810
    D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata;
slouken@1913
   811
    D3D_TextureData *data;
slouken@5173
   812
    D3DPOOL pool;
slouken@5173
   813
    DWORD usage;
slouken@1903
   814
    HRESULT result;
slouken@1895
   815
slouken@1920
   816
    data = (D3D_TextureData *) SDL_calloc(1, sizeof(*data));
slouken@1895
   817
    if (!data) {
icculus@7037
   818
        return SDL_OutOfMemory();
slouken@1895
   819
    }
slouken@5484
   820
    data->scaleMode = GetScaleQuality();
slouken@1895
   821
slouken@1895
   822
    texture->driverdata = data;
slouken@1895
   823
slouken@5173
   824
#ifdef USE_DYNAMIC_TEXTURE
slouken@5173
   825
    if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
slouken@5173
   826
        pool = D3DPOOL_DEFAULT;
slouken@5173
   827
        usage = D3DUSAGE_DYNAMIC;
slouken@5173
   828
    } else
slouken@5173
   829
#endif
slouken@6232
   830
    if (texture->access == SDL_TEXTUREACCESS_TARGET) {
slouken@6246
   831
        /* D3DPOOL_MANAGED does not work with D3DUSAGE_RENDERTARGET */
slouken@6246
   832
        pool = D3DPOOL_DEFAULT;
slouken@6232
   833
        usage = D3DUSAGE_RENDERTARGET;
slouken@6246
   834
    } else {
slouken@5173
   835
        pool = D3DPOOL_MANAGED;
slouken@5173
   836
        usage = 0;
slouken@5173
   837
    }
slouken@2973
   838
slouken@1903
   839
    result =
slouken@1903
   840
        IDirect3DDevice9_CreateTexture(renderdata->device, texture->w,
slouken@5173
   841
                                       texture->h, 1, usage,
slouken@5173
   842
                                       PixelFormatToD3DFMT(texture->format),
slouken@5173
   843
                                       pool, &data->texture, NULL);
slouken@1903
   844
    if (FAILED(result)) {
icculus@7037
   845
        return D3D_SetError("CreateTexture()", result);
slouken@1903
   846
    }
slouken@1903
   847
slouken@7505
   848
    if (texture->format == SDL_PIXELFORMAT_YV12 ||
slouken@7505
   849
        texture->format == SDL_PIXELFORMAT_IYUV) {
slouken@7505
   850
        data->yuv = SDL_TRUE;
slouken@7505
   851
slouken@7505
   852
        result =
slouken@7505
   853
            IDirect3DDevice9_CreateTexture(renderdata->device, texture->w / 2,
slouken@7505
   854
                                           texture->h / 2, 1, usage,
slouken@7505
   855
                                           PixelFormatToD3DFMT(texture->format),
slouken@7505
   856
                                           pool, &data->utexture, NULL);
slouken@7505
   857
        if (FAILED(result)) {
slouken@7505
   858
            return D3D_SetError("CreateTexture()", result);
slouken@7505
   859
        }
slouken@7505
   860
slouken@7505
   861
        result =
slouken@7505
   862
            IDirect3DDevice9_CreateTexture(renderdata->device, texture->w / 2,
slouken@7505
   863
                                           texture->h / 2, 1, usage,
slouken@7505
   864
                                           PixelFormatToD3DFMT(texture->format),
slouken@7505
   865
                                           pool, &data->vtexture, NULL);
slouken@7505
   866
        if (FAILED(result)) {
slouken@7505
   867
            return D3D_SetError("CreateTexture()", result);
slouken@7505
   868
        }
slouken@7505
   869
    }
slouken@7505
   870
slouken@7505
   871
    return 0;
slouken@7505
   872
}
slouken@7505
   873
slouken@7505
   874
static int
slouken@7505
   875
D3D_UpdateTextureInternal(IDirect3DTexture9 *texture, Uint32 format, SDL_bool full_texture, int x, int y, int w, int h, const void *pixels, int pitch)
slouken@7505
   876
{
slouken@7505
   877
    RECT d3drect;
slouken@7505
   878
    D3DLOCKED_RECT locked;
slouken@7505
   879
    const Uint8 *src;
slouken@7505
   880
    Uint8 *dst;
slouken@7505
   881
    int row, length;
slouken@7505
   882
    HRESULT result;
slouken@7505
   883
slouken@7505
   884
    if (full_texture) {
slouken@7505
   885
        result = IDirect3DTexture9_LockRect(texture, 0, &locked, NULL, D3DLOCK_DISCARD);
slouken@7505
   886
    } else {
slouken@7505
   887
        d3drect.left = x;
slouken@7505
   888
        d3drect.right = x + w;
slouken@7505
   889
        d3drect.top = y;
slouken@7505
   890
        d3drect.bottom = y + h;
slouken@7505
   891
        result = IDirect3DTexture9_LockRect(texture, 0, &locked, &d3drect, 0);
slouken@7505
   892
    }
slouken@7505
   893
slouken@7505
   894
    if (FAILED(result)) {
slouken@7505
   895
        return D3D_SetError("LockRect()", result);
slouken@7505
   896
    }
slouken@7505
   897
slouken@7505
   898
    src = (const Uint8 *)pixels;
slouken@7505
   899
    dst = locked.pBits;
slouken@7505
   900
    length = w * SDL_BYTESPERPIXEL(format);
slouken@7505
   901
    if (length == pitch && length == locked.Pitch) {
slouken@7505
   902
        SDL_memcpy(dst, src, length*h);
slouken@7505
   903
    } else {
slouken@8255
   904
        if (length > pitch) {
slouken@8255
   905
            length = pitch;
slouken@8255
   906
        }
slouken@8255
   907
        if (length > locked.Pitch) {
slouken@8255
   908
            length = locked.Pitch;
slouken@8255
   909
        }
slouken@7505
   910
        for (row = 0; row < h; ++row) {
slouken@7505
   911
            SDL_memcpy(dst, src, length);
slouken@7505
   912
            src += pitch;
slouken@7505
   913
            dst += locked.Pitch;
slouken@7505
   914
        }
slouken@7505
   915
    }
slouken@7505
   916
    IDirect3DTexture9_UnlockRect(texture, 0);
slouken@7505
   917
slouken@1895
   918
    return 0;
slouken@1895
   919
}
slouken@1895
   920
slouken@1895
   921
static int
slouken@1913
   922
D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@1913
   923
                  const SDL_Rect * rect, const void *pixels, int pitch)
slouken@1895
   924
{
slouken@1913
   925
    D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
slouken@7505
   926
    SDL_bool full_texture = SDL_FALSE;
slouken@2973
   927
slouken@5173
   928
#ifdef USE_DYNAMIC_TEXTURE
slouken@5173
   929
    if (texture->access == SDL_TEXTUREACCESS_STREAMING &&
slouken@5173
   930
        rect->x == 0 && rect->y == 0 &&
slouken@5173
   931
        rect->w == texture->w && rect->h == texture->h) {
slouken@7505
   932
        full_texture = SDL_TRUE;
slouken@7505
   933
    }
slouken@5173
   934
#endif
slouken@7505
   935
slouken@8208
   936
    if (!data) {
slouken@8208
   937
        SDL_SetError("Texture is not currently available");
slouken@8208
   938
        return -1;
slouken@8208
   939
    }
slouken@8208
   940
slouken@7505
   941
    if (D3D_UpdateTextureInternal(data->texture, texture->format, full_texture, rect->x, rect->y, rect->w, rect->h, pixels, pitch) < 0) {
slouken@7505
   942
        return -1;
slouken@5156
   943
    }
slouken@2973
   944
slouken@7505
   945
    if (data->yuv) {
slouken@7505
   946
        /* Skip to the correct offset into the next texture */
slouken@7505
   947
        pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
slouken@2973
   948
slouken@7505
   949
        if (D3D_UpdateTextureInternal(texture->format == SDL_PIXELFORMAT_YV12 ? data->vtexture : data->utexture, texture->format, full_texture, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, pixels, pitch / 2) < 0) {
slouken@7505
   950
            return -1;
slouken@7505
   951
        }
slouken@7505
   952
slouken@7505
   953
        /* Skip to the correct offset into the next texture */
slouken@7505
   954
        pixels = (const void*)((const Uint8*)pixels + (rect->h * pitch)/4);
slouken@7505
   955
        if (D3D_UpdateTextureInternal(texture->format == SDL_PIXELFORMAT_YV12 ? data->utexture : data->vtexture, texture->format, full_texture, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, pixels, pitch / 2) < 0) {
slouken@7505
   956
            return -1;
slouken@5173
   957
        }
slouken@5156
   958
    }
slouken@5156
   959
    return 0;
slouken@1895
   960
}
slouken@1895
   961
slouken@1895
   962
static int
slouken@7761
   963
D3D_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@7761
   964
                     const SDL_Rect * rect,
slouken@7761
   965
                     const Uint8 *Yplane, int Ypitch,
slouken@7761
   966
                     const Uint8 *Uplane, int Upitch,
slouken@7761
   967
                     const Uint8 *Vplane, int Vpitch)
slouken@7761
   968
{
slouken@7877
   969
    D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
slouken@7877
   970
    SDL_bool full_texture = SDL_FALSE;
slouken@7761
   971
slouken@7761
   972
#ifdef USE_DYNAMIC_TEXTURE
slouken@7877
   973
    if (texture->access == SDL_TEXTUREACCESS_STREAMING &&
slouken@7877
   974
        rect->x == 0 && rect->y == 0 &&
slouken@7877
   975
        rect->w == texture->w && rect->h == texture->h) {
slouken@7877
   976
            full_texture = SDL_TRUE;
slouken@7877
   977
    }
slouken@7761
   978
#endif
slouken@7761
   979
slouken@8208
   980
    if (!data) {
slouken@8208
   981
        SDL_SetError("Texture is not currently available");
slouken@8208
   982
        return -1;
slouken@8208
   983
    }
slouken@8208
   984
slouken@7877
   985
    if (D3D_UpdateTextureInternal(data->texture, texture->format, full_texture, rect->x, rect->y, rect->w, rect->h, Yplane, Ypitch) < 0) {
slouken@7877
   986
        return -1;
slouken@7877
   987
    }
slouken@7877
   988
    if (D3D_UpdateTextureInternal(data->utexture, texture->format, full_texture, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, Uplane, Upitch) < 0) {
slouken@7877
   989
        return -1;
slouken@7877
   990
    }
slouken@7877
   991
    if (D3D_UpdateTextureInternal(data->vtexture, texture->format, full_texture, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, Vplane, Vpitch) < 0) {
slouken@7877
   992
        return -1;
slouken@7877
   993
    }
slouken@7877
   994
    return 0;
slouken@7761
   995
}
slouken@7761
   996
slouken@7761
   997
static int
slouken@1913
   998
D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@5156
   999
                const SDL_Rect * rect, void **pixels, int *pitch)
slouken@1895
  1000
{
slouken@1913
  1001
    D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
slouken@5156
  1002
    RECT d3drect;
slouken@5156
  1003
    D3DLOCKED_RECT locked;
slouken@5156
  1004
    HRESULT result;
slouken@1895
  1005
slouken@8208
  1006
    if (!data) {
slouken@8208
  1007
        SDL_SetError("Texture is not currently available");
slouken@8208
  1008
        return -1;
slouken@8208
  1009
    }
slouken@8208
  1010
slouken@7505
  1011
    if (data->yuv) {
gabomdq@7663
  1012
        /* It's more efficient to upload directly... */
slouken@7505
  1013
        if (!data->pixels) {
slouken@7505
  1014
            data->pitch = texture->w;
slouken@7505
  1015
            data->pixels = (Uint8 *)SDL_malloc((texture->h * data->pitch * 3) / 2);
slouken@7505
  1016
            if (!data->pixels) {
slouken@7505
  1017
                return SDL_OutOfMemory();
slouken@7505
  1018
            }
slouken@7505
  1019
        }
slouken@7505
  1020
        data->locked_rect = *rect;
slouken@7505
  1021
        *pixels =
slouken@7505
  1022
            (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
slouken@7505
  1023
                      rect->x * SDL_BYTESPERPIXEL(texture->format));
slouken@7505
  1024
        *pitch = data->pitch;
slouken@7505
  1025
    } else {
slouken@7505
  1026
        d3drect.left = rect->x;
slouken@7505
  1027
        d3drect.right = rect->x + rect->w;
slouken@7505
  1028
        d3drect.top = rect->y;
slouken@7505
  1029
        d3drect.bottom = rect->y + rect->h;
slouken@1903
  1030
slouken@7505
  1031
        result = IDirect3DTexture9_LockRect(data->texture, 0, &locked, &d3drect, 0);
slouken@7505
  1032
        if (FAILED(result)) {
slouken@7505
  1033
            return D3D_SetError("LockRect()", result);
slouken@7505
  1034
        }
slouken@7505
  1035
        *pixels = locked.pBits;
slouken@7505
  1036
        *pitch = locked.Pitch;
slouken@1903
  1037
    }
slouken@5156
  1038
    return 0;
slouken@1895
  1039
}
slouken@1895
  1040
slouken@1895
  1041
static void
slouken@1913
  1042
D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@1895
  1043
{
slouken@1913
  1044
    D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
slouken@1895
  1045
slouken@8208
  1046
    if (!data) {
slouken@8208
  1047
        return;
slouken@8208
  1048
    }
slouken@8208
  1049
slouken@7505
  1050
    if (data->yuv) {
slouken@7505
  1051
        const SDL_Rect *rect = &data->locked_rect;
slouken@7505
  1052
        void *pixels =
slouken@7505
  1053
            (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
slouken@7505
  1054
                      rect->x * SDL_BYTESPERPIXEL(texture->format));
slouken@7505
  1055
        D3D_UpdateTexture(renderer, texture, rect, pixels, data->pitch);
slouken@7505
  1056
    } else {
slouken@7505
  1057
        IDirect3DTexture9_UnlockRect(data->texture, 0);
slouken@7505
  1058
    }
slouken@1895
  1059
}
slouken@1895
  1060
slouken@5297
  1061
static int
slouken@8228
  1062
D3D_SetRenderTargetInternal(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@7141
  1063
{
slouken@7141
  1064
    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
slouken@7141
  1065
    D3D_TextureData *texturedata;
slouken@7141
  1066
    HRESULT result;
slouken@7141
  1067
slouken@7141
  1068
    /* Release the previous render target if it wasn't the default one */
slouken@7141
  1069
    if (data->currentRenderTarget != NULL) {
slouken@7141
  1070
        IDirect3DSurface9_Release(data->currentRenderTarget);
slouken@7141
  1071
        data->currentRenderTarget = NULL;
slouken@7141
  1072
    }
slouken@7141
  1073
slouken@7141
  1074
    if (texture == NULL) {
slouken@7141
  1075
        IDirect3DDevice9_SetRenderTarget(data->device, 0, data->defaultRenderTarget);
slouken@7141
  1076
        return 0;
slouken@7141
  1077
    }
slouken@7141
  1078
slouken@8208
  1079
    texturedata = (D3D_TextureData *)texture->driverdata;
slouken@8208
  1080
    if (!texturedata) {
slouken@8208
  1081
        SDL_SetError("Texture is not currently available");
slouken@8208
  1082
        return -1;
slouken@8208
  1083
    }
slouken@8208
  1084
slouken@7141
  1085
    result = IDirect3DTexture9_GetSurfaceLevel(texturedata->texture, 0, &data->currentRenderTarget);
slouken@7141
  1086
    if(FAILED(result)) {
slouken@7141
  1087
        return D3D_SetError("GetSurfaceLevel()", result);
slouken@7141
  1088
    }
slouken@7141
  1089
    result = IDirect3DDevice9_SetRenderTarget(data->device, 0, data->currentRenderTarget);
slouken@7141
  1090
    if(FAILED(result)) {
slouken@7141
  1091
        return D3D_SetError("SetRenderTarget()", result);
slouken@7141
  1092
    }
slouken@7141
  1093
slouken@7141
  1094
    return 0;
slouken@7141
  1095
}
slouken@7141
  1096
slouken@7141
  1097
static int
slouken@8228
  1098
D3D_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@8228
  1099
{
slouken@8228
  1100
    D3D_ActivateRenderer(renderer);
slouken@8228
  1101
slouken@8228
  1102
    return D3D_SetRenderTargetInternal(renderer, texture);
slouken@8228
  1103
}
slouken@8228
  1104
slouken@8228
  1105
static int
slouken@5297
  1106
D3D_UpdateViewport(SDL_Renderer * renderer)
slouken@5224
  1107
{
slouken@5224
  1108
    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
slouken@5297
  1109
    D3DVIEWPORT9 viewport;
slouken@5297
  1110
    D3DMATRIX matrix;
slouken@5224
  1111
slouken@5297
  1112
    /* Set the viewport */
slouken@5297
  1113
    viewport.X = renderer->viewport.x;
slouken@5297
  1114
    viewport.Y = renderer->viewport.y;
slouken@5297
  1115
    viewport.Width = renderer->viewport.w;
slouken@5297
  1116
    viewport.Height = renderer->viewport.h;
slouken@5297
  1117
    viewport.MinZ = 0.0f;
slouken@5297
  1118
    viewport.MaxZ = 1.0f;
slouken@5297
  1119
    IDirect3DDevice9_SetViewport(data->device, &viewport);
slouken@5224
  1120
slouken@5297
  1121
    /* Set an orthographic projection matrix */
slouken@7239
  1122
    if (renderer->viewport.w && renderer->viewport.h) {
slouken@7239
  1123
        matrix.m[0][0] = 2.0f / renderer->viewport.w;
slouken@7239
  1124
        matrix.m[0][1] = 0.0f;
slouken@7239
  1125
        matrix.m[0][2] = 0.0f;
slouken@7239
  1126
        matrix.m[0][3] = 0.0f;
slouken@7239
  1127
        matrix.m[1][0] = 0.0f;
slouken@7239
  1128
        matrix.m[1][1] = -2.0f / renderer->viewport.h;
slouken@7239
  1129
        matrix.m[1][2] = 0.0f;
slouken@7239
  1130
        matrix.m[1][3] = 0.0f;
slouken@7239
  1131
        matrix.m[2][0] = 0.0f;
slouken@7239
  1132
        matrix.m[2][1] = 0.0f;
slouken@7239
  1133
        matrix.m[2][2] = 1.0f;
slouken@7239
  1134
        matrix.m[2][3] = 0.0f;
slouken@7239
  1135
        matrix.m[3][0] = -1.0f;
slouken@7239
  1136
        matrix.m[3][1] = 1.0f;
slouken@7239
  1137
        matrix.m[3][2] = 0.0f;
slouken@7239
  1138
        matrix.m[3][3] = 1.0f;
slouken@7239
  1139
        IDirect3DDevice9_SetTransform(data->device, D3DTS_PROJECTION, &matrix);
slouken@7239
  1140
    }
slouken@5297
  1141
slouken@5297
  1142
    return 0;
slouken@5297
  1143
}
slouken@5297
  1144
slouken@5297
  1145
static int
slouken@7141
  1146
D3D_UpdateClipRect(SDL_Renderer * renderer)
slouken@6246
  1147
{
slouken@7141
  1148
    const SDL_Rect *rect = &renderer->clip_rect;
slouken@6246
  1149
    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
slouken@7141
  1150
    RECT r;
slouken@6246
  1151
    HRESULT result;
slouken@6246
  1152
slouken@7141
  1153
    if (!SDL_RectEmpty(rect)) {
slouken@7141
  1154
        IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, TRUE);
slouken@7141
  1155
        r.left = rect->x;
slouken@7141
  1156
        r.top = rect->y;
slouken@7472
  1157
        r.right = rect->x + rect->w;
slouken@7141
  1158
        r.bottom = rect->y + rect->h;
slouken@6246
  1159
slouken@7141
  1160
        result = IDirect3DDevice9_SetScissorRect(data->device, &r);
slouken@7141
  1161
        if (result != D3D_OK) {
slouken@7141
  1162
            D3D_SetError("SetScissor()", result);
slouken@7141
  1163
            return -1;
slouken@7141
  1164
        }
slouken@7141
  1165
    } else {
slouken@7141
  1166
        IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, FALSE);
slouken@6246
  1167
    }
slouken@6246
  1168
    return 0;
slouken@6246
  1169
}
slouken@6246
  1170
slouken@6246
  1171
static int
slouken@5297
  1172
D3D_RenderClear(SDL_Renderer * renderer)
slouken@5297
  1173
{
slouken@5297
  1174
    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
slouken@5297
  1175
    DWORD color;
slouken@5297
  1176
    HRESULT result;
slouken@7837
  1177
    int BackBufferWidth, BackBufferHeight;
slouken@5297
  1178
slouken@5297
  1179
    if (D3D_ActivateRenderer(renderer) < 0) {
slouken@5297
  1180
        return -1;
slouken@5224
  1181
    }
slouken@5297
  1182
slouken@5297
  1183
    color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
slouken@5297
  1184
slouken@7837
  1185
    if (renderer->target) {
slouken@7837
  1186
        BackBufferWidth = renderer->target->w;
slouken@7837
  1187
        BackBufferHeight = renderer->target->h;
slouken@7837
  1188
    } else {
slouken@7837
  1189
        BackBufferWidth = data->pparams.BackBufferWidth;
slouken@7837
  1190
        BackBufferHeight = data->pparams.BackBufferHeight;
slouken@7837
  1191
    }
slouken@7837
  1192
slouken@5299
  1193
    /* Don't reset the viewport if we don't have to! */
slouken@5299
  1194
    if (!renderer->viewport.x && !renderer->viewport.y &&
slouken@7837
  1195
        renderer->viewport.w == BackBufferWidth &&
slouken@7837
  1196
        renderer->viewport.h == BackBufferHeight) {
slouken@5299
  1197
        result = IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
slouken@5299
  1198
    } else {
slouken@5299
  1199
        D3DVIEWPORT9 viewport;
slouken@5297
  1200
slouken@5299
  1201
        /* Clear is defined to clear the entire render target */
slouken@5299
  1202
        viewport.X = 0;
slouken@5299
  1203
        viewport.Y = 0;
slouken@7837
  1204
        viewport.Width = BackBufferWidth;
slouken@7837
  1205
        viewport.Height = BackBufferHeight;
slouken@5299
  1206
        viewport.MinZ = 0.0f;
slouken@5299
  1207
        viewport.MaxZ = 1.0f;
slouken@5299
  1208
        IDirect3DDevice9_SetViewport(data->device, &viewport);
slouken@5299
  1209
slouken@5299
  1210
        result = IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
slouken@5299
  1211
slouken@5299
  1212
        /* Reset the viewport */
slouken@5299
  1213
        viewport.X = renderer->viewport.x;
slouken@5299
  1214
        viewport.Y = renderer->viewport.y;
slouken@5299
  1215
        viewport.Width = renderer->viewport.w;
slouken@5299
  1216
        viewport.Height = renderer->viewport.h;
slouken@5299
  1217
        viewport.MinZ = 0.0f;
slouken@5299
  1218
        viewport.MaxZ = 1.0f;
slouken@5299
  1219
        IDirect3DDevice9_SetViewport(data->device, &viewport);
slouken@5299
  1220
    }
slouken@5297
  1221
slouken@5297
  1222
    if (FAILED(result)) {
icculus@7037
  1223
        return D3D_SetError("Clear()", result);
slouken@5297
  1224
    }
slouken@5297
  1225
    return 0;
slouken@5224
  1226
}
slouken@5224
  1227
slouken@5224
  1228
static void
slouken@2933
  1229
D3D_SetBlendMode(D3D_RenderData * data, int blendMode)
slouken@2932
  1230
{
slouken@2932
  1231
    switch (blendMode) {
slouken@2932
  1232
    case SDL_BLENDMODE_NONE:
slouken@2932
  1233
        IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
slouken@2932
  1234
                                        FALSE);
slouken@2932
  1235
        break;
slouken@2932
  1236
    case SDL_BLENDMODE_BLEND:
slouken@2932
  1237
        IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
slouken@2932
  1238
                                        TRUE);
slouken@2932
  1239
        IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
slouken@2932
  1240
                                        D3DBLEND_SRCALPHA);
slouken@2932
  1241
        IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
slouken@2932
  1242
                                        D3DBLEND_INVSRCALPHA);
slouken@7502
  1243
        if (data->enableSeparateAlphaBlend) {
slouken@7502
  1244
            IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA,
slouken@7502
  1245
                                            D3DBLEND_ONE);
slouken@7502
  1246
            IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA,
slouken@7502
  1247
                                            D3DBLEND_INVSRCALPHA);
slouken@7502
  1248
        }
slouken@2932
  1249
        break;
slouken@2932
  1250
    case SDL_BLENDMODE_ADD:
slouken@2932
  1251
        IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
slouken@2932
  1252
                                        TRUE);
slouken@2932
  1253
        IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
slouken@2932
  1254
                                        D3DBLEND_SRCALPHA);
slouken@2932
  1255
        IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
slouken@2932
  1256
                                        D3DBLEND_ONE);
slouken@7502
  1257
        if (data->enableSeparateAlphaBlend) {
slouken@7502
  1258
            IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA,
slouken@7502
  1259
                                            D3DBLEND_ZERO);
slouken@7502
  1260
            IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA,
slouken@7502
  1261
                                            D3DBLEND_ONE);
slouken@7502
  1262
        }
slouken@2932
  1263
        break;
slouken@5184
  1264
    case SDL_BLENDMODE_MOD:
slouken@5184
  1265
        IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
slouken@5184
  1266
                                        TRUE);
slouken@5184
  1267
        IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
slouken@5184
  1268
                                        D3DBLEND_ZERO);
slouken@5184
  1269
        IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
slouken@5184
  1270
                                        D3DBLEND_SRCCOLOR);
slouken@7502
  1271
        if (data->enableSeparateAlphaBlend) {
slouken@7502
  1272
            IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA,
slouken@7502
  1273
                                            D3DBLEND_ZERO);
slouken@7502
  1274
            IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA,
slouken@7502
  1275
                                            D3DBLEND_ONE);
slouken@7502
  1276
        }
slouken@5184
  1277
        break;
slouken@2932
  1278
    }
slouken@2932
  1279
}
slouken@2932
  1280
slouken@1895
  1281
static int
slouken@6528
  1282
D3D_RenderDrawPoints(SDL_Renderer * renderer, const SDL_FPoint * points,
slouken@3599
  1283
                     int count)
slouken@1895
  1284
{
slouken@1913
  1285
    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
slouken@2932
  1286
    DWORD color;
slouken@3536
  1287
    Vertex *vertices;
slouken@3536
  1288
    int i;
slouken@1900
  1289
    HRESULT result;
slouken@1895
  1290
slouken@5297
  1291
    if (D3D_ActivateRenderer(renderer) < 0) {
slouken@5297
  1292
        return -1;
slouken@1900
  1293
    }
slouken@1895
  1294
slouken@2932
  1295
    D3D_SetBlendMode(data, renderer->blendMode);
slouken@2932
  1296
slouken@2933
  1297
    result =
slouken@2933
  1298
        IDirect3DDevice9_SetTexture(data->device, 0,
slouken@2933
  1299
                                    (IDirect3DBaseTexture9 *) 0);
slouken@2932
  1300
    if (FAILED(result)) {
icculus@7037
  1301
        return D3D_SetError("SetTexture()", result);
slouken@2932
  1302
    }
slouken@3536
  1303
slouken@3536
  1304
    color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
slouken@3536
  1305
slouken@3536
  1306
    vertices = SDL_stack_alloc(Vertex, count);
slouken@3536
  1307
    for (i = 0; i < count; ++i) {
slouken@6528
  1308
        vertices[i].x = points[i].x;
slouken@6528
  1309
        vertices[i].y = points[i].y;
slouken@3536
  1310
        vertices[i].z = 0.0f;
slouken@3536
  1311
        vertices[i].color = color;
slouken@3536
  1312
        vertices[i].u = 0.0f;
slouken@3536
  1313
        vertices[i].v = 0.0f;
slouken@3536
  1314
    }
slouken@1903
  1315
    result =
slouken@3536
  1316
        IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, count,
slouken@2932
  1317
                                         vertices, sizeof(*vertices));
slouken@3536
  1318
    SDL_stack_free(vertices);
slouken@1900
  1319
    if (FAILED(result)) {
icculus@7037
  1320
        return D3D_SetError("DrawPrimitiveUP()", result);
slouken@2932
  1321
    }
slouken@2932
  1322
    return 0;
slouken@2932
  1323
}
slouken@2932
  1324
slouken@2932
  1325
static int
slouken@6528
  1326
D3D_RenderDrawLines(SDL_Renderer * renderer, const SDL_FPoint * points,
slouken@3599
  1327
                    int count)
slouken@2932
  1328
{
slouken@2932
  1329
    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
slouken@2932
  1330
    DWORD color;
slouken@3536
  1331
    Vertex *vertices;
slouken@3536
  1332
    int i;
slouken@2932
  1333
    HRESULT result;
slouken@2932
  1334
slouken@5297
  1335
    if (D3D_ActivateRenderer(renderer) < 0) {
slouken@5297
  1336
        return -1;
slouken@2932
  1337
    }
slouken@2932
  1338
slouken@2932
  1339
    D3D_SetBlendMode(data, renderer->blendMode);
slouken@2932
  1340
slouken@2933
  1341
    result =
slouken@2933
  1342
        IDirect3DDevice9_SetTexture(data->device, 0,
slouken@2933
  1343
                                    (IDirect3DBaseTexture9 *) 0);
slouken@2932
  1344
    if (FAILED(result)) {
icculus@7037
  1345
        return D3D_SetError("SetTexture()", result);
slouken@2932
  1346
    }
slouken@3536
  1347
slouken@3536
  1348
    color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
slouken@3536
  1349
slouken@3536
  1350
    vertices = SDL_stack_alloc(Vertex, count);
slouken@3536
  1351
    for (i = 0; i < count; ++i) {
slouken@6528
  1352
        vertices[i].x = points[i].x;
slouken@6528
  1353
        vertices[i].y = points[i].y;
slouken@3536
  1354
        vertices[i].z = 0.0f;
slouken@3536
  1355
        vertices[i].color = color;
slouken@3536
  1356
        vertices[i].u = 0.0f;
slouken@3536
  1357
        vertices[i].v = 0.0f;
slouken@3536
  1358
    }
slouken@2932
  1359
    result =
slouken@3551
  1360
        IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_LINESTRIP, count-1,
slouken@2932
  1361
                                         vertices, sizeof(*vertices));
slouken@3551
  1362
slouken@3551
  1363
    /* DirectX 9 has the same line rasterization semantics as GDI,
slouken@3551
  1364
       so we need to close the endpoint of the line */
slouken@6076
  1365
    if (count == 2 ||
slouken@6076
  1366
        points[0].x != points[count-1].x || points[0].y != points[count-1].y) {
slouken@6528
  1367
        vertices[0].x = points[count-1].x;
slouken@6528
  1368
        vertices[0].y = points[count-1].y;
slouken@3551
  1369
        result = IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, 1, vertices, sizeof(*vertices));
slouken@3551
  1370
    }
slouken@3551
  1371
slouken@3536
  1372
    SDL_stack_free(vertices);
slouken@2932
  1373
    if (FAILED(result)) {
icculus@7037
  1374
        return D3D_SetError("DrawPrimitiveUP()", result);
slouken@2932
  1375
    }
slouken@2932
  1376
    return 0;
slouken@2932
  1377
}
slouken@2932
  1378
slouken@2932
  1379
static int
slouken@6528
  1380
D3D_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects,
slouken@3599
  1381
                    int count)
slouken@2932
  1382
{
slouken@2932
  1383
    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
slouken@3536
  1384
    DWORD color;
slouken@3536
  1385
    int i;
slouken@2932
  1386
    float minx, miny, maxx, maxy;
slouken@2932
  1387
    Vertex vertices[4];
slouken@2932
  1388
    HRESULT result;
slouken@2932
  1389
slouken@5297
  1390
    if (D3D_ActivateRenderer(renderer) < 0) {
slouken@5297
  1391
        return -1;
slouken@2932
  1392
    }
slouken@2932
  1393
slouken@2932
  1394
    D3D_SetBlendMode(data, renderer->blendMode);
slouken@2932
  1395
slouken@2933
  1396
    result =
slouken@2933
  1397
        IDirect3DDevice9_SetTexture(data->device, 0,
slouken@2933
  1398
                                    (IDirect3DBaseTexture9 *) 0);
slouken@2932
  1399
    if (FAILED(result)) {
icculus@7037
  1400
        return D3D_SetError("SetTexture()", result);
slouken@2932
  1401
    }
slouken@3536
  1402
slouken@3536
  1403
    color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
slouken@3536
  1404
slouken@3536
  1405
    for (i = 0; i < count; ++i) {
slouken@6528
  1406
        const SDL_FRect *rect = &rects[i];
slouken@3536
  1407
slouken@6528
  1408
        minx = rect->x;
slouken@6528
  1409
        miny = rect->y;
slouken@6528
  1410
        maxx = rect->x + rect->w;
slouken@6528
  1411
        maxy = rect->y + rect->h;
slouken@3536
  1412
slouken@3536
  1413
        vertices[0].x = minx;
slouken@3536
  1414
        vertices[0].y = miny;
slouken@3536
  1415
        vertices[0].z = 0.0f;
slouken@3536
  1416
        vertices[0].color = color;
slouken@3536
  1417
        vertices[0].u = 0.0f;
slouken@3536
  1418
        vertices[0].v = 0.0f;
slouken@3536
  1419
slouken@3536
  1420
        vertices[1].x = maxx;
slouken@3536
  1421
        vertices[1].y = miny;
slouken@3536
  1422
        vertices[1].z = 0.0f;
slouken@3536
  1423
        vertices[1].color = color;
slouken@3536
  1424
        vertices[1].u = 0.0f;
slouken@3536
  1425
        vertices[1].v = 0.0f;
slouken@3536
  1426
slouken@3536
  1427
        vertices[2].x = maxx;
slouken@3536
  1428
        vertices[2].y = maxy;
slouken@3536
  1429
        vertices[2].z = 0.0f;
slouken@3536
  1430
        vertices[2].color = color;
slouken@3536
  1431
        vertices[2].u = 0.0f;
slouken@3536
  1432
        vertices[2].v = 0.0f;
slouken@3536
  1433
slouken@3536
  1434
        vertices[3].x = minx;
slouken@3536
  1435
        vertices[3].y = maxy;
slouken@3536
  1436
        vertices[3].z = 0.0f;
slouken@3536
  1437
        vertices[3].color = color;
slouken@3536
  1438
        vertices[3].u = 0.0f;
slouken@3536
  1439
        vertices[3].v = 0.0f;
slouken@3536
  1440
slouken@3536
  1441
        result =
slouken@3536
  1442
            IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN,
slouken@3536
  1443
                                             2, vertices, sizeof(*vertices));
slouken@3536
  1444
        if (FAILED(result)) {
icculus@7037
  1445
            return D3D_SetError("DrawPrimitiveUP()", result);
slouken@3536
  1446
        }
slouken@1900
  1447
    }
slouken@1895
  1448
    return 0;
slouken@1895
  1449
}
slouken@1895
  1450
slouken@7505
  1451
static void
slouken@7505
  1452
D3D_UpdateTextureScaleMode(D3D_RenderData *data, D3D_TextureData *texturedata, unsigned index)
slouken@7505
  1453
{
slouken@7505
  1454
    if (texturedata->scaleMode != data->scaleMode[index]) {
slouken@7505
  1455
        IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MINFILTER,
slouken@7505
  1456
                                         texturedata->scaleMode);
slouken@7505
  1457
        IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MAGFILTER,
slouken@7505
  1458
                                         texturedata->scaleMode);
slouken@7505
  1459
        data->scaleMode[index] = texturedata->scaleMode;
slouken@7505
  1460
    }
slouken@7505
  1461
}
slouken@7505
  1462
slouken@1895
  1463
static int
slouken@1913
  1464
D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@6528
  1465
               const SDL_Rect * srcrect, const SDL_FRect * dstrect)
slouken@1895
  1466
{
slouken@1913
  1467
    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
slouken@8208
  1468
    D3D_TextureData *texturedata;
slouken@3556
  1469
    LPDIRECT3DPIXELSHADER9 shader = NULL;
slouken@1903
  1470
    float minx, miny, maxx, maxy;
slouken@1904
  1471
    float minu, maxu, minv, maxv;
slouken@1987
  1472
    DWORD color;
slouken@1903
  1473
    Vertex vertices[4];
slouken@1903
  1474
    HRESULT result;
slouken@1895
  1475
slouken@5297
  1476
    if (D3D_ActivateRenderer(renderer) < 0) {
slouken@5297
  1477
        return -1;
slouken@1900
  1478
    }
slouken@1903
  1479
slouken@8208
  1480
    texturedata = (D3D_TextureData *)texture->driverdata;
slouken@8208
  1481
    if (!texturedata) {
slouken@8208
  1482
        SDL_SetError("Texture is not currently available");
slouken@8208
  1483
        return -1;
slouken@8208
  1484
    }
slouken@8208
  1485
slouken@6528
  1486
    minx = dstrect->x - 0.5f;
slouken@6528
  1487
    miny = dstrect->y - 0.5f;
slouken@6528
  1488
    maxx = dstrect->x + dstrect->w - 0.5f;
slouken@6528
  1489
    maxy = dstrect->y + dstrect->h - 0.5f;
slouken@1903
  1490
slouken@1904
  1491
    minu = (float) srcrect->x / texture->w;
slouken@1904
  1492
    maxu = (float) (srcrect->x + srcrect->w) / texture->w;
slouken@1904
  1493
    minv = (float) srcrect->y / texture->h;
slouken@1904
  1494
    maxv = (float) (srcrect->y + srcrect->h) / texture->h;
slouken@1903
  1495
slouken@1987
  1496
    color = D3DCOLOR_ARGB(texture->a, texture->r, texture->g, texture->b);
slouken@1987
  1497
slouken@1903
  1498
    vertices[0].x = minx;
slouken@1903
  1499
    vertices[0].y = miny;
slouken@1903
  1500
    vertices[0].z = 0.0f;
slouken@1987
  1501
    vertices[0].color = color;
slouken@1904
  1502
    vertices[0].u = minu;
slouken@1904
  1503
    vertices[0].v = minv;
slouken@1904
  1504
slouken@1903
  1505
    vertices[1].x = maxx;
slouken@1903
  1506
    vertices[1].y = miny;
slouken@1903
  1507
    vertices[1].z = 0.0f;
slouken@1987
  1508
    vertices[1].color = color;
slouken@1904
  1509
    vertices[1].u = maxu;
slouken@1904
  1510
    vertices[1].v = minv;
slouken@1904
  1511
slouken@1903
  1512
    vertices[2].x = maxx;
slouken@1903
  1513
    vertices[2].y = maxy;
slouken@1903
  1514
    vertices[2].z = 0.0f;
slouken@1987
  1515
    vertices[2].color = color;
slouken@1904
  1516
    vertices[2].u = maxu;
slouken@1904
  1517
    vertices[2].v = maxv;
slouken@1904
  1518
slouken@1903
  1519
    vertices[3].x = minx;
slouken@1903
  1520
    vertices[3].y = maxy;
slouken@1903
  1521
    vertices[3].z = 0.0f;
slouken@1987
  1522
    vertices[3].color = color;
slouken@1904
  1523
    vertices[3].u = minu;
slouken@1904
  1524
    vertices[3].v = maxv;
slouken@1903
  1525
slouken@2932
  1526
    D3D_SetBlendMode(data, texture->blendMode);
slouken@1916
  1527
slouken@7505
  1528
    D3D_UpdateTextureScaleMode(data, texturedata, 0);
slouken@1917
  1529
slouken@1903
  1530
    result =
slouken@2735
  1531
        IDirect3DDevice9_SetTexture(data->device, 0, (IDirect3DBaseTexture9 *)
slouken@2735
  1532
                                    texturedata->texture);
slouken@1903
  1533
    if (FAILED(result)) {
icculus@7037
  1534
        return D3D_SetError("SetTexture()", result);
slouken@1903
  1535
    }
slouken@7505
  1536
slouken@7505
  1537
    if (texturedata->yuv) {
slouken@7505
  1538
        shader = data->ps_yuv;
slouken@7505
  1539
slouken@7505
  1540
        D3D_UpdateTextureScaleMode(data, texturedata, 1);
slouken@7505
  1541
        D3D_UpdateTextureScaleMode(data, texturedata, 2);
slouken@7505
  1542
slouken@7505
  1543
        result =
slouken@7505
  1544
            IDirect3DDevice9_SetTexture(data->device, 1, (IDirect3DBaseTexture9 *)
slouken@7505
  1545
                                        texturedata->utexture);
slouken@7505
  1546
        if (FAILED(result)) {
slouken@7505
  1547
            return D3D_SetError("SetTexture()", result);
slouken@7505
  1548
        }
slouken@7505
  1549
slouken@7505
  1550
        result =
slouken@7505
  1551
            IDirect3DDevice9_SetTexture(data->device, 2, (IDirect3DBaseTexture9 *)
slouken@7505
  1552
                                        texturedata->vtexture);
slouken@7505
  1553
        if (FAILED(result)) {
slouken@7505
  1554
            return D3D_SetError("SetTexture()", result);
slouken@7505
  1555
        }
slouken@7505
  1556
    }
slouken@7505
  1557
slouken@3556
  1558
    if (shader) {
slouken@3556
  1559
        result = IDirect3DDevice9_SetPixelShader(data->device, shader);
slouken@3556
  1560
        if (FAILED(result)) {
icculus@7037
  1561
            return D3D_SetError("SetShader()", result);
slouken@3556
  1562
        }
slouken@3556
  1563
    }
slouken@1903
  1564
    result =
slouken@1903
  1565
        IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2,
slouken@1903
  1566
                                         vertices, sizeof(*vertices));
slouken@1903
  1567
    if (FAILED(result)) {
icculus@7037
  1568
        return D3D_SetError("DrawPrimitiveUP()", result);
slouken@1903
  1569
    }
slouken@3556
  1570
    if (shader) {
slouken@3556
  1571
        result = IDirect3DDevice9_SetPixelShader(data->device, NULL);
slouken@3556
  1572
        if (FAILED(result)) {
icculus@7037
  1573
            return D3D_SetError("SetShader()", result);
slouken@3556
  1574
        }
slouken@3556
  1575
    }
slouken@1895
  1576
    return 0;
slouken@1895
  1577
}
slouken@1895
  1578
gabomdq@6320
  1579
gabomdq@6320
  1580
static int
gabomdq@6320
  1581
D3D_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
slouken@6528
  1582
               const SDL_Rect * srcrect, const SDL_FRect * dstrect,
slouken@6528
  1583
               const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip)
gabomdq@6320
  1584
{
gabomdq@6320
  1585
    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
slouken@8208
  1586
    D3D_TextureData *texturedata;
gabomdq@6320
  1587
    LPDIRECT3DPIXELSHADER9 shader = NULL;
gabomdq@6320
  1588
    float minx, miny, maxx, maxy;
gabomdq@6320
  1589
    float minu, maxu, minv, maxv;
gabomdq@6320
  1590
    float centerx, centery;
gabomdq@6320
  1591
    DWORD color;
gabomdq@6320
  1592
    Vertex vertices[4];
slouken@8599
  1593
    Float4X4 modelMatrix;
gabomdq@6320
  1594
    HRESULT result;
gabomdq@6320
  1595
gabomdq@6320
  1596
    if (D3D_ActivateRenderer(renderer) < 0) {
gabomdq@6320
  1597
        return -1;
gabomdq@6320
  1598
    }
gabomdq@6320
  1599
slouken@8208
  1600
    texturedata = (D3D_TextureData *)texture->driverdata;
slouken@8208
  1601
    if (!texturedata) {
slouken@8208
  1602
        SDL_SetError("Texture is not currently available");
slouken@8208
  1603
        return -1;
slouken@8208
  1604
    }
slouken@8208
  1605
slouken@6528
  1606
    centerx = center->x;
slouken@6528
  1607
    centery = center->y;
gabomdq@6320
  1608
slouken@7989
  1609
    if (flip & SDL_FLIP_HORIZONTAL) {
slouken@7989
  1610
        minx = dstrect->w - centerx - 0.5f;
slouken@7989
  1611
        maxx = -centerx - 0.5f;
slouken@7989
  1612
    }
slouken@7989
  1613
    else {
slouken@7989
  1614
        minx = -centerx - 0.5f;
slouken@7989
  1615
        maxx = dstrect->w - centerx - 0.5f;
slouken@7989
  1616
    }
slouken@7989
  1617
slouken@7989
  1618
    if (flip & SDL_FLIP_VERTICAL) {
slouken@7989
  1619
        miny = dstrect->h - centery - 0.5f;
slouken@7989
  1620
        maxy = -centery - 0.5f;
slouken@7989
  1621
    }
slouken@7989
  1622
    else {
slouken@7989
  1623
        miny = -centery - 0.5f;
slouken@7989
  1624
        maxy = dstrect->h - centery - 0.5f;
gabomdq@6320
  1625
    }
gabomdq@6320
  1626
gabomdq@6320
  1627
    minu = (float) srcrect->x / texture->w;
gabomdq@6320
  1628
    maxu = (float) (srcrect->x + srcrect->w) / texture->w;
gabomdq@6320
  1629
    minv = (float) srcrect->y / texture->h;
gabomdq@6320
  1630
    maxv = (float) (srcrect->y + srcrect->h) / texture->h;
gabomdq@6320
  1631
gabomdq@6320
  1632
    color = D3DCOLOR_ARGB(texture->a, texture->r, texture->g, texture->b);
gabomdq@6320
  1633
gabomdq@6320
  1634
    vertices[0].x = minx;
gabomdq@6320
  1635
    vertices[0].y = miny;
gabomdq@6320
  1636
    vertices[0].z = 0.0f;
gabomdq@6320
  1637
    vertices[0].color = color;
gabomdq@6320
  1638
    vertices[0].u = minu;
gabomdq@6320
  1639
    vertices[0].v = minv;
gabomdq@6320
  1640
gabomdq@6320
  1641
    vertices[1].x = maxx;
gabomdq@6320
  1642
    vertices[1].y = miny;
gabomdq@6320
  1643
    vertices[1].z = 0.0f;
gabomdq@6320
  1644
    vertices[1].color = color;
gabomdq@6320
  1645
    vertices[1].u = maxu;
gabomdq@6320
  1646
    vertices[1].v = minv;
gabomdq@6320
  1647
gabomdq@6320
  1648
    vertices[2].x = maxx;
gabomdq@6320
  1649
    vertices[2].y = maxy;
gabomdq@6320
  1650
    vertices[2].z = 0.0f;
gabomdq@6320
  1651
    vertices[2].color = color;
gabomdq@6320
  1652
    vertices[2].u = maxu;
gabomdq@6320
  1653
    vertices[2].v = maxv;
gabomdq@6320
  1654
gabomdq@6320
  1655
    vertices[3].x = minx;
gabomdq@6320
  1656
    vertices[3].y = maxy;
gabomdq@6320
  1657
    vertices[3].z = 0.0f;
gabomdq@6320
  1658
    vertices[3].color = color;
gabomdq@6320
  1659
    vertices[3].u = minu;
gabomdq@6320
  1660
    vertices[3].v = maxv;
gabomdq@6320
  1661
gabomdq@6320
  1662
    D3D_SetBlendMode(data, texture->blendMode);
gabomdq@6320
  1663
slouken@7191
  1664
    /* Rotate and translate */
slouken@8599
  1665
    modelMatrix = MatrixMultiply(
slouken@8599
  1666
            MatrixRotationZ((float)(M_PI * (float) angle / 180.0f)),
slouken@8599
  1667
            MatrixTranslation(dstrect->x + center->x, dstrect->y + center->y, 0)
slouken@8599
  1668
            );
slouken@8599
  1669
    IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)&modelMatrix);
gabomdq@6320
  1670
slouken@7505
  1671
    D3D_UpdateTextureScaleMode(data, texturedata, 0);
gabomdq@6320
  1672
gabomdq@6320
  1673
    result =
gabomdq@6320
  1674
        IDirect3DDevice9_SetTexture(data->device, 0, (IDirect3DBaseTexture9 *)
gabomdq@6320
  1675
                                    texturedata->texture);
gabomdq@6320
  1676
    if (FAILED(result)) {
icculus@7037
  1677
        return D3D_SetError("SetTexture()", result);
gabomdq@6320
  1678
    }
slouken@7505
  1679
slouken@7505
  1680
    if (texturedata->yuv) {
slouken@7505
  1681
        shader = data->ps_yuv;
slouken@7505
  1682
slouken@7505
  1683
        D3D_UpdateTextureScaleMode(data, texturedata, 1);
slouken@7505
  1684
        D3D_UpdateTextureScaleMode(data, texturedata, 2);
slouken@7505
  1685
slouken@7505
  1686
        result =
slouken@7505
  1687
            IDirect3DDevice9_SetTexture(data->device, 1, (IDirect3DBaseTexture9 *)
slouken@7505
  1688
                                        texturedata->utexture);
slouken@7505
  1689
        if (FAILED(result)) {
slouken@7505
  1690
            return D3D_SetError("SetTexture()", result);
slouken@7505
  1691
        }
slouken@7505
  1692
slouken@7505
  1693
        result =
slouken@7505
  1694
            IDirect3DDevice9_SetTexture(data->device, 2, (IDirect3DBaseTexture9 *)
slouken@7505
  1695
                                        texturedata->vtexture);
slouken@7505
  1696
        if (FAILED(result)) {
slouken@7505
  1697
            return D3D_SetError("SetTexture()", result);
slouken@7505
  1698
        }
slouken@7505
  1699
    }
slouken@7505
  1700
gabomdq@6320
  1701
    if (shader) {
gabomdq@6320
  1702
        result = IDirect3DDevice9_SetPixelShader(data->device, shader);
gabomdq@6320
  1703
        if (FAILED(result)) {
icculus@7037
  1704
            return D3D_SetError("SetShader()", result);
gabomdq@6320
  1705
        }
gabomdq@6320
  1706
    }
gabomdq@6320
  1707
    result =
gabomdq@6320
  1708
        IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2,
gabomdq@6320
  1709
                                         vertices, sizeof(*vertices));
gabomdq@6320
  1710
    if (FAILED(result)) {
icculus@7037
  1711
        return D3D_SetError("DrawPrimitiveUP()", result);
gabomdq@6320
  1712
    }
gabomdq@6320
  1713
    if (shader) {
gabomdq@6320
  1714
        result = IDirect3DDevice9_SetPixelShader(data->device, NULL);
gabomdq@6320
  1715
        if (FAILED(result)) {
icculus@7037
  1716
            return D3D_SetError("SetShader()", result);
gabomdq@6320
  1717
        }
gabomdq@6320
  1718
    }
slouken@8599
  1719
slouken@8599
  1720
    modelMatrix = MatrixIdentity();
slouken@8599
  1721
    IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)&modelMatrix);
gabomdq@6320
  1722
    return 0;
gabomdq@6320
  1723
}
gabomdq@6320
  1724
slouken@3427
  1725
static int
slouken@3427
  1726
D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
slouken@3480
  1727
                     Uint32 format, void * pixels, int pitch)
slouken@3427
  1728
{
slouken@3549
  1729
    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
slouken@3549
  1730
    D3DSURFACE_DESC desc;
slouken@3549
  1731
    LPDIRECT3DSURFACE9 backBuffer;
slouken@3549
  1732
    LPDIRECT3DSURFACE9 surface;
slouken@3549
  1733
    RECT d3drect;
slouken@3549
  1734
    D3DLOCKED_RECT locked;
slouken@3549
  1735
    HRESULT result;
slouken@3427
  1736
slouken@3549
  1737
    result = IDirect3DDevice9_GetBackBuffer(data->device, 0, 0, D3DBACKBUFFER_TYPE_MONO, &backBuffer);
slouken@3549
  1738
    if (FAILED(result)) {
icculus@7037
  1739
        return D3D_SetError("GetBackBuffer()", result);
slouken@3549
  1740
    }
slouken@3427
  1741
slouken@3549
  1742
    result = IDirect3DSurface9_GetDesc(backBuffer, &desc);
slouken@3549
  1743
    if (FAILED(result)) {
slouken@3549
  1744
        IDirect3DSurface9_Release(backBuffer);
icculus@7037
  1745
        return D3D_SetError("GetDesc()", result);
slouken@3549
  1746
    }
slouken@3427
  1747
slouken@3549
  1748
    result = IDirect3DDevice9_CreateOffscreenPlainSurface(data->device, desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surface, NULL);
slouken@3549
  1749
    if (FAILED(result)) {
slouken@3549
  1750
        IDirect3DSurface9_Release(backBuffer);
icculus@7037
  1751
        return D3D_SetError("CreateOffscreenPlainSurface()", result);
slouken@3549
  1752
    }
slouken@3427
  1753
slouken@3549
  1754
    result = IDirect3DDevice9_GetRenderTargetData(data->device, backBuffer, surface);
slouken@3549
  1755
    if (FAILED(result)) {
slouken@3549
  1756
        IDirect3DSurface9_Release(surface);
slouken@3549
  1757
        IDirect3DSurface9_Release(backBuffer);
icculus@7037
  1758
        return D3D_SetError("GetRenderTargetData()", result);
slouken@3549
  1759
    }
slouken@3427
  1760
slouken@3549
  1761
    d3drect.left = rect->x;
slouken@3549
  1762
    d3drect.right = rect->x + rect->w;
slouken@3549
  1763
    d3drect.top = rect->y;
slouken@3549
  1764
    d3drect.bottom = rect->y + rect->h;
slouken@3427
  1765
slouken@3549
  1766
    result = IDirect3DSurface9_LockRect(surface, &locked, &d3drect, D3DLOCK_READONLY);
slouken@3549
  1767
    if (FAILED(result)) {
slouken@3549
  1768
        IDirect3DSurface9_Release(surface);
slouken@3549
  1769
        IDirect3DSurface9_Release(backBuffer);
icculus@7037
  1770
        return D3D_SetError("LockRect()", result);
slouken@3549
  1771
    }
slouken@3427
  1772
slouken@3549
  1773
    SDL_ConvertPixels(rect->w, rect->h,
slouken@5156
  1774
                      D3DFMTToPixelFormat(desc.Format), locked.pBits, locked.Pitch,
slouken@3549
  1775
                      format, pixels, pitch);
slouken@3549
  1776
slouken@3549
  1777
    IDirect3DSurface9_UnlockRect(surface);
slouken@3549
  1778
slouken@3549
  1779
    IDirect3DSurface9_Release(surface);
slouken@3549
  1780
    IDirect3DSurface9_Release(backBuffer);
slouken@3549
  1781
slouken@3549
  1782
    return 0;
slouken@3427
  1783
}
slouken@3427
  1784
slouken@1895
  1785
static void
slouken@1913
  1786
D3D_RenderPresent(SDL_Renderer * renderer)
slouken@1895
  1787
{
slouken@1913
  1788
    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
slouken@1900
  1789
    HRESULT result;
slouken@1900
  1790
slouken@1900
  1791
    if (!data->beginScene) {
slouken@1900
  1792
        IDirect3DDevice9_EndScene(data->device);
slouken@1900
  1793
        data->beginScene = SDL_TRUE;
slouken@1900
  1794
    }
slouken@1900
  1795
slouken@1975
  1796
    result = IDirect3DDevice9_TestCooperativeLevel(data->device);
slouken@1975
  1797
    if (result == D3DERR_DEVICELOST) {
slouken@1975
  1798
        /* We'll reset later */
slouken@1975
  1799
        return;
slouken@1975
  1800
    }
slouken@1975
  1801
    if (result == D3DERR_DEVICENOTRESET) {
slouken@1975
  1802
        D3D_Reset(renderer);
slouken@1975
  1803
    }
slouken@1900
  1804
    result = IDirect3DDevice9_Present(data->device, NULL, NULL, NULL, NULL);
slouken@1900
  1805
    if (FAILED(result)) {
slouken@1900
  1806
        D3D_SetError("Present()", result);
slouken@1900
  1807
    }
slouken@1895
  1808
}
slouken@1895
  1809
slouken@1895
  1810
static void
slouken@1913
  1811
D3D_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
slouken@1895
  1812
{
slouken@1913
  1813
    D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
slouken@1895
  1814
slouken@1895
  1815
    if (!data) {
slouken@1895
  1816
        return;
slouken@1895
  1817
    }
slouken@1903
  1818
    if (data->texture) {
slouken@1903
  1819
        IDirect3DTexture9_Release(data->texture);
slouken@1903
  1820
    }
slouken@7505
  1821
    if (data->utexture) {
slouken@7505
  1822
        IDirect3DTexture9_Release(data->utexture);
slouken@7505
  1823
    }
slouken@7505
  1824
    if (data->vtexture) {
slouken@7505
  1825
        IDirect3DTexture9_Release(data->vtexture);
slouken@7505
  1826
    }
slouken@7719
  1827
    SDL_free(data->pixels);
slouken@1895
  1828
    SDL_free(data);
slouken@1895
  1829
    texture->driverdata = NULL;
slouken@1895
  1830
}
slouken@1895
  1831
slouken@1975
  1832
static void
slouken@1913
  1833
D3D_DestroyRenderer(SDL_Renderer * renderer)
slouken@1895
  1834
{
slouken@1913
  1835
    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
slouken@1895
  1836
slouken@1895
  1837
    if (data) {
slouken@7191
  1838
        /* Release the render target */
slouken@6895
  1839
        if (data->defaultRenderTarget) {
slouken@6895
  1840
            IDirect3DSurface9_Release(data->defaultRenderTarget);
slouken@6895
  1841
            data->defaultRenderTarget = NULL;
slouken@6895
  1842
        }
slouken@6232
  1843
        if (data->currentRenderTarget != NULL) {
slouken@6232
  1844
            IDirect3DSurface9_Release(data->currentRenderTarget);
slouken@6232
  1845
            data->currentRenderTarget = NULL;
slouken@6232
  1846
        }
icculus@7658
  1847
        if (data->ps_yuv) {
icculus@7658
  1848
            IDirect3DPixelShader9_Release(data->ps_yuv);
icculus@7658
  1849
        }
slouken@1900
  1850
        if (data->device) {
slouken@1900
  1851
            IDirect3DDevice9_Release(data->device);
slouken@1900
  1852
        }
slouken@5154
  1853
        if (data->d3d) {
slouken@5154
  1854
            IDirect3D9_Release(data->d3d);
slouken@5154
  1855
            SDL_UnloadObject(data->d3dDLL);
slouken@5154
  1856
        }
slouken@1895
  1857
        SDL_free(data);
slouken@1895
  1858
    }
slouken@1895
  1859
    SDL_free(renderer);
slouken@1895
  1860
}
icculus@8130
  1861
#endif /* SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED */
slouken@1895
  1862
icculus@8131
  1863
#ifdef __WIN32__
icculus@8131
  1864
/* This function needs to always exist on Windows, for the Dynamic API. */
slouken@7763
  1865
IDirect3DDevice9 *
slouken@7765
  1866
SDL_RenderGetD3D9Device(SDL_Renderer * renderer)
slouken@7763
  1867
{
icculus@8130
  1868
    IDirect3DDevice9 *device = NULL;
icculus@8130
  1869
icculus@8130
  1870
#if SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED
slouken@7877
  1871
    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
slouken@7763
  1872
slouken@7877
  1873
    // Make sure that this is a D3D renderer
slouken@7877
  1874
    if (renderer->DestroyRenderer != D3D_DestroyRenderer) {
slouken@7877
  1875
        SDL_SetError("Renderer is not a D3D renderer");
slouken@7877
  1876
        return NULL;
slouken@7877
  1877
    }
slouken@7766
  1878
slouken@7877
  1879
    device = data->device;
slouken@7877
  1880
    if (device) {
slouken@8207
  1881
        IDirect3DDevice9_AddRef(device);
slouken@7877
  1882
    }
icculus@8130
  1883
#endif /* SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED */
icculus@8130
  1884
slouken@7877
  1885
    return device;
slouken@7763
  1886
}
slouken@8193
  1887
#endif /* __WIN32__ */
slouken@7763
  1888
slouken@1895
  1889
/* vi: set ts=4 sw=4 expandtab: */