src/video/windows/SDL_d3drender.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 31 Jan 2011 22:44:43 -0800
changeset 5138 da10636e5eca
parent 5062 e8916fe9cfc8
child 5140 e743b9c3f6d6
permissions -rw-r--r--
Making the API simpler, scaling is always defined as linear interpolation and should be supported as much as possible on all renderers.
     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 "SDL_windowsvideo.h"
    27 #include "../SDL_yuv_sw_c.h"
    28 
    29 #ifdef ASSEMBLE_SHADER
    30 ///////////////////////////////////////////////////////////////////////////
    31 // ID3DXBuffer:
    32 // ------------
    33 // The buffer object is used by D3DX to return arbitrary size data.
    34 //
    35 // GetBufferPointer -
    36 //    Returns a pointer to the beginning of the buffer.
    37 //
    38 // GetBufferSize -
    39 //    Returns the size of the buffer, in bytes.
    40 ///////////////////////////////////////////////////////////////////////////
    41 
    42 typedef interface ID3DXBuffer ID3DXBuffer;
    43 typedef interface ID3DXBuffer *LPD3DXBUFFER;
    44 
    45 // {8BA5FB08-5195-40e2-AC58-0D989C3A0102}
    46 DEFINE_GUID(IID_ID3DXBuffer, 
    47 0x8ba5fb08, 0x5195, 0x40e2, 0xac, 0x58, 0xd, 0x98, 0x9c, 0x3a, 0x1, 0x2);
    48 
    49 #undef INTERFACE
    50 #define INTERFACE ID3DXBuffer
    51 
    52 typedef interface ID3DXBuffer {
    53     const struct ID3DXBufferVtbl FAR* lpVtbl;
    54 } ID3DXBuffer;
    55 typedef const struct ID3DXBufferVtbl ID3DXBufferVtbl;
    56 const struct ID3DXBufferVtbl
    57 {
    58     // IUnknown
    59     STDMETHOD(QueryInterface)(THIS_ REFIID iid, LPVOID *ppv) PURE;
    60     STDMETHOD_(ULONG, AddRef)(THIS) PURE;
    61     STDMETHOD_(ULONG, Release)(THIS) PURE;
    62 
    63     // ID3DXBuffer
    64     STDMETHOD_(LPVOID, GetBufferPointer)(THIS) PURE;
    65     STDMETHOD_(DWORD, GetBufferSize)(THIS) PURE;
    66 };
    67 
    68 HRESULT WINAPI
    69     D3DXAssembleShader(
    70         LPCSTR                          pSrcData,
    71         UINT                            SrcDataLen,
    72         CONST LPVOID*                   pDefines,
    73         LPVOID                          pInclude,
    74         DWORD                           Flags,
    75         LPD3DXBUFFER*                   ppShader,
    76         LPD3DXBUFFER*                   ppErrorMsgs);
    77 
    78 #endif /* ASSEMBLE_SHADER */
    79 
    80 
    81 /* Direct3D renderer implementation */
    82 
    83 #if 1                           /* This takes more memory but you won't lose your texture data */
    84 #define D3DPOOL_SDL    D3DPOOL_MANAGED
    85 #define SDL_MEMORY_POOL_MANAGED
    86 #else
    87 #define D3DPOOL_SDL    D3DPOOL_DEFAULT
    88 #define SDL_MEMORY_POOL_DEFAULT
    89 #endif
    90 
    91 static SDL_Renderer *D3D_CreateRenderer(SDL_Window * window, Uint32 flags);
    92 static int D3D_DisplayModeChanged(SDL_Renderer * renderer);
    93 static int D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    94 static int D3D_QueryTexturePixels(SDL_Renderer * renderer,
    95                                   SDL_Texture * texture, void **pixels,
    96                                   int *pitch);
    97 static int D3D_SetTexturePalette(SDL_Renderer * renderer,
    98                                  SDL_Texture * texture,
    99                                  const SDL_Color * colors, int firstcolor,
   100                                  int ncolors);
   101 static int D3D_GetTexturePalette(SDL_Renderer * renderer,
   102                                  SDL_Texture * texture, SDL_Color * colors,
   103                                  int firstcolor, int ncolors);
   104 static int D3D_SetTextureColorMod(SDL_Renderer * renderer,
   105                                   SDL_Texture * texture);
   106 static int D3D_SetTextureAlphaMod(SDL_Renderer * renderer,
   107                                   SDL_Texture * texture);
   108 static int D3D_SetTextureBlendMode(SDL_Renderer * renderer,
   109                                    SDL_Texture * texture);
   110 static int D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   111                              const SDL_Rect * rect, const void *pixels,
   112                              int pitch);
   113 static int D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   114                            const SDL_Rect * rect, int markDirty,
   115                            void **pixels, int *pitch);
   116 static void D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
   117 static void D3D_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   118                              int numrects, const SDL_Rect * rects);
   119 static int D3D_RenderDrawPoints(SDL_Renderer * renderer,
   120                                 const SDL_Point * points, int count);
   121 static int D3D_RenderDrawLines(SDL_Renderer * renderer,
   122                                const SDL_Point * points, int count);
   123 static int D3D_RenderDrawRects(SDL_Renderer * renderer,
   124                                const SDL_Rect ** rects, int count);
   125 static int D3D_RenderFillRects(SDL_Renderer * renderer,
   126                                const SDL_Rect ** rects, int count);
   127 static int D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   128                           const SDL_Rect * srcrect, const SDL_Rect * dstrect);
   129 static int D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
   130                                 Uint32 format, void * pixels, int pitch);
   131 static int D3D_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect,
   132                                  Uint32 format, const void * pixels, int pitch);
   133 static void D3D_RenderPresent(SDL_Renderer * renderer);
   134 static void D3D_DestroyTexture(SDL_Renderer * renderer,
   135                                SDL_Texture * texture);
   136 static void D3D_DestroyRenderer(SDL_Renderer * renderer);
   137 
   138 
   139 SDL_RenderDriver D3D_RenderDriver = {
   140     D3D_CreateRenderer,
   141     {
   142      "d3d",
   143      (SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_PRESENTCOPY |
   144       SDL_RENDERER_PRESENTFLIP2 | SDL_RENDERER_PRESENTFLIP3 |
   145       SDL_RENDERER_PRESENTDISCARD | SDL_RENDERER_PRESENTVSYNC |
   146       SDL_RENDERER_ACCELERATED),
   147      (SDL_TEXTUREMODULATE_NONE | SDL_TEXTUREMODULATE_COLOR |
   148       SDL_TEXTUREMODULATE_ALPHA),
   149      (SDL_BLENDMODE_NONE | SDL_BLENDMODE_MASK |
   150       SDL_BLENDMODE_BLEND | SDL_BLENDMODE_ADD | SDL_BLENDMODE_MOD),
   151      0,
   152      {0},
   153      0,
   154      0}
   155 };
   156 
   157 typedef struct
   158 {
   159     IDirect3D9 *d3d;
   160     IDirect3DDevice9 *device;
   161     UINT adapter;
   162     D3DPRESENT_PARAMETERS pparams;
   163     LPDIRECT3DPIXELSHADER9 ps_mask;
   164     SDL_bool beginScene;
   165 } D3D_RenderData;
   166 
   167 typedef struct
   168 {
   169     SDL_SW_YUVTexture *yuv;
   170     Uint32 format;
   171     IDirect3DTexture9 *texture;
   172 } D3D_TextureData;
   173 
   174 typedef struct
   175 {
   176     float x, y, z;
   177     float rhw;
   178     DWORD color;
   179     float u, v;
   180 } Vertex;
   181 
   182 static void
   183 D3D_SetError(const char *prefix, HRESULT result)
   184 {
   185     const char *error;
   186 
   187     switch (result) {
   188     case D3DERR_WRONGTEXTUREFORMAT:
   189         error = "WRONGTEXTUREFORMAT";
   190         break;
   191     case D3DERR_UNSUPPORTEDCOLOROPERATION:
   192         error = "UNSUPPORTEDCOLOROPERATION";
   193         break;
   194     case D3DERR_UNSUPPORTEDCOLORARG:
   195         error = "UNSUPPORTEDCOLORARG";
   196         break;
   197     case D3DERR_UNSUPPORTEDALPHAOPERATION:
   198         error = "UNSUPPORTEDALPHAOPERATION";
   199         break;
   200     case D3DERR_UNSUPPORTEDALPHAARG:
   201         error = "UNSUPPORTEDALPHAARG";
   202         break;
   203     case D3DERR_TOOMANYOPERATIONS:
   204         error = "TOOMANYOPERATIONS";
   205         break;
   206     case D3DERR_CONFLICTINGTEXTUREFILTER:
   207         error = "CONFLICTINGTEXTUREFILTER";
   208         break;
   209     case D3DERR_UNSUPPORTEDFACTORVALUE:
   210         error = "UNSUPPORTEDFACTORVALUE";
   211         break;
   212     case D3DERR_CONFLICTINGRENDERSTATE:
   213         error = "CONFLICTINGRENDERSTATE";
   214         break;
   215     case D3DERR_UNSUPPORTEDTEXTUREFILTER:
   216         error = "UNSUPPORTEDTEXTUREFILTER";
   217         break;
   218     case D3DERR_CONFLICTINGTEXTUREPALETTE:
   219         error = "CONFLICTINGTEXTUREPALETTE";
   220         break;
   221     case D3DERR_DRIVERINTERNALERROR:
   222         error = "DRIVERINTERNALERROR";
   223         break;
   224     case D3DERR_NOTFOUND:
   225         error = "NOTFOUND";
   226         break;
   227     case D3DERR_MOREDATA:
   228         error = "MOREDATA";
   229         break;
   230     case D3DERR_DEVICELOST:
   231         error = "DEVICELOST";
   232         break;
   233     case D3DERR_DEVICENOTRESET:
   234         error = "DEVICENOTRESET";
   235         break;
   236     case D3DERR_NOTAVAILABLE:
   237         error = "NOTAVAILABLE";
   238         break;
   239     case D3DERR_OUTOFVIDEOMEMORY:
   240         error = "OUTOFVIDEOMEMORY";
   241         break;
   242     case D3DERR_INVALIDDEVICE:
   243         error = "INVALIDDEVICE";
   244         break;
   245     case D3DERR_INVALIDCALL:
   246         error = "INVALIDCALL";
   247         break;
   248     case D3DERR_DRIVERINVALIDCALL:
   249         error = "DRIVERINVALIDCALL";
   250         break;
   251     case D3DERR_WASSTILLDRAWING:
   252         error = "WASSTILLDRAWING";
   253         break;
   254     default:
   255         error = "UNKNOWN";
   256         break;
   257     }
   258     SDL_SetError("%s: %s", prefix, error);
   259 }
   260 
   261 static D3DFORMAT
   262 PixelFormatToD3DFMT(Uint32 format)
   263 {
   264     switch (format) {
   265     case SDL_PIXELFORMAT_INDEX8:
   266         return D3DFMT_P8;
   267     case SDL_PIXELFORMAT_RGB332:
   268         return D3DFMT_R3G3B2;
   269     case SDL_PIXELFORMAT_RGB444:
   270         return D3DFMT_X4R4G4B4;
   271     case SDL_PIXELFORMAT_RGB555:
   272         return D3DFMT_X1R5G5B5;
   273     case SDL_PIXELFORMAT_ARGB4444:
   274         return D3DFMT_A4R4G4B4;
   275     case SDL_PIXELFORMAT_ARGB1555:
   276         return D3DFMT_A1R5G5B5;
   277     case SDL_PIXELFORMAT_RGB565:
   278         return D3DFMT_R5G6B5;
   279     case SDL_PIXELFORMAT_RGB888:
   280         return D3DFMT_X8R8G8B8;
   281     case SDL_PIXELFORMAT_ARGB8888:
   282         return D3DFMT_A8R8G8B8;
   283     case SDL_PIXELFORMAT_ARGB2101010:
   284         return D3DFMT_A2R10G10B10;
   285     case SDL_PIXELFORMAT_YV12:
   286         return MAKEFOURCC('Y','V','1','2');
   287     case SDL_PIXELFORMAT_IYUV:
   288         return MAKEFOURCC('I','4','2','0');
   289     case SDL_PIXELFORMAT_UYVY:
   290         return D3DFMT_UYVY;
   291     case SDL_PIXELFORMAT_YUY2:
   292         return D3DFMT_YUY2;
   293     default:
   294         return D3DFMT_UNKNOWN;
   295     }
   296 }
   297 
   298 static UINT D3D_FindAdapter(IDirect3D9 * d3d, SDL_VideoDisplay * display)
   299 {
   300     SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata;
   301     UINT adapter, count;
   302 
   303     count = IDirect3D9_GetAdapterCount(d3d);
   304     for (adapter = 0; adapter < count; ++adapter) {
   305         HRESULT result;
   306         D3DADAPTER_IDENTIFIER9 info;
   307         char *name;
   308 
   309         result = IDirect3D9_GetAdapterIdentifier(d3d, adapter, 0, &info);
   310         if (FAILED(result)) {
   311             continue;
   312         }
   313         name = WIN_StringToUTF8(displaydata->DeviceName);
   314         if (SDL_strcmp(name, info.DeviceName) == 0) {
   315             SDL_free(name);
   316             return adapter;
   317         }
   318         SDL_free(name);
   319     }
   320 
   321     /* This should never happen, but just in case... */
   322     return D3DADAPTER_DEFAULT;
   323 }
   324 
   325 static SDL_bool
   326 D3D_IsTextureFormatAvailable(IDirect3D9 * d3d, UINT adapter,
   327                              Uint32 display_format,
   328                              Uint32 texture_format)
   329 {
   330     HRESULT result;
   331 
   332     result = IDirect3D9_CheckDeviceFormat(d3d, adapter,
   333                                           D3DDEVTYPE_HAL,
   334                                           PixelFormatToD3DFMT(display_format),
   335                                           0,
   336                                           D3DRTYPE_TEXTURE,
   337                                           PixelFormatToD3DFMT
   338                                           (texture_format));
   339     return FAILED(result) ? SDL_FALSE : SDL_TRUE;
   340 }
   341 
   342 static void
   343 UpdateYUVTextureData(SDL_Texture * texture)
   344 {
   345     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
   346     SDL_Rect rect;
   347     RECT d3drect;
   348     D3DLOCKED_RECT locked;
   349     HRESULT result;
   350 
   351     d3drect.left = 0;
   352     d3drect.right = texture->w;
   353     d3drect.top = 0;
   354     d3drect.bottom = texture->h;
   355 
   356     result =
   357         IDirect3DTexture9_LockRect(data->texture, 0, &locked, &d3drect, 0);
   358     if (FAILED(result)) {
   359         return;
   360     }
   361 
   362     rect.x = 0;
   363     rect.y = 0;
   364     rect.w = texture->w;
   365     rect.h = texture->h;
   366     SDL_SW_CopyYUVToRGB(data->yuv, &rect, data->format, texture->w,
   367                         texture->h, locked.pBits, locked.Pitch);
   368 
   369     IDirect3DTexture9_UnlockRect(data->texture, 0);
   370 }
   371 
   372 void
   373 D3D_AddRenderDriver(_THIS)
   374 {
   375     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   376     SDL_RendererInfo *info = &D3D_RenderDriver.info;
   377 
   378     if (data->d3d) {
   379         int i, j;
   380         int formats[] = {
   381             SDL_PIXELFORMAT_INDEX8,
   382             SDL_PIXELFORMAT_RGB332,
   383             SDL_PIXELFORMAT_RGB444,
   384             SDL_PIXELFORMAT_RGB555,
   385             SDL_PIXELFORMAT_ARGB4444,
   386             SDL_PIXELFORMAT_ARGB1555,
   387             SDL_PIXELFORMAT_RGB565,
   388             SDL_PIXELFORMAT_RGB888,
   389             SDL_PIXELFORMAT_ARGB8888,
   390             SDL_PIXELFORMAT_ARGB2101010,
   391         };
   392 
   393         for (i = 0; i < _this->num_displays; ++i) {
   394             SDL_VideoDisplay *display = &_this->displays[i];
   395             SDL_DisplayMode *mode = &display->desktop_mode;
   396             UINT adapter = D3D_FindAdapter(data->d3d, display);
   397 
   398             /* Get the matching D3D adapter for this display */
   399             info->num_texture_formats = 0;
   400             for (j = 0; j < SDL_arraysize(formats); ++j) {
   401                 if (D3D_IsTextureFormatAvailable
   402                     (data->d3d, adapter, mode->format, formats[j])) {
   403                     info->texture_formats[info->num_texture_formats++] =
   404                         formats[j];
   405                 }
   406             }
   407             info->texture_formats[info->num_texture_formats++] =
   408                 SDL_PIXELFORMAT_YV12;
   409             info->texture_formats[info->num_texture_formats++] =
   410                 SDL_PIXELFORMAT_IYUV;
   411             info->texture_formats[info->num_texture_formats++] =
   412                 SDL_PIXELFORMAT_YUY2;
   413             info->texture_formats[info->num_texture_formats++] =
   414                 SDL_PIXELFORMAT_UYVY;
   415             info->texture_formats[info->num_texture_formats++] =
   416                 SDL_PIXELFORMAT_YVYU;
   417 
   418             SDL_AddRenderDriver(display, &D3D_RenderDriver);
   419         }
   420     }
   421 }
   422 
   423 SDL_Renderer *
   424 D3D_CreateRenderer(SDL_Window * window, Uint32 flags)
   425 {
   426     SDL_VideoDisplay *display = window->display;
   427     SDL_VideoData *videodata = (SDL_VideoData *) display->device->driverdata;
   428     SDL_WindowData *windowdata = (SDL_WindowData *) window->driverdata;
   429     SDL_Renderer *renderer;
   430     D3D_RenderData *data;
   431     HRESULT result;
   432     D3DPRESENT_PARAMETERS pparams;
   433     IDirect3DSwapChain9 *chain;
   434     D3DCAPS9 caps;
   435 
   436     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   437     if (!renderer) {
   438         SDL_OutOfMemory();
   439         return NULL;
   440     }
   441 
   442     data = (D3D_RenderData *) SDL_calloc(1, sizeof(*data));
   443     if (!data) {
   444         D3D_DestroyRenderer(renderer);
   445         SDL_OutOfMemory();
   446         return NULL;
   447     }
   448     data->d3d = videodata->d3d;
   449 
   450     videodata->render = RENDER_D3D;
   451 
   452     renderer->DisplayModeChanged = D3D_DisplayModeChanged;
   453     renderer->CreateTexture = D3D_CreateTexture;
   454     renderer->QueryTexturePixels = D3D_QueryTexturePixels;
   455     renderer->SetTexturePalette = D3D_SetTexturePalette;
   456     renderer->GetTexturePalette = D3D_GetTexturePalette;
   457     renderer->SetTextureColorMod = D3D_SetTextureColorMod;
   458     renderer->SetTextureAlphaMod = D3D_SetTextureAlphaMod;
   459     renderer->SetTextureBlendMode = D3D_SetTextureBlendMode;
   460     renderer->UpdateTexture = D3D_UpdateTexture;
   461     renderer->LockTexture = D3D_LockTexture;
   462     renderer->UnlockTexture = D3D_UnlockTexture;
   463     renderer->DirtyTexture = D3D_DirtyTexture;
   464     renderer->RenderDrawPoints = D3D_RenderDrawPoints;
   465     renderer->RenderDrawLines = D3D_RenderDrawLines;
   466     renderer->RenderDrawRects = D3D_RenderDrawRects;
   467     renderer->RenderFillRects = D3D_RenderFillRects;
   468     renderer->RenderCopy = D3D_RenderCopy;
   469     renderer->RenderReadPixels = D3D_RenderReadPixels;
   470     renderer->RenderWritePixels = D3D_RenderWritePixels;
   471     renderer->RenderPresent = D3D_RenderPresent;
   472     renderer->DestroyTexture = D3D_DestroyTexture;
   473     renderer->DestroyRenderer = D3D_DestroyRenderer;
   474     renderer->info = D3D_RenderDriver.info;
   475     renderer->window = window;
   476     renderer->driverdata = data;
   477 
   478     renderer->info.flags = SDL_RENDERER_ACCELERATED;
   479 
   480     SDL_zero(pparams);
   481     pparams.BackBufferWidth = window->w;
   482     pparams.BackBufferHeight = window->h;
   483     if (window->flags & SDL_WINDOW_FULLSCREEN) {
   484         pparams.BackBufferFormat =
   485             PixelFormatToD3DFMT(window->fullscreen_mode.format);
   486     } else {
   487         pparams.BackBufferFormat = D3DFMT_UNKNOWN;
   488     }
   489     if (flags & SDL_RENDERER_PRESENTFLIP2) {
   490         pparams.BackBufferCount = 2;
   491         pparams.SwapEffect = D3DSWAPEFFECT_FLIP;
   492     } else if (flags & SDL_RENDERER_PRESENTFLIP3) {
   493         pparams.BackBufferCount = 3;
   494         pparams.SwapEffect = D3DSWAPEFFECT_FLIP;
   495     } else if (flags & SDL_RENDERER_PRESENTCOPY) {
   496         pparams.BackBufferCount = 1;
   497         pparams.SwapEffect = D3DSWAPEFFECT_COPY;
   498     } else {
   499         pparams.BackBufferCount = 1;
   500         pparams.SwapEffect = D3DSWAPEFFECT_DISCARD;
   501     }
   502     if (window->flags & SDL_WINDOW_FULLSCREEN) {
   503         pparams.Windowed = FALSE;
   504         pparams.FullScreen_RefreshRateInHz =
   505             window->fullscreen_mode.refresh_rate;
   506     } else {
   507         pparams.Windowed = TRUE;
   508         pparams.FullScreen_RefreshRateInHz = 0;
   509     }
   510     if (flags & SDL_RENDERER_PRESENTVSYNC) {
   511         pparams.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
   512     } else {
   513         pparams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
   514     }
   515 
   516     data->adapter = D3D_FindAdapter(videodata->d3d, display);
   517     IDirect3D9_GetDeviceCaps(videodata->d3d, data->adapter,
   518                              D3DDEVTYPE_HAL, &caps);
   519 
   520     result = IDirect3D9_CreateDevice(videodata->d3d, data->adapter,
   521                                      D3DDEVTYPE_HAL,
   522                                      windowdata->hwnd,
   523                                      (caps.
   524                                       DevCaps &
   525                                       D3DDEVCAPS_HWTRANSFORMANDLIGHT) ?
   526                                      D3DCREATE_HARDWARE_VERTEXPROCESSING :
   527                                      D3DCREATE_SOFTWARE_VERTEXPROCESSING,
   528                                      &pparams, &data->device);
   529     if (FAILED(result)) {
   530         D3D_DestroyRenderer(renderer);
   531         D3D_SetError("CreateDevice()", result);
   532         return NULL;
   533     }
   534     data->beginScene = SDL_TRUE;
   535 
   536     /* Get presentation parameters to fill info */
   537     result = IDirect3DDevice9_GetSwapChain(data->device, 0, &chain);
   538     if (FAILED(result)) {
   539         D3D_DestroyRenderer(renderer);
   540         D3D_SetError("GetSwapChain()", result);
   541         return NULL;
   542     }
   543     result = IDirect3DSwapChain9_GetPresentParameters(chain, &pparams);
   544     if (FAILED(result)) {
   545         IDirect3DSwapChain9_Release(chain);
   546         D3D_DestroyRenderer(renderer);
   547         D3D_SetError("GetPresentParameters()", result);
   548         return NULL;
   549     }
   550     IDirect3DSwapChain9_Release(chain);
   551     switch (pparams.SwapEffect) {
   552     case D3DSWAPEFFECT_COPY:
   553         renderer->info.flags |= SDL_RENDERER_PRESENTCOPY;
   554         break;
   555     case D3DSWAPEFFECT_FLIP:
   556         switch (pparams.BackBufferCount) {
   557         case 2:
   558             renderer->info.flags |= SDL_RENDERER_PRESENTFLIP2;
   559             break;
   560         case 3:
   561             renderer->info.flags |= SDL_RENDERER_PRESENTFLIP3;
   562             break;
   563         }
   564         break;
   565     case D3DSWAPEFFECT_DISCARD:
   566         renderer->info.flags |= SDL_RENDERER_PRESENTDISCARD;
   567         break;
   568     }
   569     if (pparams.PresentationInterval == D3DPRESENT_INTERVAL_ONE) {
   570         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
   571     }
   572     data->pparams = pparams;
   573 
   574     IDirect3DDevice9_GetDeviceCaps(data->device, &caps);
   575     renderer->info.max_texture_width = caps.MaxTextureWidth;
   576     renderer->info.max_texture_height = caps.MaxTextureHeight;
   577 
   578     /* Set up parameters for rendering */
   579     IDirect3DDevice9_SetVertexShader(data->device, NULL);
   580     IDirect3DDevice9_SetFVF(data->device,
   581                             D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1);
   582     IDirect3DDevice9_SetRenderState(data->device, D3DRS_ZENABLE, D3DZB_FALSE);
   583     IDirect3DDevice9_SetRenderState(data->device, D3DRS_CULLMODE,
   584                                     D3DCULL_NONE);
   585     IDirect3DDevice9_SetRenderState(data->device, D3DRS_LIGHTING, FALSE);
   586     /* Enable color modulation by diffuse color */
   587     IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_COLOROP,
   588                                           D3DTOP_MODULATE);
   589     IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_COLORARG1,
   590                                           D3DTA_TEXTURE);
   591     IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_COLORARG2,
   592                                           D3DTA_DIFFUSE);
   593     /* Enable alpha modulation by diffuse alpha */
   594     IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_ALPHAOP,
   595                                           D3DTOP_MODULATE);
   596     IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_ALPHAARG1,
   597                                           D3DTA_TEXTURE);
   598     IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_ALPHAARG2,
   599                                           D3DTA_DIFFUSE);
   600     /* Disable second texture stage, since we're done */
   601     IDirect3DDevice9_SetTextureStageState(data->device, 1, D3DTSS_COLOROP,
   602                                           D3DTOP_DISABLE);
   603     IDirect3DDevice9_SetTextureStageState(data->device, 1, D3DTSS_ALPHAOP,
   604                                           D3DTOP_DISABLE);
   605 
   606     {
   607 #ifdef ASSEMBLE_SHADER
   608         const char *shader_text =
   609 "ps_1_1\n"
   610 "def c0, 0, 0, 0, 0.496\n"
   611 "def c1, 0, 0, 0, 1\n"
   612 "def c2, 0, 0, 0, -1\n"
   613 "tex t0\n"
   614 "mul r1, t0, v0\n"
   615 "add r0, r1, c0\n"
   616 "cnd r0, r0.a, c1, c2\n"
   617 "add r0, r0, r1\n";
   618         LPD3DXBUFFER pCode;         // buffer with the assembled shader code
   619         LPD3DXBUFFER pErrorMsgs;    // buffer with error messages
   620         LPDWORD shader_data;
   621         DWORD   shader_size;
   622         result = D3DXAssembleShader( shader_text, SDL_strlen(shader_text), NULL, NULL, 0, &pCode, &pErrorMsgs );
   623         if (FAILED(result)) {
   624             D3D_SetError("D3DXAssembleShader()", result);
   625         }
   626         shader_data = (DWORD*)pCode->lpVtbl->GetBufferPointer(pCode);
   627         shader_size = pCode->lpVtbl->GetBufferSize(pCode);
   628 #else
   629         const DWORD shader_data[] = {
   630             0xffff0101,0x00000051,0xa00f0000,0x00000000,0x00000000,0x00000000,
   631             0x3efdf3b6,0x00000051,0xa00f0001,0x00000000,0x00000000,0x00000000,
   632             0x3f800000,0x00000051,0xa00f0002,0x00000000,0x00000000,0x00000000,
   633             0xbf800000,0x00000042,0xb00f0000,0x00000005,0x800f0001,0xb0e40000,
   634             0x90e40000,0x00000002,0x800f0000,0x80e40001,0xa0e40000,0x00000050,
   635             0x800f0000,0x80ff0000,0xa0e40001,0xa0e40002,0x00000002,0x800f0000,
   636             0x80e40000,0x80e40001,0x0000ffff
   637         };
   638 #endif
   639         result = IDirect3DDevice9_CreatePixelShader(data->device, shader_data, &data->ps_mask);
   640         if (FAILED(result)) {
   641             D3D_SetError("CreatePixelShader()", result);
   642         }
   643     }
   644 
   645     return renderer;
   646 }
   647 
   648 static int
   649 D3D_Reset(SDL_Renderer * renderer)
   650 {
   651     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   652     HRESULT result;
   653 
   654     result = IDirect3DDevice9_Reset(data->device, &data->pparams);
   655     if (FAILED(result)) {
   656         if (result == D3DERR_DEVICELOST) {
   657             /* Don't worry about it, we'll reset later... */
   658             return 0;
   659         } else {
   660             D3D_SetError("Reset()", result);
   661             return -1;
   662         }
   663     }
   664     IDirect3DDevice9_SetVertexShader(data->device, NULL);
   665     IDirect3DDevice9_SetFVF(data->device,
   666                             D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1);
   667     IDirect3DDevice9_SetRenderState(data->device, D3DRS_CULLMODE,
   668                                     D3DCULL_NONE);
   669     IDirect3DDevice9_SetRenderState(data->device, D3DRS_LIGHTING, FALSE);
   670     return 0;
   671 }
   672 
   673 static int
   674 D3D_DisplayModeChanged(SDL_Renderer * renderer)
   675 {
   676     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   677     SDL_Window *window = renderer->window;
   678     SDL_VideoDisplay *display = window->display;
   679 
   680     data->pparams.BackBufferWidth = window->w;
   681     data->pparams.BackBufferHeight = window->h;
   682     if (window->flags & SDL_WINDOW_FULLSCREEN) {
   683         data->pparams.BackBufferFormat =
   684             PixelFormatToD3DFMT(window->fullscreen_mode.format);
   685     } else {
   686         data->pparams.BackBufferFormat = D3DFMT_UNKNOWN;
   687     }
   688     return D3D_Reset(renderer);
   689 }
   690 
   691 static int
   692 D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   693 {
   694     D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata;
   695     SDL_Window *window = renderer->window;
   696     SDL_VideoDisplay *display = window->display;
   697     Uint32 display_format = display->current_mode.format;
   698     D3D_TextureData *data;
   699     HRESULT result;
   700 
   701     data = (D3D_TextureData *) SDL_calloc(1, sizeof(*data));
   702     if (!data) {
   703         SDL_OutOfMemory();
   704         return -1;
   705     }
   706 
   707     texture->driverdata = data;
   708 
   709     if (SDL_ISPIXELFORMAT_FOURCC(texture->format) &&
   710         (texture->format != SDL_PIXELFORMAT_YUY2 ||
   711          !D3D_IsTextureFormatAvailable(renderdata->d3d, renderdata->adapter,
   712                                        display_format, texture->format))
   713         && (texture->format != SDL_PIXELFORMAT_YVYU
   714             || !D3D_IsTextureFormatAvailable(renderdata->d3d, renderdata->adapter,
   715                                              display_format, texture->format))) {
   716         data->yuv =
   717             SDL_SW_CreateYUVTexture(texture->format, texture->w, texture->h);
   718         if (!data->yuv) {
   719             return -1;
   720         }
   721         data->format = display->current_mode.format;
   722     } else {
   723         data->format = texture->format;
   724     }
   725 
   726     result =
   727         IDirect3DDevice9_CreateTexture(renderdata->device, texture->w,
   728                                        texture->h, 1, 0,
   729                                        PixelFormatToD3DFMT(data->format),
   730                                        D3DPOOL_SDL, &data->texture, NULL);
   731     if (FAILED(result)) {
   732         D3D_SetError("CreateTexture()", result);
   733         return -1;
   734     }
   735 
   736     return 0;
   737 }
   738 
   739 static int
   740 D3D_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture,
   741                        void **pixels, int *pitch)
   742 {
   743     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
   744 
   745     if (data->yuv) {
   746         return SDL_SW_QueryYUVTexturePixels(data->yuv, pixels, pitch);
   747     } else {
   748         /* D3D textures don't have their pixels hanging out */
   749         return -1;
   750     }
   751 }
   752 
   753 static int
   754 D3D_SetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
   755                       const SDL_Color * colors, int firstcolor, int ncolors)
   756 {
   757     D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata;
   758     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
   759 
   760     return 0;
   761 }
   762 
   763 static int
   764 D3D_GetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
   765                       SDL_Color * colors, int firstcolor, int ncolors)
   766 {
   767     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
   768 
   769     return 0;
   770 }
   771 
   772 static int
   773 D3D_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture)
   774 {
   775     return 0;
   776 }
   777 
   778 static int
   779 D3D_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture)
   780 {
   781     return 0;
   782 }
   783 
   784 static int
   785 D3D_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture)
   786 {
   787     switch (texture->blendMode) {
   788     case SDL_BLENDMODE_NONE:
   789     case SDL_BLENDMODE_MASK:
   790     case SDL_BLENDMODE_BLEND:
   791     case SDL_BLENDMODE_ADD:
   792     case SDL_BLENDMODE_MOD:
   793         return 0;
   794     default:
   795         SDL_Unsupported();
   796         texture->blendMode = SDL_BLENDMODE_NONE;
   797         return -1;
   798     }
   799 }
   800 
   801 static int
   802 D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   803                   const SDL_Rect * rect, const void *pixels, int pitch)
   804 {
   805     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
   806     D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata;
   807 
   808     if (data->yuv) {
   809         if (SDL_SW_UpdateYUVTexture(data->yuv, rect, pixels, pitch) < 0) {
   810             return -1;
   811         }
   812         UpdateYUVTextureData(texture);
   813         return 0;
   814     } else {
   815 #ifdef SDL_MEMORY_POOL_DEFAULT
   816         IDirect3DTexture9 *temp;
   817         RECT d3drect;
   818         D3DLOCKED_RECT locked;
   819         const Uint8 *src;
   820         Uint8 *dst;
   821         int row, length;
   822         HRESULT result;
   823 
   824         result =
   825             IDirect3DDevice9_CreateTexture(renderdata->device, texture->w,
   826                                            texture->h, 1, 0,
   827                                            PixelFormatToD3DFMT(texture->
   828                                                                format),
   829                                            D3DPOOL_SYSTEMMEM, &temp, NULL);
   830         if (FAILED(result)) {
   831             D3D_SetError("CreateTexture()", result);
   832             return -1;
   833         }
   834 
   835         d3drect.left = rect->x;
   836         d3drect.right = rect->x + rect->w;
   837         d3drect.top = rect->y;
   838         d3drect.bottom = rect->y + rect->h;
   839 
   840         result = IDirect3DTexture9_LockRect(temp, 0, &locked, &d3drect, 0);
   841         if (FAILED(result)) {
   842             IDirect3DTexture9_Release(temp);
   843             D3D_SetError("LockRect()", result);
   844             return -1;
   845         }
   846 
   847         src = pixels;
   848         dst = locked.pBits;
   849         length = rect->w * SDL_BYTESPERPIXEL(texture->format);
   850         for (row = 0; row < rect->h; ++row) {
   851             SDL_memcpy(dst, src, length);
   852             src += pitch;
   853             dst += locked.Pitch;
   854         }
   855         IDirect3DTexture9_UnlockRect(temp, 0);
   856 
   857         result =
   858             IDirect3DDevice9_UpdateTexture(renderdata->device,
   859                                            (IDirect3DBaseTexture9 *) temp,
   860                                            (IDirect3DBaseTexture9 *)
   861                                            data->texture);
   862         IDirect3DTexture9_Release(temp);
   863         if (FAILED(result)) {
   864             D3D_SetError("UpdateTexture()", result);
   865             return -1;
   866         }
   867 #else
   868         RECT d3drect;
   869         D3DLOCKED_RECT locked;
   870         const Uint8 *src;
   871         Uint8 *dst;
   872         int row, length;
   873         HRESULT result;
   874 
   875         d3drect.left = rect->x;
   876         d3drect.right = rect->x + rect->w;
   877         d3drect.top = rect->y;
   878         d3drect.bottom = rect->y + rect->h;
   879 
   880         result =
   881             IDirect3DTexture9_LockRect(data->texture, 0, &locked, &d3drect,
   882                                        0);
   883         if (FAILED(result)) {
   884             D3D_SetError("LockRect()", result);
   885             return -1;
   886         }
   887 
   888         src = pixels;
   889         dst = locked.pBits;
   890         length = rect->w * SDL_BYTESPERPIXEL(texture->format);
   891         for (row = 0; row < rect->h; ++row) {
   892             SDL_memcpy(dst, src, length);
   893             src += pitch;
   894             dst += locked.Pitch;
   895         }
   896         IDirect3DTexture9_UnlockRect(data->texture, 0);
   897 #endif // SDL_MEMORY_POOL_DEFAULT
   898 
   899         return 0;
   900     }
   901 }
   902 
   903 static int
   904 D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   905                 const SDL_Rect * rect, int markDirty, void **pixels,
   906                 int *pitch)
   907 {
   908     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
   909 
   910     if (data->yuv) {
   911         return SDL_SW_LockYUVTexture(data->yuv, rect, markDirty, pixels,
   912                                      pitch);
   913     } else {
   914         RECT d3drect;
   915         D3DLOCKED_RECT locked;
   916         HRESULT result;
   917 
   918         d3drect.left = rect->x;
   919         d3drect.right = rect->x + rect->w;
   920         d3drect.top = rect->y;
   921         d3drect.bottom = rect->y + rect->h;
   922 
   923         result =
   924             IDirect3DTexture9_LockRect(data->texture, 0, &locked, &d3drect,
   925                                        markDirty ? 0 :
   926                                        D3DLOCK_NO_DIRTY_UPDATE);
   927         if (FAILED(result)) {
   928             D3D_SetError("LockRect()", result);
   929             return -1;
   930         }
   931         *pixels = locked.pBits;
   932         *pitch = locked.Pitch;
   933         return 0;
   934     }
   935 }
   936 
   937 static void
   938 D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   939 {
   940     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
   941 
   942     if (data->yuv) {
   943         SDL_SW_UnlockYUVTexture(data->yuv);
   944         UpdateYUVTextureData(texture);
   945     } else {
   946         IDirect3DTexture9_UnlockRect(data->texture, 0);
   947     }
   948 }
   949 
   950 static void
   951 D3D_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture, int numrects,
   952                  const SDL_Rect * rects)
   953 {
   954     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
   955     RECT d3drect;
   956     int i;
   957 
   958     for (i = 0; i < numrects; ++i) {
   959         const SDL_Rect *rect = &rects[i];
   960 
   961         d3drect.left = rect->x;
   962         d3drect.right = rect->x + rect->w;
   963         d3drect.top = rect->y;
   964         d3drect.bottom = rect->y + rect->h;
   965 
   966         IDirect3DTexture9_AddDirtyRect(data->texture, &d3drect);
   967     }
   968 }
   969 
   970 static void
   971 D3D_SetBlendMode(D3D_RenderData * data, int blendMode)
   972 {
   973     switch (blendMode) {
   974     case SDL_BLENDMODE_NONE:
   975         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
   976                                         FALSE);
   977         break;
   978     case SDL_BLENDMODE_MASK:
   979     case SDL_BLENDMODE_BLEND:
   980         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
   981                                         TRUE);
   982         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
   983                                         D3DBLEND_SRCALPHA);
   984         IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
   985                                         D3DBLEND_INVSRCALPHA);
   986         break;
   987     case SDL_BLENDMODE_ADD:
   988         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
   989                                         TRUE);
   990         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
   991                                         D3DBLEND_SRCALPHA);
   992         IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
   993                                         D3DBLEND_ONE);
   994         break;
   995     case SDL_BLENDMODE_MOD:
   996         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
   997                                         TRUE);
   998         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
   999                                         D3DBLEND_ZERO);
  1000         IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
  1001                                         D3DBLEND_SRCCOLOR);
  1002         break;
  1003     }
  1004 }
  1005 
  1006 static int
  1007 D3D_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points,
  1008                      int count)
  1009 {
  1010     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1011     DWORD color;
  1012     Vertex *vertices;
  1013     int i;
  1014     HRESULT result;
  1015 
  1016     if (data->beginScene) {
  1017         IDirect3DDevice9_BeginScene(data->device);
  1018         data->beginScene = SDL_FALSE;
  1019     }
  1020 
  1021     D3D_SetBlendMode(data, renderer->blendMode);
  1022 
  1023     result =
  1024         IDirect3DDevice9_SetTexture(data->device, 0,
  1025                                     (IDirect3DBaseTexture9 *) 0);
  1026     if (FAILED(result)) {
  1027         D3D_SetError("SetTexture()", result);
  1028         return -1;
  1029     }
  1030 
  1031     color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
  1032 
  1033     vertices = SDL_stack_alloc(Vertex, count);
  1034     for (i = 0; i < count; ++i) {
  1035         vertices[i].x = (float) points[i].x;
  1036         vertices[i].y = (float) points[i].y;
  1037         vertices[i].z = 0.0f;
  1038         vertices[i].rhw = 1.0f;
  1039         vertices[i].color = color;
  1040         vertices[i].u = 0.0f;
  1041         vertices[i].v = 0.0f;
  1042     }
  1043     result =
  1044         IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, count,
  1045                                          vertices, sizeof(*vertices));
  1046     SDL_stack_free(vertices);
  1047     if (FAILED(result)) {
  1048         D3D_SetError("DrawPrimitiveUP()", result);
  1049         return -1;
  1050     }
  1051     return 0;
  1052 }
  1053 
  1054 static int
  1055 D3D_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points,
  1056                     int count)
  1057 {
  1058     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1059     DWORD color;
  1060     Vertex *vertices;
  1061     int i;
  1062     HRESULT result;
  1063 
  1064     if (data->beginScene) {
  1065         IDirect3DDevice9_BeginScene(data->device);
  1066         data->beginScene = SDL_FALSE;
  1067     }
  1068 
  1069     D3D_SetBlendMode(data, renderer->blendMode);
  1070 
  1071     result =
  1072         IDirect3DDevice9_SetTexture(data->device, 0,
  1073                                     (IDirect3DBaseTexture9 *) 0);
  1074     if (FAILED(result)) {
  1075         D3D_SetError("SetTexture()", result);
  1076         return -1;
  1077     }
  1078 
  1079     color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
  1080 
  1081     vertices = SDL_stack_alloc(Vertex, count);
  1082     for (i = 0; i < count; ++i) {
  1083         vertices[i].x = (float) points[i].x;
  1084         vertices[i].y = (float) points[i].y;
  1085         vertices[i].z = 0.0f;
  1086         vertices[i].rhw = 1.0f;
  1087         vertices[i].color = color;
  1088         vertices[i].u = 0.0f;
  1089         vertices[i].v = 0.0f;
  1090     }
  1091     result =
  1092         IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_LINESTRIP, count-1,
  1093                                          vertices, sizeof(*vertices));
  1094 
  1095     /* DirectX 9 has the same line rasterization semantics as GDI,
  1096        so we need to close the endpoint of the line */
  1097     if (points[0].x != points[count-1].x || points[0].y != points[count-1].y) {
  1098         vertices[0].x = (float) points[count-1].x;
  1099         vertices[0].y = (float) points[count-1].y;
  1100         result = IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, 1, vertices, sizeof(*vertices));
  1101     }
  1102 
  1103     SDL_stack_free(vertices);
  1104     if (FAILED(result)) {
  1105         D3D_SetError("DrawPrimitiveUP()", result);
  1106         return -1;
  1107     }
  1108     return 0;
  1109 }
  1110 
  1111 static int
  1112 D3D_RenderDrawRects(SDL_Renderer * renderer, const SDL_Rect ** rects,
  1113                     int count)
  1114 {
  1115     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1116     DWORD color;
  1117     int i;
  1118     Vertex vertices[5];
  1119     HRESULT result;
  1120 
  1121     if (data->beginScene) {
  1122         IDirect3DDevice9_BeginScene(data->device);
  1123         data->beginScene = SDL_FALSE;
  1124     }
  1125 
  1126     D3D_SetBlendMode(data, renderer->blendMode);
  1127 
  1128     result =
  1129         IDirect3DDevice9_SetTexture(data->device, 0,
  1130                                     (IDirect3DBaseTexture9 *) 0);
  1131     if (FAILED(result)) {
  1132         D3D_SetError("SetTexture()", result);
  1133         return -1;
  1134     }
  1135 
  1136     color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
  1137 
  1138     for (i = 0; i < SDL_arraysize(vertices); ++i) {
  1139         vertices[i].z = 0.0f;
  1140         vertices[i].rhw = 1.0f;
  1141         vertices[i].color = color;
  1142         vertices[i].u = 0.0f;
  1143         vertices[i].v = 0.0f;
  1144     }
  1145 
  1146     for (i = 0; i < count; ++i) {
  1147         const SDL_Rect *rect = rects[i];
  1148 
  1149         vertices[0].x = (float) rect->x;
  1150         vertices[0].y = (float) rect->y;
  1151 
  1152         vertices[1].x = (float) rect->x+rect->w-1;
  1153         vertices[1].y = (float) rect->y;
  1154 
  1155         vertices[2].x = (float) rect->x+rect->w-1;
  1156         vertices[2].y = (float) rect->y+rect->h-1;
  1157 
  1158         vertices[3].x = (float) rect->x;
  1159         vertices[3].y = (float) rect->y+rect->h-1;
  1160 
  1161         vertices[4].x = (float) rect->x;
  1162         vertices[4].y = (float) rect->y;
  1163 
  1164         result =
  1165             IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_LINESTRIP, 4,
  1166                                              vertices, sizeof(*vertices));
  1167 
  1168         if (FAILED(result)) {
  1169             D3D_SetError("DrawPrimitiveUP()", result);
  1170             return -1;
  1171         }
  1172     }
  1173     return 0;
  1174 }
  1175 
  1176 static int
  1177 D3D_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect ** rects,
  1178                     int count)
  1179 {
  1180     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1181     DWORD color;
  1182     int i;
  1183     float minx, miny, maxx, maxy;
  1184     Vertex vertices[4];
  1185     HRESULT result;
  1186 
  1187     if (data->beginScene) {
  1188         IDirect3DDevice9_BeginScene(data->device);
  1189         data->beginScene = SDL_FALSE;
  1190     }
  1191 
  1192     D3D_SetBlendMode(data, renderer->blendMode);
  1193 
  1194     result =
  1195         IDirect3DDevice9_SetTexture(data->device, 0,
  1196                                     (IDirect3DBaseTexture9 *) 0);
  1197     if (FAILED(result)) {
  1198         D3D_SetError("SetTexture()", result);
  1199         return -1;
  1200     }
  1201 
  1202     color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
  1203 
  1204     for (i = 0; i < count; ++i) {
  1205         const SDL_Rect *rect = rects[i];
  1206 
  1207         minx = (float) rect->x;
  1208         miny = (float) rect->y;
  1209         maxx = (float) rect->x + rect->w;
  1210         maxy = (float) rect->y + rect->h;
  1211 
  1212         vertices[0].x = minx;
  1213         vertices[0].y = miny;
  1214         vertices[0].z = 0.0f;
  1215         vertices[0].rhw = 1.0f;
  1216         vertices[0].color = color;
  1217         vertices[0].u = 0.0f;
  1218         vertices[0].v = 0.0f;
  1219 
  1220         vertices[1].x = maxx;
  1221         vertices[1].y = miny;
  1222         vertices[1].z = 0.0f;
  1223         vertices[1].rhw = 1.0f;
  1224         vertices[1].color = color;
  1225         vertices[1].u = 0.0f;
  1226         vertices[1].v = 0.0f;
  1227 
  1228         vertices[2].x = maxx;
  1229         vertices[2].y = maxy;
  1230         vertices[2].z = 0.0f;
  1231         vertices[2].rhw = 1.0f;
  1232         vertices[2].color = color;
  1233         vertices[2].u = 0.0f;
  1234         vertices[2].v = 0.0f;
  1235 
  1236         vertices[3].x = minx;
  1237         vertices[3].y = maxy;
  1238         vertices[3].z = 0.0f;
  1239         vertices[3].rhw = 1.0f;
  1240         vertices[3].color = color;
  1241         vertices[3].u = 0.0f;
  1242         vertices[3].v = 0.0f;
  1243 
  1244         result =
  1245             IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN,
  1246                                              2, vertices, sizeof(*vertices));
  1247         if (FAILED(result)) {
  1248             D3D_SetError("DrawPrimitiveUP()", result);
  1249             return -1;
  1250         }
  1251     }
  1252     return 0;
  1253 }
  1254 
  1255 static int
  1256 D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
  1257                const SDL_Rect * srcrect, const SDL_Rect * dstrect)
  1258 {
  1259     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1260     D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata;
  1261     LPDIRECT3DPIXELSHADER9 shader = NULL;
  1262     float minx, miny, maxx, maxy;
  1263     float minu, maxu, minv, maxv;
  1264     DWORD color;
  1265     Vertex vertices[4];
  1266     HRESULT result;
  1267 
  1268     if (data->beginScene) {
  1269         IDirect3DDevice9_BeginScene(data->device);
  1270         data->beginScene = SDL_FALSE;
  1271     }
  1272 
  1273     minx = (float) dstrect->x - 0.5f;
  1274     miny = (float) dstrect->y - 0.5f;
  1275     maxx = (float) dstrect->x + dstrect->w - 0.5f;
  1276     maxy = (float) dstrect->y + dstrect->h - 0.5f;
  1277 
  1278     minu = (float) srcrect->x / texture->w;
  1279     maxu = (float) (srcrect->x + srcrect->w) / texture->w;
  1280     minv = (float) srcrect->y / texture->h;
  1281     maxv = (float) (srcrect->y + srcrect->h) / texture->h;
  1282 
  1283     color = D3DCOLOR_ARGB(texture->a, texture->r, texture->g, texture->b);
  1284 
  1285     vertices[0].x = minx;
  1286     vertices[0].y = miny;
  1287     vertices[0].z = 0.0f;
  1288     vertices[0].rhw = 1.0f;
  1289     vertices[0].color = color;
  1290     vertices[0].u = minu;
  1291     vertices[0].v = minv;
  1292 
  1293     vertices[1].x = maxx;
  1294     vertices[1].y = miny;
  1295     vertices[1].z = 0.0f;
  1296     vertices[1].rhw = 1.0f;
  1297     vertices[1].color = color;
  1298     vertices[1].u = maxu;
  1299     vertices[1].v = minv;
  1300 
  1301     vertices[2].x = maxx;
  1302     vertices[2].y = maxy;
  1303     vertices[2].z = 0.0f;
  1304     vertices[2].rhw = 1.0f;
  1305     vertices[2].color = color;
  1306     vertices[2].u = maxu;
  1307     vertices[2].v = maxv;
  1308 
  1309     vertices[3].x = minx;
  1310     vertices[3].y = maxy;
  1311     vertices[3].z = 0.0f;
  1312     vertices[3].rhw = 1.0f;
  1313     vertices[3].color = color;
  1314     vertices[3].u = minu;
  1315     vertices[3].v = maxv;
  1316 
  1317     D3D_SetBlendMode(data, texture->blendMode);
  1318 
  1319     if (texture->blendMode == SDL_BLENDMODE_MASK) {
  1320         shader = data->ps_mask;
  1321     }
  1322 
  1323     IDirect3DDevice9_SetSamplerState(data->device, 0, D3DSAMP_MINFILTER,
  1324                                      D3DTEXF_LINEAR);
  1325     IDirect3DDevice9_SetSamplerState(data->device, 0, D3DSAMP_MAGFILTER,
  1326                                      D3DTEXF_LINEAR);
  1327 
  1328     result =
  1329         IDirect3DDevice9_SetTexture(data->device, 0, (IDirect3DBaseTexture9 *)
  1330                                     texturedata->texture);
  1331     if (FAILED(result)) {
  1332         D3D_SetError("SetTexture()", result);
  1333         return -1;
  1334     }
  1335     if (shader) {
  1336         result = IDirect3DDevice9_SetPixelShader(data->device, shader);
  1337         if (FAILED(result)) {
  1338             D3D_SetError("SetShader()", result);
  1339             return -1;
  1340         }
  1341     }
  1342     result =
  1343         IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2,
  1344                                          vertices, sizeof(*vertices));
  1345     if (FAILED(result)) {
  1346         D3D_SetError("DrawPrimitiveUP()", result);
  1347         return -1;
  1348     }
  1349     if (shader) {
  1350         result = IDirect3DDevice9_SetPixelShader(data->device, NULL);
  1351         if (FAILED(result)) {
  1352             D3D_SetError("SetShader()", result);
  1353             return -1;
  1354         }
  1355     }
  1356     return 0;
  1357 }
  1358 
  1359 static int
  1360 D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
  1361                      Uint32 format, void * pixels, int pitch)
  1362 {
  1363     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1364     SDL_Window *window = renderer->window;
  1365     SDL_VideoDisplay *display = window->display;
  1366     D3DSURFACE_DESC desc;
  1367     LPDIRECT3DSURFACE9 backBuffer;
  1368     LPDIRECT3DSURFACE9 surface;
  1369     RECT d3drect;
  1370     D3DLOCKED_RECT locked;
  1371     HRESULT result;
  1372 
  1373     result = IDirect3DDevice9_GetBackBuffer(data->device, 0, 0, D3DBACKBUFFER_TYPE_MONO, &backBuffer);
  1374     if (FAILED(result)) {
  1375         D3D_SetError("GetBackBuffer()", result);
  1376         return -1;
  1377     }
  1378 
  1379     result = IDirect3DSurface9_GetDesc(backBuffer, &desc);
  1380     if (FAILED(result)) {
  1381         D3D_SetError("GetDesc()", result);
  1382         IDirect3DSurface9_Release(backBuffer);
  1383         return -1;
  1384     }
  1385 
  1386     result = IDirect3DDevice9_CreateOffscreenPlainSurface(data->device, desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surface, NULL);
  1387     if (FAILED(result)) {
  1388         D3D_SetError("CreateOffscreenPlainSurface()", result);
  1389         IDirect3DSurface9_Release(backBuffer);
  1390         return -1;
  1391     }
  1392 
  1393     result = IDirect3DDevice9_GetRenderTargetData(data->device, backBuffer, surface);
  1394     if (FAILED(result)) {
  1395         D3D_SetError("GetRenderTargetData()", result);
  1396         IDirect3DSurface9_Release(surface);
  1397         IDirect3DSurface9_Release(backBuffer);
  1398         return -1;
  1399     }
  1400 
  1401     d3drect.left = rect->x;
  1402     d3drect.right = rect->x + rect->w;
  1403     d3drect.top = rect->y;
  1404     d3drect.bottom = rect->y + rect->h;
  1405 
  1406     result = IDirect3DSurface9_LockRect(surface, &locked, &d3drect, D3DLOCK_READONLY);
  1407     if (FAILED(result)) {
  1408         D3D_SetError("LockRect()", result);
  1409         IDirect3DSurface9_Release(surface);
  1410         IDirect3DSurface9_Release(backBuffer);
  1411         return -1;
  1412     }
  1413 
  1414     SDL_ConvertPixels(rect->w, rect->h,
  1415                       display->current_mode.format, locked.pBits, locked.Pitch,
  1416                       format, pixels, pitch);
  1417 
  1418     IDirect3DSurface9_UnlockRect(surface);
  1419 
  1420     IDirect3DSurface9_Release(surface);
  1421     IDirect3DSurface9_Release(backBuffer);
  1422 
  1423     return 0;
  1424 }
  1425 
  1426 static int
  1427 D3D_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect,
  1428                       Uint32 format, const void * pixels, int pitch)
  1429 {
  1430     /* Work in progress */
  1431     SDL_Unsupported();
  1432     return -1;
  1433 }
  1434 
  1435 static void
  1436 D3D_RenderPresent(SDL_Renderer * renderer)
  1437 {
  1438     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1439     HRESULT result;
  1440 
  1441     if (!data->beginScene) {
  1442         IDirect3DDevice9_EndScene(data->device);
  1443         data->beginScene = SDL_TRUE;
  1444     }
  1445 
  1446     result = IDirect3DDevice9_TestCooperativeLevel(data->device);
  1447     if (result == D3DERR_DEVICELOST) {
  1448         /* We'll reset later */
  1449         return;
  1450     }
  1451     if (result == D3DERR_DEVICENOTRESET) {
  1452         D3D_Reset(renderer);
  1453     }
  1454     result = IDirect3DDevice9_Present(data->device, NULL, NULL, NULL, NULL);
  1455     if (FAILED(result)) {
  1456         D3D_SetError("Present()", result);
  1457     }
  1458 }
  1459 
  1460 static void
  1461 D3D_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  1462 {
  1463     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
  1464 
  1465     if (!data) {
  1466         return;
  1467     }
  1468     if (data->yuv) {
  1469         SDL_SW_DestroyYUVTexture(data->yuv);
  1470     }
  1471     if (data->texture) {
  1472         IDirect3DTexture9_Release(data->texture);
  1473     }
  1474     SDL_free(data);
  1475     texture->driverdata = NULL;
  1476 }
  1477 
  1478 static void
  1479 D3D_DestroyRenderer(SDL_Renderer * renderer)
  1480 {
  1481     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1482 
  1483     if (data) {
  1484         if (data->device) {
  1485             IDirect3DDevice9_Release(data->device);
  1486         }
  1487         SDL_free(data);
  1488     }
  1489     SDL_free(renderer);
  1490 }
  1491 
  1492 #endif /* SDL_VIDEO_RENDER_D3D */
  1493 
  1494 /* vi: set ts=4 sw=4 expandtab: */