src/render/direct3d/SDL_render_d3d.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 28 Sep 2013 14:07:05 -0700
changeset 7763 fc802d707136
parent 7762 51abf7664304
child 7764 0f48b5f28668
permissions -rw-r--r--
Added platform specific call: SDL_RenderGetD3DDevice()
     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     D3DPRESENT_PARAMETERS pparams;
   548     IDirect3DSwapChain9 *chain;
   549     D3DCAPS9 caps;
   550     Uint32 window_flags;
   551     int w, h;
   552     SDL_DisplayMode fullscreen_mode;
   553     int d3dxVersion;
   554     char d3dxDLLFile[50];
   555 	int displayIndex;
   556 
   557     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   558     if (!renderer) {
   559         SDL_OutOfMemory();
   560         return NULL;
   561     }
   562 
   563     data = (D3D_RenderData *) SDL_calloc(1, sizeof(*data));
   564     if (!data) {
   565         SDL_free(renderer);
   566         SDL_OutOfMemory();
   567         return NULL;
   568     }
   569 
   570 	if( D3D_LoadDLL( &data->d3dDLL, &data->d3d ) ) {
   571         for (d3dxVersion=50;d3dxVersion>0;d3dxVersion--) {
   572             LPTSTR dllName;
   573             SDL_snprintf(d3dxDLLFile, sizeof(d3dxDLLFile), "D3DX9_%02d.dll", d3dxVersion);
   574             dllName = WIN_UTF8ToString(d3dxDLLFile);
   575             data->d3dxDLL = (void *)LoadLibrary(dllName); /* not using SDL_LoadObject() as we want silently fail - no error message */
   576             SDL_free(dllName);
   577             if (data->d3dxDLL) {
   578                 HRESULT (WINAPI *D3DXCreateMatrixStack) (DWORD Flags, LPD3DXMATRIXSTACK*  ppStack);
   579                 D3DXCreateMatrixStack = (HRESULT (WINAPI *) (DWORD, LPD3DXMATRIXSTACK*)) SDL_LoadFunction(data->d3dxDLL, "D3DXCreateMatrixStack");
   580                 if (D3DXCreateMatrixStack) {
   581                     D3DXCreateMatrixStack(0, &data->matrixStack);
   582                     break;
   583                 }
   584             }
   585         }
   586 
   587         if (!data->matrixStack) {
   588             if (data->d3dxDLL) SDL_UnloadObject(data->d3dxDLL);
   589         }
   590     }
   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     result = IDirect3D9_CreateDevice(data->d3d, data->adapter,
   671                                      D3DDEVTYPE_HAL,
   672                                      pparams.hDeviceWindow,
   673                                      D3DCREATE_FPU_PRESERVE | ((caps.
   674                                       DevCaps &
   675                                       D3DDEVCAPS_HWTRANSFORMANDLIGHT) ?
   676                                      D3DCREATE_HARDWARE_VERTEXPROCESSING :
   677                                      D3DCREATE_SOFTWARE_VERTEXPROCESSING),
   678                                      &pparams, &data->device);
   679     if (FAILED(result)) {
   680         D3D_DestroyRenderer(renderer);
   681         D3D_SetError("CreateDevice()", result);
   682         return NULL;
   683     }
   684 
   685     /* Get presentation parameters to fill info */
   686     result = IDirect3DDevice9_GetSwapChain(data->device, 0, &chain);
   687     if (FAILED(result)) {
   688         D3D_DestroyRenderer(renderer);
   689         D3D_SetError("GetSwapChain()", result);
   690         return NULL;
   691     }
   692     result = IDirect3DSwapChain9_GetPresentParameters(chain, &pparams);
   693     if (FAILED(result)) {
   694         IDirect3DSwapChain9_Release(chain);
   695         D3D_DestroyRenderer(renderer);
   696         D3D_SetError("GetPresentParameters()", result);
   697         return NULL;
   698     }
   699     IDirect3DSwapChain9_Release(chain);
   700     if (pparams.PresentationInterval == D3DPRESENT_INTERVAL_ONE) {
   701         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
   702     }
   703     data->pparams = pparams;
   704 
   705     IDirect3DDevice9_GetDeviceCaps(data->device, &caps);
   706     renderer->info.max_texture_width = caps.MaxTextureWidth;
   707     renderer->info.max_texture_height = caps.MaxTextureHeight;
   708     if (caps.NumSimultaneousRTs >= 2) {
   709         renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE;
   710     }
   711 
   712     if (caps.PrimitiveMiscCaps & D3DPMISCCAPS_SEPARATEALPHABLEND) {
   713         data->enableSeparateAlphaBlend = SDL_TRUE;
   714     }
   715 
   716     /* Store the default render target */
   717     IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget );
   718     data->currentRenderTarget = NULL;
   719 
   720     /* Set up parameters for rendering */
   721     D3D_InitRenderState(data);
   722 
   723     if (caps.MaxSimultaneousTextures >= 3)
   724     {
   725 #ifdef ASSEMBLE_SHADER
   726         /* This shader was created by running the following HLSL through the fxc compiler
   727            and then tuning the generated assembly.
   728 
   729            fxc /T fx_4_0 /O3 /Gfa /Fc yuv.fxc yuv.fx
   730 
   731            --- yuv.fx ---
   732            Texture2D g_txY;
   733            Texture2D g_txU;
   734            Texture2D g_txV;
   735 
   736            SamplerState samLinear
   737            {
   738                Filter = ANISOTROPIC;
   739                AddressU = Clamp;
   740                AddressV = Clamp;
   741                MaxAnisotropy = 1;
   742            };
   743 
   744            struct VS_OUTPUT
   745            {
   746                 float2 TextureUV  : TEXCOORD0;
   747            };
   748 
   749            struct PS_OUTPUT
   750            {
   751                 float4 RGBAColor : SV_Target;
   752            };
   753 
   754            PS_OUTPUT YUV420( VS_OUTPUT In ) 
   755            {
   756                const float3 offset = {-0.0625, -0.5, -0.5};
   757                const float3 Rcoeff = {1.164,  0.000,  1.596};
   758                const float3 Gcoeff = {1.164, -0.391, -0.813};
   759                const float3 Bcoeff = {1.164,  2.018,  0.000};
   760 
   761                PS_OUTPUT Output;
   762                float2 TextureUV = In.TextureUV;
   763 
   764                float3 yuv;
   765                yuv.x = g_txY.Sample( samLinear, TextureUV ).r;
   766                yuv.y = g_txU.Sample( samLinear, TextureUV ).r;
   767                yuv.z = g_txV.Sample( samLinear, TextureUV ).r;
   768 
   769                yuv += offset;
   770                Output.RGBAColor.r = dot(yuv, Rcoeff);
   771                Output.RGBAColor.g = dot(yuv, Gcoeff);
   772                Output.RGBAColor.b = dot(yuv, Bcoeff);
   773                Output.RGBAColor.a = 1.0f;
   774 
   775                return Output;
   776            }
   777 
   778            technique10 RenderYUV420
   779            {
   780                pass P0
   781                {
   782                     SetPixelShader( CompileShader( ps_4_0_level_9_0, YUV420() ) );
   783                }
   784            }
   785         */
   786         const char *shader_text =
   787             "ps_2_0\n"
   788             "def c0, -0.0625, -0.5, -0.5, 1\n"
   789             "def c1, 1.16400003, 0, 1.59599996, 0\n"
   790             "def c2, 1.16400003, -0.391000003, -0.813000023, 0\n"
   791             "def c3, 1.16400003, 2.01799989, 0, 0\n"
   792             "dcl t0.xy\n"
   793             "dcl v0.xyzw\n"
   794             "dcl_2d s0\n"
   795             "dcl_2d s1\n"
   796             "dcl_2d s2\n"
   797             "texld r0, t0, s0\n"
   798             "texld r1, t0, s1\n"
   799             "texld r2, t0, s2\n"
   800             "mov r0.y, r1.x\n"
   801             "mov r0.z, r2.x\n"
   802             "add r0.xyz, r0, c0\n"
   803             "dp3 r1.x, r0, c1\n"
   804             "dp3 r1.y, r0, c2\n"
   805             "dp2add r1.z, r0, c3, c3.z\n"   /* Logically this is "dp3 r1.z, r0, c3" but the optimizer did its magic */
   806             "mov r1.w, c0.w\n"
   807             "mul r0, r1, v0\n"              /* Not in the HLSL, multiply by vertex color */
   808             "mov oC0, r0\n"
   809         ;
   810         LPD3DXBUFFER pCode;
   811         LPD3DXBUFFER pErrorMsgs;
   812         LPDWORD shader_data = NULL;
   813         DWORD   shader_size = 0;
   814         result = D3DXAssembleShader(shader_text, SDL_strlen(shader_text), NULL, NULL, 0, &pCode, &pErrorMsgs);
   815         if (!FAILED(result)) {
   816             shader_data = (DWORD*)pCode->lpVtbl->GetBufferPointer(pCode);
   817             shader_size = pCode->lpVtbl->GetBufferSize(pCode);
   818             PrintShaderData(shader_data, shader_size);
   819         } else {
   820             const char *error = (const char *)pErrorMsgs->lpVtbl->GetBufferPointer(pErrorMsgs);
   821             SDL_SetError("Couldn't assemble shader: %s", error);
   822         }
   823 #else
   824         const DWORD shader_data[] = {
   825             0xffff0200, 0x05000051, 0xa00f0000, 0xbd800000, 0xbf000000, 0xbf000000,
   826             0x3f800000, 0x05000051, 0xa00f0001, 0x3f94fdf4, 0x00000000, 0x3fcc49ba,
   827             0x00000000, 0x05000051, 0xa00f0002, 0x3f94fdf4, 0xbec83127, 0xbf5020c5,
   828             0x00000000, 0x05000051, 0xa00f0003, 0x3f94fdf4, 0x400126e9, 0x00000000,
   829             0x00000000, 0x0200001f, 0x80000000, 0xb0030000, 0x0200001f, 0x80000000,
   830             0x900f0000, 0x0200001f, 0x90000000, 0xa00f0800, 0x0200001f, 0x90000000,
   831             0xa00f0801, 0x0200001f, 0x90000000, 0xa00f0802, 0x03000042, 0x800f0000,
   832             0xb0e40000, 0xa0e40800, 0x03000042, 0x800f0001, 0xb0e40000, 0xa0e40801,
   833             0x03000042, 0x800f0002, 0xb0e40000, 0xa0e40802, 0x02000001, 0x80020000,
   834             0x80000001, 0x02000001, 0x80040000, 0x80000002, 0x03000002, 0x80070000,
   835             0x80e40000, 0xa0e40000, 0x03000008, 0x80010001, 0x80e40000, 0xa0e40001,
   836             0x03000008, 0x80020001, 0x80e40000, 0xa0e40002, 0x0400005a, 0x80040001,
   837             0x80e40000, 0xa0e40003, 0xa0aa0003, 0x02000001, 0x80080001, 0xa0ff0000,
   838             0x03000005, 0x800f0000, 0x80e40001, 0x90e40000, 0x02000001, 0x800f0800,
   839             0x80e40000, 0x0000ffff
   840         };
   841 #endif
   842         if (shader_data != NULL) {
   843             result = IDirect3DDevice9_CreatePixelShader(data->device, shader_data, &data->ps_yuv);
   844             if (!FAILED(result)) {
   845                 renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;
   846                 renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
   847             } else {
   848                 D3D_SetError("CreatePixelShader()", result);
   849             }
   850         }
   851     }
   852 
   853     return renderer;
   854 }
   855 
   856 static void
   857 D3D_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
   858 {
   859     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   860 
   861     if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) {
   862         data->updateSize = SDL_TRUE;
   863     }
   864 }
   865 
   866 static D3DTEXTUREFILTERTYPE
   867 GetScaleQuality(void)
   868 {
   869     const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
   870 
   871     if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) {
   872         return D3DTEXF_POINT;
   873     } else /* if (*hint == '1' || SDL_strcasecmp(hint, "linear") == 0) */ {
   874         return D3DTEXF_LINEAR;
   875     }
   876 }
   877 
   878 static int
   879 D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   880 {
   881     D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata;
   882     D3D_TextureData *data;
   883     D3DPOOL pool;
   884     DWORD usage;
   885     HRESULT result;
   886 
   887     data = (D3D_TextureData *) SDL_calloc(1, sizeof(*data));
   888     if (!data) {
   889         return SDL_OutOfMemory();
   890     }
   891     data->scaleMode = GetScaleQuality();
   892 
   893     texture->driverdata = data;
   894 
   895 #ifdef USE_DYNAMIC_TEXTURE
   896     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   897         pool = D3DPOOL_DEFAULT;
   898         usage = D3DUSAGE_DYNAMIC;
   899     } else
   900 #endif
   901     if (texture->access == SDL_TEXTUREACCESS_TARGET) {
   902         /* D3DPOOL_MANAGED does not work with D3DUSAGE_RENDERTARGET */
   903         pool = D3DPOOL_DEFAULT;
   904         usage = D3DUSAGE_RENDERTARGET;
   905     } else {
   906         pool = D3DPOOL_MANAGED;
   907         usage = 0;
   908     }
   909 
   910     result =
   911         IDirect3DDevice9_CreateTexture(renderdata->device, texture->w,
   912                                        texture->h, 1, usage,
   913                                        PixelFormatToD3DFMT(texture->format),
   914                                        pool, &data->texture, NULL);
   915     if (FAILED(result)) {
   916         return D3D_SetError("CreateTexture()", result);
   917     }
   918 
   919     if (texture->format == SDL_PIXELFORMAT_YV12 ||
   920         texture->format == SDL_PIXELFORMAT_IYUV) {
   921         data->yuv = SDL_TRUE;
   922 
   923         result =
   924             IDirect3DDevice9_CreateTexture(renderdata->device, texture->w / 2,
   925                                            texture->h / 2, 1, usage,
   926                                            PixelFormatToD3DFMT(texture->format),
   927                                            pool, &data->utexture, NULL);
   928         if (FAILED(result)) {
   929             return D3D_SetError("CreateTexture()", result);
   930         }
   931 
   932         result =
   933             IDirect3DDevice9_CreateTexture(renderdata->device, texture->w / 2,
   934                                            texture->h / 2, 1, usage,
   935                                            PixelFormatToD3DFMT(texture->format),
   936                                            pool, &data->vtexture, NULL);
   937         if (FAILED(result)) {
   938             return D3D_SetError("CreateTexture()", result);
   939         }
   940     }
   941 
   942     return 0;
   943 }
   944 
   945 static int
   946 D3D_UpdateTextureInternal(IDirect3DTexture9 *texture, Uint32 format, SDL_bool full_texture, int x, int y, int w, int h, const void *pixels, int pitch)
   947 {
   948     RECT d3drect;
   949     D3DLOCKED_RECT locked;
   950     const Uint8 *src;
   951     Uint8 *dst;
   952     int row, length;
   953     HRESULT result;
   954 
   955     if (full_texture) {
   956         result = IDirect3DTexture9_LockRect(texture, 0, &locked, NULL, D3DLOCK_DISCARD);
   957     } else {
   958         d3drect.left = x;
   959         d3drect.right = x + w;
   960         d3drect.top = y;
   961         d3drect.bottom = y + h;
   962         result = IDirect3DTexture9_LockRect(texture, 0, &locked, &d3drect, 0);
   963     }
   964 
   965     if (FAILED(result)) {
   966         return D3D_SetError("LockRect()", result);
   967     }
   968 
   969     src = (const Uint8 *)pixels;
   970     dst = locked.pBits;
   971     length = w * SDL_BYTESPERPIXEL(format);
   972     if (length == pitch && length == locked.Pitch) {
   973         SDL_memcpy(dst, src, length*h);
   974     } else {
   975         for (row = 0; row < h; ++row) {
   976             SDL_memcpy(dst, src, length);
   977             src += pitch;
   978             dst += locked.Pitch;
   979         }
   980     }
   981     IDirect3DTexture9_UnlockRect(texture, 0);
   982 
   983     return 0;
   984 }
   985 
   986 static int
   987 D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   988                   const SDL_Rect * rect, const void *pixels, int pitch)
   989 {
   990     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
   991     SDL_bool full_texture = SDL_FALSE;
   992 
   993 #ifdef USE_DYNAMIC_TEXTURE
   994     if (texture->access == SDL_TEXTUREACCESS_STREAMING &&
   995         rect->x == 0 && rect->y == 0 &&
   996         rect->w == texture->w && rect->h == texture->h) {
   997         full_texture = SDL_TRUE;
   998     }
   999 #endif
  1000 
  1001     if (D3D_UpdateTextureInternal(data->texture, texture->format, full_texture, rect->x, rect->y, rect->w, rect->h, pixels, pitch) < 0) {
  1002         return -1;
  1003     }
  1004 
  1005     if (data->yuv) {
  1006         /* Skip to the correct offset into the next texture */
  1007         pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
  1008 
  1009         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) {
  1010             return -1;
  1011         }
  1012 
  1013         /* Skip to the correct offset into the next texture */
  1014         pixels = (const void*)((const Uint8*)pixels + (rect->h * pitch)/4);
  1015         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) {
  1016             return -1;
  1017         }
  1018     }
  1019     return 0;
  1020 }
  1021 
  1022 static int
  1023 D3D_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
  1024                      const SDL_Rect * rect,
  1025                      const Uint8 *Yplane, int Ypitch,
  1026                      const Uint8 *Uplane, int Upitch,
  1027                      const Uint8 *Vplane, int Vpitch)
  1028 {
  1029 	D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
  1030 	SDL_bool full_texture = SDL_FALSE;
  1031 
  1032 #ifdef USE_DYNAMIC_TEXTURE
  1033 	if (texture->access == SDL_TEXTUREACCESS_STREAMING &&
  1034 		rect->x == 0 && rect->y == 0 &&
  1035 		rect->w == texture->w && rect->h == texture->h) {
  1036 			full_texture = SDL_TRUE;
  1037 	}
  1038 #endif
  1039 
  1040 	if (D3D_UpdateTextureInternal(data->texture, texture->format, full_texture, rect->x, rect->y, rect->w, rect->h, Yplane, Ypitch) < 0) {
  1041 		return -1;
  1042 	}
  1043 	if (D3D_UpdateTextureInternal(data->utexture, texture->format, full_texture, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, Uplane, Upitch) < 0) {
  1044 		return -1;
  1045 	}
  1046 	if (D3D_UpdateTextureInternal(data->vtexture, texture->format, full_texture, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, Vplane, Vpitch) < 0) {
  1047 		return -1;
  1048 	}
  1049 	return 0;
  1050 }
  1051 
  1052 static int
  1053 D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
  1054                 const SDL_Rect * rect, void **pixels, int *pitch)
  1055 {
  1056     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
  1057     RECT d3drect;
  1058     D3DLOCKED_RECT locked;
  1059     HRESULT result;
  1060 
  1061     if (data->yuv) {
  1062         /* It's more efficient to upload directly... */
  1063         if (!data->pixels) {
  1064             data->pitch = texture->w;
  1065             data->pixels = (Uint8 *)SDL_malloc((texture->h * data->pitch * 3) / 2);
  1066             if (!data->pixels) {
  1067                 return SDL_OutOfMemory();
  1068             }
  1069         }
  1070         data->locked_rect = *rect;
  1071         *pixels =
  1072             (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
  1073                       rect->x * SDL_BYTESPERPIXEL(texture->format));
  1074         *pitch = data->pitch;
  1075     } else {
  1076         d3drect.left = rect->x;
  1077         d3drect.right = rect->x + rect->w;
  1078         d3drect.top = rect->y;
  1079         d3drect.bottom = rect->y + rect->h;
  1080 
  1081         result = IDirect3DTexture9_LockRect(data->texture, 0, &locked, &d3drect, 0);
  1082         if (FAILED(result)) {
  1083             return D3D_SetError("LockRect()", result);
  1084         }
  1085         *pixels = locked.pBits;
  1086         *pitch = locked.Pitch;
  1087     }
  1088     return 0;
  1089 }
  1090 
  1091 static void
  1092 D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  1093 {
  1094     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
  1095 
  1096     if (data->yuv) {
  1097         const SDL_Rect *rect = &data->locked_rect;
  1098         void *pixels =
  1099             (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
  1100                       rect->x * SDL_BYTESPERPIXEL(texture->format));
  1101         D3D_UpdateTexture(renderer, texture, rect, pixels, data->pitch);
  1102     } else {
  1103         IDirect3DTexture9_UnlockRect(data->texture, 0);
  1104     }
  1105 }
  1106 
  1107 static int
  1108 D3D_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
  1109 {
  1110     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1111     D3D_TextureData *texturedata;
  1112     HRESULT result;
  1113 
  1114     D3D_ActivateRenderer(renderer);
  1115 
  1116     /* Release the previous render target if it wasn't the default one */
  1117     if (data->currentRenderTarget != NULL) {
  1118         IDirect3DSurface9_Release(data->currentRenderTarget);
  1119         data->currentRenderTarget = NULL;
  1120     }
  1121 
  1122     if (texture == NULL) {
  1123         IDirect3DDevice9_SetRenderTarget(data->device, 0, data->defaultRenderTarget);
  1124         return 0;
  1125     }
  1126 
  1127     texturedata = (D3D_TextureData *) texture->driverdata;
  1128     result = IDirect3DTexture9_GetSurfaceLevel(texturedata->texture, 0, &data->currentRenderTarget);
  1129     if(FAILED(result)) {
  1130         return D3D_SetError("GetSurfaceLevel()", result);
  1131     }
  1132     result = IDirect3DDevice9_SetRenderTarget(data->device, 0, data->currentRenderTarget);
  1133     if(FAILED(result)) {
  1134         return D3D_SetError("SetRenderTarget()", result);
  1135     }
  1136 
  1137     return 0;
  1138 }
  1139 
  1140 static int
  1141 D3D_UpdateViewport(SDL_Renderer * renderer)
  1142 {
  1143     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1144     D3DVIEWPORT9 viewport;
  1145     D3DMATRIX matrix;
  1146 
  1147     /* Set the viewport */
  1148     viewport.X = renderer->viewport.x;
  1149     viewport.Y = renderer->viewport.y;
  1150     viewport.Width = renderer->viewport.w;
  1151     viewport.Height = renderer->viewport.h;
  1152     viewport.MinZ = 0.0f;
  1153     viewport.MaxZ = 1.0f;
  1154     IDirect3DDevice9_SetViewport(data->device, &viewport);
  1155 
  1156     /* Set an orthographic projection matrix */
  1157     if (renderer->viewport.w && renderer->viewport.h) {
  1158         matrix.m[0][0] = 2.0f / renderer->viewport.w;
  1159         matrix.m[0][1] = 0.0f;
  1160         matrix.m[0][2] = 0.0f;
  1161         matrix.m[0][3] = 0.0f;
  1162         matrix.m[1][0] = 0.0f;
  1163         matrix.m[1][1] = -2.0f / renderer->viewport.h;
  1164         matrix.m[1][2] = 0.0f;
  1165         matrix.m[1][3] = 0.0f;
  1166         matrix.m[2][0] = 0.0f;
  1167         matrix.m[2][1] = 0.0f;
  1168         matrix.m[2][2] = 1.0f;
  1169         matrix.m[2][3] = 0.0f;
  1170         matrix.m[3][0] = -1.0f;
  1171         matrix.m[3][1] = 1.0f;
  1172         matrix.m[3][2] = 0.0f;
  1173         matrix.m[3][3] = 1.0f;
  1174         IDirect3DDevice9_SetTransform(data->device, D3DTS_PROJECTION, &matrix);
  1175     }
  1176 
  1177     return 0;
  1178 }
  1179 
  1180 static int
  1181 D3D_UpdateClipRect(SDL_Renderer * renderer)
  1182 {
  1183     const SDL_Rect *rect = &renderer->clip_rect;
  1184     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1185     RECT r;
  1186     HRESULT result;
  1187 
  1188     if (!SDL_RectEmpty(rect)) {
  1189         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, TRUE);
  1190         r.left = rect->x;
  1191         r.top = rect->y;
  1192         r.right = rect->x + rect->w;
  1193         r.bottom = rect->y + rect->h;
  1194 
  1195         result = IDirect3DDevice9_SetScissorRect(data->device, &r);
  1196         if (result != D3D_OK) {
  1197             D3D_SetError("SetScissor()", result);
  1198             return -1;
  1199         }
  1200     } else {
  1201         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, FALSE);
  1202     }
  1203     return 0;
  1204 }
  1205 
  1206 static int
  1207 D3D_RenderClear(SDL_Renderer * renderer)
  1208 {
  1209     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1210     DWORD color;
  1211     HRESULT result;
  1212 
  1213     if (D3D_ActivateRenderer(renderer) < 0) {
  1214         return -1;
  1215     }
  1216 
  1217     color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
  1218 
  1219     /* Don't reset the viewport if we don't have to! */
  1220     if (!renderer->viewport.x && !renderer->viewport.y &&
  1221         renderer->viewport.w == data->pparams.BackBufferWidth &&
  1222         renderer->viewport.h == data->pparams.BackBufferHeight) {
  1223         result = IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
  1224     } else {
  1225         D3DVIEWPORT9 viewport;
  1226 
  1227         /* Clear is defined to clear the entire render target */
  1228         viewport.X = 0;
  1229         viewport.Y = 0;
  1230         viewport.Width = data->pparams.BackBufferWidth;
  1231         viewport.Height = data->pparams.BackBufferHeight;
  1232         viewport.MinZ = 0.0f;
  1233         viewport.MaxZ = 1.0f;
  1234         IDirect3DDevice9_SetViewport(data->device, &viewport);
  1235 
  1236         result = IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
  1237 
  1238         /* Reset the viewport */
  1239         viewport.X = renderer->viewport.x;
  1240         viewport.Y = renderer->viewport.y;
  1241         viewport.Width = renderer->viewport.w;
  1242         viewport.Height = renderer->viewport.h;
  1243         viewport.MinZ = 0.0f;
  1244         viewport.MaxZ = 1.0f;
  1245         IDirect3DDevice9_SetViewport(data->device, &viewport);
  1246     }
  1247 
  1248     if (FAILED(result)) {
  1249         return D3D_SetError("Clear()", result);
  1250     }
  1251     return 0;
  1252 }
  1253 
  1254 static void
  1255 D3D_SetBlendMode(D3D_RenderData * data, int blendMode)
  1256 {
  1257     switch (blendMode) {
  1258     case SDL_BLENDMODE_NONE:
  1259         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
  1260                                         FALSE);
  1261         break;
  1262     case SDL_BLENDMODE_BLEND:
  1263         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
  1264                                         TRUE);
  1265         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
  1266                                         D3DBLEND_SRCALPHA);
  1267         IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
  1268                                         D3DBLEND_INVSRCALPHA);
  1269         if (data->enableSeparateAlphaBlend) {
  1270             IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA,
  1271                                             D3DBLEND_ONE);
  1272             IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA,
  1273                                             D3DBLEND_INVSRCALPHA);
  1274         }
  1275         break;
  1276     case SDL_BLENDMODE_ADD:
  1277         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
  1278                                         TRUE);
  1279         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
  1280                                         D3DBLEND_SRCALPHA);
  1281         IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
  1282                                         D3DBLEND_ONE);
  1283         if (data->enableSeparateAlphaBlend) {
  1284             IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA,
  1285                                             D3DBLEND_ZERO);
  1286             IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA,
  1287                                             D3DBLEND_ONE);
  1288         }
  1289         break;
  1290     case SDL_BLENDMODE_MOD:
  1291         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
  1292                                         TRUE);
  1293         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
  1294                                         D3DBLEND_ZERO);
  1295         IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
  1296                                         D3DBLEND_SRCCOLOR);
  1297         if (data->enableSeparateAlphaBlend) {
  1298             IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA,
  1299                                             D3DBLEND_ZERO);
  1300             IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA,
  1301                                             D3DBLEND_ONE);
  1302         }
  1303         break;
  1304     }
  1305 }
  1306 
  1307 static int
  1308 D3D_RenderDrawPoints(SDL_Renderer * renderer, const SDL_FPoint * points,
  1309                      int count)
  1310 {
  1311     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1312     DWORD color;
  1313     Vertex *vertices;
  1314     int i;
  1315     HRESULT result;
  1316 
  1317     if (D3D_ActivateRenderer(renderer) < 0) {
  1318         return -1;
  1319     }
  1320 
  1321     D3D_SetBlendMode(data, renderer->blendMode);
  1322 
  1323     result =
  1324         IDirect3DDevice9_SetTexture(data->device, 0,
  1325                                     (IDirect3DBaseTexture9 *) 0);
  1326     if (FAILED(result)) {
  1327         return D3D_SetError("SetTexture()", result);
  1328     }
  1329 
  1330     color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
  1331 
  1332     vertices = SDL_stack_alloc(Vertex, count);
  1333     for (i = 0; i < count; ++i) {
  1334         vertices[i].x = points[i].x;
  1335         vertices[i].y = points[i].y;
  1336         vertices[i].z = 0.0f;
  1337         vertices[i].color = color;
  1338         vertices[i].u = 0.0f;
  1339         vertices[i].v = 0.0f;
  1340     }
  1341     result =
  1342         IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, count,
  1343                                          vertices, sizeof(*vertices));
  1344     SDL_stack_free(vertices);
  1345     if (FAILED(result)) {
  1346         return D3D_SetError("DrawPrimitiveUP()", result);
  1347     }
  1348     return 0;
  1349 }
  1350 
  1351 static int
  1352 D3D_RenderDrawLines(SDL_Renderer * renderer, const SDL_FPoint * points,
  1353                     int count)
  1354 {
  1355     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1356     DWORD color;
  1357     Vertex *vertices;
  1358     int i;
  1359     HRESULT result;
  1360 
  1361     if (D3D_ActivateRenderer(renderer) < 0) {
  1362         return -1;
  1363     }
  1364 
  1365     D3D_SetBlendMode(data, renderer->blendMode);
  1366 
  1367     result =
  1368         IDirect3DDevice9_SetTexture(data->device, 0,
  1369                                     (IDirect3DBaseTexture9 *) 0);
  1370     if (FAILED(result)) {
  1371         return D3D_SetError("SetTexture()", result);
  1372     }
  1373 
  1374     color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
  1375 
  1376     vertices = SDL_stack_alloc(Vertex, count);
  1377     for (i = 0; i < count; ++i) {
  1378         vertices[i].x = points[i].x;
  1379         vertices[i].y = points[i].y;
  1380         vertices[i].z = 0.0f;
  1381         vertices[i].color = color;
  1382         vertices[i].u = 0.0f;
  1383         vertices[i].v = 0.0f;
  1384     }
  1385     result =
  1386         IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_LINESTRIP, count-1,
  1387                                          vertices, sizeof(*vertices));
  1388 
  1389     /* DirectX 9 has the same line rasterization semantics as GDI,
  1390        so we need to close the endpoint of the line */
  1391     if (count == 2 ||
  1392         points[0].x != points[count-1].x || points[0].y != points[count-1].y) {
  1393         vertices[0].x = points[count-1].x;
  1394         vertices[0].y = points[count-1].y;
  1395         result = IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, 1, vertices, sizeof(*vertices));
  1396     }
  1397 
  1398     SDL_stack_free(vertices);
  1399     if (FAILED(result)) {
  1400         return D3D_SetError("DrawPrimitiveUP()", result);
  1401     }
  1402     return 0;
  1403 }
  1404 
  1405 static int
  1406 D3D_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects,
  1407                     int count)
  1408 {
  1409     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1410     DWORD color;
  1411     int i;
  1412     float minx, miny, maxx, maxy;
  1413     Vertex vertices[4];
  1414     HRESULT result;
  1415 
  1416     if (D3D_ActivateRenderer(renderer) < 0) {
  1417         return -1;
  1418     }
  1419 
  1420     D3D_SetBlendMode(data, renderer->blendMode);
  1421 
  1422     result =
  1423         IDirect3DDevice9_SetTexture(data->device, 0,
  1424                                     (IDirect3DBaseTexture9 *) 0);
  1425     if (FAILED(result)) {
  1426         return D3D_SetError("SetTexture()", result);
  1427     }
  1428 
  1429     color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
  1430 
  1431     for (i = 0; i < count; ++i) {
  1432         const SDL_FRect *rect = &rects[i];
  1433 
  1434         minx = rect->x;
  1435         miny = rect->y;
  1436         maxx = rect->x + rect->w;
  1437         maxy = rect->y + rect->h;
  1438 
  1439         vertices[0].x = minx;
  1440         vertices[0].y = miny;
  1441         vertices[0].z = 0.0f;
  1442         vertices[0].color = color;
  1443         vertices[0].u = 0.0f;
  1444         vertices[0].v = 0.0f;
  1445 
  1446         vertices[1].x = maxx;
  1447         vertices[1].y = miny;
  1448         vertices[1].z = 0.0f;
  1449         vertices[1].color = color;
  1450         vertices[1].u = 0.0f;
  1451         vertices[1].v = 0.0f;
  1452 
  1453         vertices[2].x = maxx;
  1454         vertices[2].y = maxy;
  1455         vertices[2].z = 0.0f;
  1456         vertices[2].color = color;
  1457         vertices[2].u = 0.0f;
  1458         vertices[2].v = 0.0f;
  1459 
  1460         vertices[3].x = minx;
  1461         vertices[3].y = maxy;
  1462         vertices[3].z = 0.0f;
  1463         vertices[3].color = color;
  1464         vertices[3].u = 0.0f;
  1465         vertices[3].v = 0.0f;
  1466 
  1467         result =
  1468             IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN,
  1469                                              2, vertices, sizeof(*vertices));
  1470         if (FAILED(result)) {
  1471             return D3D_SetError("DrawPrimitiveUP()", result);
  1472         }
  1473     }
  1474     return 0;
  1475 }
  1476 
  1477 static void
  1478 D3D_UpdateTextureScaleMode(D3D_RenderData *data, D3D_TextureData *texturedata, unsigned index)
  1479 {
  1480     if (texturedata->scaleMode != data->scaleMode[index]) {
  1481         IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MINFILTER,
  1482                                          texturedata->scaleMode);
  1483         IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MAGFILTER,
  1484                                          texturedata->scaleMode);
  1485         data->scaleMode[index] = texturedata->scaleMode;
  1486     }
  1487 }
  1488 
  1489 static int
  1490 D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
  1491                const SDL_Rect * srcrect, const SDL_FRect * dstrect)
  1492 {
  1493     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1494     D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata;
  1495     LPDIRECT3DPIXELSHADER9 shader = NULL;
  1496     float minx, miny, maxx, maxy;
  1497     float minu, maxu, minv, maxv;
  1498     DWORD color;
  1499     Vertex vertices[4];
  1500     HRESULT result;
  1501 
  1502     if (D3D_ActivateRenderer(renderer) < 0) {
  1503         return -1;
  1504     }
  1505 
  1506     minx = dstrect->x - 0.5f;
  1507     miny = dstrect->y - 0.5f;
  1508     maxx = dstrect->x + dstrect->w - 0.5f;
  1509     maxy = dstrect->y + dstrect->h - 0.5f;
  1510 
  1511     minu = (float) srcrect->x / texture->w;
  1512     maxu = (float) (srcrect->x + srcrect->w) / texture->w;
  1513     minv = (float) srcrect->y / texture->h;
  1514     maxv = (float) (srcrect->y + srcrect->h) / texture->h;
  1515 
  1516     color = D3DCOLOR_ARGB(texture->a, texture->r, texture->g, texture->b);
  1517 
  1518     vertices[0].x = minx;
  1519     vertices[0].y = miny;
  1520     vertices[0].z = 0.0f;
  1521     vertices[0].color = color;
  1522     vertices[0].u = minu;
  1523     vertices[0].v = minv;
  1524 
  1525     vertices[1].x = maxx;
  1526     vertices[1].y = miny;
  1527     vertices[1].z = 0.0f;
  1528     vertices[1].color = color;
  1529     vertices[1].u = maxu;
  1530     vertices[1].v = minv;
  1531 
  1532     vertices[2].x = maxx;
  1533     vertices[2].y = maxy;
  1534     vertices[2].z = 0.0f;
  1535     vertices[2].color = color;
  1536     vertices[2].u = maxu;
  1537     vertices[2].v = maxv;
  1538 
  1539     vertices[3].x = minx;
  1540     vertices[3].y = maxy;
  1541     vertices[3].z = 0.0f;
  1542     vertices[3].color = color;
  1543     vertices[3].u = minu;
  1544     vertices[3].v = maxv;
  1545 
  1546     D3D_SetBlendMode(data, texture->blendMode);
  1547 
  1548     D3D_UpdateTextureScaleMode(data, texturedata, 0);
  1549 
  1550     result =
  1551         IDirect3DDevice9_SetTexture(data->device, 0, (IDirect3DBaseTexture9 *)
  1552                                     texturedata->texture);
  1553     if (FAILED(result)) {
  1554         return D3D_SetError("SetTexture()", result);
  1555     }
  1556 
  1557     if (texturedata->yuv) {
  1558         shader = data->ps_yuv;
  1559 
  1560         D3D_UpdateTextureScaleMode(data, texturedata, 1);
  1561         D3D_UpdateTextureScaleMode(data, texturedata, 2);
  1562 
  1563         result =
  1564             IDirect3DDevice9_SetTexture(data->device, 1, (IDirect3DBaseTexture9 *)
  1565                                         texturedata->utexture);
  1566         if (FAILED(result)) {
  1567             return D3D_SetError("SetTexture()", result);
  1568         }
  1569 
  1570         result =
  1571             IDirect3DDevice9_SetTexture(data->device, 2, (IDirect3DBaseTexture9 *)
  1572                                         texturedata->vtexture);
  1573         if (FAILED(result)) {
  1574             return D3D_SetError("SetTexture()", result);
  1575         }
  1576     }
  1577 
  1578     if (shader) {
  1579         result = IDirect3DDevice9_SetPixelShader(data->device, shader);
  1580         if (FAILED(result)) {
  1581             return D3D_SetError("SetShader()", result);
  1582         }
  1583     }
  1584     result =
  1585         IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2,
  1586                                          vertices, sizeof(*vertices));
  1587     if (FAILED(result)) {
  1588         return D3D_SetError("DrawPrimitiveUP()", result);
  1589     }
  1590     if (shader) {
  1591         result = IDirect3DDevice9_SetPixelShader(data->device, NULL);
  1592         if (FAILED(result)) {
  1593             return D3D_SetError("SetShader()", result);
  1594         }
  1595     }
  1596     return 0;
  1597 }
  1598 
  1599 
  1600 static int
  1601 D3D_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
  1602                const SDL_Rect * srcrect, const SDL_FRect * dstrect,
  1603                const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip)
  1604 {
  1605     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1606     D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata;
  1607     LPDIRECT3DPIXELSHADER9 shader = NULL;
  1608     float minx, miny, maxx, maxy;
  1609     float minu, maxu, minv, maxv;
  1610     float centerx, centery;
  1611     DWORD color;
  1612     Vertex vertices[4];
  1613     HRESULT result;
  1614 
  1615     if (D3D_ActivateRenderer(renderer) < 0) {
  1616         return -1;
  1617     }
  1618 
  1619     centerx = center->x;
  1620     centery = center->y;
  1621 
  1622     if (flip & SDL_FLIP_HORIZONTAL) {
  1623         minx = dstrect->w - centerx - 0.5f;
  1624         maxx = -centerx - 0.5f;
  1625     }
  1626     else {
  1627         minx = -centerx - 0.5f;
  1628         maxx = dstrect->w - centerx - 0.5f;
  1629     }
  1630 
  1631     if (flip & SDL_FLIP_VERTICAL) {
  1632         miny = dstrect->h - centery - 0.5f;
  1633         maxy = -centery - 0.5f;
  1634     }
  1635     else {
  1636         miny = -centery - 0.5f;
  1637         maxy = dstrect->h - centery - 0.5f;
  1638     }
  1639 
  1640     minu = (float) srcrect->x / texture->w;
  1641     maxu = (float) (srcrect->x + srcrect->w) / texture->w;
  1642     minv = (float) srcrect->y / texture->h;
  1643     maxv = (float) (srcrect->y + srcrect->h) / texture->h;
  1644 
  1645     color = D3DCOLOR_ARGB(texture->a, texture->r, texture->g, texture->b);
  1646 
  1647     vertices[0].x = minx;
  1648     vertices[0].y = miny;
  1649     vertices[0].z = 0.0f;
  1650     vertices[0].color = color;
  1651     vertices[0].u = minu;
  1652     vertices[0].v = minv;
  1653 
  1654     vertices[1].x = maxx;
  1655     vertices[1].y = miny;
  1656     vertices[1].z = 0.0f;
  1657     vertices[1].color = color;
  1658     vertices[1].u = maxu;
  1659     vertices[1].v = minv;
  1660 
  1661     vertices[2].x = maxx;
  1662     vertices[2].y = maxy;
  1663     vertices[2].z = 0.0f;
  1664     vertices[2].color = color;
  1665     vertices[2].u = maxu;
  1666     vertices[2].v = maxv;
  1667 
  1668     vertices[3].x = minx;
  1669     vertices[3].y = maxy;
  1670     vertices[3].z = 0.0f;
  1671     vertices[3].color = color;
  1672     vertices[3].u = minu;
  1673     vertices[3].v = maxv;
  1674 
  1675     D3D_SetBlendMode(data, texture->blendMode);
  1676 
  1677     /* Rotate and translate */
  1678     ID3DXMatrixStack_Push(data->matrixStack);
  1679     ID3DXMatrixStack_LoadIdentity(data->matrixStack);
  1680     ID3DXMatrixStack_RotateYawPitchRoll(data->matrixStack, 0.0, 0.0, (float)(M_PI * (float) angle / 180.0f));
  1681     ID3DXMatrixStack_Translate(data->matrixStack, (float)dstrect->x + centerx, (float)dstrect->y + centery, (float)0.0);
  1682     IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)ID3DXMatrixStack_GetTop(data->matrixStack));
  1683 
  1684     D3D_UpdateTextureScaleMode(data, texturedata, 0);
  1685 
  1686     result =
  1687         IDirect3DDevice9_SetTexture(data->device, 0, (IDirect3DBaseTexture9 *)
  1688                                     texturedata->texture);
  1689     if (FAILED(result)) {
  1690         return D3D_SetError("SetTexture()", result);
  1691     }
  1692 
  1693     if (texturedata->yuv) {
  1694         shader = data->ps_yuv;
  1695 
  1696         D3D_UpdateTextureScaleMode(data, texturedata, 1);
  1697         D3D_UpdateTextureScaleMode(data, texturedata, 2);
  1698 
  1699         result =
  1700             IDirect3DDevice9_SetTexture(data->device, 1, (IDirect3DBaseTexture9 *)
  1701                                         texturedata->utexture);
  1702         if (FAILED(result)) {
  1703             return D3D_SetError("SetTexture()", result);
  1704         }
  1705 
  1706         result =
  1707             IDirect3DDevice9_SetTexture(data->device, 2, (IDirect3DBaseTexture9 *)
  1708                                         texturedata->vtexture);
  1709         if (FAILED(result)) {
  1710             return D3D_SetError("SetTexture()", result);
  1711         }
  1712     }
  1713 
  1714     if (shader) {
  1715         result = IDirect3DDevice9_SetPixelShader(data->device, shader);
  1716         if (FAILED(result)) {
  1717             return D3D_SetError("SetShader()", result);
  1718         }
  1719     }
  1720     result =
  1721         IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2,
  1722                                          vertices, sizeof(*vertices));
  1723     if (FAILED(result)) {
  1724         return D3D_SetError("DrawPrimitiveUP()", result);
  1725     }
  1726     if (shader) {
  1727         result = IDirect3DDevice9_SetPixelShader(data->device, NULL);
  1728         if (FAILED(result)) {
  1729             return D3D_SetError("SetShader()", result);
  1730         }
  1731     }
  1732     ID3DXMatrixStack_Pop(data->matrixStack);
  1733     ID3DXMatrixStack_Push(data->matrixStack);
  1734     ID3DXMatrixStack_LoadIdentity(data->matrixStack);
  1735     IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)ID3DXMatrixStack_GetTop(data->matrixStack));
  1736     ID3DXMatrixStack_Pop(data->matrixStack);
  1737     return 0;
  1738 }
  1739 
  1740 static int
  1741 D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
  1742                      Uint32 format, void * pixels, int pitch)
  1743 {
  1744     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1745     D3DSURFACE_DESC desc;
  1746     LPDIRECT3DSURFACE9 backBuffer;
  1747     LPDIRECT3DSURFACE9 surface;
  1748     RECT d3drect;
  1749     D3DLOCKED_RECT locked;
  1750     HRESULT result;
  1751 
  1752     result = IDirect3DDevice9_GetBackBuffer(data->device, 0, 0, D3DBACKBUFFER_TYPE_MONO, &backBuffer);
  1753     if (FAILED(result)) {
  1754         return D3D_SetError("GetBackBuffer()", result);
  1755     }
  1756 
  1757     result = IDirect3DSurface9_GetDesc(backBuffer, &desc);
  1758     if (FAILED(result)) {
  1759         IDirect3DSurface9_Release(backBuffer);
  1760         return D3D_SetError("GetDesc()", result);
  1761     }
  1762 
  1763     result = IDirect3DDevice9_CreateOffscreenPlainSurface(data->device, desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surface, NULL);
  1764     if (FAILED(result)) {
  1765         IDirect3DSurface9_Release(backBuffer);
  1766         return D3D_SetError("CreateOffscreenPlainSurface()", result);
  1767     }
  1768 
  1769     result = IDirect3DDevice9_GetRenderTargetData(data->device, backBuffer, surface);
  1770     if (FAILED(result)) {
  1771         IDirect3DSurface9_Release(surface);
  1772         IDirect3DSurface9_Release(backBuffer);
  1773         return D3D_SetError("GetRenderTargetData()", result);
  1774     }
  1775 
  1776     d3drect.left = rect->x;
  1777     d3drect.right = rect->x + rect->w;
  1778     d3drect.top = rect->y;
  1779     d3drect.bottom = rect->y + rect->h;
  1780 
  1781     result = IDirect3DSurface9_LockRect(surface, &locked, &d3drect, D3DLOCK_READONLY);
  1782     if (FAILED(result)) {
  1783         IDirect3DSurface9_Release(surface);
  1784         IDirect3DSurface9_Release(backBuffer);
  1785         return D3D_SetError("LockRect()", result);
  1786     }
  1787 
  1788     SDL_ConvertPixels(rect->w, rect->h,
  1789                       D3DFMTToPixelFormat(desc.Format), locked.pBits, locked.Pitch,
  1790                       format, pixels, pitch);
  1791 
  1792     IDirect3DSurface9_UnlockRect(surface);
  1793 
  1794     IDirect3DSurface9_Release(surface);
  1795     IDirect3DSurface9_Release(backBuffer);
  1796 
  1797     return 0;
  1798 }
  1799 
  1800 static void
  1801 D3D_RenderPresent(SDL_Renderer * renderer)
  1802 {
  1803     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1804     HRESULT result;
  1805 
  1806     if (!data->beginScene) {
  1807         IDirect3DDevice9_EndScene(data->device);
  1808         data->beginScene = SDL_TRUE;
  1809     }
  1810 
  1811     result = IDirect3DDevice9_TestCooperativeLevel(data->device);
  1812     if (result == D3DERR_DEVICELOST) {
  1813         /* We'll reset later */
  1814         return;
  1815     }
  1816     if (result == D3DERR_DEVICENOTRESET) {
  1817         D3D_Reset(renderer);
  1818     }
  1819     result = IDirect3DDevice9_Present(data->device, NULL, NULL, NULL, NULL);
  1820     if (FAILED(result)) {
  1821         D3D_SetError("Present()", result);
  1822     }
  1823 }
  1824 
  1825 static void
  1826 D3D_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  1827 {
  1828     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
  1829 
  1830     if (!data) {
  1831         return;
  1832     }
  1833     if (data->texture) {
  1834         IDirect3DTexture9_Release(data->texture);
  1835     }
  1836     if (data->utexture) {
  1837         IDirect3DTexture9_Release(data->utexture);
  1838     }
  1839     if (data->vtexture) {
  1840         IDirect3DTexture9_Release(data->vtexture);
  1841     }
  1842     SDL_free(data->pixels);
  1843     SDL_free(data);
  1844     texture->driverdata = NULL;
  1845 }
  1846 
  1847 static void
  1848 D3D_DestroyRenderer(SDL_Renderer * renderer)
  1849 {
  1850     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1851 
  1852     if (data) {
  1853         /* Release the render target */
  1854         if (data->defaultRenderTarget) {
  1855             IDirect3DSurface9_Release(data->defaultRenderTarget);
  1856             data->defaultRenderTarget = NULL;
  1857         }
  1858         if (data->currentRenderTarget != NULL) {
  1859             IDirect3DSurface9_Release(data->currentRenderTarget);
  1860             data->currentRenderTarget = NULL;
  1861         }
  1862         if (data->ps_yuv) {
  1863             IDirect3DPixelShader9_Release(data->ps_yuv);
  1864         }
  1865         if (data->device) {
  1866             IDirect3DDevice9_Release(data->device);
  1867         }
  1868         if (data->d3d) {
  1869             IDirect3D9_Release(data->d3d);
  1870             ID3DXMatrixStack_Release(data->matrixStack);
  1871             SDL_UnloadObject(data->d3dDLL);
  1872         }
  1873         SDL_free(data);
  1874     }
  1875     SDL_free(renderer);
  1876 }
  1877 
  1878 IDirect3DDevice9 *
  1879 SDL_RenderGetD3DDevice(SDL_Renderer * renderer)
  1880 {
  1881 	D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1882 
  1883 	// Make sure that this is a D3D renderer
  1884 	if (renderer->DestroyRenderer != D3D_DestroyRenderer) {
  1885 		SDL_SetError("Renderer is not a D3D renderer");
  1886 		return NULL;
  1887 	}
  1888 	return data->device;
  1889 }
  1890 
  1891 #endif /* SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED */
  1892 
  1893 /* vi: set ts=4 sw=4 expandtab: */