src/render/direct3d/SDL_render_d3d.c
author David Ludwig <dludwig@pobox.com>
Fri, 24 Jun 2016 22:17:56 -0400
changeset 10183 17e0ded12e6f
parent 9998 f67cf37e9cd4
child 10408 d78b187845d6
permissions -rw-r--r--
Fixed Bug 3147 - Windows: Crash when resizing Window since hg 333216331863

Thanks for the fix, Gab!
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "../../SDL_internal.h"
    22 
    23 #include "SDL_render.h"
    24 #include "SDL_system.h"
    25 
    26 #if SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED
    27 
    28 #include "../../core/windows/SDL_windows.h"
    29 
    30 #include "SDL_hints.h"
    31 #include "SDL_loadso.h"
    32 #include "SDL_syswm.h"
    33 #include "../SDL_sysrender.h"
    34 #include "../SDL_d3dmath.h"
    35 #include "../../video/windows/SDL_windowsvideo.h"
    36 
    37 #if SDL_VIDEO_RENDER_D3D
    38 #define D3D_DEBUG_INFO
    39 #include <d3d9.h>
    40 #endif
    41 
    42 
    43 #ifdef ASSEMBLE_SHADER
    44 #pragma comment(lib, "d3dx9.lib")
    45 
    46 /**************************************************************************
    47  * ID3DXBuffer:
    48  * ------------
    49  * The buffer object is used by D3DX to return arbitrary size data.
    50  *
    51  * GetBufferPointer -
    52  *    Returns a pointer to the beginning of the buffer.
    53  *
    54  * GetBufferSize -
    55  *    Returns the size of the buffer, in bytes.
    56  **************************************************************************/
    57 
    58 typedef interface ID3DXBuffer ID3DXBuffer;
    59 typedef interface ID3DXBuffer *LPD3DXBUFFER;
    60 
    61 /* {8BA5FB08-5195-40e2-AC58-0D989C3A0102} */
    62 DEFINE_GUID(IID_ID3DXBuffer,
    63 0x8ba5fb08, 0x5195, 0x40e2, 0xac, 0x58, 0xd, 0x98, 0x9c, 0x3a, 0x1, 0x2);
    64 
    65 #undef INTERFACE
    66 #define INTERFACE ID3DXBuffer
    67 
    68 typedef interface ID3DXBuffer {
    69     const struct ID3DXBufferVtbl FAR* lpVtbl;
    70 } ID3DXBuffer;
    71 typedef const struct ID3DXBufferVtbl ID3DXBufferVtbl;
    72 const struct ID3DXBufferVtbl
    73 {
    74     /* IUnknown */
    75     STDMETHOD(QueryInterface)(THIS_ REFIID iid, LPVOID *ppv) PURE;
    76     STDMETHOD_(ULONG, AddRef)(THIS) PURE;
    77     STDMETHOD_(ULONG, Release)(THIS) PURE;
    78 
    79     /* ID3DXBuffer */
    80     STDMETHOD_(LPVOID, GetBufferPointer)(THIS) PURE;
    81     STDMETHOD_(DWORD, GetBufferSize)(THIS) PURE;
    82 };
    83 
    84 HRESULT WINAPI
    85     D3DXAssembleShader(
    86         LPCSTR                          pSrcData,
    87         UINT                            SrcDataLen,
    88         CONST LPVOID*                   pDefines,
    89         LPVOID                          pInclude,
    90         DWORD                           Flags,
    91         LPD3DXBUFFER*                   ppShader,
    92         LPD3DXBUFFER*                   ppErrorMsgs);
    93 
    94 static void PrintShaderData(LPDWORD shader_data, DWORD shader_size)
    95 {
    96     OutputDebugStringA("const DWORD shader_data[] = {\n\t");
    97     {
    98         SDL_bool newline = SDL_FALSE;
    99         unsigned i;
   100         for (i = 0; i < shader_size / sizeof(DWORD); ++i) {
   101             char dword[11];
   102             if (i > 0) {
   103                 if ((i%6) == 0) {
   104                     newline = SDL_TRUE;
   105                 }
   106                 if (newline) {
   107                     OutputDebugStringA(",\n    ");
   108                     newline = SDL_FALSE;
   109                 } else {
   110                     OutputDebugStringA(", ");
   111                 }
   112             }
   113             SDL_snprintf(dword, sizeof(dword), "0x%8.8x", shader_data[i]);
   114             OutputDebugStringA(dword);
   115         }
   116         OutputDebugStringA("\n};\n");
   117     }
   118 }
   119 
   120 #endif /* ASSEMBLE_SHADER */
   121 
   122 
   123 /* Direct3D renderer implementation */
   124 
   125 static SDL_Renderer *D3D_CreateRenderer(SDL_Window * window, Uint32 flags);
   126 static void D3D_WindowEvent(SDL_Renderer * renderer,
   127                             const SDL_WindowEvent *event);
   128 static int D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
   129 static int D3D_RecreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
   130 static int D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   131                              const SDL_Rect * rect, const void *pixels,
   132                              int pitch);
   133 static int D3D_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
   134                                 const SDL_Rect * rect,
   135                                 const Uint8 *Yplane, int Ypitch,
   136                                 const Uint8 *Uplane, int Upitch,
   137                                 const Uint8 *Vplane, int Vpitch);
   138 static int D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   139                            const SDL_Rect * rect, void **pixels, int *pitch);
   140 static void D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
   141 static int D3D_SetRenderTargetInternal(SDL_Renderer * renderer, SDL_Texture * texture);
   142 static int D3D_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture);
   143 static int D3D_UpdateViewport(SDL_Renderer * renderer);
   144 static int D3D_UpdateClipRect(SDL_Renderer * renderer);
   145 static int D3D_RenderClear(SDL_Renderer * renderer);
   146 static int D3D_RenderDrawPoints(SDL_Renderer * renderer,
   147                                 const SDL_FPoint * points, int count);
   148 static int D3D_RenderDrawLines(SDL_Renderer * renderer,
   149                                const SDL_FPoint * points, int count);
   150 static int D3D_RenderFillRects(SDL_Renderer * renderer,
   151                                const SDL_FRect * rects, int count);
   152 static int D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   153                           const SDL_Rect * srcrect, const SDL_FRect * dstrect);
   154 static int D3D_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
   155                           const SDL_Rect * srcrect, const SDL_FRect * dstrect,
   156                           const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip);
   157 static int D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
   158                                 Uint32 format, void * pixels, int pitch);
   159 static void D3D_RenderPresent(SDL_Renderer * renderer);
   160 static void D3D_DestroyTexture(SDL_Renderer * renderer,
   161                                SDL_Texture * texture);
   162 static void D3D_DestroyRenderer(SDL_Renderer * renderer);
   163 
   164 
   165 SDL_RenderDriver D3D_RenderDriver = {
   166     D3D_CreateRenderer,
   167     {
   168      "direct3d",
   169      (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
   170      1,
   171      {SDL_PIXELFORMAT_ARGB8888},
   172      0,
   173      0}
   174 };
   175 
   176 typedef struct
   177 {
   178     void* d3dDLL;
   179     IDirect3D9 *d3d;
   180     IDirect3DDevice9 *device;
   181     UINT adapter;
   182     D3DPRESENT_PARAMETERS pparams;
   183     SDL_bool updateSize;
   184     SDL_bool beginScene;
   185     SDL_bool enableSeparateAlphaBlend;
   186     D3DTEXTUREFILTERTYPE scaleMode[8];
   187     IDirect3DSurface9 *defaultRenderTarget;
   188     IDirect3DSurface9 *currentRenderTarget;
   189     void* d3dxDLL;
   190     LPDIRECT3DPIXELSHADER9 ps_yuv;
   191 } D3D_RenderData;
   192 
   193 typedef struct
   194 {
   195     SDL_bool dirty;
   196     int w, h;
   197     DWORD usage;
   198     Uint32 format;
   199     IDirect3DTexture9 *texture;
   200     IDirect3DTexture9 *staging;
   201 } D3D_TextureRep;
   202 
   203 typedef struct
   204 {
   205     D3D_TextureRep texture;
   206     D3DTEXTUREFILTERTYPE scaleMode;
   207 
   208     /* YV12 texture support */
   209     SDL_bool yuv;
   210     D3D_TextureRep utexture;
   211     D3D_TextureRep vtexture;
   212     Uint8 *pixels;
   213     int pitch;
   214     SDL_Rect locked_rect;
   215 } D3D_TextureData;
   216 
   217 typedef struct
   218 {
   219     float x, y, z;
   220     DWORD color;
   221     float u, v;
   222 } Vertex;
   223 
   224 static int
   225 D3D_SetError(const char *prefix, HRESULT result)
   226 {
   227     const char *error;
   228 
   229     switch (result) {
   230     case D3DERR_WRONGTEXTUREFORMAT:
   231         error = "WRONGTEXTUREFORMAT";
   232         break;
   233     case D3DERR_UNSUPPORTEDCOLOROPERATION:
   234         error = "UNSUPPORTEDCOLOROPERATION";
   235         break;
   236     case D3DERR_UNSUPPORTEDCOLORARG:
   237         error = "UNSUPPORTEDCOLORARG";
   238         break;
   239     case D3DERR_UNSUPPORTEDALPHAOPERATION:
   240         error = "UNSUPPORTEDALPHAOPERATION";
   241         break;
   242     case D3DERR_UNSUPPORTEDALPHAARG:
   243         error = "UNSUPPORTEDALPHAARG";
   244         break;
   245     case D3DERR_TOOMANYOPERATIONS:
   246         error = "TOOMANYOPERATIONS";
   247         break;
   248     case D3DERR_CONFLICTINGTEXTUREFILTER:
   249         error = "CONFLICTINGTEXTUREFILTER";
   250         break;
   251     case D3DERR_UNSUPPORTEDFACTORVALUE:
   252         error = "UNSUPPORTEDFACTORVALUE";
   253         break;
   254     case D3DERR_CONFLICTINGRENDERSTATE:
   255         error = "CONFLICTINGRENDERSTATE";
   256         break;
   257     case D3DERR_UNSUPPORTEDTEXTUREFILTER:
   258         error = "UNSUPPORTEDTEXTUREFILTER";
   259         break;
   260     case D3DERR_CONFLICTINGTEXTUREPALETTE:
   261         error = "CONFLICTINGTEXTUREPALETTE";
   262         break;
   263     case D3DERR_DRIVERINTERNALERROR:
   264         error = "DRIVERINTERNALERROR";
   265         break;
   266     case D3DERR_NOTFOUND:
   267         error = "NOTFOUND";
   268         break;
   269     case D3DERR_MOREDATA:
   270         error = "MOREDATA";
   271         break;
   272     case D3DERR_DEVICELOST:
   273         error = "DEVICELOST";
   274         break;
   275     case D3DERR_DEVICENOTRESET:
   276         error = "DEVICENOTRESET";
   277         break;
   278     case D3DERR_NOTAVAILABLE:
   279         error = "NOTAVAILABLE";
   280         break;
   281     case D3DERR_OUTOFVIDEOMEMORY:
   282         error = "OUTOFVIDEOMEMORY";
   283         break;
   284     case D3DERR_INVALIDDEVICE:
   285         error = "INVALIDDEVICE";
   286         break;
   287     case D3DERR_INVALIDCALL:
   288         error = "INVALIDCALL";
   289         break;
   290     case D3DERR_DRIVERINVALIDCALL:
   291         error = "DRIVERINVALIDCALL";
   292         break;
   293     case D3DERR_WASSTILLDRAWING:
   294         error = "WASSTILLDRAWING";
   295         break;
   296     default:
   297         error = "UNKNOWN";
   298         break;
   299     }
   300     return SDL_SetError("%s: %s", prefix, error);
   301 }
   302 
   303 static D3DFORMAT
   304 PixelFormatToD3DFMT(Uint32 format)
   305 {
   306     switch (format) {
   307     case SDL_PIXELFORMAT_RGB565:
   308         return D3DFMT_R5G6B5;
   309     case SDL_PIXELFORMAT_RGB888:
   310         return D3DFMT_X8R8G8B8;
   311     case SDL_PIXELFORMAT_ARGB8888:
   312         return D3DFMT_A8R8G8B8;
   313     case SDL_PIXELFORMAT_YV12:
   314     case SDL_PIXELFORMAT_IYUV:
   315         return D3DFMT_L8;
   316     default:
   317         return D3DFMT_UNKNOWN;
   318     }
   319 }
   320 
   321 static Uint32
   322 D3DFMTToPixelFormat(D3DFORMAT format)
   323 {
   324     switch (format) {
   325     case D3DFMT_R5G6B5:
   326         return SDL_PIXELFORMAT_RGB565;
   327     case D3DFMT_X8R8G8B8:
   328         return SDL_PIXELFORMAT_RGB888;
   329     case D3DFMT_A8R8G8B8:
   330         return SDL_PIXELFORMAT_ARGB8888;
   331     default:
   332         return SDL_PIXELFORMAT_UNKNOWN;
   333     }
   334 }
   335 
   336 static void
   337 D3D_InitRenderState(D3D_RenderData *data)
   338 {
   339     D3DMATRIX matrix;
   340 
   341     IDirect3DDevice9 *device = data->device;
   342 
   343     IDirect3DDevice9_SetVertexShader(device, NULL);
   344     IDirect3DDevice9_SetFVF(device, D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);
   345     IDirect3DDevice9_SetRenderState(device, D3DRS_ZENABLE, D3DZB_FALSE);
   346     IDirect3DDevice9_SetRenderState(device, D3DRS_CULLMODE, D3DCULL_NONE);
   347     IDirect3DDevice9_SetRenderState(device, D3DRS_LIGHTING, FALSE);
   348 
   349     /* Enable color modulation by diffuse color */
   350     IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLOROP,
   351                                           D3DTOP_MODULATE);
   352     IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLORARG1,
   353                                           D3DTA_TEXTURE);
   354     IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLORARG2,
   355                                           D3DTA_DIFFUSE);
   356 
   357     /* Enable alpha modulation by diffuse alpha */
   358     IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAOP,
   359                                           D3DTOP_MODULATE);
   360     IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAARG1,
   361                                           D3DTA_TEXTURE);
   362     IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAARG2,
   363                                           D3DTA_DIFFUSE);
   364 
   365     /* Enable separate alpha blend function, if possible */
   366     if (data->enableSeparateAlphaBlend) {
   367         IDirect3DDevice9_SetRenderState(device, D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
   368     }
   369 
   370     /* Disable second texture stage, since we're done */
   371     IDirect3DDevice9_SetTextureStageState(device, 1, D3DTSS_COLOROP,
   372                                           D3DTOP_DISABLE);
   373     IDirect3DDevice9_SetTextureStageState(device, 1, D3DTSS_ALPHAOP,
   374                                           D3DTOP_DISABLE);
   375 
   376     /* Set an identity world and view matrix */
   377     matrix.m[0][0] = 1.0f;
   378     matrix.m[0][1] = 0.0f;
   379     matrix.m[0][2] = 0.0f;
   380     matrix.m[0][3] = 0.0f;
   381     matrix.m[1][0] = 0.0f;
   382     matrix.m[1][1] = 1.0f;
   383     matrix.m[1][2] = 0.0f;
   384     matrix.m[1][3] = 0.0f;
   385     matrix.m[2][0] = 0.0f;
   386     matrix.m[2][1] = 0.0f;
   387     matrix.m[2][2] = 1.0f;
   388     matrix.m[2][3] = 0.0f;
   389     matrix.m[3][0] = 0.0f;
   390     matrix.m[3][1] = 0.0f;
   391     matrix.m[3][2] = 0.0f;
   392     matrix.m[3][3] = 1.0f;
   393     IDirect3DDevice9_SetTransform(device, D3DTS_WORLD, &matrix);
   394     IDirect3DDevice9_SetTransform(device, D3DTS_VIEW, &matrix);
   395 
   396     /* Reset our current scale mode */
   397     SDL_memset(data->scaleMode, 0xFF, sizeof(data->scaleMode));
   398 
   399     /* Start the render with beginScene */
   400     data->beginScene = SDL_TRUE;
   401 }
   402 
   403 static int
   404 D3D_Reset(SDL_Renderer * renderer)
   405 {
   406     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   407     HRESULT result;
   408     SDL_Texture *texture;
   409 
   410     /* Release the default render target before reset */
   411     if (data->defaultRenderTarget) {
   412         IDirect3DSurface9_Release(data->defaultRenderTarget);
   413         data->defaultRenderTarget = NULL;
   414     }
   415     if (data->currentRenderTarget != NULL) {
   416         IDirect3DSurface9_Release(data->currentRenderTarget);
   417         data->currentRenderTarget = NULL;
   418     }
   419 
   420     /* Release application render targets */
   421     for (texture = renderer->textures; texture; texture = texture->next) {
   422         if (texture->access == SDL_TEXTUREACCESS_TARGET) {
   423             D3D_DestroyTexture(renderer, texture);
   424         } else {
   425             D3D_RecreateTexture(renderer, texture);
   426         }
   427     }
   428 
   429     result = IDirect3DDevice9_Reset(data->device, &data->pparams);
   430     if (FAILED(result)) {
   431         if (result == D3DERR_DEVICELOST) {
   432             /* Don't worry about it, we'll reset later... */
   433             return 0;
   434         } else {
   435             return D3D_SetError("Reset()", result);
   436         }
   437     }
   438 
   439     /* Allocate application render targets */
   440     for (texture = renderer->textures; texture; texture = texture->next) {
   441         if (texture->access == SDL_TEXTUREACCESS_TARGET) {
   442             D3D_CreateTexture(renderer, texture);
   443         }
   444     }
   445 
   446     IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget);
   447     D3D_InitRenderState(data);
   448     D3D_SetRenderTargetInternal(renderer, renderer->target);
   449     D3D_UpdateViewport(renderer);
   450 
   451     /* Let the application know that render targets were reset */
   452     {
   453         SDL_Event event;
   454         event.type = SDL_RENDER_TARGETS_RESET;
   455         SDL_PushEvent(&event);
   456     }
   457 
   458     return 0;
   459 }
   460 
   461 static int
   462 D3D_ActivateRenderer(SDL_Renderer * renderer)
   463 {
   464     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   465     HRESULT result;
   466 
   467     if (data->updateSize) {
   468         SDL_Window *window = renderer->window;
   469         int w, h;
   470         Uint32 window_flags = SDL_GetWindowFlags(window);
   471 
   472         SDL_GetWindowSize(window, &w, &h);
   473         data->pparams.BackBufferWidth = w;
   474         data->pparams.BackBufferHeight = h;
   475         if (window_flags & SDL_WINDOW_FULLSCREEN && (window_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
   476             SDL_DisplayMode fullscreen_mode;
   477             SDL_GetWindowDisplayMode(window, &fullscreen_mode);
   478             data->pparams.Windowed = FALSE;
   479             data->pparams.BackBufferFormat = PixelFormatToD3DFMT(fullscreen_mode.format);
   480             data->pparams.FullScreen_RefreshRateInHz = fullscreen_mode.refresh_rate;
   481         } else {
   482             data->pparams.Windowed = TRUE;
   483             data->pparams.BackBufferFormat = D3DFMT_UNKNOWN;
   484             data->pparams.FullScreen_RefreshRateInHz = 0;
   485         }
   486         if (D3D_Reset(renderer) < 0) {
   487             return -1;
   488         }
   489 
   490         data->updateSize = SDL_FALSE;
   491     }
   492     if (data->beginScene) {
   493         result = IDirect3DDevice9_BeginScene(data->device);
   494         if (result == D3DERR_DEVICELOST) {
   495             if (D3D_Reset(renderer) < 0) {
   496                 return -1;
   497             }
   498             result = IDirect3DDevice9_BeginScene(data->device);
   499         }
   500         if (FAILED(result)) {
   501             return D3D_SetError("BeginScene()", result);
   502         }
   503         data->beginScene = SDL_FALSE;
   504     }
   505     return 0;
   506 }
   507 
   508 SDL_Renderer *
   509 D3D_CreateRenderer(SDL_Window * window, Uint32 flags)
   510 {
   511     SDL_Renderer *renderer;
   512     D3D_RenderData *data;
   513     SDL_SysWMinfo windowinfo;
   514     HRESULT result;
   515     const char *hint;
   516     D3DPRESENT_PARAMETERS pparams;
   517     IDirect3DSwapChain9 *chain;
   518     D3DCAPS9 caps;
   519     DWORD device_flags;
   520     Uint32 window_flags;
   521     int w, h;
   522     SDL_DisplayMode fullscreen_mode;
   523     int displayIndex;
   524 
   525     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   526     if (!renderer) {
   527         SDL_OutOfMemory();
   528         return NULL;
   529     }
   530 
   531     data = (D3D_RenderData *) SDL_calloc(1, sizeof(*data));
   532     if (!data) {
   533         SDL_free(renderer);
   534         SDL_OutOfMemory();
   535         return NULL;
   536     }
   537 
   538     if (!D3D_LoadDLL(&data->d3dDLL, &data->d3d)) {
   539         SDL_free(renderer);
   540         SDL_free(data);
   541         SDL_SetError("Unable to create Direct3D interface");
   542         return NULL;
   543     }
   544 
   545     renderer->WindowEvent = D3D_WindowEvent;
   546     renderer->CreateTexture = D3D_CreateTexture;
   547     renderer->UpdateTexture = D3D_UpdateTexture;
   548     renderer->UpdateTextureYUV = D3D_UpdateTextureYUV;
   549     renderer->LockTexture = D3D_LockTexture;
   550     renderer->UnlockTexture = D3D_UnlockTexture;
   551     renderer->SetRenderTarget = D3D_SetRenderTarget;
   552     renderer->UpdateViewport = D3D_UpdateViewport;
   553     renderer->UpdateClipRect = D3D_UpdateClipRect;
   554     renderer->RenderClear = D3D_RenderClear;
   555     renderer->RenderDrawPoints = D3D_RenderDrawPoints;
   556     renderer->RenderDrawLines = D3D_RenderDrawLines;
   557     renderer->RenderFillRects = D3D_RenderFillRects;
   558     renderer->RenderCopy = D3D_RenderCopy;
   559     renderer->RenderCopyEx = D3D_RenderCopyEx;
   560     renderer->RenderReadPixels = D3D_RenderReadPixels;
   561     renderer->RenderPresent = D3D_RenderPresent;
   562     renderer->DestroyTexture = D3D_DestroyTexture;
   563     renderer->DestroyRenderer = D3D_DestroyRenderer;
   564     renderer->info = D3D_RenderDriver.info;
   565     renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
   566     renderer->driverdata = data;
   567 
   568     SDL_VERSION(&windowinfo.version);
   569     SDL_GetWindowWMInfo(window, &windowinfo);
   570 
   571     window_flags = SDL_GetWindowFlags(window);
   572     SDL_GetWindowSize(window, &w, &h);
   573     SDL_GetWindowDisplayMode(window, &fullscreen_mode);
   574 
   575     SDL_zero(pparams);
   576     pparams.hDeviceWindow = windowinfo.info.win.window;
   577     pparams.BackBufferWidth = w;
   578     pparams.BackBufferHeight = h;
   579     pparams.BackBufferCount = 1;
   580     pparams.SwapEffect = D3DSWAPEFFECT_DISCARD;
   581 
   582     if (window_flags & SDL_WINDOW_FULLSCREEN && (window_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
   583         pparams.Windowed = FALSE;
   584         pparams.BackBufferFormat = PixelFormatToD3DFMT(fullscreen_mode.format);
   585         pparams.FullScreen_RefreshRateInHz = fullscreen_mode.refresh_rate;
   586     } else {
   587         pparams.Windowed = TRUE;
   588         pparams.BackBufferFormat = D3DFMT_UNKNOWN;
   589         pparams.FullScreen_RefreshRateInHz = 0;
   590     }
   591     if (flags & SDL_RENDERER_PRESENTVSYNC) {
   592         pparams.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
   593     } else {
   594         pparams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
   595     }
   596 
   597     /* Get the adapter for the display that the window is on */
   598     displayIndex = SDL_GetWindowDisplayIndex(window);
   599     data->adapter = SDL_Direct3D9GetAdapterIndex(displayIndex);
   600 
   601     IDirect3D9_GetDeviceCaps(data->d3d, data->adapter, D3DDEVTYPE_HAL, &caps);
   602 
   603     device_flags = D3DCREATE_FPU_PRESERVE;
   604     if (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) {
   605         device_flags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
   606     } else {
   607         device_flags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
   608     }
   609 
   610     hint = SDL_GetHint(SDL_HINT_RENDER_DIRECT3D_THREADSAFE);
   611     if (hint && SDL_atoi(hint)) {
   612         device_flags |= D3DCREATE_MULTITHREADED;
   613     }
   614 
   615     result = IDirect3D9_CreateDevice(data->d3d, data->adapter,
   616                                      D3DDEVTYPE_HAL,
   617                                      pparams.hDeviceWindow,
   618                                      device_flags,
   619                                      &pparams, &data->device);
   620     if (FAILED(result)) {
   621         D3D_DestroyRenderer(renderer);
   622         D3D_SetError("CreateDevice()", result);
   623         return NULL;
   624     }
   625 
   626     /* Get presentation parameters to fill info */
   627     result = IDirect3DDevice9_GetSwapChain(data->device, 0, &chain);
   628     if (FAILED(result)) {
   629         D3D_DestroyRenderer(renderer);
   630         D3D_SetError("GetSwapChain()", result);
   631         return NULL;
   632     }
   633     result = IDirect3DSwapChain9_GetPresentParameters(chain, &pparams);
   634     if (FAILED(result)) {
   635         IDirect3DSwapChain9_Release(chain);
   636         D3D_DestroyRenderer(renderer);
   637         D3D_SetError("GetPresentParameters()", result);
   638         return NULL;
   639     }
   640     IDirect3DSwapChain9_Release(chain);
   641     if (pparams.PresentationInterval == D3DPRESENT_INTERVAL_ONE) {
   642         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
   643     }
   644     data->pparams = pparams;
   645 
   646     IDirect3DDevice9_GetDeviceCaps(data->device, &caps);
   647     renderer->info.max_texture_width = caps.MaxTextureWidth;
   648     renderer->info.max_texture_height = caps.MaxTextureHeight;
   649     if (caps.NumSimultaneousRTs >= 2) {
   650         renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE;
   651     }
   652 
   653     if (caps.PrimitiveMiscCaps & D3DPMISCCAPS_SEPARATEALPHABLEND) {
   654         data->enableSeparateAlphaBlend = SDL_TRUE;
   655     }
   656 
   657     /* Store the default render target */
   658     IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget);
   659     data->currentRenderTarget = NULL;
   660 
   661     /* Set up parameters for rendering */
   662     D3D_InitRenderState(data);
   663 
   664     if (caps.MaxSimultaneousTextures >= 3)
   665     {
   666 #ifdef ASSEMBLE_SHADER
   667         /* This shader was created by running the following HLSL through the fxc compiler
   668            and then tuning the generated assembly.
   669 
   670            fxc /T fx_4_0 /O3 /Gfa /Fc yuv.fxc yuv.fx
   671 
   672            --- yuv.fx ---
   673            Texture2D g_txY;
   674            Texture2D g_txU;
   675            Texture2D g_txV;
   676 
   677            SamplerState samLinear
   678            {
   679                Filter = ANISOTROPIC;
   680                AddressU = Clamp;
   681                AddressV = Clamp;
   682                MaxAnisotropy = 1;
   683            };
   684 
   685            struct VS_OUTPUT
   686            {
   687                 float2 TextureUV  : TEXCOORD0;
   688            };
   689 
   690            struct PS_OUTPUT
   691            {
   692                 float4 RGBAColor : SV_Target;
   693            };
   694 
   695            PS_OUTPUT YUV420( VS_OUTPUT In ) 
   696            {
   697                const float3 offset = {-0.0627451017, -0.501960814, -0.501960814};
   698                const float3 Rcoeff = {1.164,  0.000,  1.596};
   699                const float3 Gcoeff = {1.164, -0.391, -0.813};
   700                const float3 Bcoeff = {1.164,  2.018,  0.000};
   701 
   702                PS_OUTPUT Output;
   703                float2 TextureUV = In.TextureUV;
   704 
   705                float3 yuv;
   706                yuv.x = g_txY.Sample( samLinear, TextureUV ).r;
   707                yuv.y = g_txU.Sample( samLinear, TextureUV ).r;
   708                yuv.z = g_txV.Sample( samLinear, TextureUV ).r;
   709 
   710                yuv += offset;
   711                Output.RGBAColor.r = dot(yuv, Rcoeff);
   712                Output.RGBAColor.g = dot(yuv, Gcoeff);
   713                Output.RGBAColor.b = dot(yuv, Bcoeff);
   714                Output.RGBAColor.a = 1.0f;
   715 
   716                return Output;
   717            }
   718 
   719            technique10 RenderYUV420
   720            {
   721                pass P0
   722                {
   723                     SetPixelShader( CompileShader( ps_4_0_level_9_0, YUV420() ) );
   724                }
   725            }
   726         */
   727         const char *shader_text =
   728             "ps_2_0\n"
   729             "def c0, -0.0627451017, -0.501960814, -0.501960814, 1\n"
   730             "def c1, 1.16400003, 0, 1.59599996, 0\n"
   731             "def c2, 1.16400003, -0.391000003, -0.813000023, 0\n"
   732             "def c3, 1.16400003, 2.01799989, 0, 0\n"
   733             "dcl t0.xy\n"
   734             "dcl v0.xyzw\n"
   735             "dcl_2d s0\n"
   736             "dcl_2d s1\n"
   737             "dcl_2d s2\n"
   738             "texld r0, t0, s0\n"
   739             "texld r1, t0, s1\n"
   740             "texld r2, t0, s2\n"
   741             "mov r0.y, r1.x\n"
   742             "mov r0.z, r2.x\n"
   743             "add r0.xyz, r0, c0\n"
   744             "dp3 r1.x, r0, c1\n"
   745             "dp3 r1.y, r0, c2\n"
   746             "dp2add r1.z, r0, c3, c3.z\n"   /* Logically this is "dp3 r1.z, r0, c3" but the optimizer did its magic */
   747             "mov r1.w, c0.w\n"
   748             "mul r0, r1, v0\n"              /* Not in the HLSL, multiply by vertex color */
   749             "mov oC0, r0\n"
   750         ;
   751         LPD3DXBUFFER pCode;
   752         LPD3DXBUFFER pErrorMsgs;
   753         LPDWORD shader_data = NULL;
   754         DWORD   shader_size = 0;
   755         result = D3DXAssembleShader(shader_text, SDL_strlen(shader_text), NULL, NULL, 0, &pCode, &pErrorMsgs);
   756         if (!FAILED(result)) {
   757             shader_data = (DWORD*)pCode->lpVtbl->GetBufferPointer(pCode);
   758             shader_size = pCode->lpVtbl->GetBufferSize(pCode);
   759             PrintShaderData(shader_data, shader_size);
   760         } else {
   761             const char *error = (const char *)pErrorMsgs->lpVtbl->GetBufferPointer(pErrorMsgs);
   762             SDL_SetError("Couldn't assemble shader: %s", error);
   763         }
   764 #else
   765         const DWORD shader_data[] = {
   766             0xffff0200, 0x05000051, 0xa00f0000, 0xbd808081, 0xbf008081, 0xbf008081,
   767             0x3f800000, 0x05000051, 0xa00f0001, 0x3f94fdf4, 0x00000000, 0x3fcc49ba,
   768             0x00000000, 0x05000051, 0xa00f0002, 0x3f94fdf4, 0xbec83127, 0xbf5020c5,
   769             0x00000000, 0x05000051, 0xa00f0003, 0x3f94fdf4, 0x400126e9, 0x00000000,
   770             0x00000000, 0x0200001f, 0x80000000, 0xb0030000, 0x0200001f, 0x80000000,
   771             0x900f0000, 0x0200001f, 0x90000000, 0xa00f0800, 0x0200001f, 0x90000000,
   772             0xa00f0801, 0x0200001f, 0x90000000, 0xa00f0802, 0x03000042, 0x800f0000,
   773             0xb0e40000, 0xa0e40800, 0x03000042, 0x800f0001, 0xb0e40000, 0xa0e40801,
   774             0x03000042, 0x800f0002, 0xb0e40000, 0xa0e40802, 0x02000001, 0x80020000,
   775             0x80000001, 0x02000001, 0x80040000, 0x80000002, 0x03000002, 0x80070000,
   776             0x80e40000, 0xa0e40000, 0x03000008, 0x80010001, 0x80e40000, 0xa0e40001,
   777             0x03000008, 0x80020001, 0x80e40000, 0xa0e40002, 0x0400005a, 0x80040001,
   778             0x80e40000, 0xa0e40003, 0xa0aa0003, 0x02000001, 0x80080001, 0xa0ff0000,
   779             0x03000005, 0x800f0000, 0x80e40001, 0x90e40000, 0x02000001, 0x800f0800,
   780             0x80e40000, 0x0000ffff
   781         };
   782 #endif
   783         if (shader_data != NULL) {
   784             result = IDirect3DDevice9_CreatePixelShader(data->device, shader_data, &data->ps_yuv);
   785             if (!FAILED(result)) {
   786                 renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;
   787                 renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
   788             } else {
   789                 D3D_SetError("CreatePixelShader()", result);
   790             }
   791         }
   792     }
   793 
   794     return renderer;
   795 }
   796 
   797 static void
   798 D3D_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
   799 {
   800     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   801 
   802     if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) {
   803         data->updateSize = SDL_TRUE;
   804     }
   805 }
   806 
   807 static D3DTEXTUREFILTERTYPE
   808 GetScaleQuality(void)
   809 {
   810     const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
   811 
   812     if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) {
   813         return D3DTEXF_POINT;
   814     } else /* if (*hint == '1' || SDL_strcasecmp(hint, "linear") == 0) */ {
   815         return D3DTEXF_LINEAR;
   816     }
   817 }
   818 
   819 static int
   820 D3D_CreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWORD usage, Uint32 format, int w, int h)
   821 {
   822     HRESULT result;
   823 
   824     texture->dirty = SDL_FALSE;
   825     texture->w = w;
   826     texture->h = h;
   827     texture->usage = usage;
   828     texture->format = format;
   829 
   830     result = IDirect3DDevice9_CreateTexture(device, w, h, 1, usage,
   831         PixelFormatToD3DFMT(format),
   832         D3DPOOL_DEFAULT, &texture->texture, NULL);
   833     if (FAILED(result)) {
   834         return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
   835     }
   836     return 0;
   837 }
   838 
   839 
   840 static int
   841 D3D_CreateStagingTexture(IDirect3DDevice9 *device, D3D_TextureRep *texture)
   842 {
   843     HRESULT result;
   844 
   845     if (texture->staging == NULL) {
   846         result = IDirect3DDevice9_CreateTexture(device, texture->w, texture->h, 1, 0,
   847             PixelFormatToD3DFMT(texture->format),
   848             D3DPOOL_SYSTEMMEM, &texture->staging, NULL);
   849         if (FAILED(result)) {
   850             return D3D_SetError("CreateTexture(D3DPOOL_SYSTEMMEM)", result);
   851         }
   852     }
   853     return 0;
   854 }
   855 
   856 static int
   857 D3D_BindTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWORD sampler)
   858 {
   859     HRESULT result;
   860 
   861     if (texture->dirty && texture->staging) {
   862         if (!texture->texture) {
   863             result = IDirect3DDevice9_CreateTexture(device, texture->w, texture->h, 1, texture->usage,
   864                 PixelFormatToD3DFMT(texture->format), D3DPOOL_DEFAULT, &texture->texture, NULL);
   865             if (FAILED(result)) {
   866                 return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
   867             }
   868         }
   869 
   870         result = IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)texture->staging, (IDirect3DBaseTexture9 *)texture->texture);
   871         if (FAILED(result)) {
   872             return D3D_SetError("UpdateTexture()", result);
   873         }
   874         texture->dirty = SDL_FALSE;
   875     }
   876     result = IDirect3DDevice9_SetTexture(device, sampler, (IDirect3DBaseTexture9 *)texture->texture);
   877     if (FAILED(result)) {
   878         return D3D_SetError("SetTexture()", result);
   879     }
   880     return 0;
   881 }
   882 
   883 static int
   884 D3D_RecreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, Uint32 format, int w, int h)
   885 {
   886     if (texture->texture) {
   887         IDirect3DTexture9_Release(texture->texture);
   888         texture->texture = NULL;
   889     }
   890     if (texture->staging) {
   891         IDirect3DTexture9_AddDirtyRect(texture->staging, NULL);
   892         texture->dirty = SDL_TRUE;
   893     }
   894     return 0;
   895 }
   896 
   897 static int
   898 D3D_UpdateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, Uint32 format, int x, int y, int w, int h, const void *pixels, int pitch)
   899 {
   900     RECT d3drect;
   901     D3DLOCKED_RECT locked;
   902     const Uint8 *src;
   903     Uint8 *dst;
   904     int row, length;
   905     HRESULT result;
   906 
   907     if (D3D_CreateStagingTexture(device, texture) < 0) {
   908         return -1;
   909     }
   910 
   911     d3drect.left = x;
   912     d3drect.right = x + w;
   913     d3drect.top = y;
   914     d3drect.bottom = y + h;
   915     
   916     result = IDirect3DTexture9_LockRect(texture->staging, 0, &locked, &d3drect, 0);
   917     if (FAILED(result)) {
   918         return D3D_SetError("LockRect()", result);
   919     }
   920 
   921     src = (const Uint8 *)pixels;
   922     dst = locked.pBits;
   923     length = w * SDL_BYTESPERPIXEL(format);
   924     if (length == pitch && length == locked.Pitch) {
   925         SDL_memcpy(dst, src, length*h);
   926     } else {
   927         if (length > pitch) {
   928             length = pitch;
   929         }
   930         if (length > locked.Pitch) {
   931             length = locked.Pitch;
   932         }
   933         for (row = 0; row < h; ++row) {
   934             SDL_memcpy(dst, src, length);
   935             src += pitch;
   936             dst += locked.Pitch;
   937         }
   938     }
   939     result = IDirect3DTexture9_UnlockRect(texture->staging, 0);
   940     if (FAILED(result)) {
   941         return D3D_SetError("UnlockRect()", result);
   942     }
   943     texture->dirty = SDL_TRUE;
   944 
   945     return 0;
   946 }
   947 
   948 static void
   949 D3D_DestroyTextureRep(D3D_TextureRep *texture)
   950 {
   951     if (texture->texture) {
   952         IDirect3DTexture9_Release(texture->texture);
   953         texture->texture = NULL;
   954     }
   955     if (texture->staging) {
   956         IDirect3DTexture9_Release(texture->staging);
   957         texture->staging = NULL;
   958     }
   959 }
   960 
   961 static int
   962 D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   963 {
   964     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   965     D3D_TextureData *texturedata;
   966     DWORD usage;
   967 
   968     texturedata = (D3D_TextureData *) SDL_calloc(1, sizeof(*texturedata));
   969     if (!texturedata) {
   970         return SDL_OutOfMemory();
   971     }
   972     texturedata->scaleMode = GetScaleQuality();
   973 
   974     texture->driverdata = texturedata;
   975 
   976     if (texture->access == SDL_TEXTUREACCESS_TARGET) {
   977         usage = D3DUSAGE_RENDERTARGET;
   978     } else {
   979         usage = 0;
   980     }
   981 
   982     if (D3D_CreateTextureRep(data->device, &texturedata->texture, usage, texture->format, texture->w, texture->h) < 0) {
   983         return -1;
   984     }
   985 
   986     if (texture->format == SDL_PIXELFORMAT_YV12 ||
   987         texture->format == SDL_PIXELFORMAT_IYUV) {
   988         texturedata->yuv = SDL_TRUE;
   989 
   990         if (D3D_CreateTextureRep(data->device, &texturedata->utexture, usage, texture->format, texture->w / 2, texture->h / 2) < 0) {
   991             return -1;
   992         }
   993 
   994         if (D3D_CreateTextureRep(data->device, &texturedata->vtexture, usage, texture->format, texture->w / 2, texture->h / 2) < 0) {
   995             return -1;
   996         }
   997     }
   998     return 0;
   999 }
  1000 
  1001 static int
  1002 D3D_RecreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  1003 {
  1004     D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
  1005     D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
  1006 
  1007     if (!texturedata) {
  1008         return 0;
  1009     }
  1010 
  1011     if (D3D_RecreateTextureRep(data->device, &texturedata->texture, texture->format, texture->w, texture->h) < 0) {
  1012         return -1;
  1013     }
  1014 
  1015     if (texturedata->yuv) {
  1016         if (D3D_RecreateTextureRep(data->device, &texturedata->utexture, texture->format, texture->w / 2, texture->h / 2) < 0) {
  1017             return -1;
  1018         }
  1019 
  1020         if (D3D_RecreateTextureRep(data->device, &texturedata->vtexture, texture->format, texture->w / 2, texture->h / 2) < 0) {
  1021             return -1;
  1022         }
  1023     }
  1024     return 0;
  1025 }
  1026 
  1027 static int
  1028 D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
  1029                   const SDL_Rect * rect, const void *pixels, int pitch)
  1030 {
  1031     D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
  1032     D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata;
  1033 
  1034     if (!texturedata) {
  1035         SDL_SetError("Texture is not currently available");
  1036         return -1;
  1037     }
  1038 
  1039     if (D3D_UpdateTextureRep(data->device, &texturedata->texture, texture->format, rect->x, rect->y, rect->w, rect->h, pixels, pitch) < 0) {
  1040         return -1;
  1041     }
  1042 
  1043     if (texturedata->yuv) {
  1044         /* Skip to the correct offset into the next texture */
  1045         pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
  1046 
  1047         if (D3D_UpdateTextureRep(data->device, texture->format == SDL_PIXELFORMAT_YV12 ? &texturedata->vtexture : &texturedata->utexture, texture->format, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, pixels, pitch / 2) < 0) {
  1048             return -1;
  1049         }
  1050 
  1051         /* Skip to the correct offset into the next texture */
  1052         pixels = (const void*)((const Uint8*)pixels + (rect->h * pitch)/4);
  1053         if (D3D_UpdateTextureRep(data->device, texture->format == SDL_PIXELFORMAT_YV12 ? &texturedata->utexture : &texturedata->vtexture, texture->format, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, pixels, pitch / 2) < 0) {
  1054             return -1;
  1055         }
  1056     }
  1057     return 0;
  1058 }
  1059 
  1060 static int
  1061 D3D_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
  1062                      const SDL_Rect * rect,
  1063                      const Uint8 *Yplane, int Ypitch,
  1064                      const Uint8 *Uplane, int Upitch,
  1065                      const Uint8 *Vplane, int Vpitch)
  1066 {
  1067     D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
  1068     D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata;
  1069 
  1070     if (!texturedata) {
  1071         SDL_SetError("Texture is not currently available");
  1072         return -1;
  1073     }
  1074 
  1075     if (D3D_UpdateTextureRep(data->device, &texturedata->texture, texture->format, rect->x, rect->y, rect->w, rect->h, Yplane, Ypitch) < 0) {
  1076         return -1;
  1077     }
  1078     if (D3D_UpdateTextureRep(data->device, &texturedata->utexture, texture->format, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, Uplane, Upitch) < 0) {
  1079         return -1;
  1080     }
  1081     if (D3D_UpdateTextureRep(data->device, &texturedata->vtexture, texture->format, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, Vplane, Vpitch) < 0) {
  1082         return -1;
  1083     }
  1084     return 0;
  1085 }
  1086 
  1087 static int
  1088 D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
  1089                 const SDL_Rect * rect, void **pixels, int *pitch)
  1090 {
  1091     D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
  1092     D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
  1093     IDirect3DDevice9 *device = data->device;
  1094 
  1095     if (!texturedata) {
  1096         SDL_SetError("Texture is not currently available");
  1097         return -1;
  1098     }
  1099 
  1100     texturedata->locked_rect = *rect;
  1101 
  1102     if (texturedata->yuv) {
  1103         /* It's more efficient to upload directly... */
  1104         if (!texturedata->pixels) {
  1105             texturedata->pitch = texture->w;
  1106             texturedata->pixels = (Uint8 *)SDL_malloc((texture->h * texturedata->pitch * 3) / 2);
  1107             if (!texturedata->pixels) {
  1108                 return SDL_OutOfMemory();
  1109             }
  1110         }
  1111         *pixels =
  1112             (void *) ((Uint8 *) texturedata->pixels + rect->y * texturedata->pitch +
  1113                       rect->x * SDL_BYTESPERPIXEL(texture->format));
  1114         *pitch = texturedata->pitch;
  1115     } else {
  1116         RECT d3drect;
  1117         D3DLOCKED_RECT locked;
  1118         HRESULT result;
  1119 
  1120         if (D3D_CreateStagingTexture(device, &texturedata->texture) < 0) {
  1121             return -1;
  1122         }
  1123 
  1124         d3drect.left = rect->x;
  1125         d3drect.right = rect->x + rect->w;
  1126         d3drect.top = rect->y;
  1127         d3drect.bottom = rect->y + rect->h;
  1128 
  1129         result = IDirect3DTexture9_LockRect(texturedata->texture.staging, 0, &locked, &d3drect, 0);
  1130         if (FAILED(result)) {
  1131             return D3D_SetError("LockRect()", result);
  1132         }
  1133         *pixels = locked.pBits;
  1134         *pitch = locked.Pitch;
  1135     }
  1136     return 0;
  1137 }
  1138 
  1139 static void
  1140 D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  1141 {
  1142     /*D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;*/
  1143     D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
  1144 
  1145     if (!texturedata) {
  1146         return;
  1147     }
  1148 
  1149     if (texturedata->yuv) {
  1150         const SDL_Rect *rect = &texturedata->locked_rect;
  1151         void *pixels =
  1152             (void *) ((Uint8 *) texturedata->pixels + rect->y * texturedata->pitch +
  1153                       rect->x * SDL_BYTESPERPIXEL(texture->format));
  1154         D3D_UpdateTexture(renderer, texture, rect, pixels, texturedata->pitch);
  1155     } else {
  1156         IDirect3DTexture9_UnlockRect(texturedata->texture.staging, 0);
  1157         texturedata->texture.dirty = SDL_TRUE;
  1158    }
  1159 }
  1160 
  1161 static int
  1162 D3D_SetRenderTargetInternal(SDL_Renderer * renderer, SDL_Texture * texture)
  1163 {
  1164     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1165     D3D_TextureData *texturedata;
  1166     D3D_TextureRep *texturerep;
  1167     HRESULT result;
  1168     IDirect3DDevice9 *device = data->device;
  1169 
  1170     /* Release the previous render target if it wasn't the default one */
  1171     if (data->currentRenderTarget != NULL) {
  1172         IDirect3DSurface9_Release(data->currentRenderTarget);
  1173         data->currentRenderTarget = NULL;
  1174     }
  1175 
  1176     if (texture == NULL) {
  1177         IDirect3DDevice9_SetRenderTarget(data->device, 0, data->defaultRenderTarget);
  1178         return 0;
  1179     }
  1180 
  1181     texturedata = (D3D_TextureData *)texture->driverdata;
  1182     if (!texturedata) {
  1183         SDL_SetError("Texture is not currently available");
  1184         return -1;
  1185     }
  1186 
  1187     /* Make sure the render target is updated if it was locked and written to */
  1188     texturerep = &texturedata->texture;
  1189     if (texturerep->dirty && texturerep->staging) {
  1190         if (!texturerep->texture) {
  1191             result = IDirect3DDevice9_CreateTexture(device, texturerep->w, texturerep->h, 1, texturerep->usage,
  1192                 PixelFormatToD3DFMT(texturerep->format), D3DPOOL_DEFAULT, &texturerep->texture, NULL);
  1193             if (FAILED(result)) {
  1194                 return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
  1195             }
  1196         }
  1197 
  1198         result = IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)texturerep->staging, (IDirect3DBaseTexture9 *)texturerep->texture);
  1199         if (FAILED(result)) {
  1200             return D3D_SetError("UpdateTexture()", result);
  1201         }
  1202         texturerep->dirty = SDL_FALSE;
  1203     }
  1204 
  1205     result = IDirect3DTexture9_GetSurfaceLevel(texturedata->texture.texture, 0, &data->currentRenderTarget);
  1206     if(FAILED(result)) {
  1207         return D3D_SetError("GetSurfaceLevel()", result);
  1208     }
  1209     result = IDirect3DDevice9_SetRenderTarget(data->device, 0, data->currentRenderTarget);
  1210     if(FAILED(result)) {
  1211         return D3D_SetError("SetRenderTarget()", result);
  1212     }
  1213 
  1214     return 0;
  1215 }
  1216 
  1217 static int
  1218 D3D_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
  1219 {
  1220     D3D_ActivateRenderer(renderer);
  1221 
  1222     return D3D_SetRenderTargetInternal(renderer, texture);
  1223 }
  1224 
  1225 static int
  1226 D3D_UpdateViewport(SDL_Renderer * renderer)
  1227 {
  1228     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1229     D3DVIEWPORT9 viewport;
  1230     D3DMATRIX matrix;
  1231 
  1232     /* Set the viewport */
  1233     viewport.X = renderer->viewport.x;
  1234     viewport.Y = renderer->viewport.y;
  1235     viewport.Width = renderer->viewport.w;
  1236     viewport.Height = renderer->viewport.h;
  1237     viewport.MinZ = 0.0f;
  1238     viewport.MaxZ = 1.0f;
  1239     IDirect3DDevice9_SetViewport(data->device, &viewport);
  1240 
  1241     /* Set an orthographic projection matrix */
  1242     if (renderer->viewport.w && renderer->viewport.h) {
  1243         matrix.m[0][0] = 2.0f / renderer->viewport.w;
  1244         matrix.m[0][1] = 0.0f;
  1245         matrix.m[0][2] = 0.0f;
  1246         matrix.m[0][3] = 0.0f;
  1247         matrix.m[1][0] = 0.0f;
  1248         matrix.m[1][1] = -2.0f / renderer->viewport.h;
  1249         matrix.m[1][2] = 0.0f;
  1250         matrix.m[1][3] = 0.0f;
  1251         matrix.m[2][0] = 0.0f;
  1252         matrix.m[2][1] = 0.0f;
  1253         matrix.m[2][2] = 1.0f;
  1254         matrix.m[2][3] = 0.0f;
  1255         matrix.m[3][0] = -1.0f;
  1256         matrix.m[3][1] = 1.0f;
  1257         matrix.m[3][2] = 0.0f;
  1258         matrix.m[3][3] = 1.0f;
  1259         IDirect3DDevice9_SetTransform(data->device, D3DTS_PROJECTION, &matrix);
  1260     }
  1261 
  1262     return 0;
  1263 }
  1264 
  1265 static int
  1266 D3D_UpdateClipRect(SDL_Renderer * renderer)
  1267 {
  1268     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1269 
  1270     if (renderer->clipping_enabled) {
  1271         const SDL_Rect *rect = &renderer->clip_rect;
  1272         RECT r;
  1273         HRESULT result;
  1274 
  1275         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, TRUE);
  1276         r.left = renderer->viewport.x + rect->x;
  1277         r.top = renderer->viewport.y + rect->y;
  1278         r.right = renderer->viewport.x + rect->x + rect->w;
  1279         r.bottom = renderer->viewport.y + rect->y + rect->h;
  1280 
  1281         result = IDirect3DDevice9_SetScissorRect(data->device, &r);
  1282         if (result != D3D_OK) {
  1283             D3D_SetError("SetScissor()", result);
  1284             return -1;
  1285         }
  1286     } else {
  1287         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, FALSE);
  1288     }
  1289     return 0;
  1290 }
  1291 
  1292 static int
  1293 D3D_RenderClear(SDL_Renderer * renderer)
  1294 {
  1295     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1296     DWORD color;
  1297     HRESULT result;
  1298     int BackBufferWidth, BackBufferHeight;
  1299 
  1300     if (D3D_ActivateRenderer(renderer) < 0) {
  1301         return -1;
  1302     }
  1303 
  1304     color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
  1305 
  1306     if (renderer->target) {
  1307         BackBufferWidth = renderer->target->w;
  1308         BackBufferHeight = renderer->target->h;
  1309     } else {
  1310         BackBufferWidth = data->pparams.BackBufferWidth;
  1311         BackBufferHeight = data->pparams.BackBufferHeight;
  1312     }
  1313 
  1314     /* Don't reset the viewport if we don't have to! */
  1315     if (!renderer->viewport.x && !renderer->viewport.y &&
  1316         renderer->viewport.w == BackBufferWidth &&
  1317         renderer->viewport.h == BackBufferHeight) {
  1318         result = IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
  1319     } else {
  1320         D3DVIEWPORT9 viewport;
  1321 
  1322         /* Clear is defined to clear the entire render target */
  1323         viewport.X = 0;
  1324         viewport.Y = 0;
  1325         viewport.Width = BackBufferWidth;
  1326         viewport.Height = BackBufferHeight;
  1327         viewport.MinZ = 0.0f;
  1328         viewport.MaxZ = 1.0f;
  1329         IDirect3DDevice9_SetViewport(data->device, &viewport);
  1330 
  1331         result = IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
  1332 
  1333         /* Reset the viewport */
  1334         viewport.X = renderer->viewport.x;
  1335         viewport.Y = renderer->viewport.y;
  1336         viewport.Width = renderer->viewport.w;
  1337         viewport.Height = renderer->viewport.h;
  1338         viewport.MinZ = 0.0f;
  1339         viewport.MaxZ = 1.0f;
  1340         IDirect3DDevice9_SetViewport(data->device, &viewport);
  1341     }
  1342 
  1343     if (FAILED(result)) {
  1344         return D3D_SetError("Clear()", result);
  1345     }
  1346     return 0;
  1347 }
  1348 
  1349 static void
  1350 D3D_SetBlendMode(D3D_RenderData * data, int blendMode)
  1351 {
  1352     switch (blendMode) {
  1353     case SDL_BLENDMODE_NONE:
  1354         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
  1355                                         FALSE);
  1356         break;
  1357     case SDL_BLENDMODE_BLEND:
  1358         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
  1359                                         TRUE);
  1360         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
  1361                                         D3DBLEND_SRCALPHA);
  1362         IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
  1363                                         D3DBLEND_INVSRCALPHA);
  1364         if (data->enableSeparateAlphaBlend) {
  1365             IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA,
  1366                                             D3DBLEND_ONE);
  1367             IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA,
  1368                                             D3DBLEND_INVSRCALPHA);
  1369         }
  1370         break;
  1371     case SDL_BLENDMODE_ADD:
  1372         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
  1373                                         TRUE);
  1374         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
  1375                                         D3DBLEND_SRCALPHA);
  1376         IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
  1377                                         D3DBLEND_ONE);
  1378         if (data->enableSeparateAlphaBlend) {
  1379             IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA,
  1380                                             D3DBLEND_ZERO);
  1381             IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA,
  1382                                             D3DBLEND_ONE);
  1383         }
  1384         break;
  1385     case SDL_BLENDMODE_MOD:
  1386         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
  1387                                         TRUE);
  1388         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
  1389                                         D3DBLEND_ZERO);
  1390         IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
  1391                                         D3DBLEND_SRCCOLOR);
  1392         if (data->enableSeparateAlphaBlend) {
  1393             IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA,
  1394                                             D3DBLEND_ZERO);
  1395             IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA,
  1396                                             D3DBLEND_ONE);
  1397         }
  1398         break;
  1399     }
  1400 }
  1401 
  1402 static int
  1403 D3D_RenderDrawPoints(SDL_Renderer * renderer, const SDL_FPoint * points,
  1404                      int count)
  1405 {
  1406     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1407     DWORD color;
  1408     Vertex *vertices;
  1409     int i;
  1410     HRESULT result;
  1411 
  1412     if (D3D_ActivateRenderer(renderer) < 0) {
  1413         return -1;
  1414     }
  1415 
  1416     D3D_SetBlendMode(data, renderer->blendMode);
  1417 
  1418     result =
  1419         IDirect3DDevice9_SetTexture(data->device, 0,
  1420                                     (IDirect3DBaseTexture9 *) 0);
  1421     if (FAILED(result)) {
  1422         return D3D_SetError("SetTexture()", result);
  1423     }
  1424 
  1425     color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
  1426 
  1427     vertices = SDL_stack_alloc(Vertex, count);
  1428     for (i = 0; i < count; ++i) {
  1429         vertices[i].x = points[i].x;
  1430         vertices[i].y = points[i].y;
  1431         vertices[i].z = 0.0f;
  1432         vertices[i].color = color;
  1433         vertices[i].u = 0.0f;
  1434         vertices[i].v = 0.0f;
  1435     }
  1436     result =
  1437         IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, count,
  1438                                          vertices, sizeof(*vertices));
  1439     SDL_stack_free(vertices);
  1440     if (FAILED(result)) {
  1441         return D3D_SetError("DrawPrimitiveUP()", result);
  1442     }
  1443     return 0;
  1444 }
  1445 
  1446 static int
  1447 D3D_RenderDrawLines(SDL_Renderer * renderer, const SDL_FPoint * points,
  1448                     int count)
  1449 {
  1450     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1451     DWORD color;
  1452     Vertex *vertices;
  1453     int i;
  1454     HRESULT result;
  1455 
  1456     if (D3D_ActivateRenderer(renderer) < 0) {
  1457         return -1;
  1458     }
  1459 
  1460     D3D_SetBlendMode(data, renderer->blendMode);
  1461 
  1462     result =
  1463         IDirect3DDevice9_SetTexture(data->device, 0,
  1464                                     (IDirect3DBaseTexture9 *) 0);
  1465     if (FAILED(result)) {
  1466         return D3D_SetError("SetTexture()", result);
  1467     }
  1468 
  1469     color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
  1470 
  1471     vertices = SDL_stack_alloc(Vertex, count);
  1472     for (i = 0; i < count; ++i) {
  1473         vertices[i].x = points[i].x;
  1474         vertices[i].y = points[i].y;
  1475         vertices[i].z = 0.0f;
  1476         vertices[i].color = color;
  1477         vertices[i].u = 0.0f;
  1478         vertices[i].v = 0.0f;
  1479     }
  1480     result =
  1481         IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_LINESTRIP, count-1,
  1482                                          vertices, sizeof(*vertices));
  1483 
  1484     /* DirectX 9 has the same line rasterization semantics as GDI,
  1485        so we need to close the endpoint of the line */
  1486     if (count == 2 ||
  1487         points[0].x != points[count-1].x || points[0].y != points[count-1].y) {
  1488         vertices[0].x = points[count-1].x;
  1489         vertices[0].y = points[count-1].y;
  1490         result = IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, 1, vertices, sizeof(*vertices));
  1491     }
  1492 
  1493     SDL_stack_free(vertices);
  1494     if (FAILED(result)) {
  1495         return D3D_SetError("DrawPrimitiveUP()", result);
  1496     }
  1497     return 0;
  1498 }
  1499 
  1500 static int
  1501 D3D_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects,
  1502                     int count)
  1503 {
  1504     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1505     DWORD color;
  1506     int i;
  1507     float minx, miny, maxx, maxy;
  1508     Vertex vertices[4];
  1509     HRESULT result;
  1510 
  1511     if (D3D_ActivateRenderer(renderer) < 0) {
  1512         return -1;
  1513     }
  1514 
  1515     D3D_SetBlendMode(data, renderer->blendMode);
  1516 
  1517     result =
  1518         IDirect3DDevice9_SetTexture(data->device, 0,
  1519                                     (IDirect3DBaseTexture9 *) 0);
  1520     if (FAILED(result)) {
  1521         return D3D_SetError("SetTexture()", result);
  1522     }
  1523 
  1524     color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
  1525 
  1526     for (i = 0; i < count; ++i) {
  1527         const SDL_FRect *rect = &rects[i];
  1528 
  1529         minx = rect->x;
  1530         miny = rect->y;
  1531         maxx = rect->x + rect->w;
  1532         maxy = rect->y + rect->h;
  1533 
  1534         vertices[0].x = minx;
  1535         vertices[0].y = miny;
  1536         vertices[0].z = 0.0f;
  1537         vertices[0].color = color;
  1538         vertices[0].u = 0.0f;
  1539         vertices[0].v = 0.0f;
  1540 
  1541         vertices[1].x = maxx;
  1542         vertices[1].y = miny;
  1543         vertices[1].z = 0.0f;
  1544         vertices[1].color = color;
  1545         vertices[1].u = 0.0f;
  1546         vertices[1].v = 0.0f;
  1547 
  1548         vertices[2].x = maxx;
  1549         vertices[2].y = maxy;
  1550         vertices[2].z = 0.0f;
  1551         vertices[2].color = color;
  1552         vertices[2].u = 0.0f;
  1553         vertices[2].v = 0.0f;
  1554 
  1555         vertices[3].x = minx;
  1556         vertices[3].y = maxy;
  1557         vertices[3].z = 0.0f;
  1558         vertices[3].color = color;
  1559         vertices[3].u = 0.0f;
  1560         vertices[3].v = 0.0f;
  1561 
  1562         result =
  1563             IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN,
  1564                                              2, vertices, sizeof(*vertices));
  1565         if (FAILED(result)) {
  1566             return D3D_SetError("DrawPrimitiveUP()", result);
  1567         }
  1568     }
  1569     return 0;
  1570 }
  1571 
  1572 static void
  1573 D3D_UpdateTextureScaleMode(D3D_RenderData *data, D3D_TextureData *texturedata, unsigned index)
  1574 {
  1575     if (texturedata->scaleMode != data->scaleMode[index]) {
  1576         IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MINFILTER,
  1577                                          texturedata->scaleMode);
  1578         IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MAGFILTER,
  1579                                          texturedata->scaleMode);
  1580         data->scaleMode[index] = texturedata->scaleMode;
  1581     }
  1582 }
  1583 
  1584 static int
  1585 D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
  1586                const SDL_Rect * srcrect, const SDL_FRect * dstrect)
  1587 {
  1588     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1589     D3D_TextureData *texturedata;
  1590     LPDIRECT3DPIXELSHADER9 shader = NULL;
  1591     float minx, miny, maxx, maxy;
  1592     float minu, maxu, minv, maxv;
  1593     DWORD color;
  1594     Vertex vertices[4];
  1595     HRESULT result;
  1596 
  1597     if (D3D_ActivateRenderer(renderer) < 0) {
  1598         return -1;
  1599     }
  1600 
  1601     texturedata = (D3D_TextureData *)texture->driverdata;
  1602     if (!texturedata) {
  1603         SDL_SetError("Texture is not currently available");
  1604         return -1;
  1605     }
  1606 
  1607     minx = dstrect->x - 0.5f;
  1608     miny = dstrect->y - 0.5f;
  1609     maxx = dstrect->x + dstrect->w - 0.5f;
  1610     maxy = dstrect->y + dstrect->h - 0.5f;
  1611 
  1612     minu = (float) srcrect->x / texture->w;
  1613     maxu = (float) (srcrect->x + srcrect->w) / texture->w;
  1614     minv = (float) srcrect->y / texture->h;
  1615     maxv = (float) (srcrect->y + srcrect->h) / texture->h;
  1616 
  1617     color = D3DCOLOR_ARGB(texture->a, texture->r, texture->g, texture->b);
  1618 
  1619     vertices[0].x = minx;
  1620     vertices[0].y = miny;
  1621     vertices[0].z = 0.0f;
  1622     vertices[0].color = color;
  1623     vertices[0].u = minu;
  1624     vertices[0].v = minv;
  1625 
  1626     vertices[1].x = maxx;
  1627     vertices[1].y = miny;
  1628     vertices[1].z = 0.0f;
  1629     vertices[1].color = color;
  1630     vertices[1].u = maxu;
  1631     vertices[1].v = minv;
  1632 
  1633     vertices[2].x = maxx;
  1634     vertices[2].y = maxy;
  1635     vertices[2].z = 0.0f;
  1636     vertices[2].color = color;
  1637     vertices[2].u = maxu;
  1638     vertices[2].v = maxv;
  1639 
  1640     vertices[3].x = minx;
  1641     vertices[3].y = maxy;
  1642     vertices[3].z = 0.0f;
  1643     vertices[3].color = color;
  1644     vertices[3].u = minu;
  1645     vertices[3].v = maxv;
  1646 
  1647     D3D_SetBlendMode(data, texture->blendMode);
  1648 
  1649     D3D_UpdateTextureScaleMode(data, texturedata, 0);
  1650 
  1651     if (D3D_BindTextureRep(data->device, &texturedata->texture, 0) < 0) {
  1652         return -1;
  1653     }
  1654 
  1655     if (texturedata->yuv) {
  1656         shader = data->ps_yuv;
  1657 
  1658         D3D_UpdateTextureScaleMode(data, texturedata, 1);
  1659         D3D_UpdateTextureScaleMode(data, texturedata, 2);
  1660 
  1661         if (D3D_BindTextureRep(data->device, &texturedata->utexture, 1) < 0) {
  1662             return -1;
  1663         }
  1664         if (D3D_BindTextureRep(data->device, &texturedata->vtexture, 2) < 0) {
  1665             return -1;
  1666         }
  1667     }
  1668 
  1669     if (shader) {
  1670         result = IDirect3DDevice9_SetPixelShader(data->device, shader);
  1671         if (FAILED(result)) {
  1672             return D3D_SetError("SetShader()", result);
  1673         }
  1674     }
  1675     result =
  1676         IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2,
  1677                                          vertices, sizeof(*vertices));
  1678     if (FAILED(result)) {
  1679         return D3D_SetError("DrawPrimitiveUP()", result);
  1680     }
  1681     if (shader) {
  1682         result = IDirect3DDevice9_SetPixelShader(data->device, NULL);
  1683         if (FAILED(result)) {
  1684             return D3D_SetError("SetShader()", result);
  1685         }
  1686     }
  1687     return 0;
  1688 }
  1689 
  1690 
  1691 static int
  1692 D3D_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
  1693                const SDL_Rect * srcrect, const SDL_FRect * dstrect,
  1694                const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip)
  1695 {
  1696     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1697     D3D_TextureData *texturedata;
  1698     LPDIRECT3DPIXELSHADER9 shader = NULL;
  1699     float minx, miny, maxx, maxy;
  1700     float minu, maxu, minv, maxv;
  1701     float centerx, centery;
  1702     DWORD color;
  1703     Vertex vertices[4];
  1704     Float4X4 modelMatrix;
  1705     HRESULT result;
  1706 
  1707     if (D3D_ActivateRenderer(renderer) < 0) {
  1708         return -1;
  1709     }
  1710 
  1711     texturedata = (D3D_TextureData *)texture->driverdata;
  1712     if (!texturedata) {
  1713         SDL_SetError("Texture is not currently available");
  1714         return -1;
  1715     }
  1716 
  1717     centerx = center->x;
  1718     centery = center->y;
  1719 
  1720     if (flip & SDL_FLIP_HORIZONTAL) {
  1721         minx = dstrect->w - centerx - 0.5f;
  1722         maxx = -centerx - 0.5f;
  1723     }
  1724     else {
  1725         minx = -centerx - 0.5f;
  1726         maxx = dstrect->w - centerx - 0.5f;
  1727     }
  1728 
  1729     if (flip & SDL_FLIP_VERTICAL) {
  1730         miny = dstrect->h - centery - 0.5f;
  1731         maxy = -centery - 0.5f;
  1732     }
  1733     else {
  1734         miny = -centery - 0.5f;
  1735         maxy = dstrect->h - centery - 0.5f;
  1736     }
  1737 
  1738     minu = (float) srcrect->x / texture->w;
  1739     maxu = (float) (srcrect->x + srcrect->w) / texture->w;
  1740     minv = (float) srcrect->y / texture->h;
  1741     maxv = (float) (srcrect->y + srcrect->h) / texture->h;
  1742 
  1743     color = D3DCOLOR_ARGB(texture->a, texture->r, texture->g, texture->b);
  1744 
  1745     vertices[0].x = minx;
  1746     vertices[0].y = miny;
  1747     vertices[0].z = 0.0f;
  1748     vertices[0].color = color;
  1749     vertices[0].u = minu;
  1750     vertices[0].v = minv;
  1751 
  1752     vertices[1].x = maxx;
  1753     vertices[1].y = miny;
  1754     vertices[1].z = 0.0f;
  1755     vertices[1].color = color;
  1756     vertices[1].u = maxu;
  1757     vertices[1].v = minv;
  1758 
  1759     vertices[2].x = maxx;
  1760     vertices[2].y = maxy;
  1761     vertices[2].z = 0.0f;
  1762     vertices[2].color = color;
  1763     vertices[2].u = maxu;
  1764     vertices[2].v = maxv;
  1765 
  1766     vertices[3].x = minx;
  1767     vertices[3].y = maxy;
  1768     vertices[3].z = 0.0f;
  1769     vertices[3].color = color;
  1770     vertices[3].u = minu;
  1771     vertices[3].v = maxv;
  1772 
  1773     D3D_SetBlendMode(data, texture->blendMode);
  1774 
  1775     /* Rotate and translate */
  1776     modelMatrix = MatrixMultiply(
  1777             MatrixRotationZ((float)(M_PI * (float) angle / 180.0f)),
  1778             MatrixTranslation(dstrect->x + center->x, dstrect->y + center->y, 0)
  1779 );
  1780     IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)&modelMatrix);
  1781 
  1782     D3D_UpdateTextureScaleMode(data, texturedata, 0);
  1783 
  1784     if (D3D_BindTextureRep(data->device, &texturedata->texture, 0) < 0) {
  1785         return -1;
  1786     }
  1787 
  1788     if (texturedata->yuv) {
  1789         shader = data->ps_yuv;
  1790 
  1791         D3D_UpdateTextureScaleMode(data, texturedata, 1);
  1792         D3D_UpdateTextureScaleMode(data, texturedata, 2);
  1793         
  1794         if (D3D_BindTextureRep(data->device, &texturedata->utexture, 1) < 0) {
  1795             return -1;
  1796         }
  1797         if (D3D_BindTextureRep(data->device, &texturedata->vtexture, 2) < 0) {
  1798             return -1;
  1799         }
  1800     }
  1801 
  1802     if (shader) {
  1803         result = IDirect3DDevice9_SetPixelShader(data->device, shader);
  1804         if (FAILED(result)) {
  1805             return D3D_SetError("SetShader()", result);
  1806         }
  1807     }
  1808     result =
  1809         IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2,
  1810                                          vertices, sizeof(*vertices));
  1811     if (FAILED(result)) {
  1812         return D3D_SetError("DrawPrimitiveUP()", result);
  1813     }
  1814     if (shader) {
  1815         result = IDirect3DDevice9_SetPixelShader(data->device, NULL);
  1816         if (FAILED(result)) {
  1817             return D3D_SetError("SetShader()", result);
  1818         }
  1819     }
  1820 
  1821     modelMatrix = MatrixIdentity();
  1822     IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)&modelMatrix);
  1823     return 0;
  1824 }
  1825 
  1826 static int
  1827 D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
  1828                      Uint32 format, void * pixels, int pitch)
  1829 {
  1830     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1831     D3DSURFACE_DESC desc;
  1832     LPDIRECT3DSURFACE9 backBuffer;
  1833     LPDIRECT3DSURFACE9 surface;
  1834     RECT d3drect;
  1835     D3DLOCKED_RECT locked;
  1836     HRESULT result;
  1837 
  1838     if (data->currentRenderTarget) {
  1839         backBuffer = data->currentRenderTarget;
  1840     } else {
  1841         backBuffer = data->defaultRenderTarget;
  1842     }
  1843 
  1844     result = IDirect3DSurface9_GetDesc(backBuffer, &desc);
  1845     if (FAILED(result)) {
  1846         IDirect3DSurface9_Release(backBuffer);
  1847         return D3D_SetError("GetDesc()", result);
  1848     }
  1849 
  1850     result = IDirect3DDevice9_CreateOffscreenPlainSurface(data->device, desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surface, NULL);
  1851     if (FAILED(result)) {
  1852         IDirect3DSurface9_Release(backBuffer);
  1853         return D3D_SetError("CreateOffscreenPlainSurface()", result);
  1854     }
  1855 
  1856     result = IDirect3DDevice9_GetRenderTargetData(data->device, backBuffer, surface);
  1857     if (FAILED(result)) {
  1858         IDirect3DSurface9_Release(surface);
  1859         IDirect3DSurface9_Release(backBuffer);
  1860         return D3D_SetError("GetRenderTargetData()", result);
  1861     }
  1862 
  1863     d3drect.left = rect->x;
  1864     d3drect.right = rect->x + rect->w;
  1865     d3drect.top = rect->y;
  1866     d3drect.bottom = rect->y + rect->h;
  1867 
  1868     result = IDirect3DSurface9_LockRect(surface, &locked, &d3drect, D3DLOCK_READONLY);
  1869     if (FAILED(result)) {
  1870         IDirect3DSurface9_Release(surface);
  1871         IDirect3DSurface9_Release(backBuffer);
  1872         return D3D_SetError("LockRect()", result);
  1873     }
  1874 
  1875     SDL_ConvertPixels(rect->w, rect->h,
  1876                       D3DFMTToPixelFormat(desc.Format), locked.pBits, locked.Pitch,
  1877                       format, pixels, pitch);
  1878 
  1879     IDirect3DSurface9_UnlockRect(surface);
  1880 
  1881     IDirect3DSurface9_Release(surface);
  1882 
  1883     return 0;
  1884 }
  1885 
  1886 static void
  1887 D3D_RenderPresent(SDL_Renderer * renderer)
  1888 {
  1889     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1890     HRESULT result;
  1891 
  1892     if (!data->beginScene) {
  1893         IDirect3DDevice9_EndScene(data->device);
  1894         data->beginScene = SDL_TRUE;
  1895     }
  1896 
  1897     result = IDirect3DDevice9_TestCooperativeLevel(data->device);
  1898     if (result == D3DERR_DEVICELOST) {
  1899         /* We'll reset later */
  1900         return;
  1901     }
  1902     if (result == D3DERR_DEVICENOTRESET) {
  1903         D3D_Reset(renderer);
  1904     }
  1905     result = IDirect3DDevice9_Present(data->device, NULL, NULL, NULL, NULL);
  1906     if (FAILED(result)) {
  1907         D3D_SetError("Present()", result);
  1908     }
  1909 }
  1910 
  1911 static void
  1912 D3D_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  1913 {
  1914     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
  1915 
  1916     if (!data) {
  1917         return;
  1918     }
  1919     D3D_DestroyTextureRep(&data->texture);
  1920     D3D_DestroyTextureRep(&data->utexture);
  1921     D3D_DestroyTextureRep(&data->vtexture);
  1922     SDL_free(data->pixels);
  1923     SDL_free(data);
  1924     texture->driverdata = NULL;
  1925 }
  1926 
  1927 static void
  1928 D3D_DestroyRenderer(SDL_Renderer * renderer)
  1929 {
  1930     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1931 
  1932     if (data) {
  1933         /* Release the render target */
  1934         if (data->defaultRenderTarget) {
  1935             IDirect3DSurface9_Release(data->defaultRenderTarget);
  1936             data->defaultRenderTarget = NULL;
  1937         }
  1938         if (data->currentRenderTarget != NULL) {
  1939             IDirect3DSurface9_Release(data->currentRenderTarget);
  1940             data->currentRenderTarget = NULL;
  1941         }
  1942         if (data->ps_yuv) {
  1943             IDirect3DPixelShader9_Release(data->ps_yuv);
  1944         }
  1945         if (data->device) {
  1946             IDirect3DDevice9_Release(data->device);
  1947         }
  1948         if (data->d3d) {
  1949             IDirect3D9_Release(data->d3d);
  1950             SDL_UnloadObject(data->d3dDLL);
  1951         }
  1952         SDL_free(data);
  1953     }
  1954     SDL_free(renderer);
  1955 }
  1956 #endif /* SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED */
  1957 
  1958 #ifdef __WIN32__
  1959 /* This function needs to always exist on Windows, for the Dynamic API. */
  1960 IDirect3DDevice9 *
  1961 SDL_RenderGetD3D9Device(SDL_Renderer * renderer)
  1962 {
  1963     IDirect3DDevice9 *device = NULL;
  1964 
  1965 #if SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED
  1966     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1967 
  1968     /* Make sure that this is a D3D renderer */
  1969     if (renderer->DestroyRenderer != D3D_DestroyRenderer) {
  1970         SDL_SetError("Renderer is not a D3D renderer");
  1971         return NULL;
  1972     }
  1973 
  1974     device = data->device;
  1975     if (device) {
  1976         IDirect3DDevice9_AddRef(device);
  1977     }
  1978 #endif /* SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED */
  1979 
  1980     return device;
  1981 }
  1982 #endif /* __WIN32__ */
  1983 
  1984 /* vi: set ts=4 sw=4 expandtab: */