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