src/render/direct3d/SDL_render_d3d.c
author Philipp Wiesemann
Sun, 07 Jul 2013 16:13:17 +0200
changeset 7369 80215ecb81cf
parent 7250 bbb6b079cfe5
child 7472 0ec51bd57d56
permissions -rw-r--r--
Changed include directive to standard header.
     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_sysrender.h"
    32 #include <stdio.h>
    33 
    34 #if SDL_VIDEO_RENDER_D3D
    35 #define D3D_DEBUG_INFO
    36 #include <d3d9.h>
    37 #endif
    38 
    39 
    40 typedef interface ID3DXMatrixStack *LPD3DXMATRIXSTACK;
    41 typedef struct _D3DMATRIX D3DXMATRIX, *LPD3DXMATRIX;
    42 typedef struct _D3DVECTOR D3DXVECTOR3, *LPD3DXVECTOR3;
    43 
    44 DEFINE_GUID(IID_ID3DXMatrixStack,
    45 0xc7885ba7, 0xf990, 0x4fe7, 0x92, 0x2d, 0x85, 0x15, 0xe4, 0x77, 0xdd, 0x85);
    46 
    47 #undef INTERFACE
    48 #define INTERFACE ID3DXMatrixStack
    49 
    50 DECLARE_INTERFACE_(ID3DXMatrixStack, IUnknown)
    51 {
    52     STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID * ppvObj) PURE;
    53     STDMETHOD_(ULONG,AddRef)(THIS) PURE;
    54     STDMETHOD_(ULONG,Release)(THIS) PURE;
    55     STDMETHOD(Pop)(THIS) PURE;
    56     STDMETHOD(Push)(THIS) PURE;
    57     STDMETHOD(LoadIdentity)(THIS) PURE;
    58     STDMETHOD(LoadMatrix)(THIS_ CONST D3DXMATRIX* pM ) PURE;
    59     STDMETHOD(MultMatrix)(THIS_ CONST D3DXMATRIX* pM ) PURE;
    60     STDMETHOD(MultMatrixLocal)(THIS_ CONST D3DXMATRIX* pM ) PURE;
    61     STDMETHOD(RotateAxis)(THIS_ CONST D3DXVECTOR3* pV, FLOAT Angle) PURE;
    62     STDMETHOD(RotateAxisLocal)(THIS_ CONST D3DXVECTOR3* pV, FLOAT Angle) PURE;
    63     STDMETHOD(RotateYawPitchRoll)(THIS_ FLOAT Yaw, FLOAT Pitch, FLOAT Roll) PURE;
    64     STDMETHOD(RotateYawPitchRollLocal)(THIS_ FLOAT Yaw, FLOAT Pitch, FLOAT Roll) PURE;
    65     STDMETHOD(Scale)(THIS_ FLOAT x, FLOAT y, FLOAT z) PURE;
    66     STDMETHOD(ScaleLocal)(THIS_ FLOAT x, FLOAT y, FLOAT z) PURE;
    67     STDMETHOD(Translate)(THIS_ FLOAT x, FLOAT y, FLOAT z ) PURE;
    68     STDMETHOD(TranslateLocal)(THIS_ FLOAT x, FLOAT y, FLOAT z) PURE;
    69     STDMETHOD_(D3DXMATRIX*, GetTop)(THIS) PURE;
    70 };
    71 
    72 #undef INTERFACE
    73 
    74 #if !defined(__cplusplus) || defined(CINTERFACE)
    75 #define ID3DXMatrixStack_QueryInterface(p,a,b)            (p)->lpVtbl->QueryInterface(p,a,b)
    76 #define ID3DXMatrixStack_AddRef(p)                        (p)->lpVtbl->AddRef(p)
    77 #define ID3DXMatrixStack_Release(p)                       (p)->lpVtbl->Release(p)
    78 #define ID3DXMatrixStack_Pop(p)                           (p)->lpVtbl->Pop(p)
    79 #define ID3DXMatrixStack_Push(p)                          (p)->lpVtbl->Push(p)
    80 #define ID3DXMatrixStack_LoadIdentity(p)                  (p)->lpVtbl->LoadIdentity(p)
    81 #define ID3DXMatrixStack_LoadMatrix(p,a)                  (p)->lpVtbl->LoadMatrix(p,a)
    82 #define ID3DXMatrixStack_MultMatrix(p,a)                  (p)->lpVtbl->MultMatrix(p,a)
    83 #define ID3DXMatrixStack_MultMatrixLocal(p,a)             (p)->lpVtbl->MultMatrixLocal(p,a)
    84 #define ID3DXMatrixStack_RotateAxis(p,a,b)                (p)->lpVtbl->RotateAxis(p,a,b)
    85 #define ID3DXMatrixStack_RotateAxisLocal(p,a,b)           (p)->lpVtbl->RotateAxisLocal(p,a,b)
    86 #define ID3DXMatrixStack_RotateYawPitchRoll(p,a,b,c)      (p)->lpVtbl->RotateYawPitchRoll(p,a,b,c)
    87 #define ID3DXMatrixStack_RotateYawPitchRollLocal(p,a,b,c) (p)->lpVtbl->RotateYawPitchRollLocal(p,a,b,c)
    88 #define ID3DXMatrixStack_Scale(p,a,b,c)                   (p)->lpVtbl->Scale(p,a,b,c)
    89 #define ID3DXMatrixStack_ScaleLocal(p,a,b,c)              (p)->lpVtbl->ScaleLocal(p,a,b,c)
    90 #define ID3DXMatrixStack_Translate(p,a,b,c)               (p)->lpVtbl->Translate(p,a,b,c)
    91 #define ID3DXMatrixStack_TranslateLocal(p,a,b,c)          (p)->lpVtbl->TranslateLocal(p,a,b,c)
    92 #define ID3DXMatrixStack_GetTop(p)                        (p)->lpVtbl->GetTop(p)
    93 #else
    94 #define ID3DXMatrixStack_QueryInterface(p,a,b)            (p)->QueryInterface(a,b)
    95 #define ID3DXMatrixStack_AddRef(p)                        (p)->AddRef()
    96 #define ID3DXMatrixStack_Release(p)                       (p)->Release()
    97 #define ID3DXMatrixStack_Pop(p)    (p)->Pop()
    98 #define ID3DXMatrixStack_Push(p)    (p)->Push()
    99 #define ID3DXMatrixStack_LoadIdentity(p)    (p)->LoadIdentity()
   100 #define ID3DXMatrixStack_LoadMatrix(p,a)    (p)->LoadMatrix(a)
   101 #define ID3DXMatrixStack_MultMatrix(p,a)    (p)->MultMatrix(a)
   102 #define ID3DXMatrixStack_MultMatrixLocal(p,a)    (p)->MultMatrixLocal(a)
   103 #define ID3DXMatrixStack_RotateAxis(p,a,b)    (p)->RotateAxis(a,b)
   104 #define ID3DXMatrixStack_RotateAxisLocal(p,a,b)    (p)->RotateAxisLocal(a,b)
   105 #define ID3DXMatrixStack_RotateYawPitchRoll(p,a,b,c)    (p)->RotateYawPitchRollLocal(a,b,c)
   106 #define ID3DXMatrixStack_Scale(p,a,b,c)    (p)->Scale(a,b,c)
   107 #define ID3DXMatrixStack_ScaleLocal(p,a,b,c)    (p)->ScaleLocal(a,b,c)
   108 #define ID3DXMatrixStack_Translate(p,a,b,c)    (p)->Translate(a,b,c)
   109 #define ID3DXMatrixStack_TranslateLocal(p,a,b,c)    (p)->TranslateLocal(a,b,c)
   110 #define ID3DXMatrixStack_GetTop(p)    (p)->GetTop()
   111 #endif
   112 
   113 #ifdef __cplusplus
   114 extern "C" {
   115 #endif
   116 
   117 HRESULT WINAPI D3DXCreateMatrixStack(DWORD flags, LPD3DXMATRIXSTACK* ppstack);
   118 
   119 #ifdef __cplusplus
   120 }
   121 #endif
   122 
   123 #ifdef ASSEMBLE_SHADER
   124 /**************************************************************************
   125  * ID3DXBuffer:
   126  * ------------
   127  * The buffer object is used by D3DX to return arbitrary size data.
   128  *
   129  * GetBufferPointer -
   130  *    Returns a pointer to the beginning of the buffer.
   131  *
   132  * GetBufferSize -
   133  *    Returns the size of the buffer, in bytes.
   134  **************************************************************************/
   135 
   136 typedef interface ID3DXBuffer ID3DXBuffer;
   137 typedef interface ID3DXBuffer *LPD3DXBUFFER;
   138 
   139 /* {8BA5FB08-5195-40e2-AC58-0D989C3A0102} */
   140 DEFINE_GUID(IID_ID3DXBuffer,
   141 0x8ba5fb08, 0x5195, 0x40e2, 0xac, 0x58, 0xd, 0x98, 0x9c, 0x3a, 0x1, 0x2);
   142 
   143 #undef INTERFACE
   144 #define INTERFACE ID3DXBuffer
   145 
   146 typedef interface ID3DXBuffer {
   147     const struct ID3DXBufferVtbl FAR* lpVtbl;
   148 } ID3DXBuffer;
   149 typedef const struct ID3DXBufferVtbl ID3DXBufferVtbl;
   150 const struct ID3DXBufferVtbl
   151 {
   152     /* IUnknown */
   153     STDMETHOD(QueryInterface)(THIS_ REFIID iid, LPVOID *ppv) PURE;
   154     STDMETHOD_(ULONG, AddRef)(THIS) PURE;
   155     STDMETHOD_(ULONG, Release)(THIS) PURE;
   156 
   157     /* ID3DXBuffer */
   158     STDMETHOD_(LPVOID, GetBufferPointer)(THIS) PURE;
   159     STDMETHOD_(DWORD, GetBufferSize)(THIS) PURE;
   160 };
   161 
   162 HRESULT WINAPI
   163     D3DXAssembleShader(
   164         LPCSTR                          pSrcData,
   165         UINT                            SrcDataLen,
   166         CONST LPVOID*                   pDefines,
   167         LPVOID                          pInclude,
   168         DWORD                           Flags,
   169         LPD3DXBUFFER*                   ppShader,
   170         LPD3DXBUFFER*                   ppErrorMsgs);
   171 
   172 #endif /* ASSEMBLE_SHADER */
   173 
   174 
   175 /* Direct3D renderer implementation */
   176 
   177 static SDL_Renderer *D3D_CreateRenderer(SDL_Window * window, Uint32 flags);
   178 static void D3D_WindowEvent(SDL_Renderer * renderer,
   179                             const SDL_WindowEvent *event);
   180 static int D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
   181 static int D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   182                              const SDL_Rect * rect, const void *pixels,
   183                              int pitch);
   184 static int D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   185                            const SDL_Rect * rect, void **pixels, int *pitch);
   186 static void D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
   187 static int D3D_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture);
   188 static int D3D_UpdateViewport(SDL_Renderer * renderer);
   189 static int D3D_UpdateClipRect(SDL_Renderer * renderer);
   190 static int D3D_RenderClear(SDL_Renderer * renderer);
   191 static int D3D_RenderDrawPoints(SDL_Renderer * renderer,
   192                                 const SDL_FPoint * points, int count);
   193 static int D3D_RenderDrawLines(SDL_Renderer * renderer,
   194                                const SDL_FPoint * points, int count);
   195 static int D3D_RenderFillRects(SDL_Renderer * renderer,
   196                                const SDL_FRect * rects, int count);
   197 static int D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   198                           const SDL_Rect * srcrect, const SDL_FRect * dstrect);
   199 static int D3D_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
   200                           const SDL_Rect * srcrect, const SDL_FRect * dstrect,
   201                           const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip);
   202 static int D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
   203                                 Uint32 format, void * pixels, int pitch);
   204 static void D3D_RenderPresent(SDL_Renderer * renderer);
   205 static void D3D_DestroyTexture(SDL_Renderer * renderer,
   206                                SDL_Texture * texture);
   207 static void D3D_DestroyRenderer(SDL_Renderer * renderer);
   208 
   209 
   210 SDL_RenderDriver D3D_RenderDriver = {
   211     D3D_CreateRenderer,
   212     {
   213      "direct3d",
   214      (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
   215      1,
   216      {SDL_PIXELFORMAT_ARGB8888},
   217      0,
   218      0}
   219 };
   220 
   221 typedef struct
   222 {
   223     void* d3dDLL;
   224     IDirect3D9 *d3d;
   225     IDirect3DDevice9 *device;
   226     UINT adapter;
   227     D3DPRESENT_PARAMETERS pparams;
   228     SDL_bool updateSize;
   229     SDL_bool beginScene;
   230     D3DTEXTUREFILTERTYPE scaleMode;
   231     IDirect3DSurface9 *defaultRenderTarget;
   232     IDirect3DSurface9 *currentRenderTarget;
   233     void* d3dxDLL;
   234     ID3DXMatrixStack *matrixStack;
   235 } D3D_RenderData;
   236 
   237 typedef struct
   238 {
   239     IDirect3DTexture9 *texture;
   240     D3DTEXTUREFILTERTYPE scaleMode;
   241 } D3D_TextureData;
   242 
   243 typedef struct
   244 {
   245     float x, y, z;
   246     DWORD color;
   247     float u, v;
   248 } Vertex;
   249 
   250 static int
   251 D3D_SetError(const char *prefix, HRESULT result)
   252 {
   253     const char *error;
   254 
   255     switch (result) {
   256     case D3DERR_WRONGTEXTUREFORMAT:
   257         error = "WRONGTEXTUREFORMAT";
   258         break;
   259     case D3DERR_UNSUPPORTEDCOLOROPERATION:
   260         error = "UNSUPPORTEDCOLOROPERATION";
   261         break;
   262     case D3DERR_UNSUPPORTEDCOLORARG:
   263         error = "UNSUPPORTEDCOLORARG";
   264         break;
   265     case D3DERR_UNSUPPORTEDALPHAOPERATION:
   266         error = "UNSUPPORTEDALPHAOPERATION";
   267         break;
   268     case D3DERR_UNSUPPORTEDALPHAARG:
   269         error = "UNSUPPORTEDALPHAARG";
   270         break;
   271     case D3DERR_TOOMANYOPERATIONS:
   272         error = "TOOMANYOPERATIONS";
   273         break;
   274     case D3DERR_CONFLICTINGTEXTUREFILTER:
   275         error = "CONFLICTINGTEXTUREFILTER";
   276         break;
   277     case D3DERR_UNSUPPORTEDFACTORVALUE:
   278         error = "UNSUPPORTEDFACTORVALUE";
   279         break;
   280     case D3DERR_CONFLICTINGRENDERSTATE:
   281         error = "CONFLICTINGRENDERSTATE";
   282         break;
   283     case D3DERR_UNSUPPORTEDTEXTUREFILTER:
   284         error = "UNSUPPORTEDTEXTUREFILTER";
   285         break;
   286     case D3DERR_CONFLICTINGTEXTUREPALETTE:
   287         error = "CONFLICTINGTEXTUREPALETTE";
   288         break;
   289     case D3DERR_DRIVERINTERNALERROR:
   290         error = "DRIVERINTERNALERROR";
   291         break;
   292     case D3DERR_NOTFOUND:
   293         error = "NOTFOUND";
   294         break;
   295     case D3DERR_MOREDATA:
   296         error = "MOREDATA";
   297         break;
   298     case D3DERR_DEVICELOST:
   299         error = "DEVICELOST";
   300         break;
   301     case D3DERR_DEVICENOTRESET:
   302         error = "DEVICENOTRESET";
   303         break;
   304     case D3DERR_NOTAVAILABLE:
   305         error = "NOTAVAILABLE";
   306         break;
   307     case D3DERR_OUTOFVIDEOMEMORY:
   308         error = "OUTOFVIDEOMEMORY";
   309         break;
   310     case D3DERR_INVALIDDEVICE:
   311         error = "INVALIDDEVICE";
   312         break;
   313     case D3DERR_INVALIDCALL:
   314         error = "INVALIDCALL";
   315         break;
   316     case D3DERR_DRIVERINVALIDCALL:
   317         error = "DRIVERINVALIDCALL";
   318         break;
   319     case D3DERR_WASSTILLDRAWING:
   320         error = "WASSTILLDRAWING";
   321         break;
   322     default:
   323         error = "UNKNOWN";
   324         break;
   325     }
   326     return SDL_SetError("%s: %s", prefix, error);
   327 }
   328 
   329 static D3DFORMAT
   330 PixelFormatToD3DFMT(Uint32 format)
   331 {
   332     switch (format) {
   333     case SDL_PIXELFORMAT_RGB565:
   334         return D3DFMT_R5G6B5;
   335     case SDL_PIXELFORMAT_RGB888:
   336         return D3DFMT_X8R8G8B8;
   337     case SDL_PIXELFORMAT_ARGB8888:
   338         return D3DFMT_A8R8G8B8;
   339     default:
   340         return D3DFMT_UNKNOWN;
   341     }
   342 }
   343 
   344 static Uint32
   345 D3DFMTToPixelFormat(D3DFORMAT format)
   346 {
   347     switch (format) {
   348     case D3DFMT_R5G6B5:
   349         return SDL_PIXELFORMAT_RGB565;
   350     case D3DFMT_X8R8G8B8:
   351         return SDL_PIXELFORMAT_RGB888;
   352     case D3DFMT_A8R8G8B8:
   353         return SDL_PIXELFORMAT_ARGB8888;
   354     default:
   355         return SDL_PIXELFORMAT_UNKNOWN;
   356     }
   357 }
   358 
   359 static int
   360 D3D_Reset(SDL_Renderer * renderer)
   361 {
   362     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   363     HRESULT result;
   364 
   365     /* Release the default render target before reset */
   366     if (data->defaultRenderTarget) {
   367         IDirect3DSurface9_Release(data->defaultRenderTarget);
   368         data->defaultRenderTarget = NULL;
   369     }
   370 
   371     result = IDirect3DDevice9_Reset(data->device, &data->pparams);
   372     if (FAILED(result)) {
   373         if (result == D3DERR_DEVICELOST) {
   374             /* Don't worry about it, we'll reset later... */
   375             return 0;
   376         } else {
   377             return D3D_SetError("Reset()", result);
   378         }
   379     }
   380     IDirect3DDevice9_SetVertexShader(data->device, NULL);
   381     IDirect3DDevice9_SetFVF(data->device,
   382                             D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);
   383     IDirect3DDevice9_SetRenderState(data->device, D3DRS_CULLMODE,
   384                                     D3DCULL_NONE);
   385     IDirect3DDevice9_SetRenderState(data->device, D3DRS_LIGHTING, FALSE);
   386     IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget);
   387     data->scaleMode = D3DTEXF_FORCE_DWORD;
   388     return 0;
   389 }
   390 
   391 static int
   392 D3D_ActivateRenderer(SDL_Renderer * renderer)
   393 {
   394     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   395     HRESULT result;
   396 
   397     if (data->updateSize) {
   398         SDL_Window *window = renderer->window;
   399         int w, h;
   400 
   401         SDL_GetWindowSize(window, &w, &h);
   402         data->pparams.BackBufferWidth = w;
   403         data->pparams.BackBufferHeight = h;
   404         if (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN) {
   405             data->pparams.BackBufferFormat =
   406                 PixelFormatToD3DFMT(SDL_GetWindowPixelFormat(window));
   407         } else {
   408             data->pparams.BackBufferFormat = D3DFMT_UNKNOWN;
   409         }
   410         if (D3D_Reset(renderer) < 0) {
   411             return -1;
   412         }
   413         D3D_UpdateViewport(renderer);
   414 
   415         data->updateSize = SDL_FALSE;
   416     }
   417     if (data->beginScene) {
   418         result = IDirect3DDevice9_BeginScene(data->device);
   419         if (result == D3DERR_DEVICELOST) {
   420             if (D3D_Reset(renderer) < 0) {
   421                 return -1;
   422             }
   423             result = IDirect3DDevice9_BeginScene(data->device);
   424         }
   425         if (FAILED(result)) {
   426             return D3D_SetError("BeginScene()", result);
   427         }
   428         data->beginScene = SDL_FALSE;
   429     }
   430     return 0;
   431 }
   432 
   433 SDL_Renderer *
   434 D3D_CreateRenderer(SDL_Window * window, Uint32 flags)
   435 {
   436     SDL_Renderer *renderer;
   437     D3D_RenderData *data;
   438     SDL_SysWMinfo windowinfo;
   439     HRESULT result;
   440     D3DPRESENT_PARAMETERS pparams;
   441     IDirect3DSwapChain9 *chain;
   442     D3DCAPS9 caps;
   443     Uint32 window_flags;
   444     int w, h;
   445     SDL_DisplayMode fullscreen_mode;
   446     D3DMATRIX matrix;
   447     int d3dxVersion;
   448     char d3dxDLLFile[50];
   449 
   450     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   451     if (!renderer) {
   452         SDL_OutOfMemory();
   453         return NULL;
   454     }
   455 
   456     data = (D3D_RenderData *) SDL_calloc(1, sizeof(*data));
   457     if (!data) {
   458         SDL_free(renderer);
   459         SDL_OutOfMemory();
   460         return NULL;
   461     }
   462 
   463     data->d3dDLL = SDL_LoadObject("D3D9.DLL");
   464     if (data->d3dDLL) {
   465         IDirect3D9 *(WINAPI * D3DCreate) (UINT SDKVersion);
   466 
   467         D3DCreate =
   468             (IDirect3D9 * (WINAPI *) (UINT)) SDL_LoadFunction(data->d3dDLL,
   469                                                             "Direct3DCreate9");
   470         if (D3DCreate) {
   471             data->d3d = D3DCreate(D3D_SDK_VERSION);
   472         }
   473         if (!data->d3d) {
   474             SDL_UnloadObject(data->d3dDLL);
   475             data->d3dDLL = NULL;
   476         }
   477 
   478         for (d3dxVersion=50;d3dxVersion>0;d3dxVersion--) {
   479             LPTSTR dllName;
   480             SDL_snprintf(d3dxDLLFile, sizeof(d3dxDLLFile), "D3DX9_%02d.dll", d3dxVersion);
   481             dllName = WIN_UTF8ToString(d3dxDLLFile);
   482             data->d3dxDLL = (void *)LoadLibrary(dllName); /* not using SDL_LoadObject() as we want silently fail - no error message */
   483             SDL_free(dllName);
   484             if (data->d3dxDLL) {
   485                 HRESULT (WINAPI *D3DXCreateMatrixStack) (DWORD Flags, LPD3DXMATRIXSTACK*  ppStack);
   486                 D3DXCreateMatrixStack = (HRESULT (WINAPI *) (DWORD, LPD3DXMATRIXSTACK*)) SDL_LoadFunction(data->d3dxDLL, "D3DXCreateMatrixStack");
   487                 if (D3DXCreateMatrixStack) {
   488                     D3DXCreateMatrixStack(0, &data->matrixStack);
   489                     break;
   490                 }
   491             }
   492         }
   493 
   494         if (!data->matrixStack) {
   495             if (data->d3dxDLL) SDL_UnloadObject(data->d3dxDLL);
   496         }
   497     }
   498 
   499 
   500 
   501     if (!data->d3d || !data->matrixStack) {
   502         SDL_free(renderer);
   503         SDL_free(data);
   504         SDL_SetError("Unable to create Direct3D interface");
   505         return NULL;
   506     }
   507 
   508     renderer->WindowEvent = D3D_WindowEvent;
   509     renderer->CreateTexture = D3D_CreateTexture;
   510     renderer->UpdateTexture = D3D_UpdateTexture;
   511     renderer->LockTexture = D3D_LockTexture;
   512     renderer->UnlockTexture = D3D_UnlockTexture;
   513     renderer->SetRenderTarget = D3D_SetRenderTarget;
   514     renderer->UpdateViewport = D3D_UpdateViewport;
   515     renderer->UpdateClipRect = D3D_UpdateClipRect;
   516     renderer->RenderClear = D3D_RenderClear;
   517     renderer->RenderDrawPoints = D3D_RenderDrawPoints;
   518     renderer->RenderDrawLines = D3D_RenderDrawLines;
   519     renderer->RenderFillRects = D3D_RenderFillRects;
   520     renderer->RenderCopy = D3D_RenderCopy;
   521     renderer->RenderCopyEx = D3D_RenderCopyEx;
   522     renderer->RenderReadPixels = D3D_RenderReadPixels;
   523     renderer->RenderPresent = D3D_RenderPresent;
   524     renderer->DestroyTexture = D3D_DestroyTexture;
   525     renderer->DestroyRenderer = D3D_DestroyRenderer;
   526     renderer->info = D3D_RenderDriver.info;
   527     renderer->driverdata = data;
   528 
   529     renderer->info.flags = SDL_RENDERER_ACCELERATED;
   530 
   531     SDL_VERSION(&windowinfo.version);
   532     SDL_GetWindowWMInfo(window, &windowinfo);
   533 
   534     window_flags = SDL_GetWindowFlags(window);
   535     SDL_GetWindowSize(window, &w, &h);
   536     SDL_GetWindowDisplayMode(window, &fullscreen_mode);
   537 
   538     SDL_zero(pparams);
   539     pparams.hDeviceWindow = windowinfo.info.win.window;
   540     pparams.BackBufferWidth = w;
   541     pparams.BackBufferHeight = h;
   542     if (window_flags & SDL_WINDOW_FULLSCREEN) {
   543         pparams.BackBufferFormat =
   544             PixelFormatToD3DFMT(fullscreen_mode.format);
   545     } else {
   546         pparams.BackBufferFormat = D3DFMT_UNKNOWN;
   547     }
   548     pparams.BackBufferCount = 1;
   549     pparams.SwapEffect = D3DSWAPEFFECT_DISCARD;
   550 
   551     if (window_flags & SDL_WINDOW_FULLSCREEN) {
   552         if ( ( window_flags & SDL_WINDOW_FULLSCREEN_DESKTOP ) == SDL_WINDOW_FULLSCREEN_DESKTOP )  {
   553             pparams.Windowed = TRUE;
   554             pparams.FullScreen_RefreshRateInHz = 0;
   555         } else {
   556         pparams.Windowed = FALSE;
   557         pparams.FullScreen_RefreshRateInHz =
   558             fullscreen_mode.refresh_rate;
   559         }
   560     } else {
   561         pparams.Windowed = TRUE;
   562         pparams.FullScreen_RefreshRateInHz = 0;
   563     }
   564     if (flags & SDL_RENDERER_PRESENTVSYNC) {
   565         pparams.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
   566     } else {
   567         pparams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
   568     }
   569 
   570     /* FIXME: Which adapter? */
   571     data->adapter = D3DADAPTER_DEFAULT;
   572     IDirect3D9_GetDeviceCaps(data->d3d, data->adapter, D3DDEVTYPE_HAL, &caps);
   573 
   574     result = IDirect3D9_CreateDevice(data->d3d, data->adapter,
   575                                      D3DDEVTYPE_HAL,
   576                                      pparams.hDeviceWindow,
   577                                      D3DCREATE_FPU_PRESERVE | ((caps.
   578                                       DevCaps &
   579                                       D3DDEVCAPS_HWTRANSFORMANDLIGHT) ?
   580                                      D3DCREATE_HARDWARE_VERTEXPROCESSING :
   581                                      D3DCREATE_SOFTWARE_VERTEXPROCESSING),
   582                                      &pparams, &data->device);
   583     if (FAILED(result)) {
   584         D3D_DestroyRenderer(renderer);
   585         D3D_SetError("CreateDevice()", result);
   586         return NULL;
   587     }
   588     data->beginScene = SDL_TRUE;
   589     data->scaleMode = D3DTEXF_FORCE_DWORD;
   590 
   591     /* Get presentation parameters to fill info */
   592     result = IDirect3DDevice9_GetSwapChain(data->device, 0, &chain);
   593     if (FAILED(result)) {
   594         D3D_DestroyRenderer(renderer);
   595         D3D_SetError("GetSwapChain()", result);
   596         return NULL;
   597     }
   598     result = IDirect3DSwapChain9_GetPresentParameters(chain, &pparams);
   599     if (FAILED(result)) {
   600         IDirect3DSwapChain9_Release(chain);
   601         D3D_DestroyRenderer(renderer);
   602         D3D_SetError("GetPresentParameters()", result);
   603         return NULL;
   604     }
   605     IDirect3DSwapChain9_Release(chain);
   606     if (pparams.PresentationInterval == D3DPRESENT_INTERVAL_ONE) {
   607         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
   608     }
   609     data->pparams = pparams;
   610 
   611     IDirect3DDevice9_GetDeviceCaps(data->device, &caps);
   612     renderer->info.max_texture_width = caps.MaxTextureWidth;
   613     renderer->info.max_texture_height = caps.MaxTextureHeight;
   614     if (caps.NumSimultaneousRTs >= 2) {
   615         renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE;
   616     }
   617 
   618     /* Set up parameters for rendering */
   619     IDirect3DDevice9_SetVertexShader(data->device, NULL);
   620     IDirect3DDevice9_SetFVF(data->device,
   621                             D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);
   622     IDirect3DDevice9_SetRenderState(data->device, D3DRS_ZENABLE, D3DZB_FALSE);
   623     IDirect3DDevice9_SetRenderState(data->device, D3DRS_CULLMODE,
   624                                     D3DCULL_NONE);
   625     IDirect3DDevice9_SetRenderState(data->device, D3DRS_LIGHTING, FALSE);
   626     /* Enable color modulation by diffuse color */
   627     IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_COLOROP,
   628                                           D3DTOP_MODULATE);
   629     IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_COLORARG1,
   630                                           D3DTA_TEXTURE);
   631     IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_COLORARG2,
   632                                           D3DTA_DIFFUSE);
   633     /* Enable alpha modulation by diffuse alpha */
   634     IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_ALPHAOP,
   635                                           D3DTOP_MODULATE);
   636     IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_ALPHAARG1,
   637                                           D3DTA_TEXTURE);
   638     IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_ALPHAARG2,
   639                                           D3DTA_DIFFUSE);
   640     /* Disable second texture stage, since we're done */
   641     IDirect3DDevice9_SetTextureStageState(data->device, 1, D3DTSS_COLOROP,
   642                                           D3DTOP_DISABLE);
   643     IDirect3DDevice9_SetTextureStageState(data->device, 1, D3DTSS_ALPHAOP,
   644                                           D3DTOP_DISABLE);
   645 
   646     /* Store the default render target */
   647     IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget );
   648     data->currentRenderTarget = NULL;
   649 
   650     /* Set an identity world and view matrix */
   651     matrix.m[0][0] = 1.0f;
   652     matrix.m[0][1] = 0.0f;
   653     matrix.m[0][2] = 0.0f;
   654     matrix.m[0][3] = 0.0f;
   655     matrix.m[1][0] = 0.0f;
   656     matrix.m[1][1] = 1.0f;
   657     matrix.m[1][2] = 0.0f;
   658     matrix.m[1][3] = 0.0f;
   659     matrix.m[2][0] = 0.0f;
   660     matrix.m[2][1] = 0.0f;
   661     matrix.m[2][2] = 1.0f;
   662     matrix.m[2][3] = 0.0f;
   663     matrix.m[3][0] = 0.0f;
   664     matrix.m[3][1] = 0.0f;
   665     matrix.m[3][2] = 0.0f;
   666     matrix.m[3][3] = 1.0f;
   667     IDirect3DDevice9_SetTransform(data->device, D3DTS_WORLD, &matrix);
   668     IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, &matrix);
   669 
   670     return renderer;
   671 }
   672 
   673 static void
   674 D3D_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
   675 {
   676     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   677 
   678     if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) {
   679         data->updateSize = SDL_TRUE;
   680     }
   681 }
   682 
   683 static D3DTEXTUREFILTERTYPE
   684 GetScaleQuality(void)
   685 {
   686     const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
   687 
   688     if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) {
   689         return D3DTEXF_POINT;
   690     } else if (*hint == '1' || SDL_strcasecmp(hint, "linear") == 0) {
   691         return D3DTEXF_LINEAR;
   692     } else {
   693         return D3DTEXF_ANISOTROPIC;
   694     }
   695 }
   696 
   697 static int
   698 D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   699 {
   700     D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata;
   701     D3D_TextureData *data;
   702     D3DPOOL pool;
   703     DWORD usage;
   704     HRESULT result;
   705 
   706     data = (D3D_TextureData *) SDL_calloc(1, sizeof(*data));
   707     if (!data) {
   708         return SDL_OutOfMemory();
   709     }
   710     data->scaleMode = GetScaleQuality();
   711 
   712     texture->driverdata = data;
   713 
   714 #ifdef USE_DYNAMIC_TEXTURE
   715     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   716         pool = D3DPOOL_DEFAULT;
   717         usage = D3DUSAGE_DYNAMIC;
   718     } else
   719 #endif
   720     if (texture->access == SDL_TEXTUREACCESS_TARGET) {
   721         /* D3DPOOL_MANAGED does not work with D3DUSAGE_RENDERTARGET */
   722         pool = D3DPOOL_DEFAULT;
   723         usage = D3DUSAGE_RENDERTARGET;
   724     } else {
   725         pool = D3DPOOL_MANAGED;
   726         usage = 0;
   727     }
   728 
   729     result =
   730         IDirect3DDevice9_CreateTexture(renderdata->device, texture->w,
   731                                        texture->h, 1, usage,
   732                                        PixelFormatToD3DFMT(texture->format),
   733                                        pool, &data->texture, NULL);
   734     if (FAILED(result)) {
   735         return D3D_SetError("CreateTexture()", result);
   736     }
   737 
   738     return 0;
   739 }
   740 
   741 static int
   742 D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   743                   const SDL_Rect * rect, const void *pixels, int pitch)
   744 {
   745     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
   746     RECT d3drect;
   747     D3DLOCKED_RECT locked;
   748     const Uint8 *src;
   749     Uint8 *dst;
   750     int row, length;
   751     HRESULT result;
   752 
   753 #ifdef USE_DYNAMIC_TEXTURE
   754     if (texture->access == SDL_TEXTUREACCESS_STREAMING &&
   755         rect->x == 0 && rect->y == 0 &&
   756         rect->w == texture->w && rect->h == texture->h) {
   757         result = IDirect3DTexture9_LockRect(data->texture, 0, &locked, NULL, D3DLOCK_DISCARD);
   758     } else
   759 #endif
   760     {
   761         d3drect.left = rect->x;
   762         d3drect.right = rect->x + rect->w;
   763         d3drect.top = rect->y;
   764         d3drect.bottom = rect->y + rect->h;
   765         result = IDirect3DTexture9_LockRect(data->texture, 0, &locked, &d3drect, 0);
   766     }
   767 
   768     if (FAILED(result)) {
   769         return D3D_SetError("LockRect()", result);
   770     }
   771 
   772     src = pixels;
   773     dst = locked.pBits;
   774     length = rect->w * SDL_BYTESPERPIXEL(texture->format);
   775     if (length == pitch && length == locked.Pitch) {
   776         SDL_memcpy(dst, src, length*rect->h);
   777     } else {
   778         for (row = 0; row < rect->h; ++row) {
   779             SDL_memcpy(dst, src, length);
   780             src += pitch;
   781             dst += locked.Pitch;
   782         }
   783     }
   784     IDirect3DTexture9_UnlockRect(data->texture, 0);
   785 
   786     return 0;
   787 }
   788 
   789 static int
   790 D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   791                 const SDL_Rect * rect, void **pixels, int *pitch)
   792 {
   793     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
   794     RECT d3drect;
   795     D3DLOCKED_RECT locked;
   796     HRESULT result;
   797 
   798     d3drect.left = rect->x;
   799     d3drect.right = rect->x + rect->w;
   800     d3drect.top = rect->y;
   801     d3drect.bottom = rect->y + rect->h;
   802 
   803     result = IDirect3DTexture9_LockRect(data->texture, 0, &locked, &d3drect, 0);
   804     if (FAILED(result)) {
   805         return D3D_SetError("LockRect()", result);
   806     }
   807     *pixels = locked.pBits;
   808     *pitch = locked.Pitch;
   809     return 0;
   810 }
   811 
   812 static void
   813 D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   814 {
   815     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
   816 
   817     IDirect3DTexture9_UnlockRect(data->texture, 0);
   818 }
   819 
   820 static int
   821 D3D_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
   822 {
   823     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   824     D3D_TextureData *texturedata;
   825     HRESULT result;
   826 
   827     D3D_ActivateRenderer(renderer);
   828 
   829     /* Release the previous render target if it wasn't the default one */
   830     if (data->currentRenderTarget != NULL) {
   831         IDirect3DSurface9_Release(data->currentRenderTarget);
   832         data->currentRenderTarget = NULL;
   833     }
   834 
   835     if (texture == NULL) {
   836         IDirect3DDevice9_SetRenderTarget(data->device, 0, data->defaultRenderTarget);
   837         return 0;
   838     }
   839 
   840     texturedata = (D3D_TextureData *) texture->driverdata;
   841     result = IDirect3DTexture9_GetSurfaceLevel(texturedata->texture, 0, &data->currentRenderTarget);
   842     if(FAILED(result)) {
   843         return D3D_SetError("GetSurfaceLevel()", result);
   844     }
   845     result = IDirect3DDevice9_SetRenderTarget(data->device, 0, data->currentRenderTarget);
   846     if(FAILED(result)) {
   847         return D3D_SetError("SetRenderTarget()", result);
   848     }
   849 
   850     return 0;
   851 }
   852 
   853 static int
   854 D3D_UpdateViewport(SDL_Renderer * renderer)
   855 {
   856     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   857     D3DVIEWPORT9 viewport;
   858     D3DMATRIX matrix;
   859 
   860     /* Set the viewport */
   861     viewport.X = renderer->viewport.x;
   862     viewport.Y = renderer->viewport.y;
   863     viewport.Width = renderer->viewport.w;
   864     viewport.Height = renderer->viewport.h;
   865     viewport.MinZ = 0.0f;
   866     viewport.MaxZ = 1.0f;
   867     IDirect3DDevice9_SetViewport(data->device, &viewport);
   868 
   869     /* Set an orthographic projection matrix */
   870     if (renderer->viewport.w && renderer->viewport.h) {
   871         matrix.m[0][0] = 2.0f / renderer->viewport.w;
   872         matrix.m[0][1] = 0.0f;
   873         matrix.m[0][2] = 0.0f;
   874         matrix.m[0][3] = 0.0f;
   875         matrix.m[1][0] = 0.0f;
   876         matrix.m[1][1] = -2.0f / renderer->viewport.h;
   877         matrix.m[1][2] = 0.0f;
   878         matrix.m[1][3] = 0.0f;
   879         matrix.m[2][0] = 0.0f;
   880         matrix.m[2][1] = 0.0f;
   881         matrix.m[2][2] = 1.0f;
   882         matrix.m[2][3] = 0.0f;
   883         matrix.m[3][0] = -1.0f;
   884         matrix.m[3][1] = 1.0f;
   885         matrix.m[3][2] = 0.0f;
   886         matrix.m[3][3] = 1.0f;
   887         IDirect3DDevice9_SetTransform(data->device, D3DTS_PROJECTION, &matrix);
   888     }
   889 
   890     return 0;
   891 }
   892 
   893 static int
   894 D3D_UpdateClipRect(SDL_Renderer * renderer)
   895 {
   896     const SDL_Rect *rect = &renderer->clip_rect;
   897     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   898     RECT r;
   899     HRESULT result;
   900 
   901     if (!SDL_RectEmpty(rect)) {
   902         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, TRUE);
   903         r.left = rect->x;
   904         r.top = rect->y;
   905         r.right = rect->w + rect->w;
   906         r.bottom = rect->y + rect->h;
   907 
   908         result = IDirect3DDevice9_SetScissorRect(data->device, &r);
   909         if (result != D3D_OK) {
   910             D3D_SetError("SetScissor()", result);
   911             return -1;
   912         }
   913     } else {
   914         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, FALSE);
   915     }
   916     return 0;
   917 }
   918 
   919 static int
   920 D3D_RenderClear(SDL_Renderer * renderer)
   921 {
   922     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   923     DWORD color;
   924     HRESULT result;
   925 
   926     if (D3D_ActivateRenderer(renderer) < 0) {
   927         return -1;
   928     }
   929 
   930     color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
   931 
   932     /* Don't reset the viewport if we don't have to! */
   933     if (!renderer->viewport.x && !renderer->viewport.y &&
   934         renderer->viewport.w == data->pparams.BackBufferWidth &&
   935         renderer->viewport.h == data->pparams.BackBufferHeight) {
   936         result = IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
   937     } else {
   938         D3DVIEWPORT9 viewport;
   939 
   940         /* Clear is defined to clear the entire render target */
   941         viewport.X = 0;
   942         viewport.Y = 0;
   943         viewport.Width = data->pparams.BackBufferWidth;
   944         viewport.Height = data->pparams.BackBufferHeight;
   945         viewport.MinZ = 0.0f;
   946         viewport.MaxZ = 1.0f;
   947         IDirect3DDevice9_SetViewport(data->device, &viewport);
   948 
   949         result = IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
   950 
   951         /* Reset the viewport */
   952         viewport.X = renderer->viewport.x;
   953         viewport.Y = renderer->viewport.y;
   954         viewport.Width = renderer->viewport.w;
   955         viewport.Height = renderer->viewport.h;
   956         viewport.MinZ = 0.0f;
   957         viewport.MaxZ = 1.0f;
   958         IDirect3DDevice9_SetViewport(data->device, &viewport);
   959     }
   960 
   961     if (FAILED(result)) {
   962         return D3D_SetError("Clear()", result);
   963     }
   964     return 0;
   965 }
   966 
   967 static void
   968 D3D_SetBlendMode(D3D_RenderData * data, int blendMode)
   969 {
   970     switch (blendMode) {
   971     case SDL_BLENDMODE_NONE:
   972         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
   973                                         FALSE);
   974         break;
   975     case SDL_BLENDMODE_BLEND:
   976         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
   977                                         TRUE);
   978         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
   979                                         D3DBLEND_SRCALPHA);
   980         IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
   981                                         D3DBLEND_INVSRCALPHA);
   982         break;
   983     case SDL_BLENDMODE_ADD:
   984         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
   985                                         TRUE);
   986         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
   987                                         D3DBLEND_SRCALPHA);
   988         IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
   989                                         D3DBLEND_ONE);
   990         break;
   991     case SDL_BLENDMODE_MOD:
   992         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
   993                                         TRUE);
   994         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
   995                                         D3DBLEND_ZERO);
   996         IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
   997                                         D3DBLEND_SRCCOLOR);
   998         break;
   999     }
  1000 }
  1001 
  1002 static int
  1003 D3D_RenderDrawPoints(SDL_Renderer * renderer, const SDL_FPoint * points,
  1004                      int count)
  1005 {
  1006     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1007     DWORD color;
  1008     Vertex *vertices;
  1009     int i;
  1010     HRESULT result;
  1011 
  1012     if (D3D_ActivateRenderer(renderer) < 0) {
  1013         return -1;
  1014     }
  1015 
  1016     D3D_SetBlendMode(data, renderer->blendMode);
  1017 
  1018     result =
  1019         IDirect3DDevice9_SetTexture(data->device, 0,
  1020                                     (IDirect3DBaseTexture9 *) 0);
  1021     if (FAILED(result)) {
  1022         return D3D_SetError("SetTexture()", result);
  1023     }
  1024 
  1025     color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
  1026 
  1027     vertices = SDL_stack_alloc(Vertex, count);
  1028     for (i = 0; i < count; ++i) {
  1029         vertices[i].x = points[i].x;
  1030         vertices[i].y = points[i].y;
  1031         vertices[i].z = 0.0f;
  1032         vertices[i].color = color;
  1033         vertices[i].u = 0.0f;
  1034         vertices[i].v = 0.0f;
  1035     }
  1036     result =
  1037         IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, count,
  1038                                          vertices, sizeof(*vertices));
  1039     SDL_stack_free(vertices);
  1040     if (FAILED(result)) {
  1041         return D3D_SetError("DrawPrimitiveUP()", result);
  1042     }
  1043     return 0;
  1044 }
  1045 
  1046 static int
  1047 D3D_RenderDrawLines(SDL_Renderer * renderer, const SDL_FPoint * points,
  1048                     int count)
  1049 {
  1050     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1051     DWORD color;
  1052     Vertex *vertices;
  1053     int i;
  1054     HRESULT result;
  1055 
  1056     if (D3D_ActivateRenderer(renderer) < 0) {
  1057         return -1;
  1058     }
  1059 
  1060     D3D_SetBlendMode(data, renderer->blendMode);
  1061 
  1062     result =
  1063         IDirect3DDevice9_SetTexture(data->device, 0,
  1064                                     (IDirect3DBaseTexture9 *) 0);
  1065     if (FAILED(result)) {
  1066         return D3D_SetError("SetTexture()", result);
  1067     }
  1068 
  1069     color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
  1070 
  1071     vertices = SDL_stack_alloc(Vertex, count);
  1072     for (i = 0; i < count; ++i) {
  1073         vertices[i].x = points[i].x;
  1074         vertices[i].y = points[i].y;
  1075         vertices[i].z = 0.0f;
  1076         vertices[i].color = color;
  1077         vertices[i].u = 0.0f;
  1078         vertices[i].v = 0.0f;
  1079     }
  1080     result =
  1081         IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_LINESTRIP, count-1,
  1082                                          vertices, sizeof(*vertices));
  1083 
  1084     /* DirectX 9 has the same line rasterization semantics as GDI,
  1085        so we need to close the endpoint of the line */
  1086     if (count == 2 ||
  1087         points[0].x != points[count-1].x || points[0].y != points[count-1].y) {
  1088         vertices[0].x = points[count-1].x;
  1089         vertices[0].y = points[count-1].y;
  1090         result = IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, 1, vertices, sizeof(*vertices));
  1091     }
  1092 
  1093     SDL_stack_free(vertices);
  1094     if (FAILED(result)) {
  1095         return D3D_SetError("DrawPrimitiveUP()", result);
  1096     }
  1097     return 0;
  1098 }
  1099 
  1100 static int
  1101 D3D_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects,
  1102                     int count)
  1103 {
  1104     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1105     DWORD color;
  1106     int i;
  1107     float minx, miny, maxx, maxy;
  1108     Vertex vertices[4];
  1109     HRESULT result;
  1110 
  1111     if (D3D_ActivateRenderer(renderer) < 0) {
  1112         return -1;
  1113     }
  1114 
  1115     D3D_SetBlendMode(data, renderer->blendMode);
  1116 
  1117     result =
  1118         IDirect3DDevice9_SetTexture(data->device, 0,
  1119                                     (IDirect3DBaseTexture9 *) 0);
  1120     if (FAILED(result)) {
  1121         return D3D_SetError("SetTexture()", result);
  1122     }
  1123 
  1124     color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
  1125 
  1126     for (i = 0; i < count; ++i) {
  1127         const SDL_FRect *rect = &rects[i];
  1128 
  1129         minx = rect->x;
  1130         miny = rect->y;
  1131         maxx = rect->x + rect->w;
  1132         maxy = rect->y + rect->h;
  1133 
  1134         vertices[0].x = minx;
  1135         vertices[0].y = miny;
  1136         vertices[0].z = 0.0f;
  1137         vertices[0].color = color;
  1138         vertices[0].u = 0.0f;
  1139         vertices[0].v = 0.0f;
  1140 
  1141         vertices[1].x = maxx;
  1142         vertices[1].y = miny;
  1143         vertices[1].z = 0.0f;
  1144         vertices[1].color = color;
  1145         vertices[1].u = 0.0f;
  1146         vertices[1].v = 0.0f;
  1147 
  1148         vertices[2].x = maxx;
  1149         vertices[2].y = maxy;
  1150         vertices[2].z = 0.0f;
  1151         vertices[2].color = color;
  1152         vertices[2].u = 0.0f;
  1153         vertices[2].v = 0.0f;
  1154 
  1155         vertices[3].x = minx;
  1156         vertices[3].y = maxy;
  1157         vertices[3].z = 0.0f;
  1158         vertices[3].color = color;
  1159         vertices[3].u = 0.0f;
  1160         vertices[3].v = 0.0f;
  1161 
  1162         result =
  1163             IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN,
  1164                                              2, vertices, sizeof(*vertices));
  1165         if (FAILED(result)) {
  1166             return D3D_SetError("DrawPrimitiveUP()", result);
  1167         }
  1168     }
  1169     return 0;
  1170 }
  1171 
  1172 static int
  1173 D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
  1174                const SDL_Rect * srcrect, const SDL_FRect * dstrect)
  1175 {
  1176     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1177     D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata;
  1178     LPDIRECT3DPIXELSHADER9 shader = NULL;
  1179     float minx, miny, maxx, maxy;
  1180     float minu, maxu, minv, maxv;
  1181     DWORD color;
  1182     Vertex vertices[4];
  1183     HRESULT result;
  1184 
  1185     if (D3D_ActivateRenderer(renderer) < 0) {
  1186         return -1;
  1187     }
  1188 
  1189     minx = dstrect->x - 0.5f;
  1190     miny = dstrect->y - 0.5f;
  1191     maxx = dstrect->x + dstrect->w - 0.5f;
  1192     maxy = dstrect->y + dstrect->h - 0.5f;
  1193 
  1194     minu = (float) srcrect->x / texture->w;
  1195     maxu = (float) (srcrect->x + srcrect->w) / texture->w;
  1196     minv = (float) srcrect->y / texture->h;
  1197     maxv = (float) (srcrect->y + srcrect->h) / texture->h;
  1198 
  1199     color = D3DCOLOR_ARGB(texture->a, texture->r, texture->g, texture->b);
  1200 
  1201     vertices[0].x = minx;
  1202     vertices[0].y = miny;
  1203     vertices[0].z = 0.0f;
  1204     vertices[0].color = color;
  1205     vertices[0].u = minu;
  1206     vertices[0].v = minv;
  1207 
  1208     vertices[1].x = maxx;
  1209     vertices[1].y = miny;
  1210     vertices[1].z = 0.0f;
  1211     vertices[1].color = color;
  1212     vertices[1].u = maxu;
  1213     vertices[1].v = minv;
  1214 
  1215     vertices[2].x = maxx;
  1216     vertices[2].y = maxy;
  1217     vertices[2].z = 0.0f;
  1218     vertices[2].color = color;
  1219     vertices[2].u = maxu;
  1220     vertices[2].v = maxv;
  1221 
  1222     vertices[3].x = minx;
  1223     vertices[3].y = maxy;
  1224     vertices[3].z = 0.0f;
  1225     vertices[3].color = color;
  1226     vertices[3].u = minu;
  1227     vertices[3].v = maxv;
  1228 
  1229     D3D_SetBlendMode(data, texture->blendMode);
  1230 
  1231     if (texturedata->scaleMode != data->scaleMode) {
  1232         IDirect3DDevice9_SetSamplerState(data->device, 0, D3DSAMP_MINFILTER,
  1233                                          texturedata->scaleMode);
  1234         IDirect3DDevice9_SetSamplerState(data->device, 0, D3DSAMP_MAGFILTER,
  1235                                          texturedata->scaleMode);
  1236         data->scaleMode = texturedata->scaleMode;
  1237     }
  1238 
  1239     result =
  1240         IDirect3DDevice9_SetTexture(data->device, 0, (IDirect3DBaseTexture9 *)
  1241                                     texturedata->texture);
  1242     if (FAILED(result)) {
  1243         return D3D_SetError("SetTexture()", result);
  1244     }
  1245     if (shader) {
  1246         result = IDirect3DDevice9_SetPixelShader(data->device, shader);
  1247         if (FAILED(result)) {
  1248             return D3D_SetError("SetShader()", result);
  1249         }
  1250     }
  1251     result =
  1252         IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2,
  1253                                          vertices, sizeof(*vertices));
  1254     if (FAILED(result)) {
  1255         return D3D_SetError("DrawPrimitiveUP()", result);
  1256     }
  1257     if (shader) {
  1258         result = IDirect3DDevice9_SetPixelShader(data->device, NULL);
  1259         if (FAILED(result)) {
  1260             return D3D_SetError("SetShader()", result);
  1261         }
  1262     }
  1263     return 0;
  1264 }
  1265 
  1266 
  1267 static int
  1268 D3D_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
  1269                const SDL_Rect * srcrect, const SDL_FRect * dstrect,
  1270                const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip)
  1271 {
  1272     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1273     D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata;
  1274     LPDIRECT3DPIXELSHADER9 shader = NULL;
  1275     float minx, miny, maxx, maxy;
  1276     float minu, maxu, minv, maxv;
  1277     float centerx, centery;
  1278     DWORD color;
  1279     Vertex vertices[4];
  1280     HRESULT result;
  1281 
  1282     if (D3D_ActivateRenderer(renderer) < 0) {
  1283         return -1;
  1284     }
  1285 
  1286     centerx = center->x;
  1287     centery = center->y;
  1288 
  1289     if (flip & SDL_FLIP_HORIZONTAL) {
  1290         minx = dstrect->w - centerx - 0.5f;
  1291         maxx = -centerx - 0.5f;
  1292     }
  1293     else {
  1294         minx = -centerx - 0.5f;
  1295         maxx = dstrect->w - centerx - 0.5f;
  1296     }
  1297 
  1298     if (flip & SDL_FLIP_VERTICAL) {
  1299         miny = dstrect->h - centery - 0.5f;
  1300         maxy = -centery - 0.5f;
  1301     }
  1302     else {
  1303         miny = -centery - 0.5f;
  1304         maxy = dstrect->h - centery - 0.5f;
  1305     }
  1306 
  1307     minu = (float) srcrect->x / texture->w;
  1308     maxu = (float) (srcrect->x + srcrect->w) / texture->w;
  1309     minv = (float) srcrect->y / texture->h;
  1310     maxv = (float) (srcrect->y + srcrect->h) / texture->h;
  1311 
  1312     color = D3DCOLOR_ARGB(texture->a, texture->r, texture->g, texture->b);
  1313 
  1314     vertices[0].x = minx;
  1315     vertices[0].y = miny;
  1316     vertices[0].z = 0.0f;
  1317     vertices[0].color = color;
  1318     vertices[0].u = minu;
  1319     vertices[0].v = minv;
  1320 
  1321     vertices[1].x = maxx;
  1322     vertices[1].y = miny;
  1323     vertices[1].z = 0.0f;
  1324     vertices[1].color = color;
  1325     vertices[1].u = maxu;
  1326     vertices[1].v = minv;
  1327 
  1328     vertices[2].x = maxx;
  1329     vertices[2].y = maxy;
  1330     vertices[2].z = 0.0f;
  1331     vertices[2].color = color;
  1332     vertices[2].u = maxu;
  1333     vertices[2].v = maxv;
  1334 
  1335     vertices[3].x = minx;
  1336     vertices[3].y = maxy;
  1337     vertices[3].z = 0.0f;
  1338     vertices[3].color = color;
  1339     vertices[3].u = minu;
  1340     vertices[3].v = maxv;
  1341 
  1342     D3D_SetBlendMode(data, texture->blendMode);
  1343 
  1344     /* Rotate and translate */
  1345     ID3DXMatrixStack_Push(data->matrixStack);
  1346     ID3DXMatrixStack_LoadIdentity(data->matrixStack);
  1347     ID3DXMatrixStack_RotateYawPitchRoll(data->matrixStack, 0.0, 0.0, (float)(M_PI * (float) angle / 180.0f));
  1348     ID3DXMatrixStack_Translate(data->matrixStack, (float)dstrect->x + centerx, (float)dstrect->y + centery, (float)0.0);
  1349     IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)ID3DXMatrixStack_GetTop(data->matrixStack));
  1350 
  1351     if (texturedata->scaleMode != data->scaleMode) {
  1352         IDirect3DDevice9_SetSamplerState(data->device, 0, D3DSAMP_MINFILTER,
  1353                                          texturedata->scaleMode);
  1354         IDirect3DDevice9_SetSamplerState(data->device, 0, D3DSAMP_MAGFILTER,
  1355                                          texturedata->scaleMode);
  1356         data->scaleMode = texturedata->scaleMode;
  1357     }
  1358 
  1359     result =
  1360         IDirect3DDevice9_SetTexture(data->device, 0, (IDirect3DBaseTexture9 *)
  1361                                     texturedata->texture);
  1362     if (FAILED(result)) {
  1363         return D3D_SetError("SetTexture()", result);
  1364     }
  1365     if (shader) {
  1366         result = IDirect3DDevice9_SetPixelShader(data->device, shader);
  1367         if (FAILED(result)) {
  1368             return D3D_SetError("SetShader()", result);
  1369         }
  1370     }
  1371     result =
  1372         IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2,
  1373                                          vertices, sizeof(*vertices));
  1374     if (FAILED(result)) {
  1375         return D3D_SetError("DrawPrimitiveUP()", result);
  1376     }
  1377     if (shader) {
  1378         result = IDirect3DDevice9_SetPixelShader(data->device, NULL);
  1379         if (FAILED(result)) {
  1380             return D3D_SetError("SetShader()", result);
  1381         }
  1382     }
  1383     ID3DXMatrixStack_Pop(data->matrixStack);
  1384     ID3DXMatrixStack_Push(data->matrixStack);
  1385     ID3DXMatrixStack_LoadIdentity(data->matrixStack);
  1386     IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)ID3DXMatrixStack_GetTop(data->matrixStack));
  1387     ID3DXMatrixStack_Pop(data->matrixStack);
  1388     return 0;
  1389 }
  1390 
  1391 static int
  1392 D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
  1393                      Uint32 format, void * pixels, int pitch)
  1394 {
  1395     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1396     D3DSURFACE_DESC desc;
  1397     LPDIRECT3DSURFACE9 backBuffer;
  1398     LPDIRECT3DSURFACE9 surface;
  1399     RECT d3drect;
  1400     D3DLOCKED_RECT locked;
  1401     HRESULT result;
  1402 
  1403     result = IDirect3DDevice9_GetBackBuffer(data->device, 0, 0, D3DBACKBUFFER_TYPE_MONO, &backBuffer);
  1404     if (FAILED(result)) {
  1405         return D3D_SetError("GetBackBuffer()", result);
  1406     }
  1407 
  1408     result = IDirect3DSurface9_GetDesc(backBuffer, &desc);
  1409     if (FAILED(result)) {
  1410         IDirect3DSurface9_Release(backBuffer);
  1411         return D3D_SetError("GetDesc()", result);
  1412     }
  1413 
  1414     result = IDirect3DDevice9_CreateOffscreenPlainSurface(data->device, desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surface, NULL);
  1415     if (FAILED(result)) {
  1416         IDirect3DSurface9_Release(backBuffer);
  1417         return D3D_SetError("CreateOffscreenPlainSurface()", result);
  1418     }
  1419 
  1420     result = IDirect3DDevice9_GetRenderTargetData(data->device, backBuffer, surface);
  1421     if (FAILED(result)) {
  1422         IDirect3DSurface9_Release(surface);
  1423         IDirect3DSurface9_Release(backBuffer);
  1424         return D3D_SetError("GetRenderTargetData()", result);
  1425     }
  1426 
  1427     d3drect.left = rect->x;
  1428     d3drect.right = rect->x + rect->w;
  1429     d3drect.top = rect->y;
  1430     d3drect.bottom = rect->y + rect->h;
  1431 
  1432     result = IDirect3DSurface9_LockRect(surface, &locked, &d3drect, D3DLOCK_READONLY);
  1433     if (FAILED(result)) {
  1434         IDirect3DSurface9_Release(surface);
  1435         IDirect3DSurface9_Release(backBuffer);
  1436         return D3D_SetError("LockRect()", result);
  1437     }
  1438 
  1439     SDL_ConvertPixels(rect->w, rect->h,
  1440                       D3DFMTToPixelFormat(desc.Format), locked.pBits, locked.Pitch,
  1441                       format, pixels, pitch);
  1442 
  1443     IDirect3DSurface9_UnlockRect(surface);
  1444 
  1445     IDirect3DSurface9_Release(surface);
  1446     IDirect3DSurface9_Release(backBuffer);
  1447 
  1448     return 0;
  1449 }
  1450 
  1451 static void
  1452 D3D_RenderPresent(SDL_Renderer * renderer)
  1453 {
  1454     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1455     HRESULT result;
  1456 
  1457     if (!data->beginScene) {
  1458         IDirect3DDevice9_EndScene(data->device);
  1459         data->beginScene = SDL_TRUE;
  1460     }
  1461 
  1462     result = IDirect3DDevice9_TestCooperativeLevel(data->device);
  1463     if (result == D3DERR_DEVICELOST) {
  1464         /* We'll reset later */
  1465         return;
  1466     }
  1467     if (result == D3DERR_DEVICENOTRESET) {
  1468         D3D_Reset(renderer);
  1469     }
  1470     result = IDirect3DDevice9_Present(data->device, NULL, NULL, NULL, NULL);
  1471     if (FAILED(result)) {
  1472         D3D_SetError("Present()", result);
  1473     }
  1474 }
  1475 
  1476 static void
  1477 D3D_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  1478 {
  1479     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
  1480 
  1481     if (!data) {
  1482         return;
  1483     }
  1484     if (data->texture) {
  1485         IDirect3DTexture9_Release(data->texture);
  1486     }
  1487     SDL_free(data);
  1488     texture->driverdata = NULL;
  1489 }
  1490 
  1491 static void
  1492 D3D_DestroyRenderer(SDL_Renderer * renderer)
  1493 {
  1494     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1495 
  1496     if (data) {
  1497         /* Release the render target */
  1498         if (data->defaultRenderTarget) {
  1499             IDirect3DSurface9_Release(data->defaultRenderTarget);
  1500             data->defaultRenderTarget = NULL;
  1501         }
  1502         if (data->currentRenderTarget != NULL) {
  1503             IDirect3DSurface9_Release(data->currentRenderTarget);
  1504             data->currentRenderTarget = NULL;
  1505         }
  1506 
  1507         if (data->device) {
  1508             IDirect3DDevice9_Release(data->device);
  1509         }
  1510         if (data->d3d) {
  1511             IDirect3D9_Release(data->d3d);
  1512             ID3DXMatrixStack_Release(data->matrixStack);
  1513             SDL_UnloadObject(data->d3dDLL);
  1514         }
  1515         SDL_free(data);
  1516     }
  1517     SDL_free(renderer);
  1518 }
  1519 
  1520 #endif /* SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED */
  1521 
  1522 /* vi: set ts=4 sw=4 expandtab: */