src/render/direct3d/SDL_render_d3d.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 15 Feb 2011 13:59:59 -0800
changeset 5297 1800dc39b74c
parent 5262 b530ef003506
child 5299 33987021a1ed
permissions -rw-r--r--
Changed the concept of a render clip rect to a render viewport.
The render viewport is automatically re-centered when the window changes size, so applications that don't care will not have to handle recalculating their rendering coordinates.

Fixed API for drawing and filling multiple rectangles - the parameter should be an array of rects, not an array of pointers to rects.

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