src/render/direct3d/SDL_render_d3d.c
author Ryan C. Gordon
Tue, 24 Jan 2017 16:18:25 -0500
changeset 10850 c9dc0068b0e7
parent 10737 3406a0f8b041
child 11282 180e8906dc3c
permissions -rw-r--r--
configure: report libsamplerate support status.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2017 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     D3DPRESENT_PARAMETERS pparams;
   516     IDirect3DSwapChain9 *chain;
   517     D3DCAPS9 caps;
   518     DWORD device_flags;
   519     Uint32 window_flags;
   520     int w, h;
   521     SDL_DisplayMode fullscreen_mode;
   522     int displayIndex;
   523 
   524     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   525     if (!renderer) {
   526         SDL_OutOfMemory();
   527         return NULL;
   528     }
   529 
   530     data = (D3D_RenderData *) SDL_calloc(1, sizeof(*data));
   531     if (!data) {
   532         SDL_free(renderer);
   533         SDL_OutOfMemory();
   534         return NULL;
   535     }
   536 
   537     if (!D3D_LoadDLL(&data->d3dDLL, &data->d3d)) {
   538         SDL_free(renderer);
   539         SDL_free(data);
   540         SDL_SetError("Unable to create Direct3D interface");
   541         return NULL;
   542     }
   543 
   544     renderer->WindowEvent = D3D_WindowEvent;
   545     renderer->CreateTexture = D3D_CreateTexture;
   546     renderer->UpdateTexture = D3D_UpdateTexture;
   547     renderer->UpdateTextureYUV = D3D_UpdateTextureYUV;
   548     renderer->LockTexture = D3D_LockTexture;
   549     renderer->UnlockTexture = D3D_UnlockTexture;
   550     renderer->SetRenderTarget = D3D_SetRenderTarget;
   551     renderer->UpdateViewport = D3D_UpdateViewport;
   552     renderer->UpdateClipRect = D3D_UpdateClipRect;
   553     renderer->RenderClear = D3D_RenderClear;
   554     renderer->RenderDrawPoints = D3D_RenderDrawPoints;
   555     renderer->RenderDrawLines = D3D_RenderDrawLines;
   556     renderer->RenderFillRects = D3D_RenderFillRects;
   557     renderer->RenderCopy = D3D_RenderCopy;
   558     renderer->RenderCopyEx = D3D_RenderCopyEx;
   559     renderer->RenderReadPixels = D3D_RenderReadPixels;
   560     renderer->RenderPresent = D3D_RenderPresent;
   561     renderer->DestroyTexture = D3D_DestroyTexture;
   562     renderer->DestroyRenderer = D3D_DestroyRenderer;
   563     renderer->info = D3D_RenderDriver.info;
   564     renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
   565     renderer->driverdata = data;
   566 
   567     SDL_VERSION(&windowinfo.version);
   568     SDL_GetWindowWMInfo(window, &windowinfo);
   569 
   570     window_flags = SDL_GetWindowFlags(window);
   571     SDL_GetWindowSize(window, &w, &h);
   572     SDL_GetWindowDisplayMode(window, &fullscreen_mode);
   573 
   574     SDL_zero(pparams);
   575     pparams.hDeviceWindow = windowinfo.info.win.window;
   576     pparams.BackBufferWidth = w;
   577     pparams.BackBufferHeight = h;
   578     pparams.BackBufferCount = 1;
   579     pparams.SwapEffect = D3DSWAPEFFECT_DISCARD;
   580 
   581     if (window_flags & SDL_WINDOW_FULLSCREEN && (window_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
   582         pparams.Windowed = FALSE;
   583         pparams.BackBufferFormat = PixelFormatToD3DFMT(fullscreen_mode.format);
   584         pparams.FullScreen_RefreshRateInHz = fullscreen_mode.refresh_rate;
   585     } else {
   586         pparams.Windowed = TRUE;
   587         pparams.BackBufferFormat = D3DFMT_UNKNOWN;
   588         pparams.FullScreen_RefreshRateInHz = 0;
   589     }
   590     if (flags & SDL_RENDERER_PRESENTVSYNC) {
   591         pparams.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
   592     } else {
   593         pparams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
   594     }
   595 
   596     /* Get the adapter for the display that the window is on */
   597     displayIndex = SDL_GetWindowDisplayIndex(window);
   598     data->adapter = SDL_Direct3D9GetAdapterIndex(displayIndex);
   599 
   600     IDirect3D9_GetDeviceCaps(data->d3d, data->adapter, D3DDEVTYPE_HAL, &caps);
   601 
   602     device_flags = D3DCREATE_FPU_PRESERVE;
   603     if (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) {
   604         device_flags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
   605     } else {
   606         device_flags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
   607     }
   608 
   609     if (SDL_GetHintBoolean(SDL_HINT_RENDER_DIRECT3D_THREADSAFE, SDL_FALSE)) {
   610         device_flags |= D3DCREATE_MULTITHREADED;
   611     }
   612 
   613     result = IDirect3D9_CreateDevice(data->d3d, data->adapter,
   614                                      D3DDEVTYPE_HAL,
   615                                      pparams.hDeviceWindow,
   616                                      device_flags,
   617                                      &pparams, &data->device);
   618     if (FAILED(result)) {
   619         D3D_DestroyRenderer(renderer);
   620         D3D_SetError("CreateDevice()", result);
   621         return NULL;
   622     }
   623 
   624     /* Get presentation parameters to fill info */
   625     result = IDirect3DDevice9_GetSwapChain(data->device, 0, &chain);
   626     if (FAILED(result)) {
   627         D3D_DestroyRenderer(renderer);
   628         D3D_SetError("GetSwapChain()", result);
   629         return NULL;
   630     }
   631     result = IDirect3DSwapChain9_GetPresentParameters(chain, &pparams);
   632     if (FAILED(result)) {
   633         IDirect3DSwapChain9_Release(chain);
   634         D3D_DestroyRenderer(renderer);
   635         D3D_SetError("GetPresentParameters()", result);
   636         return NULL;
   637     }
   638     IDirect3DSwapChain9_Release(chain);
   639     if (pparams.PresentationInterval == D3DPRESENT_INTERVAL_ONE) {
   640         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
   641     }
   642     data->pparams = pparams;
   643 
   644     IDirect3DDevice9_GetDeviceCaps(data->device, &caps);
   645     renderer->info.max_texture_width = caps.MaxTextureWidth;
   646     renderer->info.max_texture_height = caps.MaxTextureHeight;
   647     if (caps.NumSimultaneousRTs >= 2) {
   648         renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE;
   649     }
   650 
   651     if (caps.PrimitiveMiscCaps & D3DPMISCCAPS_SEPARATEALPHABLEND) {
   652         data->enableSeparateAlphaBlend = SDL_TRUE;
   653     }
   654 
   655     /* Store the default render target */
   656     IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget);
   657     data->currentRenderTarget = NULL;
   658 
   659     /* Set up parameters for rendering */
   660     D3D_InitRenderState(data);
   661 
   662     if (caps.MaxSimultaneousTextures >= 3)
   663     {
   664 #ifdef ASSEMBLE_SHADER
   665         /* This shader was created by running the following HLSL through the fxc compiler
   666            and then tuning the generated assembly.
   667 
   668            fxc /T fx_4_0 /O3 /Gfa /Fc yuv.fxc yuv.fx
   669 
   670            --- yuv.fx ---
   671            Texture2D g_txY;
   672            Texture2D g_txU;
   673            Texture2D g_txV;
   674 
   675            SamplerState samLinear
   676            {
   677                Filter = ANISOTROPIC;
   678                AddressU = Clamp;
   679                AddressV = Clamp;
   680                MaxAnisotropy = 1;
   681            };
   682 
   683            struct VS_OUTPUT
   684            {
   685                 float2 TextureUV  : TEXCOORD0;
   686            };
   687 
   688            struct PS_OUTPUT
   689            {
   690                 float4 RGBAColor : SV_Target;
   691            };
   692 
   693            PS_OUTPUT YUV420( VS_OUTPUT In ) 
   694            {
   695                const float3 offset = {-0.0627451017, -0.501960814, -0.501960814};
   696                const float3 Rcoeff = {1.164,  0.000,  1.596};
   697                const float3 Gcoeff = {1.164, -0.391, -0.813};
   698                const float3 Bcoeff = {1.164,  2.018,  0.000};
   699 
   700                PS_OUTPUT Output;
   701                float2 TextureUV = In.TextureUV;
   702 
   703                float3 yuv;
   704                yuv.x = g_txY.Sample( samLinear, TextureUV ).r;
   705                yuv.y = g_txU.Sample( samLinear, TextureUV ).r;
   706                yuv.z = g_txV.Sample( samLinear, TextureUV ).r;
   707 
   708                yuv += offset;
   709                Output.RGBAColor.r = dot(yuv, Rcoeff);
   710                Output.RGBAColor.g = dot(yuv, Gcoeff);
   711                Output.RGBAColor.b = dot(yuv, Bcoeff);
   712                Output.RGBAColor.a = 1.0f;
   713 
   714                return Output;
   715            }
   716 
   717            technique10 RenderYUV420
   718            {
   719                pass P0
   720                {
   721                     SetPixelShader( CompileShader( ps_4_0_level_9_0, YUV420() ) );
   722                }
   723            }
   724         */
   725         const char *shader_text =
   726             "ps_2_0\n"
   727             "def c0, -0.0627451017, -0.501960814, -0.501960814, 1\n"
   728             "def c1, 1.16400003, 0, 1.59599996, 0\n"
   729             "def c2, 1.16400003, -0.391000003, -0.813000023, 0\n"
   730             "def c3, 1.16400003, 2.01799989, 0, 0\n"
   731             "dcl t0.xy\n"
   732             "dcl v0.xyzw\n"
   733             "dcl_2d s0\n"
   734             "dcl_2d s1\n"
   735             "dcl_2d s2\n"
   736             "texld r0, t0, s0\n"
   737             "texld r1, t0, s1\n"
   738             "texld r2, t0, s2\n"
   739             "mov r0.y, r1.x\n"
   740             "mov r0.z, r2.x\n"
   741             "add r0.xyz, r0, c0\n"
   742             "dp3 r1.x, r0, c1\n"
   743             "dp3 r1.y, r0, c2\n"
   744             "dp2add r1.z, r0, c3, c3.z\n"   /* Logically this is "dp3 r1.z, r0, c3" but the optimizer did its magic */
   745             "mov r1.w, c0.w\n"
   746             "mul r0, r1, v0\n"              /* Not in the HLSL, multiply by vertex color */
   747             "mov oC0, r0\n"
   748         ;
   749         LPD3DXBUFFER pCode;
   750         LPD3DXBUFFER pErrorMsgs;
   751         LPDWORD shader_data = NULL;
   752         DWORD   shader_size = 0;
   753         result = D3DXAssembleShader(shader_text, SDL_strlen(shader_text), NULL, NULL, 0, &pCode, &pErrorMsgs);
   754         if (!FAILED(result)) {
   755             shader_data = (DWORD*)pCode->lpVtbl->GetBufferPointer(pCode);
   756             shader_size = pCode->lpVtbl->GetBufferSize(pCode);
   757             PrintShaderData(shader_data, shader_size);
   758         } else {
   759             const char *error = (const char *)pErrorMsgs->lpVtbl->GetBufferPointer(pErrorMsgs);
   760             SDL_SetError("Couldn't assemble shader: %s", error);
   761         }
   762 #else
   763         const DWORD shader_data[] = {
   764             0xffff0200, 0x05000051, 0xa00f0000, 0xbd808081, 0xbf008081, 0xbf008081,
   765             0x3f800000, 0x05000051, 0xa00f0001, 0x3f94fdf4, 0x00000000, 0x3fcc49ba,
   766             0x00000000, 0x05000051, 0xa00f0002, 0x3f94fdf4, 0xbec83127, 0xbf5020c5,
   767             0x00000000, 0x05000051, 0xa00f0003, 0x3f94fdf4, 0x400126e9, 0x00000000,
   768             0x00000000, 0x0200001f, 0x80000000, 0xb0030000, 0x0200001f, 0x80000000,
   769             0x900f0000, 0x0200001f, 0x90000000, 0xa00f0800, 0x0200001f, 0x90000000,
   770             0xa00f0801, 0x0200001f, 0x90000000, 0xa00f0802, 0x03000042, 0x800f0000,
   771             0xb0e40000, 0xa0e40800, 0x03000042, 0x800f0001, 0xb0e40000, 0xa0e40801,
   772             0x03000042, 0x800f0002, 0xb0e40000, 0xa0e40802, 0x02000001, 0x80020000,
   773             0x80000001, 0x02000001, 0x80040000, 0x80000002, 0x03000002, 0x80070000,
   774             0x80e40000, 0xa0e40000, 0x03000008, 0x80010001, 0x80e40000, 0xa0e40001,
   775             0x03000008, 0x80020001, 0x80e40000, 0xa0e40002, 0x0400005a, 0x80040001,
   776             0x80e40000, 0xa0e40003, 0xa0aa0003, 0x02000001, 0x80080001, 0xa0ff0000,
   777             0x03000005, 0x800f0000, 0x80e40001, 0x90e40000, 0x02000001, 0x800f0800,
   778             0x80e40000, 0x0000ffff
   779         };
   780 #endif
   781         if (shader_data != NULL) {
   782             result = IDirect3DDevice9_CreatePixelShader(data->device, shader_data, &data->ps_yuv);
   783             if (!FAILED(result)) {
   784                 renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;
   785                 renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
   786             } else {
   787                 D3D_SetError("CreatePixelShader()", result);
   788             }
   789         }
   790     }
   791 
   792     return renderer;
   793 }
   794 
   795 static void
   796 D3D_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
   797 {
   798     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   799 
   800     if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) {
   801         data->updateSize = SDL_TRUE;
   802     }
   803 }
   804 
   805 static D3DTEXTUREFILTERTYPE
   806 GetScaleQuality(void)
   807 {
   808     const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
   809 
   810     if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) {
   811         return D3DTEXF_POINT;
   812     } else /* if (*hint == '1' || SDL_strcasecmp(hint, "linear") == 0) */ {
   813         return D3DTEXF_LINEAR;
   814     }
   815 }
   816 
   817 static int
   818 D3D_CreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWORD usage, Uint32 format, int w, int h)
   819 {
   820     HRESULT result;
   821 
   822     texture->dirty = SDL_FALSE;
   823     texture->w = w;
   824     texture->h = h;
   825     texture->usage = usage;
   826     texture->format = format;
   827 
   828     result = IDirect3DDevice9_CreateTexture(device, w, h, 1, usage,
   829         PixelFormatToD3DFMT(format),
   830         D3DPOOL_DEFAULT, &texture->texture, NULL);
   831     if (FAILED(result)) {
   832         return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
   833     }
   834     return 0;
   835 }
   836 
   837 
   838 static int
   839 D3D_CreateStagingTexture(IDirect3DDevice9 *device, D3D_TextureRep *texture)
   840 {
   841     HRESULT result;
   842 
   843     if (texture->staging == NULL) {
   844         result = IDirect3DDevice9_CreateTexture(device, texture->w, texture->h, 1, 0,
   845             PixelFormatToD3DFMT(texture->format),
   846             D3DPOOL_SYSTEMMEM, &texture->staging, NULL);
   847         if (FAILED(result)) {
   848             return D3D_SetError("CreateTexture(D3DPOOL_SYSTEMMEM)", result);
   849         }
   850     }
   851     return 0;
   852 }
   853 
   854 static int
   855 D3D_BindTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWORD sampler)
   856 {
   857     HRESULT result;
   858 
   859     if (texture->dirty && texture->staging) {
   860         if (!texture->texture) {
   861             result = IDirect3DDevice9_CreateTexture(device, texture->w, texture->h, 1, texture->usage,
   862                 PixelFormatToD3DFMT(texture->format), D3DPOOL_DEFAULT, &texture->texture, NULL);
   863             if (FAILED(result)) {
   864                 return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
   865             }
   866         }
   867 
   868         result = IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)texture->staging, (IDirect3DBaseTexture9 *)texture->texture);
   869         if (FAILED(result)) {
   870             return D3D_SetError("UpdateTexture()", result);
   871         }
   872         texture->dirty = SDL_FALSE;
   873     }
   874     result = IDirect3DDevice9_SetTexture(device, sampler, (IDirect3DBaseTexture9 *)texture->texture);
   875     if (FAILED(result)) {
   876         return D3D_SetError("SetTexture()", result);
   877     }
   878     return 0;
   879 }
   880 
   881 static int
   882 D3D_RecreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, Uint32 format, int w, int h)
   883 {
   884     if (texture->texture) {
   885         IDirect3DTexture9_Release(texture->texture);
   886         texture->texture = NULL;
   887     }
   888     if (texture->staging) {
   889         IDirect3DTexture9_AddDirtyRect(texture->staging, NULL);
   890         texture->dirty = SDL_TRUE;
   891     }
   892     return 0;
   893 }
   894 
   895 static int
   896 D3D_UpdateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, Uint32 format, int x, int y, int w, int h, const void *pixels, int pitch)
   897 {
   898     RECT d3drect;
   899     D3DLOCKED_RECT locked;
   900     const Uint8 *src;
   901     Uint8 *dst;
   902     int row, length;
   903     HRESULT result;
   904 
   905     if (D3D_CreateStagingTexture(device, texture) < 0) {
   906         return -1;
   907     }
   908 
   909     d3drect.left = x;
   910     d3drect.right = x + w;
   911     d3drect.top = y;
   912     d3drect.bottom = y + h;
   913     
   914     result = IDirect3DTexture9_LockRect(texture->staging, 0, &locked, &d3drect, 0);
   915     if (FAILED(result)) {
   916         return D3D_SetError("LockRect()", result);
   917     }
   918 
   919     src = (const Uint8 *)pixels;
   920     dst = locked.pBits;
   921     length = w * SDL_BYTESPERPIXEL(format);
   922     if (length == pitch && length == locked.Pitch) {
   923         SDL_memcpy(dst, src, length*h);
   924     } else {
   925         if (length > pitch) {
   926             length = pitch;
   927         }
   928         if (length > locked.Pitch) {
   929             length = locked.Pitch;
   930         }
   931         for (row = 0; row < h; ++row) {
   932             SDL_memcpy(dst, src, length);
   933             src += pitch;
   934             dst += locked.Pitch;
   935         }
   936     }
   937     result = IDirect3DTexture9_UnlockRect(texture->staging, 0);
   938     if (FAILED(result)) {
   939         return D3D_SetError("UnlockRect()", result);
   940     }
   941     texture->dirty = SDL_TRUE;
   942 
   943     return 0;
   944 }
   945 
   946 static void
   947 D3D_DestroyTextureRep(D3D_TextureRep *texture)
   948 {
   949     if (texture->texture) {
   950         IDirect3DTexture9_Release(texture->texture);
   951         texture->texture = NULL;
   952     }
   953     if (texture->staging) {
   954         IDirect3DTexture9_Release(texture->staging);
   955         texture->staging = NULL;
   956     }
   957 }
   958 
   959 static int
   960 D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   961 {
   962     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   963     D3D_TextureData *texturedata;
   964     DWORD usage;
   965 
   966     texturedata = (D3D_TextureData *) SDL_calloc(1, sizeof(*texturedata));
   967     if (!texturedata) {
   968         return SDL_OutOfMemory();
   969     }
   970     texturedata->scaleMode = GetScaleQuality();
   971 
   972     texture->driverdata = texturedata;
   973 
   974     if (texture->access == SDL_TEXTUREACCESS_TARGET) {
   975         usage = D3DUSAGE_RENDERTARGET;
   976     } else {
   977         usage = 0;
   978     }
   979 
   980     if (D3D_CreateTextureRep(data->device, &texturedata->texture, usage, texture->format, texture->w, texture->h) < 0) {
   981         return -1;
   982     }
   983 
   984     if (texture->format == SDL_PIXELFORMAT_YV12 ||
   985         texture->format == SDL_PIXELFORMAT_IYUV) {
   986         texturedata->yuv = SDL_TRUE;
   987 
   988         if (D3D_CreateTextureRep(data->device, &texturedata->utexture, usage, texture->format, texture->w / 2, texture->h / 2) < 0) {
   989             return -1;
   990         }
   991 
   992         if (D3D_CreateTextureRep(data->device, &texturedata->vtexture, usage, texture->format, texture->w / 2, texture->h / 2) < 0) {
   993             return -1;
   994         }
   995     }
   996     return 0;
   997 }
   998 
   999 static int
  1000 D3D_RecreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  1001 {
  1002     D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
  1003     D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
  1004 
  1005     if (!texturedata) {
  1006         return 0;
  1007     }
  1008 
  1009     if (D3D_RecreateTextureRep(data->device, &texturedata->texture, texture->format, texture->w, texture->h) < 0) {
  1010         return -1;
  1011     }
  1012 
  1013     if (texturedata->yuv) {
  1014         if (D3D_RecreateTextureRep(data->device, &texturedata->utexture, texture->format, texture->w / 2, texture->h / 2) < 0) {
  1015             return -1;
  1016         }
  1017 
  1018         if (D3D_RecreateTextureRep(data->device, &texturedata->vtexture, texture->format, texture->w / 2, texture->h / 2) < 0) {
  1019             return -1;
  1020         }
  1021     }
  1022     return 0;
  1023 }
  1024 
  1025 static int
  1026 D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
  1027                   const SDL_Rect * rect, const void *pixels, int pitch)
  1028 {
  1029     D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
  1030     D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata;
  1031 
  1032     if (!texturedata) {
  1033         SDL_SetError("Texture is not currently available");
  1034         return -1;
  1035     }
  1036 
  1037     if (D3D_UpdateTextureRep(data->device, &texturedata->texture, texture->format, rect->x, rect->y, rect->w, rect->h, pixels, pitch) < 0) {
  1038         return -1;
  1039     }
  1040 
  1041     if (texturedata->yuv) {
  1042         /* Skip to the correct offset into the next texture */
  1043         pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
  1044 
  1045         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) {
  1046             return -1;
  1047         }
  1048 
  1049         /* Skip to the correct offset into the next texture */
  1050         pixels = (const void*)((const Uint8*)pixels + (rect->h * pitch)/4);
  1051         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) {
  1052             return -1;
  1053         }
  1054     }
  1055     return 0;
  1056 }
  1057 
  1058 static int
  1059 D3D_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
  1060                      const SDL_Rect * rect,
  1061                      const Uint8 *Yplane, int Ypitch,
  1062                      const Uint8 *Uplane, int Upitch,
  1063                      const Uint8 *Vplane, int Vpitch)
  1064 {
  1065     D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
  1066     D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata;
  1067 
  1068     if (!texturedata) {
  1069         SDL_SetError("Texture is not currently available");
  1070         return -1;
  1071     }
  1072 
  1073     if (D3D_UpdateTextureRep(data->device, &texturedata->texture, texture->format, rect->x, rect->y, rect->w, rect->h, Yplane, Ypitch) < 0) {
  1074         return -1;
  1075     }
  1076     if (D3D_UpdateTextureRep(data->device, &texturedata->utexture, texture->format, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, Uplane, Upitch) < 0) {
  1077         return -1;
  1078     }
  1079     if (D3D_UpdateTextureRep(data->device, &texturedata->vtexture, texture->format, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, Vplane, Vpitch) < 0) {
  1080         return -1;
  1081     }
  1082     return 0;
  1083 }
  1084 
  1085 static int
  1086 D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
  1087                 const SDL_Rect * rect, void **pixels, int *pitch)
  1088 {
  1089     D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
  1090     D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
  1091     IDirect3DDevice9 *device = data->device;
  1092 
  1093     if (!texturedata) {
  1094         SDL_SetError("Texture is not currently available");
  1095         return -1;
  1096     }
  1097 
  1098     texturedata->locked_rect = *rect;
  1099 
  1100     if (texturedata->yuv) {
  1101         /* It's more efficient to upload directly... */
  1102         if (!texturedata->pixels) {
  1103             texturedata->pitch = texture->w;
  1104             texturedata->pixels = (Uint8 *)SDL_malloc((texture->h * texturedata->pitch * 3) / 2);
  1105             if (!texturedata->pixels) {
  1106                 return SDL_OutOfMemory();
  1107             }
  1108         }
  1109         *pixels =
  1110             (void *) ((Uint8 *) texturedata->pixels + rect->y * texturedata->pitch +
  1111                       rect->x * SDL_BYTESPERPIXEL(texture->format));
  1112         *pitch = texturedata->pitch;
  1113     } else {
  1114         RECT d3drect;
  1115         D3DLOCKED_RECT locked;
  1116         HRESULT result;
  1117 
  1118         if (D3D_CreateStagingTexture(device, &texturedata->texture) < 0) {
  1119             return -1;
  1120         }
  1121 
  1122         d3drect.left = rect->x;
  1123         d3drect.right = rect->x + rect->w;
  1124         d3drect.top = rect->y;
  1125         d3drect.bottom = rect->y + rect->h;
  1126 
  1127         result = IDirect3DTexture9_LockRect(texturedata->texture.staging, 0, &locked, &d3drect, 0);
  1128         if (FAILED(result)) {
  1129             return D3D_SetError("LockRect()", result);
  1130         }
  1131         *pixels = locked.pBits;
  1132         *pitch = locked.Pitch;
  1133     }
  1134     return 0;
  1135 }
  1136 
  1137 static void
  1138 D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  1139 {
  1140     /*D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;*/
  1141     D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
  1142 
  1143     if (!texturedata) {
  1144         return;
  1145     }
  1146 
  1147     if (texturedata->yuv) {
  1148         const SDL_Rect *rect = &texturedata->locked_rect;
  1149         void *pixels =
  1150             (void *) ((Uint8 *) texturedata->pixels + rect->y * texturedata->pitch +
  1151                       rect->x * SDL_BYTESPERPIXEL(texture->format));
  1152         D3D_UpdateTexture(renderer, texture, rect, pixels, texturedata->pitch);
  1153     } else {
  1154         IDirect3DTexture9_UnlockRect(texturedata->texture.staging, 0);
  1155         texturedata->texture.dirty = SDL_TRUE;
  1156    }
  1157 }
  1158 
  1159 static int
  1160 D3D_SetRenderTargetInternal(SDL_Renderer * renderer, SDL_Texture * texture)
  1161 {
  1162     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1163     D3D_TextureData *texturedata;
  1164     D3D_TextureRep *texturerep;
  1165     HRESULT result;
  1166     IDirect3DDevice9 *device = data->device;
  1167 
  1168     /* Release the previous render target if it wasn't the default one */
  1169     if (data->currentRenderTarget != NULL) {
  1170         IDirect3DSurface9_Release(data->currentRenderTarget);
  1171         data->currentRenderTarget = NULL;
  1172     }
  1173 
  1174     if (texture == NULL) {
  1175         IDirect3DDevice9_SetRenderTarget(data->device, 0, data->defaultRenderTarget);
  1176         return 0;
  1177     }
  1178 
  1179     texturedata = (D3D_TextureData *)texture->driverdata;
  1180     if (!texturedata) {
  1181         SDL_SetError("Texture is not currently available");
  1182         return -1;
  1183     }
  1184 
  1185     /* Make sure the render target is updated if it was locked and written to */
  1186     texturerep = &texturedata->texture;
  1187     if (texturerep->dirty && texturerep->staging) {
  1188         if (!texturerep->texture) {
  1189             result = IDirect3DDevice9_CreateTexture(device, texturerep->w, texturerep->h, 1, texturerep->usage,
  1190                 PixelFormatToD3DFMT(texturerep->format), D3DPOOL_DEFAULT, &texturerep->texture, NULL);
  1191             if (FAILED(result)) {
  1192                 return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
  1193             }
  1194         }
  1195 
  1196         result = IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)texturerep->staging, (IDirect3DBaseTexture9 *)texturerep->texture);
  1197         if (FAILED(result)) {
  1198             return D3D_SetError("UpdateTexture()", result);
  1199         }
  1200         texturerep->dirty = SDL_FALSE;
  1201     }
  1202 
  1203     result = IDirect3DTexture9_GetSurfaceLevel(texturedata->texture.texture, 0, &data->currentRenderTarget);
  1204     if(FAILED(result)) {
  1205         return D3D_SetError("GetSurfaceLevel()", result);
  1206     }
  1207     result = IDirect3DDevice9_SetRenderTarget(data->device, 0, data->currentRenderTarget);
  1208     if(FAILED(result)) {
  1209         return D3D_SetError("SetRenderTarget()", result);
  1210     }
  1211 
  1212     return 0;
  1213 }
  1214 
  1215 static int
  1216 D3D_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
  1217 {
  1218     D3D_ActivateRenderer(renderer);
  1219 
  1220     return D3D_SetRenderTargetInternal(renderer, texture);
  1221 }
  1222 
  1223 static int
  1224 D3D_UpdateViewport(SDL_Renderer * renderer)
  1225 {
  1226     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1227     D3DVIEWPORT9 viewport;
  1228     D3DMATRIX matrix;
  1229 
  1230     /* Set the viewport */
  1231     viewport.X = renderer->viewport.x;
  1232     viewport.Y = renderer->viewport.y;
  1233     viewport.Width = renderer->viewport.w;
  1234     viewport.Height = renderer->viewport.h;
  1235     viewport.MinZ = 0.0f;
  1236     viewport.MaxZ = 1.0f;
  1237     IDirect3DDevice9_SetViewport(data->device, &viewport);
  1238 
  1239     /* Set an orthographic projection matrix */
  1240     if (renderer->viewport.w && renderer->viewport.h) {
  1241         matrix.m[0][0] = 2.0f / renderer->viewport.w;
  1242         matrix.m[0][1] = 0.0f;
  1243         matrix.m[0][2] = 0.0f;
  1244         matrix.m[0][3] = 0.0f;
  1245         matrix.m[1][0] = 0.0f;
  1246         matrix.m[1][1] = -2.0f / renderer->viewport.h;
  1247         matrix.m[1][2] = 0.0f;
  1248         matrix.m[1][3] = 0.0f;
  1249         matrix.m[2][0] = 0.0f;
  1250         matrix.m[2][1] = 0.0f;
  1251         matrix.m[2][2] = 1.0f;
  1252         matrix.m[2][3] = 0.0f;
  1253         matrix.m[3][0] = -1.0f;
  1254         matrix.m[3][1] = 1.0f;
  1255         matrix.m[3][2] = 0.0f;
  1256         matrix.m[3][3] = 1.0f;
  1257         IDirect3DDevice9_SetTransform(data->device, D3DTS_PROJECTION, &matrix);
  1258     }
  1259 
  1260     return 0;
  1261 }
  1262 
  1263 static int
  1264 D3D_UpdateClipRect(SDL_Renderer * renderer)
  1265 {
  1266     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1267 
  1268     if (renderer->clipping_enabled) {
  1269         const SDL_Rect *rect = &renderer->clip_rect;
  1270         RECT r;
  1271         HRESULT result;
  1272 
  1273         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, TRUE);
  1274         r.left = renderer->viewport.x + rect->x;
  1275         r.top = renderer->viewport.y + rect->y;
  1276         r.right = renderer->viewport.x + rect->x + rect->w;
  1277         r.bottom = renderer->viewport.y + rect->y + rect->h;
  1278 
  1279         result = IDirect3DDevice9_SetScissorRect(data->device, &r);
  1280         if (result != D3D_OK) {
  1281             D3D_SetError("SetScissor()", result);
  1282             return -1;
  1283         }
  1284     } else {
  1285         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, FALSE);
  1286     }
  1287     return 0;
  1288 }
  1289 
  1290 static int
  1291 D3D_RenderClear(SDL_Renderer * renderer)
  1292 {
  1293     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1294     DWORD color;
  1295     HRESULT result;
  1296     int BackBufferWidth, BackBufferHeight;
  1297 
  1298     if (D3D_ActivateRenderer(renderer) < 0) {
  1299         return -1;
  1300     }
  1301 
  1302     color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
  1303 
  1304     if (renderer->target) {
  1305         BackBufferWidth = renderer->target->w;
  1306         BackBufferHeight = renderer->target->h;
  1307     } else {
  1308         BackBufferWidth = data->pparams.BackBufferWidth;
  1309         BackBufferHeight = data->pparams.BackBufferHeight;
  1310     }
  1311 
  1312     if (renderer->clipping_enabled) {
  1313         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, FALSE);
  1314     }
  1315 
  1316     /* Don't reset the viewport if we don't have to! */
  1317     if (!renderer->viewport.x && !renderer->viewport.y &&
  1318         renderer->viewport.w == BackBufferWidth &&
  1319         renderer->viewport.h == BackBufferHeight) {
  1320         result = IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
  1321     } else {
  1322         D3DVIEWPORT9 viewport;
  1323 
  1324         /* Clear is defined to clear the entire render target */
  1325         viewport.X = 0;
  1326         viewport.Y = 0;
  1327         viewport.Width = BackBufferWidth;
  1328         viewport.Height = BackBufferHeight;
  1329         viewport.MinZ = 0.0f;
  1330         viewport.MaxZ = 1.0f;
  1331         IDirect3DDevice9_SetViewport(data->device, &viewport);
  1332 
  1333         result = IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
  1334 
  1335         /* Reset the viewport */
  1336         viewport.X = renderer->viewport.x;
  1337         viewport.Y = renderer->viewport.y;
  1338         viewport.Width = renderer->viewport.w;
  1339         viewport.Height = renderer->viewport.h;
  1340         viewport.MinZ = 0.0f;
  1341         viewport.MaxZ = 1.0f;
  1342         IDirect3DDevice9_SetViewport(data->device, &viewport);
  1343     }
  1344 
  1345     if (renderer->clipping_enabled) {
  1346         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, TRUE);
  1347     }
  1348 
  1349     if (FAILED(result)) {
  1350         return D3D_SetError("Clear()", result);
  1351     }
  1352     return 0;
  1353 }
  1354 
  1355 static void
  1356 D3D_SetBlendMode(D3D_RenderData * data, int blendMode)
  1357 {
  1358     switch (blendMode) {
  1359     case SDL_BLENDMODE_NONE:
  1360         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
  1361                                         FALSE);
  1362         break;
  1363     case SDL_BLENDMODE_BLEND:
  1364         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
  1365                                         TRUE);
  1366         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
  1367                                         D3DBLEND_SRCALPHA);
  1368         IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
  1369                                         D3DBLEND_INVSRCALPHA);
  1370         if (data->enableSeparateAlphaBlend) {
  1371             IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA,
  1372                                             D3DBLEND_ONE);
  1373             IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA,
  1374                                             D3DBLEND_INVSRCALPHA);
  1375         }
  1376         break;
  1377     case SDL_BLENDMODE_ADD:
  1378         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
  1379                                         TRUE);
  1380         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
  1381                                         D3DBLEND_SRCALPHA);
  1382         IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
  1383                                         D3DBLEND_ONE);
  1384         if (data->enableSeparateAlphaBlend) {
  1385             IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA,
  1386                                             D3DBLEND_ZERO);
  1387             IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA,
  1388                                             D3DBLEND_ONE);
  1389         }
  1390         break;
  1391     case SDL_BLENDMODE_MOD:
  1392         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
  1393                                         TRUE);
  1394         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
  1395                                         D3DBLEND_ZERO);
  1396         IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
  1397                                         D3DBLEND_SRCCOLOR);
  1398         if (data->enableSeparateAlphaBlend) {
  1399             IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA,
  1400                                             D3DBLEND_ZERO);
  1401             IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA,
  1402                                             D3DBLEND_ONE);
  1403         }
  1404         break;
  1405     }
  1406 }
  1407 
  1408 static int
  1409 D3D_RenderDrawPoints(SDL_Renderer * renderer, const SDL_FPoint * points,
  1410                      int count)
  1411 {
  1412     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1413     DWORD color;
  1414     Vertex *vertices;
  1415     int i;
  1416     HRESULT result;
  1417 
  1418     if (D3D_ActivateRenderer(renderer) < 0) {
  1419         return -1;
  1420     }
  1421 
  1422     D3D_SetBlendMode(data, renderer->blendMode);
  1423 
  1424     result =
  1425         IDirect3DDevice9_SetTexture(data->device, 0,
  1426                                     (IDirect3DBaseTexture9 *) 0);
  1427     if (FAILED(result)) {
  1428         return D3D_SetError("SetTexture()", result);
  1429     }
  1430 
  1431     color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
  1432 
  1433     vertices = SDL_stack_alloc(Vertex, count);
  1434     for (i = 0; i < count; ++i) {
  1435         vertices[i].x = points[i].x;
  1436         vertices[i].y = points[i].y;
  1437         vertices[i].z = 0.0f;
  1438         vertices[i].color = color;
  1439         vertices[i].u = 0.0f;
  1440         vertices[i].v = 0.0f;
  1441     }
  1442     result =
  1443         IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, count,
  1444                                          vertices, sizeof(*vertices));
  1445     SDL_stack_free(vertices);
  1446     if (FAILED(result)) {
  1447         return D3D_SetError("DrawPrimitiveUP()", result);
  1448     }
  1449     return 0;
  1450 }
  1451 
  1452 static int
  1453 D3D_RenderDrawLines(SDL_Renderer * renderer, const SDL_FPoint * points,
  1454                     int count)
  1455 {
  1456     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1457     DWORD color;
  1458     Vertex *vertices;
  1459     int i;
  1460     HRESULT result;
  1461 
  1462     if (D3D_ActivateRenderer(renderer) < 0) {
  1463         return -1;
  1464     }
  1465 
  1466     D3D_SetBlendMode(data, renderer->blendMode);
  1467 
  1468     result =
  1469         IDirect3DDevice9_SetTexture(data->device, 0,
  1470                                     (IDirect3DBaseTexture9 *) 0);
  1471     if (FAILED(result)) {
  1472         return D3D_SetError("SetTexture()", result);
  1473     }
  1474 
  1475     color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
  1476 
  1477     vertices = SDL_stack_alloc(Vertex, count);
  1478     for (i = 0; i < count; ++i) {
  1479         vertices[i].x = points[i].x;
  1480         vertices[i].y = points[i].y;
  1481         vertices[i].z = 0.0f;
  1482         vertices[i].color = color;
  1483         vertices[i].u = 0.0f;
  1484         vertices[i].v = 0.0f;
  1485     }
  1486     result =
  1487         IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_LINESTRIP, count-1,
  1488                                          vertices, sizeof(*vertices));
  1489 
  1490     /* DirectX 9 has the same line rasterization semantics as GDI,
  1491        so we need to close the endpoint of the line */
  1492     if (count == 2 ||
  1493         points[0].x != points[count-1].x || points[0].y != points[count-1].y) {
  1494         vertices[0].x = points[count-1].x;
  1495         vertices[0].y = points[count-1].y;
  1496         result = IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, 1, vertices, sizeof(*vertices));
  1497     }
  1498 
  1499     SDL_stack_free(vertices);
  1500     if (FAILED(result)) {
  1501         return D3D_SetError("DrawPrimitiveUP()", result);
  1502     }
  1503     return 0;
  1504 }
  1505 
  1506 static int
  1507 D3D_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects,
  1508                     int count)
  1509 {
  1510     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1511     DWORD color;
  1512     int i;
  1513     float minx, miny, maxx, maxy;
  1514     Vertex vertices[4];
  1515     HRESULT result;
  1516 
  1517     if (D3D_ActivateRenderer(renderer) < 0) {
  1518         return -1;
  1519     }
  1520 
  1521     D3D_SetBlendMode(data, renderer->blendMode);
  1522 
  1523     result =
  1524         IDirect3DDevice9_SetTexture(data->device, 0,
  1525                                     (IDirect3DBaseTexture9 *) 0);
  1526     if (FAILED(result)) {
  1527         return D3D_SetError("SetTexture()", result);
  1528     }
  1529 
  1530     color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
  1531 
  1532     for (i = 0; i < count; ++i) {
  1533         const SDL_FRect *rect = &rects[i];
  1534 
  1535         minx = rect->x;
  1536         miny = rect->y;
  1537         maxx = rect->x + rect->w;
  1538         maxy = rect->y + rect->h;
  1539 
  1540         vertices[0].x = minx;
  1541         vertices[0].y = miny;
  1542         vertices[0].z = 0.0f;
  1543         vertices[0].color = color;
  1544         vertices[0].u = 0.0f;
  1545         vertices[0].v = 0.0f;
  1546 
  1547         vertices[1].x = maxx;
  1548         vertices[1].y = miny;
  1549         vertices[1].z = 0.0f;
  1550         vertices[1].color = color;
  1551         vertices[1].u = 0.0f;
  1552         vertices[1].v = 0.0f;
  1553 
  1554         vertices[2].x = maxx;
  1555         vertices[2].y = maxy;
  1556         vertices[2].z = 0.0f;
  1557         vertices[2].color = color;
  1558         vertices[2].u = 0.0f;
  1559         vertices[2].v = 0.0f;
  1560 
  1561         vertices[3].x = minx;
  1562         vertices[3].y = maxy;
  1563         vertices[3].z = 0.0f;
  1564         vertices[3].color = color;
  1565         vertices[3].u = 0.0f;
  1566         vertices[3].v = 0.0f;
  1567 
  1568         result =
  1569             IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN,
  1570                                              2, vertices, sizeof(*vertices));
  1571         if (FAILED(result)) {
  1572             return D3D_SetError("DrawPrimitiveUP()", result);
  1573         }
  1574     }
  1575     return 0;
  1576 }
  1577 
  1578 static void
  1579 D3D_UpdateTextureScaleMode(D3D_RenderData *data, D3D_TextureData *texturedata, unsigned index)
  1580 {
  1581     if (texturedata->scaleMode != data->scaleMode[index]) {
  1582         IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MINFILTER,
  1583                                          texturedata->scaleMode);
  1584         IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MAGFILTER,
  1585                                          texturedata->scaleMode);
  1586         data->scaleMode[index] = texturedata->scaleMode;
  1587     }
  1588 }
  1589 
  1590 static int
  1591 D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
  1592                const SDL_Rect * srcrect, const SDL_FRect * dstrect)
  1593 {
  1594     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1595     D3D_TextureData *texturedata;
  1596     LPDIRECT3DPIXELSHADER9 shader = NULL;
  1597     float minx, miny, maxx, maxy;
  1598     float minu, maxu, minv, maxv;
  1599     DWORD color;
  1600     Vertex vertices[4];
  1601     HRESULT result;
  1602 
  1603     if (D3D_ActivateRenderer(renderer) < 0) {
  1604         return -1;
  1605     }
  1606 
  1607     texturedata = (D3D_TextureData *)texture->driverdata;
  1608     if (!texturedata) {
  1609         SDL_SetError("Texture is not currently available");
  1610         return -1;
  1611     }
  1612 
  1613     minx = dstrect->x - 0.5f;
  1614     miny = dstrect->y - 0.5f;
  1615     maxx = dstrect->x + dstrect->w - 0.5f;
  1616     maxy = dstrect->y + dstrect->h - 0.5f;
  1617 
  1618     minu = (float) srcrect->x / texture->w;
  1619     maxu = (float) (srcrect->x + srcrect->w) / texture->w;
  1620     minv = (float) srcrect->y / texture->h;
  1621     maxv = (float) (srcrect->y + srcrect->h) / texture->h;
  1622 
  1623     color = D3DCOLOR_ARGB(texture->a, texture->r, texture->g, texture->b);
  1624 
  1625     vertices[0].x = minx;
  1626     vertices[0].y = miny;
  1627     vertices[0].z = 0.0f;
  1628     vertices[0].color = color;
  1629     vertices[0].u = minu;
  1630     vertices[0].v = minv;
  1631 
  1632     vertices[1].x = maxx;
  1633     vertices[1].y = miny;
  1634     vertices[1].z = 0.0f;
  1635     vertices[1].color = color;
  1636     vertices[1].u = maxu;
  1637     vertices[1].v = minv;
  1638 
  1639     vertices[2].x = maxx;
  1640     vertices[2].y = maxy;
  1641     vertices[2].z = 0.0f;
  1642     vertices[2].color = color;
  1643     vertices[2].u = maxu;
  1644     vertices[2].v = maxv;
  1645 
  1646     vertices[3].x = minx;
  1647     vertices[3].y = maxy;
  1648     vertices[3].z = 0.0f;
  1649     vertices[3].color = color;
  1650     vertices[3].u = minu;
  1651     vertices[3].v = maxv;
  1652 
  1653     D3D_SetBlendMode(data, texture->blendMode);
  1654 
  1655     D3D_UpdateTextureScaleMode(data, texturedata, 0);
  1656 
  1657     if (D3D_BindTextureRep(data->device, &texturedata->texture, 0) < 0) {
  1658         return -1;
  1659     }
  1660 
  1661     if (texturedata->yuv) {
  1662         shader = data->ps_yuv;
  1663 
  1664         D3D_UpdateTextureScaleMode(data, texturedata, 1);
  1665         D3D_UpdateTextureScaleMode(data, texturedata, 2);
  1666 
  1667         if (D3D_BindTextureRep(data->device, &texturedata->utexture, 1) < 0) {
  1668             return -1;
  1669         }
  1670         if (D3D_BindTextureRep(data->device, &texturedata->vtexture, 2) < 0) {
  1671             return -1;
  1672         }
  1673     }
  1674 
  1675     if (shader) {
  1676         result = IDirect3DDevice9_SetPixelShader(data->device, shader);
  1677         if (FAILED(result)) {
  1678             return D3D_SetError("SetShader()", result);
  1679         }
  1680     }
  1681     result =
  1682         IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2,
  1683                                          vertices, sizeof(*vertices));
  1684     if (FAILED(result)) {
  1685         return D3D_SetError("DrawPrimitiveUP()", result);
  1686     }
  1687     if (shader) {
  1688         result = IDirect3DDevice9_SetPixelShader(data->device, NULL);
  1689         if (FAILED(result)) {
  1690             return D3D_SetError("SetShader()", result);
  1691         }
  1692     }
  1693     return 0;
  1694 }
  1695 
  1696 
  1697 static int
  1698 D3D_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
  1699                const SDL_Rect * srcrect, const SDL_FRect * dstrect,
  1700                const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip)
  1701 {
  1702     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1703     D3D_TextureData *texturedata;
  1704     LPDIRECT3DPIXELSHADER9 shader = NULL;
  1705     float minx, miny, maxx, maxy;
  1706     float minu, maxu, minv, maxv;
  1707     float centerx, centery;
  1708     DWORD color;
  1709     Vertex vertices[4];
  1710     Float4X4 modelMatrix;
  1711     HRESULT result;
  1712 
  1713     if (D3D_ActivateRenderer(renderer) < 0) {
  1714         return -1;
  1715     }
  1716 
  1717     texturedata = (D3D_TextureData *)texture->driverdata;
  1718     if (!texturedata) {
  1719         SDL_SetError("Texture is not currently available");
  1720         return -1;
  1721     }
  1722 
  1723     centerx = center->x;
  1724     centery = center->y;
  1725 
  1726     minx = -centerx;
  1727     maxx = dstrect->w - centerx;
  1728     miny = -centery;
  1729     maxy = dstrect->h - centery;
  1730 
  1731     minu = (float) srcrect->x / texture->w;
  1732     maxu = (float) (srcrect->x + srcrect->w) / texture->w;
  1733     minv = (float) srcrect->y / texture->h;
  1734     maxv = (float) (srcrect->y + srcrect->h) / texture->h;
  1735 
  1736     if (flip & SDL_FLIP_HORIZONTAL) {
  1737         float tmp = maxu;
  1738         maxu = minu;
  1739         minu = tmp;
  1740     }
  1741     if (flip & SDL_FLIP_VERTICAL) {
  1742         float tmp = maxv;
  1743         maxv = minv;
  1744         minv = tmp;
  1745     }
  1746 
  1747     color = D3DCOLOR_ARGB(texture->a, texture->r, texture->g, texture->b);
  1748 
  1749     vertices[0].x = minx;
  1750     vertices[0].y = miny;
  1751     vertices[0].z = 0.0f;
  1752     vertices[0].color = color;
  1753     vertices[0].u = minu;
  1754     vertices[0].v = minv;
  1755 
  1756     vertices[1].x = maxx;
  1757     vertices[1].y = miny;
  1758     vertices[1].z = 0.0f;
  1759     vertices[1].color = color;
  1760     vertices[1].u = maxu;
  1761     vertices[1].v = minv;
  1762 
  1763     vertices[2].x = maxx;
  1764     vertices[2].y = maxy;
  1765     vertices[2].z = 0.0f;
  1766     vertices[2].color = color;
  1767     vertices[2].u = maxu;
  1768     vertices[2].v = maxv;
  1769 
  1770     vertices[3].x = minx;
  1771     vertices[3].y = maxy;
  1772     vertices[3].z = 0.0f;
  1773     vertices[3].color = color;
  1774     vertices[3].u = minu;
  1775     vertices[3].v = maxv;
  1776 
  1777     D3D_SetBlendMode(data, texture->blendMode);
  1778 
  1779     /* Rotate and translate */
  1780     modelMatrix = MatrixMultiply(
  1781             MatrixRotationZ((float)(M_PI * (float) angle / 180.0f)),
  1782             MatrixTranslation(dstrect->x + center->x - 0.5f, dstrect->y + center->y - 0.5f, 0));
  1783     IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)&modelMatrix);
  1784 
  1785     D3D_UpdateTextureScaleMode(data, texturedata, 0);
  1786 
  1787     if (D3D_BindTextureRep(data->device, &texturedata->texture, 0) < 0) {
  1788         return -1;
  1789     }
  1790 
  1791     if (texturedata->yuv) {
  1792         shader = data->ps_yuv;
  1793 
  1794         D3D_UpdateTextureScaleMode(data, texturedata, 1);
  1795         D3D_UpdateTextureScaleMode(data, texturedata, 2);
  1796         
  1797         if (D3D_BindTextureRep(data->device, &texturedata->utexture, 1) < 0) {
  1798             return -1;
  1799         }
  1800         if (D3D_BindTextureRep(data->device, &texturedata->vtexture, 2) < 0) {
  1801             return -1;
  1802         }
  1803     }
  1804 
  1805     if (shader) {
  1806         result = IDirect3DDevice9_SetPixelShader(data->device, shader);
  1807         if (FAILED(result)) {
  1808             return D3D_SetError("SetShader()", result);
  1809         }
  1810     }
  1811     result =
  1812         IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2,
  1813                                          vertices, sizeof(*vertices));
  1814     if (FAILED(result)) {
  1815         return D3D_SetError("DrawPrimitiveUP()", result);
  1816     }
  1817     if (shader) {
  1818         result = IDirect3DDevice9_SetPixelShader(data->device, NULL);
  1819         if (FAILED(result)) {
  1820             return D3D_SetError("SetShader()", result);
  1821         }
  1822     }
  1823 
  1824     modelMatrix = MatrixIdentity();
  1825     IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)&modelMatrix);
  1826     return 0;
  1827 }
  1828 
  1829 static int
  1830 D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
  1831                      Uint32 format, void * pixels, int pitch)
  1832 {
  1833     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1834     D3DSURFACE_DESC desc;
  1835     LPDIRECT3DSURFACE9 backBuffer;
  1836     LPDIRECT3DSURFACE9 surface;
  1837     RECT d3drect;
  1838     D3DLOCKED_RECT locked;
  1839     HRESULT result;
  1840 
  1841     if (data->currentRenderTarget) {
  1842         backBuffer = data->currentRenderTarget;
  1843     } else {
  1844         backBuffer = data->defaultRenderTarget;
  1845     }
  1846 
  1847     result = IDirect3DSurface9_GetDesc(backBuffer, &desc);
  1848     if (FAILED(result)) {
  1849         IDirect3DSurface9_Release(backBuffer);
  1850         return D3D_SetError("GetDesc()", result);
  1851     }
  1852 
  1853     result = IDirect3DDevice9_CreateOffscreenPlainSurface(data->device, desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surface, NULL);
  1854     if (FAILED(result)) {
  1855         IDirect3DSurface9_Release(backBuffer);
  1856         return D3D_SetError("CreateOffscreenPlainSurface()", result);
  1857     }
  1858 
  1859     result = IDirect3DDevice9_GetRenderTargetData(data->device, backBuffer, surface);
  1860     if (FAILED(result)) {
  1861         IDirect3DSurface9_Release(surface);
  1862         IDirect3DSurface9_Release(backBuffer);
  1863         return D3D_SetError("GetRenderTargetData()", result);
  1864     }
  1865 
  1866     d3drect.left = rect->x;
  1867     d3drect.right = rect->x + rect->w;
  1868     d3drect.top = rect->y;
  1869     d3drect.bottom = rect->y + rect->h;
  1870 
  1871     result = IDirect3DSurface9_LockRect(surface, &locked, &d3drect, D3DLOCK_READONLY);
  1872     if (FAILED(result)) {
  1873         IDirect3DSurface9_Release(surface);
  1874         IDirect3DSurface9_Release(backBuffer);
  1875         return D3D_SetError("LockRect()", result);
  1876     }
  1877 
  1878     SDL_ConvertPixels(rect->w, rect->h,
  1879                       D3DFMTToPixelFormat(desc.Format), locked.pBits, locked.Pitch,
  1880                       format, pixels, pitch);
  1881 
  1882     IDirect3DSurface9_UnlockRect(surface);
  1883 
  1884     IDirect3DSurface9_Release(surface);
  1885 
  1886     return 0;
  1887 }
  1888 
  1889 static void
  1890 D3D_RenderPresent(SDL_Renderer * renderer)
  1891 {
  1892     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1893     HRESULT result;
  1894 
  1895     if (!data->beginScene) {
  1896         IDirect3DDevice9_EndScene(data->device);
  1897         data->beginScene = SDL_TRUE;
  1898     }
  1899 
  1900     result = IDirect3DDevice9_TestCooperativeLevel(data->device);
  1901     if (result == D3DERR_DEVICELOST) {
  1902         /* We'll reset later */
  1903         return;
  1904     }
  1905     if (result == D3DERR_DEVICENOTRESET) {
  1906         D3D_Reset(renderer);
  1907     }
  1908     result = IDirect3DDevice9_Present(data->device, NULL, NULL, NULL, NULL);
  1909     if (FAILED(result)) {
  1910         D3D_SetError("Present()", result);
  1911     }
  1912 }
  1913 
  1914 static void
  1915 D3D_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  1916 {
  1917     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
  1918 
  1919     if (!data) {
  1920         return;
  1921     }
  1922     D3D_DestroyTextureRep(&data->texture);
  1923     D3D_DestroyTextureRep(&data->utexture);
  1924     D3D_DestroyTextureRep(&data->vtexture);
  1925     SDL_free(data->pixels);
  1926     SDL_free(data);
  1927     texture->driverdata = NULL;
  1928 }
  1929 
  1930 static void
  1931 D3D_DestroyRenderer(SDL_Renderer * renderer)
  1932 {
  1933     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1934 
  1935     if (data) {
  1936         /* Release the render target */
  1937         if (data->defaultRenderTarget) {
  1938             IDirect3DSurface9_Release(data->defaultRenderTarget);
  1939             data->defaultRenderTarget = NULL;
  1940         }
  1941         if (data->currentRenderTarget != NULL) {
  1942             IDirect3DSurface9_Release(data->currentRenderTarget);
  1943             data->currentRenderTarget = NULL;
  1944         }
  1945         if (data->ps_yuv) {
  1946             IDirect3DPixelShader9_Release(data->ps_yuv);
  1947         }
  1948         if (data->device) {
  1949             IDirect3DDevice9_Release(data->device);
  1950         }
  1951         if (data->d3d) {
  1952             IDirect3D9_Release(data->d3d);
  1953             SDL_UnloadObject(data->d3dDLL);
  1954         }
  1955         SDL_free(data);
  1956     }
  1957     SDL_free(renderer);
  1958 }
  1959 #endif /* SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED */
  1960 
  1961 #ifdef __WIN32__
  1962 /* This function needs to always exist on Windows, for the Dynamic API. */
  1963 IDirect3DDevice9 *
  1964 SDL_RenderGetD3D9Device(SDL_Renderer * renderer)
  1965 {
  1966     IDirect3DDevice9 *device = NULL;
  1967 
  1968 #if SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED
  1969     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1970 
  1971     /* Make sure that this is a D3D renderer */
  1972     if (renderer->DestroyRenderer != D3D_DestroyRenderer) {
  1973         SDL_SetError("Renderer is not a D3D renderer");
  1974         return NULL;
  1975     }
  1976 
  1977     device = data->device;
  1978     if (device) {
  1979         IDirect3DDevice9_AddRef(device);
  1980     }
  1981 #endif /* SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED */
  1982 
  1983     return device;
  1984 }
  1985 #endif /* __WIN32__ */
  1986 
  1987 /* vi: set ts=4 sw=4 expandtab: */