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