src/render/direct3d/SDL_render_d3d.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 13 Mar 2011 11:18:35 -0700
changeset 5484 e20c93bc9122
parent 5299 33987021a1ed
child 5535 96594ac5fd1a
permissions -rw-r--r--
Added the SDL_HINT_RENDER_SCALE_QUALITY hint, which defaults to nearest pixel sampling.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2011 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 #if SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED
    25 
    26 
    27 #include "../../core/windows/SDL_windows.h"
    28 
    29 #include "SDL_hints.h"
    30 #include "SDL_loadso.h"
    31 #include "SDL_syswm.h"
    32 #include "../SDL_sysrender.h"
    33 
    34 #if SDL_VIDEO_RENDER_D3D
    35 #define D3D_DEBUG_INFO
    36 #include <d3d9.h>
    37 #endif
    38 
    39 #ifdef ASSEMBLE_SHADER
    40 ///////////////////////////////////////////////////////////////////////////
    41 // ID3DXBuffer:
    42 // ------------
    43 // The buffer object is used by D3DX to return arbitrary size data.
    44 //
    45 // GetBufferPointer -
    46 //    Returns a pointer to the beginning of the buffer.
    47 //
    48 // GetBufferSize -
    49 //    Returns the size of the buffer, in bytes.
    50 ///////////////////////////////////////////////////////////////////////////
    51 
    52 typedef interface ID3DXBuffer ID3DXBuffer;
    53 typedef interface ID3DXBuffer *LPD3DXBUFFER;
    54 
    55 // {8BA5FB08-5195-40e2-AC58-0D989C3A0102}
    56 DEFINE_GUID(IID_ID3DXBuffer, 
    57 0x8ba5fb08, 0x5195, 0x40e2, 0xac, 0x58, 0xd, 0x98, 0x9c, 0x3a, 0x1, 0x2);
    58 
    59 #undef INTERFACE
    60 #define INTERFACE ID3DXBuffer
    61 
    62 typedef interface ID3DXBuffer {
    63     const struct ID3DXBufferVtbl FAR* lpVtbl;
    64 } ID3DXBuffer;
    65 typedef const struct ID3DXBufferVtbl ID3DXBufferVtbl;
    66 const struct ID3DXBufferVtbl
    67 {
    68     // IUnknown
    69     STDMETHOD(QueryInterface)(THIS_ REFIID iid, LPVOID *ppv) PURE;
    70     STDMETHOD_(ULONG, AddRef)(THIS) PURE;
    71     STDMETHOD_(ULONG, Release)(THIS) PURE;
    72 
    73     // ID3DXBuffer
    74     STDMETHOD_(LPVOID, GetBufferPointer)(THIS) PURE;
    75     STDMETHOD_(DWORD, GetBufferSize)(THIS) PURE;
    76 };
    77 
    78 HRESULT WINAPI
    79     D3DXAssembleShader(
    80         LPCSTR                          pSrcData,
    81         UINT                            SrcDataLen,
    82         CONST LPVOID*                   pDefines,
    83         LPVOID                          pInclude,
    84         DWORD                           Flags,
    85         LPD3DXBUFFER*                   ppShader,
    86         LPD3DXBUFFER*                   ppErrorMsgs);
    87 
    88 #endif /* ASSEMBLE_SHADER */
    89 
    90 
    91 /* Direct3D renderer implementation */
    92 
    93 static SDL_Renderer *D3D_CreateRenderer(SDL_Window * window, Uint32 flags);
    94 static void D3D_WindowEvent(SDL_Renderer * renderer,
    95                             const SDL_WindowEvent *event);
    96 static int D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    97 static int D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    98                              const SDL_Rect * rect, const void *pixels,
    99                              int pitch);
   100 static int D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   101                            const SDL_Rect * rect, void **pixels, int *pitch);
   102 static void D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
   103 static int D3D_UpdateViewport(SDL_Renderer * renderer);
   104 static int D3D_RenderClear(SDL_Renderer * renderer);
   105 static int D3D_RenderDrawPoints(SDL_Renderer * renderer,
   106                                 const SDL_Point * points, int count);
   107 static int D3D_RenderDrawLines(SDL_Renderer * renderer,
   108                                const SDL_Point * points, int count);
   109 static int D3D_RenderFillRects(SDL_Renderer * renderer,
   110                                const SDL_Rect * rects, int count);
   111 static int D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   112                           const SDL_Rect * srcrect, const SDL_Rect * dstrect);
   113 static int D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
   114                                 Uint32 format, void * pixels, int pitch);
   115 static void D3D_RenderPresent(SDL_Renderer * renderer);
   116 static void D3D_DestroyTexture(SDL_Renderer * renderer,
   117                                SDL_Texture * texture);
   118 static void D3D_DestroyRenderer(SDL_Renderer * renderer);
   119 
   120 
   121 SDL_RenderDriver D3D_RenderDriver = {
   122     D3D_CreateRenderer,
   123     {
   124      "direct3d",
   125      (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC),
   126      1,
   127      {SDL_PIXELFORMAT_ARGB8888},
   128      0,
   129      0}
   130 };
   131 
   132 typedef struct
   133 {
   134     void* d3dDLL;
   135     IDirect3D9 *d3d;
   136     IDirect3DDevice9 *device;
   137     UINT adapter;
   138     D3DPRESENT_PARAMETERS pparams;
   139     SDL_bool updateSize;
   140     SDL_bool beginScene;
   141     D3DTEXTUREFILTERTYPE scaleMode;
   142 } D3D_RenderData;
   143 
   144 typedef struct
   145 {
   146     IDirect3DTexture9 *texture;
   147     D3DTEXTUREFILTERTYPE scaleMode;
   148 } D3D_TextureData;
   149 
   150 typedef struct
   151 {
   152     float x, y, z;
   153     DWORD color;
   154     float u, v;
   155 } Vertex;
   156 
   157 static void
   158 D3D_SetError(const char *prefix, HRESULT result)
   159 {
   160     const char *error;
   161 
   162     switch (result) {
   163     case D3DERR_WRONGTEXTUREFORMAT:
   164         error = "WRONGTEXTUREFORMAT";
   165         break;
   166     case D3DERR_UNSUPPORTEDCOLOROPERATION:
   167         error = "UNSUPPORTEDCOLOROPERATION";
   168         break;
   169     case D3DERR_UNSUPPORTEDCOLORARG:
   170         error = "UNSUPPORTEDCOLORARG";
   171         break;
   172     case D3DERR_UNSUPPORTEDALPHAOPERATION:
   173         error = "UNSUPPORTEDALPHAOPERATION";
   174         break;
   175     case D3DERR_UNSUPPORTEDALPHAARG:
   176         error = "UNSUPPORTEDALPHAARG";
   177         break;
   178     case D3DERR_TOOMANYOPERATIONS:
   179         error = "TOOMANYOPERATIONS";
   180         break;
   181     case D3DERR_CONFLICTINGTEXTUREFILTER:
   182         error = "CONFLICTINGTEXTUREFILTER";
   183         break;
   184     case D3DERR_UNSUPPORTEDFACTORVALUE:
   185         error = "UNSUPPORTEDFACTORVALUE";
   186         break;
   187     case D3DERR_CONFLICTINGRENDERSTATE:
   188         error = "CONFLICTINGRENDERSTATE";
   189         break;
   190     case D3DERR_UNSUPPORTEDTEXTUREFILTER:
   191         error = "UNSUPPORTEDTEXTUREFILTER";
   192         break;
   193     case D3DERR_CONFLICTINGTEXTUREPALETTE:
   194         error = "CONFLICTINGTEXTUREPALETTE";
   195         break;
   196     case D3DERR_DRIVERINTERNALERROR:
   197         error = "DRIVERINTERNALERROR";
   198         break;
   199     case D3DERR_NOTFOUND:
   200         error = "NOTFOUND";
   201         break;
   202     case D3DERR_MOREDATA:
   203         error = "MOREDATA";
   204         break;
   205     case D3DERR_DEVICELOST:
   206         error = "DEVICELOST";
   207         break;
   208     case D3DERR_DEVICENOTRESET:
   209         error = "DEVICENOTRESET";
   210         break;
   211     case D3DERR_NOTAVAILABLE:
   212         error = "NOTAVAILABLE";
   213         break;
   214     case D3DERR_OUTOFVIDEOMEMORY:
   215         error = "OUTOFVIDEOMEMORY";
   216         break;
   217     case D3DERR_INVALIDDEVICE:
   218         error = "INVALIDDEVICE";
   219         break;
   220     case D3DERR_INVALIDCALL:
   221         error = "INVALIDCALL";
   222         break;
   223     case D3DERR_DRIVERINVALIDCALL:
   224         error = "DRIVERINVALIDCALL";
   225         break;
   226     case D3DERR_WASSTILLDRAWING:
   227         error = "WASSTILLDRAWING";
   228         break;
   229     default:
   230         error = "UNKNOWN";
   231         break;
   232     }
   233     SDL_SetError("%s: %s", prefix, error);
   234 }
   235 
   236 static D3DFORMAT
   237 PixelFormatToD3DFMT(Uint32 format)
   238 {
   239     switch (format) {
   240     case SDL_PIXELFORMAT_RGB565:
   241         return D3DFMT_R5G6B5;
   242     case SDL_PIXELFORMAT_RGB888:
   243         return D3DFMT_X8R8G8B8;
   244     case SDL_PIXELFORMAT_ARGB8888:
   245         return D3DFMT_A8R8G8B8;
   246     default:
   247         return D3DFMT_UNKNOWN;
   248     }
   249 }
   250 
   251 static Uint32
   252 D3DFMTToPixelFormat(D3DFORMAT format)
   253 {
   254     switch (format) {
   255     case D3DFMT_R5G6B5:
   256         return SDL_PIXELFORMAT_RGB565;
   257     case D3DFMT_X8R8G8B8:
   258         return SDL_PIXELFORMAT_RGB888;
   259     case D3DFMT_A8R8G8B8:
   260         return SDL_PIXELFORMAT_ARGB8888;
   261     default:
   262         return SDL_PIXELFORMAT_UNKNOWN;
   263     }
   264 }
   265 
   266 static int
   267 D3D_Reset(SDL_Renderer * renderer)
   268 {
   269     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   270     HRESULT result;
   271 
   272     result = IDirect3DDevice9_Reset(data->device, &data->pparams);
   273     if (FAILED(result)) {
   274         if (result == D3DERR_DEVICELOST) {
   275             /* Don't worry about it, we'll reset later... */
   276             return 0;
   277         } else {
   278             D3D_SetError("Reset()", result);
   279             return -1;
   280         }
   281     }
   282     IDirect3DDevice9_SetVertexShader(data->device, NULL);
   283     IDirect3DDevice9_SetFVF(data->device,
   284                             D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);
   285     IDirect3DDevice9_SetRenderState(data->device, D3DRS_CULLMODE,
   286                                     D3DCULL_NONE);
   287     IDirect3DDevice9_SetRenderState(data->device, D3DRS_LIGHTING, FALSE);
   288     return 0;
   289 }
   290 
   291 static int
   292 D3D_ActivateRenderer(SDL_Renderer * renderer)
   293 {
   294     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   295     HRESULT result;
   296 
   297     if (data->updateSize) {
   298         SDL_Window *window = renderer->window;
   299         int w, h;
   300 
   301         SDL_GetWindowSize(window, &w, &h);
   302         data->pparams.BackBufferWidth = w;
   303         data->pparams.BackBufferHeight = h;
   304         if (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN) {
   305             data->pparams.BackBufferFormat =
   306                 PixelFormatToD3DFMT(SDL_GetWindowPixelFormat(window));
   307         } else {
   308             data->pparams.BackBufferFormat = D3DFMT_UNKNOWN;
   309         }
   310         if (D3D_Reset(renderer) < 0) {
   311             return -1;
   312         }
   313         D3D_UpdateViewport(renderer);
   314 
   315         data->updateSize = SDL_FALSE;
   316     }
   317     if (data->beginScene) {
   318         result = IDirect3DDevice9_BeginScene(data->device);
   319         if (result == D3DERR_DEVICELOST) {
   320             if (D3D_Reset(renderer) < 0) {
   321                 return -1;
   322             }
   323             result = IDirect3DDevice9_BeginScene(data->device);
   324         }
   325         if (FAILED(result)) {
   326             D3D_SetError("BeginScene()", result);
   327             return -1;
   328         }
   329         data->beginScene = SDL_FALSE;
   330     }
   331     return 0;
   332 }
   333 
   334 SDL_Renderer *
   335 D3D_CreateRenderer(SDL_Window * window, Uint32 flags)
   336 {
   337     SDL_Renderer *renderer;
   338     D3D_RenderData *data;
   339     SDL_SysWMinfo windowinfo;
   340     HRESULT result;
   341     D3DPRESENT_PARAMETERS pparams;
   342     IDirect3DSwapChain9 *chain;
   343     D3DCAPS9 caps;
   344     Uint32 window_flags;
   345     int w, h;
   346     SDL_DisplayMode fullscreen_mode;
   347     D3DMATRIX matrix;
   348 
   349     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   350     if (!renderer) {
   351         SDL_OutOfMemory();
   352         return NULL;
   353     }
   354 
   355     data = (D3D_RenderData *) SDL_calloc(1, sizeof(*data));
   356     if (!data) {
   357         SDL_free(renderer);
   358         SDL_OutOfMemory();
   359         return NULL;
   360     }
   361 
   362     data->d3dDLL = SDL_LoadObject("D3D9.DLL");
   363     if (data->d3dDLL) {
   364         IDirect3D9 *(WINAPI * D3DCreate) (UINT SDKVersion);
   365 
   366         D3DCreate =
   367             (IDirect3D9 * (WINAPI *) (UINT)) SDL_LoadFunction(data->d3dDLL,
   368                                                             "Direct3DCreate9");
   369         if (D3DCreate) {
   370             data->d3d = D3DCreate(D3D_SDK_VERSION);
   371         }
   372         if (!data->d3d) {
   373             SDL_UnloadObject(data->d3dDLL);
   374             data->d3dDLL = NULL;
   375         }
   376     }
   377     if (!data->d3d) {
   378         SDL_free(renderer);
   379         SDL_free(data);
   380         SDL_SetError("Unable to create Direct3D interface");
   381         return NULL;
   382     }
   383 
   384     renderer->WindowEvent = D3D_WindowEvent;
   385     renderer->CreateTexture = D3D_CreateTexture;
   386     renderer->UpdateTexture = D3D_UpdateTexture;
   387     renderer->LockTexture = D3D_LockTexture;
   388     renderer->UnlockTexture = D3D_UnlockTexture;
   389     renderer->UpdateViewport = D3D_UpdateViewport;
   390     renderer->RenderClear = D3D_RenderClear;
   391     renderer->RenderDrawPoints = D3D_RenderDrawPoints;
   392     renderer->RenderDrawLines = D3D_RenderDrawLines;
   393     renderer->RenderFillRects = D3D_RenderFillRects;
   394     renderer->RenderCopy = D3D_RenderCopy;
   395     renderer->RenderReadPixels = D3D_RenderReadPixels;
   396     renderer->RenderPresent = D3D_RenderPresent;
   397     renderer->DestroyTexture = D3D_DestroyTexture;
   398     renderer->DestroyRenderer = D3D_DestroyRenderer;
   399     renderer->info = D3D_RenderDriver.info;
   400     renderer->driverdata = data;
   401 
   402     renderer->info.flags = SDL_RENDERER_ACCELERATED;
   403 
   404     SDL_VERSION(&windowinfo.version);
   405     SDL_GetWindowWMInfo(window, &windowinfo);
   406 
   407     window_flags = SDL_GetWindowFlags(window);
   408     SDL_GetWindowSize(window, &w, &h);
   409     SDL_GetWindowDisplayMode(window, &fullscreen_mode);
   410 
   411     SDL_zero(pparams);
   412     pparams.hDeviceWindow = windowinfo.info.win.window;
   413     pparams.BackBufferWidth = w;
   414     pparams.BackBufferHeight = h;
   415     if (window_flags & SDL_WINDOW_FULLSCREEN) {
   416         pparams.BackBufferFormat =
   417             PixelFormatToD3DFMT(fullscreen_mode.format);
   418     } else {
   419         pparams.BackBufferFormat = D3DFMT_UNKNOWN;
   420     }
   421     pparams.BackBufferCount = 1;
   422     pparams.SwapEffect = D3DSWAPEFFECT_DISCARD;
   423 
   424     if (window_flags & SDL_WINDOW_FULLSCREEN) {
   425         pparams.Windowed = FALSE;
   426         pparams.FullScreen_RefreshRateInHz =
   427             fullscreen_mode.refresh_rate;
   428     } else {
   429         pparams.Windowed = TRUE;
   430         pparams.FullScreen_RefreshRateInHz = 0;
   431     }
   432     if (flags & SDL_RENDERER_PRESENTVSYNC) {
   433         pparams.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
   434     } else {
   435         pparams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
   436     }
   437 
   438     /* FIXME: Which adapter? */
   439     data->adapter = D3DADAPTER_DEFAULT;
   440     IDirect3D9_GetDeviceCaps(data->d3d, data->adapter, D3DDEVTYPE_HAL, &caps);
   441 
   442     result = IDirect3D9_CreateDevice(data->d3d, data->adapter,
   443                                      D3DDEVTYPE_HAL,
   444                                      pparams.hDeviceWindow,
   445                                      (caps.
   446                                       DevCaps &
   447                                       D3DDEVCAPS_HWTRANSFORMANDLIGHT) ?
   448                                      D3DCREATE_HARDWARE_VERTEXPROCESSING :
   449                                      D3DCREATE_SOFTWARE_VERTEXPROCESSING,
   450                                      &pparams, &data->device);
   451     if (FAILED(result)) {
   452         D3D_DestroyRenderer(renderer);
   453         D3D_SetError("CreateDevice()", result);
   454         return NULL;
   455     }
   456     data->beginScene = SDL_TRUE;
   457     data->scaleMode = D3DTEXF_FORCE_DWORD;
   458 
   459     /* Get presentation parameters to fill info */
   460     result = IDirect3DDevice9_GetSwapChain(data->device, 0, &chain);
   461     if (FAILED(result)) {
   462         D3D_DestroyRenderer(renderer);
   463         D3D_SetError("GetSwapChain()", result);
   464         return NULL;
   465     }
   466     result = IDirect3DSwapChain9_GetPresentParameters(chain, &pparams);
   467     if (FAILED(result)) {
   468         IDirect3DSwapChain9_Release(chain);
   469         D3D_DestroyRenderer(renderer);
   470         D3D_SetError("GetPresentParameters()", result);
   471         return NULL;
   472     }
   473     IDirect3DSwapChain9_Release(chain);
   474     if (pparams.PresentationInterval == D3DPRESENT_INTERVAL_ONE) {
   475         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
   476     }
   477     data->pparams = pparams;
   478 
   479     IDirect3DDevice9_GetDeviceCaps(data->device, &caps);
   480     renderer->info.max_texture_width = caps.MaxTextureWidth;
   481     renderer->info.max_texture_height = caps.MaxTextureHeight;
   482 
   483     /* Set up parameters for rendering */
   484     IDirect3DDevice9_SetVertexShader(data->device, NULL);
   485     IDirect3DDevice9_SetFVF(data->device,
   486                             D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);
   487     IDirect3DDevice9_SetRenderState(data->device, D3DRS_ZENABLE, D3DZB_FALSE);
   488     IDirect3DDevice9_SetRenderState(data->device, D3DRS_CULLMODE,
   489                                     D3DCULL_NONE);
   490     IDirect3DDevice9_SetRenderState(data->device, D3DRS_LIGHTING, FALSE);
   491     /* Enable color modulation by diffuse color */
   492     IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_COLOROP,
   493                                           D3DTOP_MODULATE);
   494     IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_COLORARG1,
   495                                           D3DTA_TEXTURE);
   496     IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_COLORARG2,
   497                                           D3DTA_DIFFUSE);
   498     /* Enable alpha modulation by diffuse alpha */
   499     IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_ALPHAOP,
   500                                           D3DTOP_MODULATE);
   501     IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_ALPHAARG1,
   502                                           D3DTA_TEXTURE);
   503     IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_ALPHAARG2,
   504                                           D3DTA_DIFFUSE);
   505     /* Disable second texture stage, since we're done */
   506     IDirect3DDevice9_SetTextureStageState(data->device, 1, D3DTSS_COLOROP,
   507                                           D3DTOP_DISABLE);
   508     IDirect3DDevice9_SetTextureStageState(data->device, 1, D3DTSS_ALPHAOP,
   509                                           D3DTOP_DISABLE);
   510 
   511     /* Set an identity world and view matrix */
   512     matrix.m[0][0] = 1.0f;
   513     matrix.m[0][1] = 0.0f;
   514     matrix.m[0][2] = 0.0f;
   515     matrix.m[0][3] = 0.0f;
   516     matrix.m[1][0] = 0.0f;
   517     matrix.m[1][1] = 1.0f;
   518     matrix.m[1][2] = 0.0f;
   519     matrix.m[1][3] = 0.0f;
   520     matrix.m[2][0] = 0.0f;
   521     matrix.m[2][1] = 0.0f;
   522     matrix.m[2][2] = 1.0f;
   523     matrix.m[2][3] = 0.0f;
   524     matrix.m[3][0] = 0.0f;
   525     matrix.m[3][1] = 0.0f;
   526     matrix.m[3][2] = 0.0f;
   527     matrix.m[3][3] = 1.0f;
   528     IDirect3DDevice9_SetTransform(data->device, D3DTS_WORLD, &matrix);
   529     IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, &matrix);
   530 
   531     return renderer;
   532 }
   533 
   534 static void
   535 D3D_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
   536 {
   537     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   538 
   539     if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) {
   540         data->updateSize = SDL_TRUE;
   541     }
   542 }
   543 
   544 static D3DTEXTUREFILTERTYPE
   545 GetScaleQuality(void)
   546 {
   547     const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
   548 
   549     if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) {
   550         return D3DTEXF_POINT;
   551     } else if (*hint == '1' || SDL_strcasecmp(hint, "linear") == 0) {
   552         return D3DTEXF_LINEAR;
   553     } else {
   554         return D3DTEXF_ANISOTROPIC;
   555     }
   556 }
   557 
   558 static int
   559 D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   560 {
   561     D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata;
   562     SDL_Window *window = renderer->window;
   563     D3DFORMAT display_format = renderdata->pparams.BackBufferFormat;
   564     D3D_TextureData *data;
   565     D3DPOOL pool;
   566     DWORD usage;
   567     HRESULT result;
   568 
   569     data = (D3D_TextureData *) SDL_calloc(1, sizeof(*data));
   570     if (!data) {
   571         SDL_OutOfMemory();
   572         return -1;
   573     }
   574     data->scaleMode = GetScaleQuality();
   575 
   576     texture->driverdata = data;
   577 
   578 #ifdef USE_DYNAMIC_TEXTURE
   579     if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
   580         pool = D3DPOOL_DEFAULT;
   581         usage = D3DUSAGE_DYNAMIC;
   582     } else
   583 #endif
   584     {
   585         pool = D3DPOOL_MANAGED;
   586         usage = 0;
   587     }
   588 
   589     result =
   590         IDirect3DDevice9_CreateTexture(renderdata->device, texture->w,
   591                                        texture->h, 1, usage,
   592                                        PixelFormatToD3DFMT(texture->format),
   593                                        pool, &data->texture, NULL);
   594     if (FAILED(result)) {
   595         D3D_SetError("CreateTexture()", result);
   596         return -1;
   597     }
   598 
   599     return 0;
   600 }
   601 
   602 static int
   603 D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   604                   const SDL_Rect * rect, const void *pixels, int pitch)
   605 {
   606     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
   607     D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata;
   608     RECT d3drect;
   609     D3DLOCKED_RECT locked;
   610     const Uint8 *src;
   611     Uint8 *dst;
   612     int row, length;
   613     HRESULT result;
   614 
   615 #ifdef USE_DYNAMIC_TEXTURE
   616     if (texture->access == SDL_TEXTUREACCESS_STREAMING &&
   617         rect->x == 0 && rect->y == 0 &&
   618         rect->w == texture->w && rect->h == texture->h) {
   619         result = IDirect3DTexture9_LockRect(data->texture, 0, &locked, NULL, D3DLOCK_DISCARD);
   620     } else
   621 #endif
   622     {
   623         d3drect.left = rect->x;
   624         d3drect.right = rect->x + rect->w;
   625         d3drect.top = rect->y;
   626         d3drect.bottom = rect->y + rect->h;
   627         result = IDirect3DTexture9_LockRect(data->texture, 0, &locked, &d3drect, 0);
   628     }
   629 
   630     if (FAILED(result)) {
   631         D3D_SetError("LockRect()", result);
   632         return -1;
   633     }
   634 
   635     src = pixels;
   636     dst = locked.pBits;
   637     length = rect->w * SDL_BYTESPERPIXEL(texture->format);
   638     if (length == pitch && length == locked.Pitch) {
   639         SDL_memcpy(dst, src, length*rect->h);
   640     } else {
   641         for (row = 0; row < rect->h; ++row) {
   642             SDL_memcpy(dst, src, length);
   643             src += pitch;
   644             dst += locked.Pitch;
   645         }
   646     }
   647     IDirect3DTexture9_UnlockRect(data->texture, 0);
   648 
   649     return 0;
   650 }
   651 
   652 static int
   653 D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   654                 const SDL_Rect * rect, void **pixels, int *pitch)
   655 {
   656     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
   657     RECT d3drect;
   658     D3DLOCKED_RECT locked;
   659     HRESULT result;
   660 
   661     d3drect.left = rect->x;
   662     d3drect.right = rect->x + rect->w;
   663     d3drect.top = rect->y;
   664     d3drect.bottom = rect->y + rect->h;
   665 
   666     result = IDirect3DTexture9_LockRect(data->texture, 0, &locked, &d3drect, 0);
   667     if (FAILED(result)) {
   668         D3D_SetError("LockRect()", result);
   669         return -1;
   670     }
   671     *pixels = locked.pBits;
   672     *pitch = locked.Pitch;
   673     return 0;
   674 }
   675 
   676 static void
   677 D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   678 {
   679     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
   680 
   681     IDirect3DTexture9_UnlockRect(data->texture, 0);
   682 }
   683 
   684 static int
   685 D3D_UpdateViewport(SDL_Renderer * renderer)
   686 {
   687     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   688     D3DVIEWPORT9 viewport;
   689     D3DMATRIX matrix;
   690 
   691     /* Set the viewport */
   692     viewport.X = renderer->viewport.x;
   693     viewport.Y = renderer->viewport.y;
   694     viewport.Width = renderer->viewport.w;
   695     viewport.Height = renderer->viewport.h;
   696     viewport.MinZ = 0.0f;
   697     viewport.MaxZ = 1.0f;
   698     IDirect3DDevice9_SetViewport(data->device, &viewport);
   699 
   700     /* Set an orthographic projection matrix */
   701     matrix.m[0][0] = 2.0f / renderer->viewport.w;
   702     matrix.m[0][1] = 0.0f;
   703     matrix.m[0][2] = 0.0f;
   704     matrix.m[0][3] = 0.0f;
   705     matrix.m[1][0] = 0.0f;
   706     matrix.m[1][1] = -2.0f / renderer->viewport.h;
   707     matrix.m[1][2] = 0.0f;
   708     matrix.m[1][3] = 0.0f;
   709     matrix.m[2][0] = 0.0f;
   710     matrix.m[2][1] = 0.0f;
   711     matrix.m[2][2] = 1.0f;
   712     matrix.m[2][3] = 0.0f;
   713     matrix.m[3][0] = -1.0f;
   714     matrix.m[3][1] = 1.0f;
   715     matrix.m[3][2] = 0.0f;
   716     matrix.m[3][3] = 1.0f;
   717     IDirect3DDevice9_SetTransform(data->device, D3DTS_PROJECTION, &matrix);
   718 
   719     return 0;
   720 }
   721 
   722 static int
   723 D3D_RenderClear(SDL_Renderer * renderer)
   724 {
   725     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   726     DWORD color;
   727     HRESULT result;
   728 
   729     if (D3D_ActivateRenderer(renderer) < 0) {
   730         return -1;
   731     }
   732 
   733     color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
   734 
   735     /* Don't reset the viewport if we don't have to! */
   736     if (!renderer->viewport.x && !renderer->viewport.y &&
   737         renderer->viewport.w == data->pparams.BackBufferWidth &&
   738         renderer->viewport.h == data->pparams.BackBufferHeight) {
   739         result = IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
   740     } else {
   741         D3DVIEWPORT9 viewport;
   742 
   743         /* Clear is defined to clear the entire render target */
   744         viewport.X = 0;
   745         viewport.Y = 0;
   746         viewport.Width = data->pparams.BackBufferWidth;
   747         viewport.Height = data->pparams.BackBufferHeight;
   748         viewport.MinZ = 0.0f;
   749         viewport.MaxZ = 1.0f;
   750         IDirect3DDevice9_SetViewport(data->device, &viewport);
   751 
   752         result = IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
   753 
   754         /* Reset the viewport */
   755         viewport.X = renderer->viewport.x;
   756         viewport.Y = renderer->viewport.y;
   757         viewport.Width = renderer->viewport.w;
   758         viewport.Height = renderer->viewport.h;
   759         viewport.MinZ = 0.0f;
   760         viewport.MaxZ = 1.0f;
   761         IDirect3DDevice9_SetViewport(data->device, &viewport);
   762     }
   763 
   764     if (FAILED(result)) {
   765         D3D_SetError("Clear()", result);
   766         return -1;
   767     }
   768     return 0;
   769 }
   770 
   771 static void
   772 D3D_SetBlendMode(D3D_RenderData * data, int blendMode)
   773 {
   774     switch (blendMode) {
   775     case SDL_BLENDMODE_NONE:
   776         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
   777                                         FALSE);
   778         break;
   779     case SDL_BLENDMODE_BLEND:
   780         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
   781                                         TRUE);
   782         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
   783                                         D3DBLEND_SRCALPHA);
   784         IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
   785                                         D3DBLEND_INVSRCALPHA);
   786         break;
   787     case SDL_BLENDMODE_ADD:
   788         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
   789                                         TRUE);
   790         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
   791                                         D3DBLEND_SRCALPHA);
   792         IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
   793                                         D3DBLEND_ONE);
   794         break;
   795     case SDL_BLENDMODE_MOD:
   796         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
   797                                         TRUE);
   798         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
   799                                         D3DBLEND_ZERO);
   800         IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
   801                                         D3DBLEND_SRCCOLOR);
   802         break;
   803     }
   804 }
   805 
   806 static int
   807 D3D_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points,
   808                      int count)
   809 {
   810     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   811     DWORD color;
   812     Vertex *vertices;
   813     int i;
   814     HRESULT result;
   815 
   816     if (D3D_ActivateRenderer(renderer) < 0) {
   817         return -1;
   818     }
   819 
   820     D3D_SetBlendMode(data, renderer->blendMode);
   821 
   822     result =
   823         IDirect3DDevice9_SetTexture(data->device, 0,
   824                                     (IDirect3DBaseTexture9 *) 0);
   825     if (FAILED(result)) {
   826         D3D_SetError("SetTexture()", result);
   827         return -1;
   828     }
   829 
   830     color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
   831 
   832     vertices = SDL_stack_alloc(Vertex, count);
   833     for (i = 0; i < count; ++i) {
   834         vertices[i].x = (float) points[i].x;
   835         vertices[i].y = (float) points[i].y;
   836         vertices[i].z = 0.0f;
   837         vertices[i].color = color;
   838         vertices[i].u = 0.0f;
   839         vertices[i].v = 0.0f;
   840     }
   841     result =
   842         IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, count,
   843                                          vertices, sizeof(*vertices));
   844     SDL_stack_free(vertices);
   845     if (FAILED(result)) {
   846         D3D_SetError("DrawPrimitiveUP()", result);
   847         return -1;
   848     }
   849     return 0;
   850 }
   851 
   852 static int
   853 D3D_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points,
   854                     int count)
   855 {
   856     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   857     DWORD color;
   858     Vertex *vertices;
   859     int i;
   860     HRESULT result;
   861 
   862     if (D3D_ActivateRenderer(renderer) < 0) {
   863         return -1;
   864     }
   865 
   866     D3D_SetBlendMode(data, renderer->blendMode);
   867 
   868     result =
   869         IDirect3DDevice9_SetTexture(data->device, 0,
   870                                     (IDirect3DBaseTexture9 *) 0);
   871     if (FAILED(result)) {
   872         D3D_SetError("SetTexture()", result);
   873         return -1;
   874     }
   875 
   876     color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
   877 
   878     vertices = SDL_stack_alloc(Vertex, count);
   879     for (i = 0; i < count; ++i) {
   880         vertices[i].x = (float) points[i].x;
   881         vertices[i].y = (float) points[i].y;
   882         vertices[i].z = 0.0f;
   883         vertices[i].color = color;
   884         vertices[i].u = 0.0f;
   885         vertices[i].v = 0.0f;
   886     }
   887     result =
   888         IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_LINESTRIP, count-1,
   889                                          vertices, sizeof(*vertices));
   890 
   891     /* DirectX 9 has the same line rasterization semantics as GDI,
   892        so we need to close the endpoint of the line */
   893     if (points[0].x != points[count-1].x || points[0].y != points[count-1].y) {
   894         vertices[0].x = (float) points[count-1].x;
   895         vertices[0].y = (float) points[count-1].y;
   896         result = IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, 1, vertices, sizeof(*vertices));
   897     }
   898 
   899     SDL_stack_free(vertices);
   900     if (FAILED(result)) {
   901         D3D_SetError("DrawPrimitiveUP()", result);
   902         return -1;
   903     }
   904     return 0;
   905 }
   906 
   907 static int
   908 D3D_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect * rects,
   909                     int count)
   910 {
   911     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   912     DWORD color;
   913     int i;
   914     float minx, miny, maxx, maxy;
   915     Vertex vertices[4];
   916     HRESULT result;
   917 
   918     if (D3D_ActivateRenderer(renderer) < 0) {
   919         return -1;
   920     }
   921 
   922     D3D_SetBlendMode(data, renderer->blendMode);
   923 
   924     result =
   925         IDirect3DDevice9_SetTexture(data->device, 0,
   926                                     (IDirect3DBaseTexture9 *) 0);
   927     if (FAILED(result)) {
   928         D3D_SetError("SetTexture()", result);
   929         return -1;
   930     }
   931 
   932     color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
   933 
   934     for (i = 0; i < count; ++i) {
   935         const SDL_Rect *rect = &rects[i];
   936 
   937         minx = (float) rect->x;
   938         miny = (float) rect->y;
   939         maxx = (float) rect->x + rect->w;
   940         maxy = (float) rect->y + rect->h;
   941 
   942         vertices[0].x = minx;
   943         vertices[0].y = miny;
   944         vertices[0].z = 0.0f;
   945         vertices[0].color = color;
   946         vertices[0].u = 0.0f;
   947         vertices[0].v = 0.0f;
   948 
   949         vertices[1].x = maxx;
   950         vertices[1].y = miny;
   951         vertices[1].z = 0.0f;
   952         vertices[1].color = color;
   953         vertices[1].u = 0.0f;
   954         vertices[1].v = 0.0f;
   955 
   956         vertices[2].x = maxx;
   957         vertices[2].y = maxy;
   958         vertices[2].z = 0.0f;
   959         vertices[2].color = color;
   960         vertices[2].u = 0.0f;
   961         vertices[2].v = 0.0f;
   962 
   963         vertices[3].x = minx;
   964         vertices[3].y = maxy;
   965         vertices[3].z = 0.0f;
   966         vertices[3].color = color;
   967         vertices[3].u = 0.0f;
   968         vertices[3].v = 0.0f;
   969 
   970         result =
   971             IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN,
   972                                              2, vertices, sizeof(*vertices));
   973         if (FAILED(result)) {
   974             D3D_SetError("DrawPrimitiveUP()", result);
   975             return -1;
   976         }
   977     }
   978     return 0;
   979 }
   980 
   981 static int
   982 D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   983                const SDL_Rect * srcrect, const SDL_Rect * dstrect)
   984 {
   985     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   986     D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata;
   987     LPDIRECT3DPIXELSHADER9 shader = NULL;
   988     float minx, miny, maxx, maxy;
   989     float minu, maxu, minv, maxv;
   990     DWORD color;
   991     Vertex vertices[4];
   992     HRESULT result;
   993 
   994     if (D3D_ActivateRenderer(renderer) < 0) {
   995         return -1;
   996     }
   997 
   998     minx = (float) dstrect->x - 0.5f;
   999     miny = (float) dstrect->y - 0.5f;
  1000     maxx = (float) dstrect->x + dstrect->w - 0.5f;
  1001     maxy = (float) dstrect->y + dstrect->h - 0.5f;
  1002 
  1003     minu = (float) srcrect->x / texture->w;
  1004     maxu = (float) (srcrect->x + srcrect->w) / texture->w;
  1005     minv = (float) srcrect->y / texture->h;
  1006     maxv = (float) (srcrect->y + srcrect->h) / texture->h;
  1007 
  1008     color = D3DCOLOR_ARGB(texture->a, texture->r, texture->g, texture->b);
  1009 
  1010     vertices[0].x = minx;
  1011     vertices[0].y = miny;
  1012     vertices[0].z = 0.0f;
  1013     vertices[0].color = color;
  1014     vertices[0].u = minu;
  1015     vertices[0].v = minv;
  1016 
  1017     vertices[1].x = maxx;
  1018     vertices[1].y = miny;
  1019     vertices[1].z = 0.0f;
  1020     vertices[1].color = color;
  1021     vertices[1].u = maxu;
  1022     vertices[1].v = minv;
  1023 
  1024     vertices[2].x = maxx;
  1025     vertices[2].y = maxy;
  1026     vertices[2].z = 0.0f;
  1027     vertices[2].color = color;
  1028     vertices[2].u = maxu;
  1029     vertices[2].v = maxv;
  1030 
  1031     vertices[3].x = minx;
  1032     vertices[3].y = maxy;
  1033     vertices[3].z = 0.0f;
  1034     vertices[3].color = color;
  1035     vertices[3].u = minu;
  1036     vertices[3].v = maxv;
  1037 
  1038     D3D_SetBlendMode(data, texture->blendMode);
  1039 
  1040     if (texturedata->scaleMode != data->scaleMode) {
  1041         IDirect3DDevice9_SetSamplerState(data->device, 0, D3DSAMP_MINFILTER,
  1042                                          texturedata->scaleMode);
  1043         IDirect3DDevice9_SetSamplerState(data->device, 0, D3DSAMP_MAGFILTER,
  1044                                          texturedata->scaleMode);
  1045         data->scaleMode = texturedata->scaleMode;
  1046     }
  1047 
  1048     result =
  1049         IDirect3DDevice9_SetTexture(data->device, 0, (IDirect3DBaseTexture9 *)
  1050                                     texturedata->texture);
  1051     if (FAILED(result)) {
  1052         D3D_SetError("SetTexture()", result);
  1053         return -1;
  1054     }
  1055     if (shader) {
  1056         result = IDirect3DDevice9_SetPixelShader(data->device, shader);
  1057         if (FAILED(result)) {
  1058             D3D_SetError("SetShader()", result);
  1059             return -1;
  1060         }
  1061     }
  1062     result =
  1063         IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2,
  1064                                          vertices, sizeof(*vertices));
  1065     if (FAILED(result)) {
  1066         D3D_SetError("DrawPrimitiveUP()", result);
  1067         return -1;
  1068     }
  1069     if (shader) {
  1070         result = IDirect3DDevice9_SetPixelShader(data->device, NULL);
  1071         if (FAILED(result)) {
  1072             D3D_SetError("SetShader()", result);
  1073             return -1;
  1074         }
  1075     }
  1076     return 0;
  1077 }
  1078 
  1079 static int
  1080 D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
  1081                      Uint32 format, void * pixels, int pitch)
  1082 {
  1083     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1084     D3DSURFACE_DESC desc;
  1085     LPDIRECT3DSURFACE9 backBuffer;
  1086     LPDIRECT3DSURFACE9 surface;
  1087     RECT d3drect;
  1088     D3DLOCKED_RECT locked;
  1089     HRESULT result;
  1090 
  1091     result = IDirect3DDevice9_GetBackBuffer(data->device, 0, 0, D3DBACKBUFFER_TYPE_MONO, &backBuffer);
  1092     if (FAILED(result)) {
  1093         D3D_SetError("GetBackBuffer()", result);
  1094         return -1;
  1095     }
  1096 
  1097     result = IDirect3DSurface9_GetDesc(backBuffer, &desc);
  1098     if (FAILED(result)) {
  1099         D3D_SetError("GetDesc()", result);
  1100         IDirect3DSurface9_Release(backBuffer);
  1101         return -1;
  1102     }
  1103 
  1104     result = IDirect3DDevice9_CreateOffscreenPlainSurface(data->device, desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surface, NULL);
  1105     if (FAILED(result)) {
  1106         D3D_SetError("CreateOffscreenPlainSurface()", result);
  1107         IDirect3DSurface9_Release(backBuffer);
  1108         return -1;
  1109     }
  1110 
  1111     result = IDirect3DDevice9_GetRenderTargetData(data->device, backBuffer, surface);
  1112     if (FAILED(result)) {
  1113         D3D_SetError("GetRenderTargetData()", result);
  1114         IDirect3DSurface9_Release(surface);
  1115         IDirect3DSurface9_Release(backBuffer);
  1116         return -1;
  1117     }
  1118 
  1119     d3drect.left = rect->x;
  1120     d3drect.right = rect->x + rect->w;
  1121     d3drect.top = rect->y;
  1122     d3drect.bottom = rect->y + rect->h;
  1123 
  1124     result = IDirect3DSurface9_LockRect(surface, &locked, &d3drect, D3DLOCK_READONLY);
  1125     if (FAILED(result)) {
  1126         D3D_SetError("LockRect()", result);
  1127         IDirect3DSurface9_Release(surface);
  1128         IDirect3DSurface9_Release(backBuffer);
  1129         return -1;
  1130     }
  1131 
  1132     SDL_ConvertPixels(rect->w, rect->h,
  1133                       D3DFMTToPixelFormat(desc.Format), locked.pBits, locked.Pitch,
  1134                       format, pixels, pitch);
  1135 
  1136     IDirect3DSurface9_UnlockRect(surface);
  1137 
  1138     IDirect3DSurface9_Release(surface);
  1139     IDirect3DSurface9_Release(backBuffer);
  1140 
  1141     return 0;
  1142 }
  1143 
  1144 static void
  1145 D3D_RenderPresent(SDL_Renderer * renderer)
  1146 {
  1147     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1148     HRESULT result;
  1149 
  1150     if (!data->beginScene) {
  1151         IDirect3DDevice9_EndScene(data->device);
  1152         data->beginScene = SDL_TRUE;
  1153     }
  1154 
  1155     result = IDirect3DDevice9_TestCooperativeLevel(data->device);
  1156     if (result == D3DERR_DEVICELOST) {
  1157         /* We'll reset later */
  1158         return;
  1159     }
  1160     if (result == D3DERR_DEVICENOTRESET) {
  1161         D3D_Reset(renderer);
  1162     }
  1163     result = IDirect3DDevice9_Present(data->device, NULL, NULL, NULL, NULL);
  1164     if (FAILED(result)) {
  1165         D3D_SetError("Present()", result);
  1166     }
  1167 }
  1168 
  1169 static void
  1170 D3D_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  1171 {
  1172     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
  1173 
  1174     if (!data) {
  1175         return;
  1176     }
  1177     if (data->texture) {
  1178         IDirect3DTexture9_Release(data->texture);
  1179     }
  1180     SDL_free(data);
  1181     texture->driverdata = NULL;
  1182 }
  1183 
  1184 static void
  1185 D3D_DestroyRenderer(SDL_Renderer * renderer)
  1186 {
  1187     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1188 
  1189     if (data) {
  1190         if (data->device) {
  1191             IDirect3DDevice9_Release(data->device);
  1192         }
  1193         if (data->d3d) {
  1194             IDirect3D9_Release(data->d3d);
  1195             SDL_UnloadObject(data->d3dDLL);
  1196         }
  1197         SDL_free(data);
  1198     }
  1199     SDL_free(renderer);
  1200 }
  1201 
  1202 #endif /* SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED */
  1203 
  1204 /* vi: set ts=4 sw=4 expandtab: */