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