src/render/direct3d/SDL_render_d3d.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 28 Aug 2017 01:42:18 -0700
changeset 11386 d5c2d689bf6d
parent 11330 6ae35c5f7f7b
child 11702 cf166abbde4a
permissions -rw-r--r--
Fixed build when Wayland is dynamically loaded
     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 SDL_bool D3D_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode);
   129 static int D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
   130 static int D3D_RecreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
   131 static int D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   132                              const SDL_Rect * rect, const void *pixels,
   133                              int pitch);
   134 static int D3D_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
   135                                 const SDL_Rect * rect,
   136                                 const Uint8 *Yplane, int Ypitch,
   137                                 const Uint8 *Uplane, int Upitch,
   138                                 const Uint8 *Vplane, int Vpitch);
   139 static int D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   140                            const SDL_Rect * rect, void **pixels, int *pitch);
   141 static void D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
   142 static int D3D_SetRenderTargetInternal(SDL_Renderer * renderer, SDL_Texture * texture);
   143 static int D3D_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture);
   144 static int D3D_UpdateViewport(SDL_Renderer * renderer);
   145 static int D3D_UpdateClipRect(SDL_Renderer * renderer);
   146 static int D3D_RenderClear(SDL_Renderer * renderer);
   147 static int D3D_RenderDrawPoints(SDL_Renderer * renderer,
   148                                 const SDL_FPoint * points, int count);
   149 static int D3D_RenderDrawLines(SDL_Renderer * renderer,
   150                                const SDL_FPoint * points, int count);
   151 static int D3D_RenderFillRects(SDL_Renderer * renderer,
   152                                const SDL_FRect * rects, int count);
   153 static int D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   154                           const SDL_Rect * srcrect, const SDL_FRect * dstrect);
   155 static int D3D_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
   156                           const SDL_Rect * srcrect, const SDL_FRect * dstrect,
   157                           const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip);
   158 static int D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
   159                                 Uint32 format, void * pixels, int pitch);
   160 static void D3D_RenderPresent(SDL_Renderer * renderer);
   161 static void D3D_DestroyTexture(SDL_Renderer * renderer,
   162                                SDL_Texture * texture);
   163 static void D3D_DestroyRenderer(SDL_Renderer * renderer);
   164 
   165 
   166 SDL_RenderDriver D3D_RenderDriver = {
   167     D3D_CreateRenderer,
   168     {
   169      "direct3d",
   170      (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
   171      1,
   172      {SDL_PIXELFORMAT_ARGB8888},
   173      0,
   174      0}
   175 };
   176 
   177 typedef struct
   178 {
   179     void* d3dDLL;
   180     IDirect3D9 *d3d;
   181     IDirect3DDevice9 *device;
   182     UINT adapter;
   183     D3DPRESENT_PARAMETERS pparams;
   184     SDL_bool updateSize;
   185     SDL_bool beginScene;
   186     SDL_bool enableSeparateAlphaBlend;
   187     D3DTEXTUREFILTERTYPE scaleMode[8];
   188     IDirect3DSurface9 *defaultRenderTarget;
   189     IDirect3DSurface9 *currentRenderTarget;
   190     void* d3dxDLL;
   191     LPDIRECT3DPIXELSHADER9 ps_yuv;
   192 } D3D_RenderData;
   193 
   194 typedef struct
   195 {
   196     SDL_bool dirty;
   197     int w, h;
   198     DWORD usage;
   199     Uint32 format;
   200     IDirect3DTexture9 *texture;
   201     IDirect3DTexture9 *staging;
   202 } D3D_TextureRep;
   203 
   204 typedef struct
   205 {
   206     D3D_TextureRep texture;
   207     D3DTEXTUREFILTERTYPE scaleMode;
   208 
   209     /* YV12 texture support */
   210     SDL_bool yuv;
   211     D3D_TextureRep utexture;
   212     D3D_TextureRep vtexture;
   213     Uint8 *pixels;
   214     int pitch;
   215     SDL_Rect locked_rect;
   216 } D3D_TextureData;
   217 
   218 typedef struct
   219 {
   220     float x, y, z;
   221     DWORD color;
   222     float u, v;
   223 } Vertex;
   224 
   225 static int
   226 D3D_SetError(const char *prefix, HRESULT result)
   227 {
   228     const char *error;
   229 
   230     switch (result) {
   231     case D3DERR_WRONGTEXTUREFORMAT:
   232         error = "WRONGTEXTUREFORMAT";
   233         break;
   234     case D3DERR_UNSUPPORTEDCOLOROPERATION:
   235         error = "UNSUPPORTEDCOLOROPERATION";
   236         break;
   237     case D3DERR_UNSUPPORTEDCOLORARG:
   238         error = "UNSUPPORTEDCOLORARG";
   239         break;
   240     case D3DERR_UNSUPPORTEDALPHAOPERATION:
   241         error = "UNSUPPORTEDALPHAOPERATION";
   242         break;
   243     case D3DERR_UNSUPPORTEDALPHAARG:
   244         error = "UNSUPPORTEDALPHAARG";
   245         break;
   246     case D3DERR_TOOMANYOPERATIONS:
   247         error = "TOOMANYOPERATIONS";
   248         break;
   249     case D3DERR_CONFLICTINGTEXTUREFILTER:
   250         error = "CONFLICTINGTEXTUREFILTER";
   251         break;
   252     case D3DERR_UNSUPPORTEDFACTORVALUE:
   253         error = "UNSUPPORTEDFACTORVALUE";
   254         break;
   255     case D3DERR_CONFLICTINGRENDERSTATE:
   256         error = "CONFLICTINGRENDERSTATE";
   257         break;
   258     case D3DERR_UNSUPPORTEDTEXTUREFILTER:
   259         error = "UNSUPPORTEDTEXTUREFILTER";
   260         break;
   261     case D3DERR_CONFLICTINGTEXTUREPALETTE:
   262         error = "CONFLICTINGTEXTUREPALETTE";
   263         break;
   264     case D3DERR_DRIVERINTERNALERROR:
   265         error = "DRIVERINTERNALERROR";
   266         break;
   267     case D3DERR_NOTFOUND:
   268         error = "NOTFOUND";
   269         break;
   270     case D3DERR_MOREDATA:
   271         error = "MOREDATA";
   272         break;
   273     case D3DERR_DEVICELOST:
   274         error = "DEVICELOST";
   275         break;
   276     case D3DERR_DEVICENOTRESET:
   277         error = "DEVICENOTRESET";
   278         break;
   279     case D3DERR_NOTAVAILABLE:
   280         error = "NOTAVAILABLE";
   281         break;
   282     case D3DERR_OUTOFVIDEOMEMORY:
   283         error = "OUTOFVIDEOMEMORY";
   284         break;
   285     case D3DERR_INVALIDDEVICE:
   286         error = "INVALIDDEVICE";
   287         break;
   288     case D3DERR_INVALIDCALL:
   289         error = "INVALIDCALL";
   290         break;
   291     case D3DERR_DRIVERINVALIDCALL:
   292         error = "DRIVERINVALIDCALL";
   293         break;
   294     case D3DERR_WASSTILLDRAWING:
   295         error = "WASSTILLDRAWING";
   296         break;
   297     default:
   298         error = "UNKNOWN";
   299         break;
   300     }
   301     return SDL_SetError("%s: %s", prefix, error);
   302 }
   303 
   304 static D3DFORMAT
   305 PixelFormatToD3DFMT(Uint32 format)
   306 {
   307     switch (format) {
   308     case SDL_PIXELFORMAT_RGB565:
   309         return D3DFMT_R5G6B5;
   310     case SDL_PIXELFORMAT_RGB888:
   311         return D3DFMT_X8R8G8B8;
   312     case SDL_PIXELFORMAT_ARGB8888:
   313         return D3DFMT_A8R8G8B8;
   314     case SDL_PIXELFORMAT_YV12:
   315     case SDL_PIXELFORMAT_IYUV:
   316         return D3DFMT_L8;
   317     default:
   318         return D3DFMT_UNKNOWN;
   319     }
   320 }
   321 
   322 static Uint32
   323 D3DFMTToPixelFormat(D3DFORMAT format)
   324 {
   325     switch (format) {
   326     case D3DFMT_R5G6B5:
   327         return SDL_PIXELFORMAT_RGB565;
   328     case D3DFMT_X8R8G8B8:
   329         return SDL_PIXELFORMAT_RGB888;
   330     case D3DFMT_A8R8G8B8:
   331         return SDL_PIXELFORMAT_ARGB8888;
   332     default:
   333         return SDL_PIXELFORMAT_UNKNOWN;
   334     }
   335 }
   336 
   337 static void
   338 D3D_InitRenderState(D3D_RenderData *data)
   339 {
   340     D3DMATRIX matrix;
   341 
   342     IDirect3DDevice9 *device = data->device;
   343 
   344     IDirect3DDevice9_SetVertexShader(device, NULL);
   345     IDirect3DDevice9_SetFVF(device, D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);
   346     IDirect3DDevice9_SetRenderState(device, D3DRS_ZENABLE, D3DZB_FALSE);
   347     IDirect3DDevice9_SetRenderState(device, D3DRS_CULLMODE, D3DCULL_NONE);
   348     IDirect3DDevice9_SetRenderState(device, D3DRS_LIGHTING, FALSE);
   349 
   350     /* Enable color modulation by diffuse color */
   351     IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLOROP,
   352                                           D3DTOP_MODULATE);
   353     IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLORARG1,
   354                                           D3DTA_TEXTURE);
   355     IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLORARG2,
   356                                           D3DTA_DIFFUSE);
   357 
   358     /* Enable alpha modulation by diffuse alpha */
   359     IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAOP,
   360                                           D3DTOP_MODULATE);
   361     IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAARG1,
   362                                           D3DTA_TEXTURE);
   363     IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAARG2,
   364                                           D3DTA_DIFFUSE);
   365 
   366     /* Enable separate alpha blend function, if possible */
   367     if (data->enableSeparateAlphaBlend) {
   368         IDirect3DDevice9_SetRenderState(device, D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
   369     }
   370 
   371     /* Disable second texture stage, since we're done */
   372     IDirect3DDevice9_SetTextureStageState(device, 1, D3DTSS_COLOROP,
   373                                           D3DTOP_DISABLE);
   374     IDirect3DDevice9_SetTextureStageState(device, 1, D3DTSS_ALPHAOP,
   375                                           D3DTOP_DISABLE);
   376 
   377     /* Set an identity world and view matrix */
   378     matrix.m[0][0] = 1.0f;
   379     matrix.m[0][1] = 0.0f;
   380     matrix.m[0][2] = 0.0f;
   381     matrix.m[0][3] = 0.0f;
   382     matrix.m[1][0] = 0.0f;
   383     matrix.m[1][1] = 1.0f;
   384     matrix.m[1][2] = 0.0f;
   385     matrix.m[1][3] = 0.0f;
   386     matrix.m[2][0] = 0.0f;
   387     matrix.m[2][1] = 0.0f;
   388     matrix.m[2][2] = 1.0f;
   389     matrix.m[2][3] = 0.0f;
   390     matrix.m[3][0] = 0.0f;
   391     matrix.m[3][1] = 0.0f;
   392     matrix.m[3][2] = 0.0f;
   393     matrix.m[3][3] = 1.0f;
   394     IDirect3DDevice9_SetTransform(device, D3DTS_WORLD, &matrix);
   395     IDirect3DDevice9_SetTransform(device, D3DTS_VIEW, &matrix);
   396 
   397     /* Reset our current scale mode */
   398     SDL_memset(data->scaleMode, 0xFF, sizeof(data->scaleMode));
   399 
   400     /* Start the render with beginScene */
   401     data->beginScene = SDL_TRUE;
   402 }
   403 
   404 static int
   405 D3D_Reset(SDL_Renderer * renderer)
   406 {
   407     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   408     HRESULT result;
   409     SDL_Texture *texture;
   410 
   411     /* Release the default render target before reset */
   412     if (data->defaultRenderTarget) {
   413         IDirect3DSurface9_Release(data->defaultRenderTarget);
   414         data->defaultRenderTarget = NULL;
   415     }
   416     if (data->currentRenderTarget != NULL) {
   417         IDirect3DSurface9_Release(data->currentRenderTarget);
   418         data->currentRenderTarget = NULL;
   419     }
   420 
   421     /* Release application render targets */
   422     for (texture = renderer->textures; texture; texture = texture->next) {
   423         if (texture->access == SDL_TEXTUREACCESS_TARGET) {
   424             D3D_DestroyTexture(renderer, texture);
   425         } else {
   426             D3D_RecreateTexture(renderer, texture);
   427         }
   428     }
   429 
   430     result = IDirect3DDevice9_Reset(data->device, &data->pparams);
   431     if (FAILED(result)) {
   432         if (result == D3DERR_DEVICELOST) {
   433             /* Don't worry about it, we'll reset later... */
   434             return 0;
   435         } else {
   436             return D3D_SetError("Reset()", result);
   437         }
   438     }
   439 
   440     /* Allocate application render targets */
   441     for (texture = renderer->textures; texture; texture = texture->next) {
   442         if (texture->access == SDL_TEXTUREACCESS_TARGET) {
   443             D3D_CreateTexture(renderer, texture);
   444         }
   445     }
   446 
   447     IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget);
   448     D3D_InitRenderState(data);
   449     D3D_SetRenderTargetInternal(renderer, renderer->target);
   450     D3D_UpdateViewport(renderer);
   451 
   452     /* Let the application know that render targets were reset */
   453     {
   454         SDL_Event event;
   455         event.type = SDL_RENDER_TARGETS_RESET;
   456         SDL_PushEvent(&event);
   457     }
   458 
   459     return 0;
   460 }
   461 
   462 static int
   463 D3D_ActivateRenderer(SDL_Renderer * renderer)
   464 {
   465     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   466     HRESULT result;
   467 
   468     if (data->updateSize) {
   469         SDL_Window *window = renderer->window;
   470         int w, h;
   471         Uint32 window_flags = SDL_GetWindowFlags(window);
   472 
   473         SDL_GetWindowSize(window, &w, &h);
   474         data->pparams.BackBufferWidth = w;
   475         data->pparams.BackBufferHeight = h;
   476         if (window_flags & SDL_WINDOW_FULLSCREEN && (window_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
   477             SDL_DisplayMode fullscreen_mode;
   478             SDL_GetWindowDisplayMode(window, &fullscreen_mode);
   479             data->pparams.Windowed = FALSE;
   480             data->pparams.BackBufferFormat = PixelFormatToD3DFMT(fullscreen_mode.format);
   481             data->pparams.FullScreen_RefreshRateInHz = fullscreen_mode.refresh_rate;
   482         } else {
   483             data->pparams.Windowed = TRUE;
   484             data->pparams.BackBufferFormat = D3DFMT_UNKNOWN;
   485             data->pparams.FullScreen_RefreshRateInHz = 0;
   486         }
   487         if (D3D_Reset(renderer) < 0) {
   488             return -1;
   489         }
   490 
   491         data->updateSize = SDL_FALSE;
   492     }
   493     if (data->beginScene) {
   494         result = IDirect3DDevice9_BeginScene(data->device);
   495         if (result == D3DERR_DEVICELOST) {
   496             if (D3D_Reset(renderer) < 0) {
   497                 return -1;
   498             }
   499             result = IDirect3DDevice9_BeginScene(data->device);
   500         }
   501         if (FAILED(result)) {
   502             return D3D_SetError("BeginScene()", result);
   503         }
   504         data->beginScene = SDL_FALSE;
   505     }
   506     return 0;
   507 }
   508 
   509 SDL_Renderer *
   510 D3D_CreateRenderer(SDL_Window * window, Uint32 flags)
   511 {
   512     SDL_Renderer *renderer;
   513     D3D_RenderData *data;
   514     SDL_SysWMinfo windowinfo;
   515     HRESULT result;
   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->SupportsBlendMode = D3D_SupportsBlendMode;
   547     renderer->CreateTexture = D3D_CreateTexture;
   548     renderer->UpdateTexture = D3D_UpdateTexture;
   549     renderer->UpdateTextureYUV = D3D_UpdateTextureYUV;
   550     renderer->LockTexture = D3D_LockTexture;
   551     renderer->UnlockTexture = D3D_UnlockTexture;
   552     renderer->SetRenderTarget = D3D_SetRenderTarget;
   553     renderer->UpdateViewport = D3D_UpdateViewport;
   554     renderer->UpdateClipRect = D3D_UpdateClipRect;
   555     renderer->RenderClear = D3D_RenderClear;
   556     renderer->RenderDrawPoints = D3D_RenderDrawPoints;
   557     renderer->RenderDrawLines = D3D_RenderDrawLines;
   558     renderer->RenderFillRects = D3D_RenderFillRects;
   559     renderer->RenderCopy = D3D_RenderCopy;
   560     renderer->RenderCopyEx = D3D_RenderCopyEx;
   561     renderer->RenderReadPixels = D3D_RenderReadPixels;
   562     renderer->RenderPresent = D3D_RenderPresent;
   563     renderer->DestroyTexture = D3D_DestroyTexture;
   564     renderer->DestroyRenderer = D3D_DestroyRenderer;
   565     renderer->info = D3D_RenderDriver.info;
   566     renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
   567     renderer->driverdata = data;
   568 
   569     SDL_VERSION(&windowinfo.version);
   570     SDL_GetWindowWMInfo(window, &windowinfo);
   571 
   572     window_flags = SDL_GetWindowFlags(window);
   573     SDL_GetWindowSize(window, &w, &h);
   574     SDL_GetWindowDisplayMode(window, &fullscreen_mode);
   575 
   576     SDL_zero(pparams);
   577     pparams.hDeviceWindow = windowinfo.info.win.window;
   578     pparams.BackBufferWidth = w;
   579     pparams.BackBufferHeight = h;
   580     pparams.BackBufferCount = 1;
   581     pparams.SwapEffect = D3DSWAPEFFECT_DISCARD;
   582 
   583     if (window_flags & SDL_WINDOW_FULLSCREEN && (window_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
   584         pparams.Windowed = FALSE;
   585         pparams.BackBufferFormat = PixelFormatToD3DFMT(fullscreen_mode.format);
   586         pparams.FullScreen_RefreshRateInHz = fullscreen_mode.refresh_rate;
   587     } else {
   588         pparams.Windowed = TRUE;
   589         pparams.BackBufferFormat = D3DFMT_UNKNOWN;
   590         pparams.FullScreen_RefreshRateInHz = 0;
   591     }
   592     if (flags & SDL_RENDERER_PRESENTVSYNC) {
   593         pparams.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
   594     } else {
   595         pparams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
   596     }
   597 
   598     /* Get the adapter for the display that the window is on */
   599     displayIndex = SDL_GetWindowDisplayIndex(window);
   600     data->adapter = SDL_Direct3D9GetAdapterIndex(displayIndex);
   601 
   602     IDirect3D9_GetDeviceCaps(data->d3d, data->adapter, D3DDEVTYPE_HAL, &caps);
   603 
   604     device_flags = D3DCREATE_FPU_PRESERVE;
   605     if (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) {
   606         device_flags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
   607     } else {
   608         device_flags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
   609     }
   610 
   611     if (SDL_GetHintBoolean(SDL_HINT_RENDER_DIRECT3D_THREADSAFE, SDL_FALSE)) {
   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         if (shader_data != NULL)
   765 #else
   766         const DWORD shader_data[] = {
   767             0xffff0200, 0x05000051, 0xa00f0000, 0xbd808081, 0xbf008081, 0xbf008081,
   768             0x3f800000, 0x05000051, 0xa00f0001, 0x3f94fdf4, 0x00000000, 0x3fcc49ba,
   769             0x00000000, 0x05000051, 0xa00f0002, 0x3f94fdf4, 0xbec83127, 0xbf5020c5,
   770             0x00000000, 0x05000051, 0xa00f0003, 0x3f94fdf4, 0x400126e9, 0x00000000,
   771             0x00000000, 0x0200001f, 0x80000000, 0xb0030000, 0x0200001f, 0x80000000,
   772             0x900f0000, 0x0200001f, 0x90000000, 0xa00f0800, 0x0200001f, 0x90000000,
   773             0xa00f0801, 0x0200001f, 0x90000000, 0xa00f0802, 0x03000042, 0x800f0000,
   774             0xb0e40000, 0xa0e40800, 0x03000042, 0x800f0001, 0xb0e40000, 0xa0e40801,
   775             0x03000042, 0x800f0002, 0xb0e40000, 0xa0e40802, 0x02000001, 0x80020000,
   776             0x80000001, 0x02000001, 0x80040000, 0x80000002, 0x03000002, 0x80070000,
   777             0x80e40000, 0xa0e40000, 0x03000008, 0x80010001, 0x80e40000, 0xa0e40001,
   778             0x03000008, 0x80020001, 0x80e40000, 0xa0e40002, 0x0400005a, 0x80040001,
   779             0x80e40000, 0xa0e40003, 0xa0aa0003, 0x02000001, 0x80080001, 0xa0ff0000,
   780             0x03000005, 0x800f0000, 0x80e40001, 0x90e40000, 0x02000001, 0x800f0800,
   781             0x80e40000, 0x0000ffff
   782         };
   783 #endif
   784         {
   785             result = IDirect3DDevice9_CreatePixelShader(data->device, shader_data, &data->ps_yuv);
   786             if (!FAILED(result)) {
   787                 renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;
   788                 renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
   789             } else {
   790                 D3D_SetError("CreatePixelShader()", result);
   791             }
   792         }
   793     }
   794 
   795     return renderer;
   796 }
   797 
   798 static void
   799 D3D_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
   800 {
   801     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   802 
   803     if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) {
   804         data->updateSize = SDL_TRUE;
   805     }
   806 }
   807 
   808 static D3DBLEND GetBlendFunc(SDL_BlendFactor factor)
   809 {
   810     switch (factor) {
   811     case SDL_BLENDFACTOR_ZERO:
   812         return D3DBLEND_ZERO;
   813     case SDL_BLENDFACTOR_ONE:
   814         return D3DBLEND_ONE;
   815     case SDL_BLENDFACTOR_SRC_COLOR:
   816         return D3DBLEND_SRCCOLOR;
   817     case SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR:
   818         return D3DBLEND_INVSRCCOLOR;
   819     case SDL_BLENDFACTOR_SRC_ALPHA:
   820         return D3DBLEND_SRCALPHA;
   821     case SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA:
   822         return D3DBLEND_INVSRCALPHA;
   823     case SDL_BLENDFACTOR_DST_COLOR:
   824         return D3DBLEND_DESTCOLOR;
   825     case SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR:
   826         return D3DBLEND_INVDESTCOLOR;
   827     case SDL_BLENDFACTOR_DST_ALPHA:
   828         return D3DBLEND_DESTALPHA;
   829     case SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA:
   830         return D3DBLEND_INVDESTALPHA;
   831     default:
   832         return (D3DBLEND)0;
   833     }
   834 }
   835 
   836 static SDL_bool
   837 D3D_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
   838 {
   839     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   840     SDL_BlendFactor srcColorFactor = SDL_GetBlendModeSrcColorFactor(blendMode);
   841     SDL_BlendFactor srcAlphaFactor = SDL_GetBlendModeSrcAlphaFactor(blendMode);
   842     SDL_BlendOperation colorOperation = SDL_GetBlendModeColorOperation(blendMode);
   843     SDL_BlendFactor dstColorFactor = SDL_GetBlendModeDstColorFactor(blendMode);
   844     SDL_BlendFactor dstAlphaFactor = SDL_GetBlendModeDstAlphaFactor(blendMode);
   845     SDL_BlendOperation alphaOperation = SDL_GetBlendModeAlphaOperation(blendMode);
   846 
   847     if (!GetBlendFunc(srcColorFactor) || !GetBlendFunc(srcAlphaFactor) ||
   848         !GetBlendFunc(dstColorFactor) || !GetBlendFunc(dstAlphaFactor)) {
   849         return SDL_FALSE;
   850     }
   851     if ((srcColorFactor != srcAlphaFactor || dstColorFactor != dstAlphaFactor) && !data->enableSeparateAlphaBlend) {
   852         return SDL_FALSE;
   853     }
   854     if (colorOperation != SDL_BLENDOPERATION_ADD || alphaOperation != SDL_BLENDOPERATION_ADD) {
   855         return SDL_FALSE;
   856     }
   857     return SDL_TRUE;
   858 }
   859 
   860 static D3DTEXTUREFILTERTYPE
   861 GetScaleQuality(void)
   862 {
   863     const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
   864 
   865     if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) {
   866         return D3DTEXF_POINT;
   867     } else /* if (*hint == '1' || SDL_strcasecmp(hint, "linear") == 0) */ {
   868         return D3DTEXF_LINEAR;
   869     }
   870 }
   871 
   872 static int
   873 D3D_CreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWORD usage, Uint32 format, int w, int h)
   874 {
   875     HRESULT result;
   876 
   877     texture->dirty = SDL_FALSE;
   878     texture->w = w;
   879     texture->h = h;
   880     texture->usage = usage;
   881     texture->format = format;
   882 
   883     result = IDirect3DDevice9_CreateTexture(device, w, h, 1, usage,
   884         PixelFormatToD3DFMT(format),
   885         D3DPOOL_DEFAULT, &texture->texture, NULL);
   886     if (FAILED(result)) {
   887         return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
   888     }
   889     return 0;
   890 }
   891 
   892 
   893 static int
   894 D3D_CreateStagingTexture(IDirect3DDevice9 *device, D3D_TextureRep *texture)
   895 {
   896     HRESULT result;
   897 
   898     if (texture->staging == NULL) {
   899         result = IDirect3DDevice9_CreateTexture(device, texture->w, texture->h, 1, 0,
   900             PixelFormatToD3DFMT(texture->format),
   901             D3DPOOL_SYSTEMMEM, &texture->staging, NULL);
   902         if (FAILED(result)) {
   903             return D3D_SetError("CreateTexture(D3DPOOL_SYSTEMMEM)", result);
   904         }
   905     }
   906     return 0;
   907 }
   908 
   909 static int
   910 D3D_BindTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWORD sampler)
   911 {
   912     HRESULT result;
   913 
   914     if (texture->dirty && texture->staging) {
   915         if (!texture->texture) {
   916             result = IDirect3DDevice9_CreateTexture(device, texture->w, texture->h, 1, texture->usage,
   917                 PixelFormatToD3DFMT(texture->format), D3DPOOL_DEFAULT, &texture->texture, NULL);
   918             if (FAILED(result)) {
   919                 return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
   920             }
   921         }
   922 
   923         result = IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)texture->staging, (IDirect3DBaseTexture9 *)texture->texture);
   924         if (FAILED(result)) {
   925             return D3D_SetError("UpdateTexture()", result);
   926         }
   927         texture->dirty = SDL_FALSE;
   928     }
   929     result = IDirect3DDevice9_SetTexture(device, sampler, (IDirect3DBaseTexture9 *)texture->texture);
   930     if (FAILED(result)) {
   931         return D3D_SetError("SetTexture()", result);
   932     }
   933     return 0;
   934 }
   935 
   936 static int
   937 D3D_RecreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, Uint32 format, int w, int h)
   938 {
   939     if (texture->texture) {
   940         IDirect3DTexture9_Release(texture->texture);
   941         texture->texture = NULL;
   942     }
   943     if (texture->staging) {
   944         IDirect3DTexture9_AddDirtyRect(texture->staging, NULL);
   945         texture->dirty = SDL_TRUE;
   946     }
   947     return 0;
   948 }
   949 
   950 static int
   951 D3D_UpdateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, Uint32 format, int x, int y, int w, int h, const void *pixels, int pitch)
   952 {
   953     RECT d3drect;
   954     D3DLOCKED_RECT locked;
   955     const Uint8 *src;
   956     Uint8 *dst;
   957     int row, length;
   958     HRESULT result;
   959 
   960     if (D3D_CreateStagingTexture(device, texture) < 0) {
   961         return -1;
   962     }
   963 
   964     d3drect.left = x;
   965     d3drect.right = x + w;
   966     d3drect.top = y;
   967     d3drect.bottom = y + h;
   968     
   969     result = IDirect3DTexture9_LockRect(texture->staging, 0, &locked, &d3drect, 0);
   970     if (FAILED(result)) {
   971         return D3D_SetError("LockRect()", result);
   972     }
   973 
   974     src = (const Uint8 *)pixels;
   975     dst = locked.pBits;
   976     length = w * SDL_BYTESPERPIXEL(format);
   977     if (length == pitch && length == locked.Pitch) {
   978         SDL_memcpy(dst, src, length*h);
   979     } else {
   980         if (length > pitch) {
   981             length = pitch;
   982         }
   983         if (length > locked.Pitch) {
   984             length = locked.Pitch;
   985         }
   986         for (row = 0; row < h; ++row) {
   987             SDL_memcpy(dst, src, length);
   988             src += pitch;
   989             dst += locked.Pitch;
   990         }
   991     }
   992     result = IDirect3DTexture9_UnlockRect(texture->staging, 0);
   993     if (FAILED(result)) {
   994         return D3D_SetError("UnlockRect()", result);
   995     }
   996     texture->dirty = SDL_TRUE;
   997 
   998     return 0;
   999 }
  1000 
  1001 static void
  1002 D3D_DestroyTextureRep(D3D_TextureRep *texture)
  1003 {
  1004     if (texture->texture) {
  1005         IDirect3DTexture9_Release(texture->texture);
  1006         texture->texture = NULL;
  1007     }
  1008     if (texture->staging) {
  1009         IDirect3DTexture9_Release(texture->staging);
  1010         texture->staging = NULL;
  1011     }
  1012 }
  1013 
  1014 static int
  1015 D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  1016 {
  1017     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1018     D3D_TextureData *texturedata;
  1019     DWORD usage;
  1020 
  1021     texturedata = (D3D_TextureData *) SDL_calloc(1, sizeof(*texturedata));
  1022     if (!texturedata) {
  1023         return SDL_OutOfMemory();
  1024     }
  1025     texturedata->scaleMode = GetScaleQuality();
  1026 
  1027     texture->driverdata = texturedata;
  1028 
  1029     if (texture->access == SDL_TEXTUREACCESS_TARGET) {
  1030         usage = D3DUSAGE_RENDERTARGET;
  1031     } else {
  1032         usage = 0;
  1033     }
  1034 
  1035     if (D3D_CreateTextureRep(data->device, &texturedata->texture, usage, texture->format, texture->w, texture->h) < 0) {
  1036         return -1;
  1037     }
  1038 
  1039     if (texture->format == SDL_PIXELFORMAT_YV12 ||
  1040         texture->format == SDL_PIXELFORMAT_IYUV) {
  1041         texturedata->yuv = SDL_TRUE;
  1042 
  1043         if (D3D_CreateTextureRep(data->device, &texturedata->utexture, usage, texture->format, texture->w / 2, texture->h / 2) < 0) {
  1044             return -1;
  1045         }
  1046 
  1047         if (D3D_CreateTextureRep(data->device, &texturedata->vtexture, usage, texture->format, texture->w / 2, texture->h / 2) < 0) {
  1048             return -1;
  1049         }
  1050     }
  1051     return 0;
  1052 }
  1053 
  1054 static int
  1055 D3D_RecreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  1056 {
  1057     D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
  1058     D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
  1059 
  1060     if (!texturedata) {
  1061         return 0;
  1062     }
  1063 
  1064     if (D3D_RecreateTextureRep(data->device, &texturedata->texture, texture->format, texture->w, texture->h) < 0) {
  1065         return -1;
  1066     }
  1067 
  1068     if (texturedata->yuv) {
  1069         if (D3D_RecreateTextureRep(data->device, &texturedata->utexture, texture->format, texture->w / 2, texture->h / 2) < 0) {
  1070             return -1;
  1071         }
  1072 
  1073         if (D3D_RecreateTextureRep(data->device, &texturedata->vtexture, texture->format, texture->w / 2, texture->h / 2) < 0) {
  1074             return -1;
  1075         }
  1076     }
  1077     return 0;
  1078 }
  1079 
  1080 static int
  1081 D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
  1082                   const SDL_Rect * rect, const void *pixels, int pitch)
  1083 {
  1084     D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
  1085     D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata;
  1086 
  1087     if (!texturedata) {
  1088         SDL_SetError("Texture is not currently available");
  1089         return -1;
  1090     }
  1091 
  1092     if (D3D_UpdateTextureRep(data->device, &texturedata->texture, texture->format, rect->x, rect->y, rect->w, rect->h, pixels, pitch) < 0) {
  1093         return -1;
  1094     }
  1095 
  1096     if (texturedata->yuv) {
  1097         /* Skip to the correct offset into the next texture */
  1098         pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
  1099 
  1100         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) {
  1101             return -1;
  1102         }
  1103 
  1104         /* Skip to the correct offset into the next texture */
  1105         pixels = (const void*)((const Uint8*)pixels + (rect->h * pitch)/4);
  1106         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) {
  1107             return -1;
  1108         }
  1109     }
  1110     return 0;
  1111 }
  1112 
  1113 static int
  1114 D3D_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
  1115                      const SDL_Rect * rect,
  1116                      const Uint8 *Yplane, int Ypitch,
  1117                      const Uint8 *Uplane, int Upitch,
  1118                      const Uint8 *Vplane, int Vpitch)
  1119 {
  1120     D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
  1121     D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata;
  1122 
  1123     if (!texturedata) {
  1124         SDL_SetError("Texture is not currently available");
  1125         return -1;
  1126     }
  1127 
  1128     if (D3D_UpdateTextureRep(data->device, &texturedata->texture, texture->format, rect->x, rect->y, rect->w, rect->h, Yplane, Ypitch) < 0) {
  1129         return -1;
  1130     }
  1131     if (D3D_UpdateTextureRep(data->device, &texturedata->utexture, texture->format, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, Uplane, Upitch) < 0) {
  1132         return -1;
  1133     }
  1134     if (D3D_UpdateTextureRep(data->device, &texturedata->vtexture, texture->format, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, Vplane, Vpitch) < 0) {
  1135         return -1;
  1136     }
  1137     return 0;
  1138 }
  1139 
  1140 static int
  1141 D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
  1142                 const SDL_Rect * rect, void **pixels, int *pitch)
  1143 {
  1144     D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
  1145     D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
  1146     IDirect3DDevice9 *device = data->device;
  1147 
  1148     if (!texturedata) {
  1149         SDL_SetError("Texture is not currently available");
  1150         return -1;
  1151     }
  1152 
  1153     texturedata->locked_rect = *rect;
  1154 
  1155     if (texturedata->yuv) {
  1156         /* It's more efficient to upload directly... */
  1157         if (!texturedata->pixels) {
  1158             texturedata->pitch = texture->w;
  1159             texturedata->pixels = (Uint8 *)SDL_malloc((texture->h * texturedata->pitch * 3) / 2);
  1160             if (!texturedata->pixels) {
  1161                 return SDL_OutOfMemory();
  1162             }
  1163         }
  1164         *pixels =
  1165             (void *) ((Uint8 *) texturedata->pixels + rect->y * texturedata->pitch +
  1166                       rect->x * SDL_BYTESPERPIXEL(texture->format));
  1167         *pitch = texturedata->pitch;
  1168     } else {
  1169         RECT d3drect;
  1170         D3DLOCKED_RECT locked;
  1171         HRESULT result;
  1172 
  1173         if (D3D_CreateStagingTexture(device, &texturedata->texture) < 0) {
  1174             return -1;
  1175         }
  1176 
  1177         d3drect.left = rect->x;
  1178         d3drect.right = rect->x + rect->w;
  1179         d3drect.top = rect->y;
  1180         d3drect.bottom = rect->y + rect->h;
  1181 
  1182         result = IDirect3DTexture9_LockRect(texturedata->texture.staging, 0, &locked, &d3drect, 0);
  1183         if (FAILED(result)) {
  1184             return D3D_SetError("LockRect()", result);
  1185         }
  1186         *pixels = locked.pBits;
  1187         *pitch = locked.Pitch;
  1188     }
  1189     return 0;
  1190 }
  1191 
  1192 static void
  1193 D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  1194 {
  1195     /*D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;*/
  1196     D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
  1197 
  1198     if (!texturedata) {
  1199         return;
  1200     }
  1201 
  1202     if (texturedata->yuv) {
  1203         const SDL_Rect *rect = &texturedata->locked_rect;
  1204         void *pixels =
  1205             (void *) ((Uint8 *) texturedata->pixels + rect->y * texturedata->pitch +
  1206                       rect->x * SDL_BYTESPERPIXEL(texture->format));
  1207         D3D_UpdateTexture(renderer, texture, rect, pixels, texturedata->pitch);
  1208     } else {
  1209         IDirect3DTexture9_UnlockRect(texturedata->texture.staging, 0);
  1210         texturedata->texture.dirty = SDL_TRUE;
  1211    }
  1212 }
  1213 
  1214 static int
  1215 D3D_SetRenderTargetInternal(SDL_Renderer * renderer, SDL_Texture * texture)
  1216 {
  1217     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1218     D3D_TextureData *texturedata;
  1219     D3D_TextureRep *texturerep;
  1220     HRESULT result;
  1221     IDirect3DDevice9 *device = data->device;
  1222 
  1223     /* Release the previous render target if it wasn't the default one */
  1224     if (data->currentRenderTarget != NULL) {
  1225         IDirect3DSurface9_Release(data->currentRenderTarget);
  1226         data->currentRenderTarget = NULL;
  1227     }
  1228 
  1229     if (texture == NULL) {
  1230         IDirect3DDevice9_SetRenderTarget(data->device, 0, data->defaultRenderTarget);
  1231         return 0;
  1232     }
  1233 
  1234     texturedata = (D3D_TextureData *)texture->driverdata;
  1235     if (!texturedata) {
  1236         SDL_SetError("Texture is not currently available");
  1237         return -1;
  1238     }
  1239 
  1240     /* Make sure the render target is updated if it was locked and written to */
  1241     texturerep = &texturedata->texture;
  1242     if (texturerep->dirty && texturerep->staging) {
  1243         if (!texturerep->texture) {
  1244             result = IDirect3DDevice9_CreateTexture(device, texturerep->w, texturerep->h, 1, texturerep->usage,
  1245                 PixelFormatToD3DFMT(texturerep->format), D3DPOOL_DEFAULT, &texturerep->texture, NULL);
  1246             if (FAILED(result)) {
  1247                 return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
  1248             }
  1249         }
  1250 
  1251         result = IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)texturerep->staging, (IDirect3DBaseTexture9 *)texturerep->texture);
  1252         if (FAILED(result)) {
  1253             return D3D_SetError("UpdateTexture()", result);
  1254         }
  1255         texturerep->dirty = SDL_FALSE;
  1256     }
  1257 
  1258     result = IDirect3DTexture9_GetSurfaceLevel(texturedata->texture.texture, 0, &data->currentRenderTarget);
  1259     if(FAILED(result)) {
  1260         return D3D_SetError("GetSurfaceLevel()", result);
  1261     }
  1262     result = IDirect3DDevice9_SetRenderTarget(data->device, 0, data->currentRenderTarget);
  1263     if(FAILED(result)) {
  1264         return D3D_SetError("SetRenderTarget()", result);
  1265     }
  1266 
  1267     return 0;
  1268 }
  1269 
  1270 static int
  1271 D3D_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
  1272 {
  1273     D3D_ActivateRenderer(renderer);
  1274 
  1275     return D3D_SetRenderTargetInternal(renderer, texture);
  1276 }
  1277 
  1278 static int
  1279 D3D_UpdateViewport(SDL_Renderer * renderer)
  1280 {
  1281     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1282     D3DVIEWPORT9 viewport;
  1283     D3DMATRIX matrix;
  1284 
  1285     /* Set the viewport */
  1286     viewport.X = renderer->viewport.x;
  1287     viewport.Y = renderer->viewport.y;
  1288     viewport.Width = renderer->viewport.w;
  1289     viewport.Height = renderer->viewport.h;
  1290     viewport.MinZ = 0.0f;
  1291     viewport.MaxZ = 1.0f;
  1292     IDirect3DDevice9_SetViewport(data->device, &viewport);
  1293 
  1294     /* Set an orthographic projection matrix */
  1295     if (renderer->viewport.w && renderer->viewport.h) {
  1296         matrix.m[0][0] = 2.0f / renderer->viewport.w;
  1297         matrix.m[0][1] = 0.0f;
  1298         matrix.m[0][2] = 0.0f;
  1299         matrix.m[0][3] = 0.0f;
  1300         matrix.m[1][0] = 0.0f;
  1301         matrix.m[1][1] = -2.0f / renderer->viewport.h;
  1302         matrix.m[1][2] = 0.0f;
  1303         matrix.m[1][3] = 0.0f;
  1304         matrix.m[2][0] = 0.0f;
  1305         matrix.m[2][1] = 0.0f;
  1306         matrix.m[2][2] = 1.0f;
  1307         matrix.m[2][3] = 0.0f;
  1308         matrix.m[3][0] = -1.0f;
  1309         matrix.m[3][1] = 1.0f;
  1310         matrix.m[3][2] = 0.0f;
  1311         matrix.m[3][3] = 1.0f;
  1312         IDirect3DDevice9_SetTransform(data->device, D3DTS_PROJECTION, &matrix);
  1313     }
  1314 
  1315     return 0;
  1316 }
  1317 
  1318 static int
  1319 D3D_UpdateClipRect(SDL_Renderer * renderer)
  1320 {
  1321     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1322 
  1323     if (renderer->clipping_enabled) {
  1324         const SDL_Rect *rect = &renderer->clip_rect;
  1325         RECT r;
  1326         HRESULT result;
  1327 
  1328         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, TRUE);
  1329         r.left = renderer->viewport.x + rect->x;
  1330         r.top = renderer->viewport.y + rect->y;
  1331         r.right = renderer->viewport.x + rect->x + rect->w;
  1332         r.bottom = renderer->viewport.y + rect->y + rect->h;
  1333 
  1334         result = IDirect3DDevice9_SetScissorRect(data->device, &r);
  1335         if (result != D3D_OK) {
  1336             D3D_SetError("SetScissor()", result);
  1337             return -1;
  1338         }
  1339     } else {
  1340         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, FALSE);
  1341     }
  1342     return 0;
  1343 }
  1344 
  1345 static int
  1346 D3D_RenderClear(SDL_Renderer * renderer)
  1347 {
  1348     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1349     DWORD color;
  1350     HRESULT result;
  1351     int BackBufferWidth, BackBufferHeight;
  1352 
  1353     if (D3D_ActivateRenderer(renderer) < 0) {
  1354         return -1;
  1355     }
  1356 
  1357     color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
  1358 
  1359     if (renderer->target) {
  1360         BackBufferWidth = renderer->target->w;
  1361         BackBufferHeight = renderer->target->h;
  1362     } else {
  1363         BackBufferWidth = data->pparams.BackBufferWidth;
  1364         BackBufferHeight = data->pparams.BackBufferHeight;
  1365     }
  1366 
  1367     if (renderer->clipping_enabled) {
  1368         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, FALSE);
  1369     }
  1370 
  1371     /* Don't reset the viewport if we don't have to! */
  1372     if (!renderer->viewport.x && !renderer->viewport.y &&
  1373         renderer->viewport.w == BackBufferWidth &&
  1374         renderer->viewport.h == BackBufferHeight) {
  1375         result = IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
  1376     } else {
  1377         D3DVIEWPORT9 viewport;
  1378 
  1379         /* Clear is defined to clear the entire render target */
  1380         viewport.X = 0;
  1381         viewport.Y = 0;
  1382         viewport.Width = BackBufferWidth;
  1383         viewport.Height = BackBufferHeight;
  1384         viewport.MinZ = 0.0f;
  1385         viewport.MaxZ = 1.0f;
  1386         IDirect3DDevice9_SetViewport(data->device, &viewport);
  1387 
  1388         result = IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
  1389 
  1390         /* Reset the viewport */
  1391         viewport.X = renderer->viewport.x;
  1392         viewport.Y = renderer->viewport.y;
  1393         viewport.Width = renderer->viewport.w;
  1394         viewport.Height = renderer->viewport.h;
  1395         viewport.MinZ = 0.0f;
  1396         viewport.MaxZ = 1.0f;
  1397         IDirect3DDevice9_SetViewport(data->device, &viewport);
  1398     }
  1399 
  1400     if (renderer->clipping_enabled) {
  1401         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, TRUE);
  1402     }
  1403 
  1404     if (FAILED(result)) {
  1405         return D3D_SetError("Clear()", result);
  1406     }
  1407     return 0;
  1408 }
  1409 
  1410 static void
  1411 D3D_SetBlendMode(D3D_RenderData * data, SDL_BlendMode blendMode)
  1412 {
  1413     if (blendMode == SDL_BLENDMODE_NONE) {
  1414         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, FALSE);
  1415     } else {
  1416         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, TRUE);
  1417         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
  1418                                         GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blendMode)));
  1419         IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
  1420                                         GetBlendFunc(SDL_GetBlendModeDstColorFactor(blendMode)));
  1421         if (data->enableSeparateAlphaBlend) {
  1422             IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA,
  1423                                             GetBlendFunc(SDL_GetBlendModeSrcAlphaFactor(blendMode)));
  1424             IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA,
  1425                                             GetBlendFunc(SDL_GetBlendModeDstAlphaFactor(blendMode)));
  1426         }
  1427     }
  1428 }
  1429 
  1430 static int
  1431 D3D_RenderDrawPoints(SDL_Renderer * renderer, const SDL_FPoint * points,
  1432                      int count)
  1433 {
  1434     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1435     DWORD color;
  1436     Vertex *vertices;
  1437     int i;
  1438     HRESULT result;
  1439 
  1440     if (D3D_ActivateRenderer(renderer) < 0) {
  1441         return -1;
  1442     }
  1443 
  1444     D3D_SetBlendMode(data, renderer->blendMode);
  1445 
  1446     result =
  1447         IDirect3DDevice9_SetTexture(data->device, 0,
  1448                                     (IDirect3DBaseTexture9 *) 0);
  1449     if (FAILED(result)) {
  1450         return D3D_SetError("SetTexture()", result);
  1451     }
  1452 
  1453     color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
  1454 
  1455     vertices = SDL_stack_alloc(Vertex, count);
  1456     for (i = 0; i < count; ++i) {
  1457         vertices[i].x = points[i].x;
  1458         vertices[i].y = points[i].y;
  1459         vertices[i].z = 0.0f;
  1460         vertices[i].color = color;
  1461         vertices[i].u = 0.0f;
  1462         vertices[i].v = 0.0f;
  1463     }
  1464     result =
  1465         IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, count,
  1466                                          vertices, sizeof(*vertices));
  1467     SDL_stack_free(vertices);
  1468     if (FAILED(result)) {
  1469         return D3D_SetError("DrawPrimitiveUP()", result);
  1470     }
  1471     return 0;
  1472 }
  1473 
  1474 static int
  1475 D3D_RenderDrawLines(SDL_Renderer * renderer, const SDL_FPoint * points,
  1476                     int count)
  1477 {
  1478     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1479     DWORD color;
  1480     Vertex *vertices;
  1481     int i;
  1482     HRESULT result;
  1483 
  1484     if (D3D_ActivateRenderer(renderer) < 0) {
  1485         return -1;
  1486     }
  1487 
  1488     D3D_SetBlendMode(data, renderer->blendMode);
  1489 
  1490     result =
  1491         IDirect3DDevice9_SetTexture(data->device, 0,
  1492                                     (IDirect3DBaseTexture9 *) 0);
  1493     if (FAILED(result)) {
  1494         return D3D_SetError("SetTexture()", result);
  1495     }
  1496 
  1497     color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
  1498 
  1499     vertices = SDL_stack_alloc(Vertex, count);
  1500     for (i = 0; i < count; ++i) {
  1501         vertices[i].x = points[i].x;
  1502         vertices[i].y = points[i].y;
  1503         vertices[i].z = 0.0f;
  1504         vertices[i].color = color;
  1505         vertices[i].u = 0.0f;
  1506         vertices[i].v = 0.0f;
  1507     }
  1508     result =
  1509         IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_LINESTRIP, count-1,
  1510                                          vertices, sizeof(*vertices));
  1511 
  1512     /* DirectX 9 has the same line rasterization semantics as GDI,
  1513        so we need to close the endpoint of the line */
  1514     if (count == 2 ||
  1515         points[0].x != points[count-1].x || points[0].y != points[count-1].y) {
  1516         vertices[0].x = points[count-1].x;
  1517         vertices[0].y = points[count-1].y;
  1518         result = IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, 1, vertices, sizeof(*vertices));
  1519     }
  1520 
  1521     SDL_stack_free(vertices);
  1522     if (FAILED(result)) {
  1523         return D3D_SetError("DrawPrimitiveUP()", result);
  1524     }
  1525     return 0;
  1526 }
  1527 
  1528 static int
  1529 D3D_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects,
  1530                     int count)
  1531 {
  1532     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1533     DWORD color;
  1534     int i;
  1535     float minx, miny, maxx, maxy;
  1536     Vertex vertices[4];
  1537     HRESULT result;
  1538 
  1539     if (D3D_ActivateRenderer(renderer) < 0) {
  1540         return -1;
  1541     }
  1542 
  1543     D3D_SetBlendMode(data, renderer->blendMode);
  1544 
  1545     result =
  1546         IDirect3DDevice9_SetTexture(data->device, 0,
  1547                                     (IDirect3DBaseTexture9 *) 0);
  1548     if (FAILED(result)) {
  1549         return D3D_SetError("SetTexture()", result);
  1550     }
  1551 
  1552     color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
  1553 
  1554     for (i = 0; i < count; ++i) {
  1555         const SDL_FRect *rect = &rects[i];
  1556 
  1557         minx = rect->x;
  1558         miny = rect->y;
  1559         maxx = rect->x + rect->w;
  1560         maxy = rect->y + rect->h;
  1561 
  1562         vertices[0].x = minx;
  1563         vertices[0].y = miny;
  1564         vertices[0].z = 0.0f;
  1565         vertices[0].color = color;
  1566         vertices[0].u = 0.0f;
  1567         vertices[0].v = 0.0f;
  1568 
  1569         vertices[1].x = maxx;
  1570         vertices[1].y = miny;
  1571         vertices[1].z = 0.0f;
  1572         vertices[1].color = color;
  1573         vertices[1].u = 0.0f;
  1574         vertices[1].v = 0.0f;
  1575 
  1576         vertices[2].x = maxx;
  1577         vertices[2].y = maxy;
  1578         vertices[2].z = 0.0f;
  1579         vertices[2].color = color;
  1580         vertices[2].u = 0.0f;
  1581         vertices[2].v = 0.0f;
  1582 
  1583         vertices[3].x = minx;
  1584         vertices[3].y = maxy;
  1585         vertices[3].z = 0.0f;
  1586         vertices[3].color = color;
  1587         vertices[3].u = 0.0f;
  1588         vertices[3].v = 0.0f;
  1589 
  1590         result =
  1591             IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN,
  1592                                              2, vertices, sizeof(*vertices));
  1593         if (FAILED(result)) {
  1594             return D3D_SetError("DrawPrimitiveUP()", result);
  1595         }
  1596     }
  1597     return 0;
  1598 }
  1599 
  1600 static void
  1601 D3D_UpdateTextureScaleMode(D3D_RenderData *data, D3D_TextureData *texturedata, unsigned index)
  1602 {
  1603     if (texturedata->scaleMode != data->scaleMode[index]) {
  1604         IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MINFILTER,
  1605                                          texturedata->scaleMode);
  1606         IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MAGFILTER,
  1607                                          texturedata->scaleMode);
  1608         data->scaleMode[index] = texturedata->scaleMode;
  1609     }
  1610 }
  1611 
  1612 static int
  1613 D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
  1614                const SDL_Rect * srcrect, const SDL_FRect * dstrect)
  1615 {
  1616     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1617     D3D_TextureData *texturedata;
  1618     LPDIRECT3DPIXELSHADER9 shader = NULL;
  1619     float minx, miny, maxx, maxy;
  1620     float minu, maxu, minv, maxv;
  1621     DWORD color;
  1622     Vertex vertices[4];
  1623     HRESULT result;
  1624 
  1625     if (D3D_ActivateRenderer(renderer) < 0) {
  1626         return -1;
  1627     }
  1628 
  1629     texturedata = (D3D_TextureData *)texture->driverdata;
  1630     if (!texturedata) {
  1631         SDL_SetError("Texture is not currently available");
  1632         return -1;
  1633     }
  1634 
  1635     minx = dstrect->x - 0.5f;
  1636     miny = dstrect->y - 0.5f;
  1637     maxx = dstrect->x + dstrect->w - 0.5f;
  1638     maxy = dstrect->y + dstrect->h - 0.5f;
  1639 
  1640     minu = (float) srcrect->x / texture->w;
  1641     maxu = (float) (srcrect->x + srcrect->w) / texture->w;
  1642     minv = (float) srcrect->y / texture->h;
  1643     maxv = (float) (srcrect->y + srcrect->h) / texture->h;
  1644 
  1645     color = D3DCOLOR_ARGB(texture->a, texture->r, texture->g, texture->b);
  1646 
  1647     vertices[0].x = minx;
  1648     vertices[0].y = miny;
  1649     vertices[0].z = 0.0f;
  1650     vertices[0].color = color;
  1651     vertices[0].u = minu;
  1652     vertices[0].v = minv;
  1653 
  1654     vertices[1].x = maxx;
  1655     vertices[1].y = miny;
  1656     vertices[1].z = 0.0f;
  1657     vertices[1].color = color;
  1658     vertices[1].u = maxu;
  1659     vertices[1].v = minv;
  1660 
  1661     vertices[2].x = maxx;
  1662     vertices[2].y = maxy;
  1663     vertices[2].z = 0.0f;
  1664     vertices[2].color = color;
  1665     vertices[2].u = maxu;
  1666     vertices[2].v = maxv;
  1667 
  1668     vertices[3].x = minx;
  1669     vertices[3].y = maxy;
  1670     vertices[3].z = 0.0f;
  1671     vertices[3].color = color;
  1672     vertices[3].u = minu;
  1673     vertices[3].v = maxv;
  1674 
  1675     D3D_SetBlendMode(data, texture->blendMode);
  1676 
  1677     D3D_UpdateTextureScaleMode(data, texturedata, 0);
  1678 
  1679     if (D3D_BindTextureRep(data->device, &texturedata->texture, 0) < 0) {
  1680         return -1;
  1681     }
  1682 
  1683     if (texturedata->yuv) {
  1684         shader = data->ps_yuv;
  1685 
  1686         D3D_UpdateTextureScaleMode(data, texturedata, 1);
  1687         D3D_UpdateTextureScaleMode(data, texturedata, 2);
  1688 
  1689         if (D3D_BindTextureRep(data->device, &texturedata->utexture, 1) < 0) {
  1690             return -1;
  1691         }
  1692         if (D3D_BindTextureRep(data->device, &texturedata->vtexture, 2) < 0) {
  1693             return -1;
  1694         }
  1695     }
  1696 
  1697     if (shader) {
  1698         result = IDirect3DDevice9_SetPixelShader(data->device, shader);
  1699         if (FAILED(result)) {
  1700             return D3D_SetError("SetShader()", result);
  1701         }
  1702     }
  1703     result =
  1704         IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2,
  1705                                          vertices, sizeof(*vertices));
  1706     if (FAILED(result)) {
  1707         return D3D_SetError("DrawPrimitiveUP()", result);
  1708     }
  1709     if (shader) {
  1710         result = IDirect3DDevice9_SetPixelShader(data->device, NULL);
  1711         if (FAILED(result)) {
  1712             return D3D_SetError("SetShader()", result);
  1713         }
  1714     }
  1715     return 0;
  1716 }
  1717 
  1718 
  1719 static int
  1720 D3D_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
  1721                const SDL_Rect * srcrect, const SDL_FRect * dstrect,
  1722                const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip)
  1723 {
  1724     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1725     D3D_TextureData *texturedata;
  1726     LPDIRECT3DPIXELSHADER9 shader = NULL;
  1727     float minx, miny, maxx, maxy;
  1728     float minu, maxu, minv, maxv;
  1729     float centerx, centery;
  1730     DWORD color;
  1731     Vertex vertices[4];
  1732     Float4X4 modelMatrix;
  1733     HRESULT result;
  1734 
  1735     if (D3D_ActivateRenderer(renderer) < 0) {
  1736         return -1;
  1737     }
  1738 
  1739     texturedata = (D3D_TextureData *)texture->driverdata;
  1740     if (!texturedata) {
  1741         SDL_SetError("Texture is not currently available");
  1742         return -1;
  1743     }
  1744 
  1745     centerx = center->x;
  1746     centery = center->y;
  1747 
  1748     minx = -centerx;
  1749     maxx = dstrect->w - centerx;
  1750     miny = -centery;
  1751     maxy = dstrect->h - centery;
  1752 
  1753     minu = (float) srcrect->x / texture->w;
  1754     maxu = (float) (srcrect->x + srcrect->w) / texture->w;
  1755     minv = (float) srcrect->y / texture->h;
  1756     maxv = (float) (srcrect->y + srcrect->h) / texture->h;
  1757 
  1758     if (flip & SDL_FLIP_HORIZONTAL) {
  1759         float tmp = maxu;
  1760         maxu = minu;
  1761         minu = tmp;
  1762     }
  1763     if (flip & SDL_FLIP_VERTICAL) {
  1764         float tmp = maxv;
  1765         maxv = minv;
  1766         minv = tmp;
  1767     }
  1768 
  1769     color = D3DCOLOR_ARGB(texture->a, texture->r, texture->g, texture->b);
  1770 
  1771     vertices[0].x = minx;
  1772     vertices[0].y = miny;
  1773     vertices[0].z = 0.0f;
  1774     vertices[0].color = color;
  1775     vertices[0].u = minu;
  1776     vertices[0].v = minv;
  1777 
  1778     vertices[1].x = maxx;
  1779     vertices[1].y = miny;
  1780     vertices[1].z = 0.0f;
  1781     vertices[1].color = color;
  1782     vertices[1].u = maxu;
  1783     vertices[1].v = minv;
  1784 
  1785     vertices[2].x = maxx;
  1786     vertices[2].y = maxy;
  1787     vertices[2].z = 0.0f;
  1788     vertices[2].color = color;
  1789     vertices[2].u = maxu;
  1790     vertices[2].v = maxv;
  1791 
  1792     vertices[3].x = minx;
  1793     vertices[3].y = maxy;
  1794     vertices[3].z = 0.0f;
  1795     vertices[3].color = color;
  1796     vertices[3].u = minu;
  1797     vertices[3].v = maxv;
  1798 
  1799     D3D_SetBlendMode(data, texture->blendMode);
  1800 
  1801     /* Rotate and translate */
  1802     modelMatrix = MatrixMultiply(
  1803             MatrixRotationZ((float)(M_PI * (float) angle / 180.0f)),
  1804             MatrixTranslation(dstrect->x + center->x - 0.5f, dstrect->y + center->y - 0.5f, 0));
  1805     IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)&modelMatrix);
  1806 
  1807     D3D_UpdateTextureScaleMode(data, texturedata, 0);
  1808 
  1809     if (D3D_BindTextureRep(data->device, &texturedata->texture, 0) < 0) {
  1810         return -1;
  1811     }
  1812 
  1813     if (texturedata->yuv) {
  1814         shader = data->ps_yuv;
  1815 
  1816         D3D_UpdateTextureScaleMode(data, texturedata, 1);
  1817         D3D_UpdateTextureScaleMode(data, texturedata, 2);
  1818         
  1819         if (D3D_BindTextureRep(data->device, &texturedata->utexture, 1) < 0) {
  1820             return -1;
  1821         }
  1822         if (D3D_BindTextureRep(data->device, &texturedata->vtexture, 2) < 0) {
  1823             return -1;
  1824         }
  1825     }
  1826 
  1827     if (shader) {
  1828         result = IDirect3DDevice9_SetPixelShader(data->device, shader);
  1829         if (FAILED(result)) {
  1830             return D3D_SetError("SetShader()", result);
  1831         }
  1832     }
  1833     result =
  1834         IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2,
  1835                                          vertices, sizeof(*vertices));
  1836     if (FAILED(result)) {
  1837         return D3D_SetError("DrawPrimitiveUP()", result);
  1838     }
  1839     if (shader) {
  1840         result = IDirect3DDevice9_SetPixelShader(data->device, NULL);
  1841         if (FAILED(result)) {
  1842             return D3D_SetError("SetShader()", result);
  1843         }
  1844     }
  1845 
  1846     modelMatrix = MatrixIdentity();
  1847     IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)&modelMatrix);
  1848     return 0;
  1849 }
  1850 
  1851 static int
  1852 D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
  1853                      Uint32 format, void * pixels, int pitch)
  1854 {
  1855     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1856     D3DSURFACE_DESC desc;
  1857     LPDIRECT3DSURFACE9 backBuffer;
  1858     LPDIRECT3DSURFACE9 surface;
  1859     RECT d3drect;
  1860     D3DLOCKED_RECT locked;
  1861     HRESULT result;
  1862 
  1863     if (data->currentRenderTarget) {
  1864         backBuffer = data->currentRenderTarget;
  1865     } else {
  1866         backBuffer = data->defaultRenderTarget;
  1867     }
  1868 
  1869     result = IDirect3DSurface9_GetDesc(backBuffer, &desc);
  1870     if (FAILED(result)) {
  1871         IDirect3DSurface9_Release(backBuffer);
  1872         return D3D_SetError("GetDesc()", result);
  1873     }
  1874 
  1875     result = IDirect3DDevice9_CreateOffscreenPlainSurface(data->device, desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surface, NULL);
  1876     if (FAILED(result)) {
  1877         IDirect3DSurface9_Release(backBuffer);
  1878         return D3D_SetError("CreateOffscreenPlainSurface()", result);
  1879     }
  1880 
  1881     result = IDirect3DDevice9_GetRenderTargetData(data->device, backBuffer, surface);
  1882     if (FAILED(result)) {
  1883         IDirect3DSurface9_Release(surface);
  1884         IDirect3DSurface9_Release(backBuffer);
  1885         return D3D_SetError("GetRenderTargetData()", result);
  1886     }
  1887 
  1888     d3drect.left = rect->x;
  1889     d3drect.right = rect->x + rect->w;
  1890     d3drect.top = rect->y;
  1891     d3drect.bottom = rect->y + rect->h;
  1892 
  1893     result = IDirect3DSurface9_LockRect(surface, &locked, &d3drect, D3DLOCK_READONLY);
  1894     if (FAILED(result)) {
  1895         IDirect3DSurface9_Release(surface);
  1896         IDirect3DSurface9_Release(backBuffer);
  1897         return D3D_SetError("LockRect()", result);
  1898     }
  1899 
  1900     SDL_ConvertPixels(rect->w, rect->h,
  1901                       D3DFMTToPixelFormat(desc.Format), locked.pBits, locked.Pitch,
  1902                       format, pixels, pitch);
  1903 
  1904     IDirect3DSurface9_UnlockRect(surface);
  1905 
  1906     IDirect3DSurface9_Release(surface);
  1907 
  1908     return 0;
  1909 }
  1910 
  1911 static void
  1912 D3D_RenderPresent(SDL_Renderer * renderer)
  1913 {
  1914     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1915     HRESULT result;
  1916 
  1917     if (!data->beginScene) {
  1918         IDirect3DDevice9_EndScene(data->device);
  1919         data->beginScene = SDL_TRUE;
  1920     }
  1921 
  1922     result = IDirect3DDevice9_TestCooperativeLevel(data->device);
  1923     if (result == D3DERR_DEVICELOST) {
  1924         /* We'll reset later */
  1925         return;
  1926     }
  1927     if (result == D3DERR_DEVICENOTRESET) {
  1928         D3D_Reset(renderer);
  1929     }
  1930     result = IDirect3DDevice9_Present(data->device, NULL, NULL, NULL, NULL);
  1931     if (FAILED(result)) {
  1932         D3D_SetError("Present()", result);
  1933     }
  1934 }
  1935 
  1936 static void
  1937 D3D_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  1938 {
  1939     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
  1940 
  1941     if (!data) {
  1942         return;
  1943     }
  1944     D3D_DestroyTextureRep(&data->texture);
  1945     D3D_DestroyTextureRep(&data->utexture);
  1946     D3D_DestroyTextureRep(&data->vtexture);
  1947     SDL_free(data->pixels);
  1948     SDL_free(data);
  1949     texture->driverdata = NULL;
  1950 }
  1951 
  1952 static void
  1953 D3D_DestroyRenderer(SDL_Renderer * renderer)
  1954 {
  1955     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1956 
  1957     if (data) {
  1958         /* Release the render target */
  1959         if (data->defaultRenderTarget) {
  1960             IDirect3DSurface9_Release(data->defaultRenderTarget);
  1961             data->defaultRenderTarget = NULL;
  1962         }
  1963         if (data->currentRenderTarget != NULL) {
  1964             IDirect3DSurface9_Release(data->currentRenderTarget);
  1965             data->currentRenderTarget = NULL;
  1966         }
  1967         if (data->ps_yuv) {
  1968             IDirect3DPixelShader9_Release(data->ps_yuv);
  1969         }
  1970         if (data->device) {
  1971             IDirect3DDevice9_Release(data->device);
  1972         }
  1973         if (data->d3d) {
  1974             IDirect3D9_Release(data->d3d);
  1975             SDL_UnloadObject(data->d3dDLL);
  1976         }
  1977         SDL_free(data);
  1978     }
  1979     SDL_free(renderer);
  1980 }
  1981 #endif /* SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED */
  1982 
  1983 #ifdef __WIN32__
  1984 /* This function needs to always exist on Windows, for the Dynamic API. */
  1985 IDirect3DDevice9 *
  1986 SDL_RenderGetD3D9Device(SDL_Renderer * renderer)
  1987 {
  1988     IDirect3DDevice9 *device = NULL;
  1989 
  1990 #if SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED
  1991     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1992 
  1993     /* Make sure that this is a D3D renderer */
  1994     if (renderer->DestroyRenderer != D3D_DestroyRenderer) {
  1995         SDL_SetError("Renderer is not a D3D renderer");
  1996         return NULL;
  1997     }
  1998 
  1999     device = data->device;
  2000     if (device) {
  2001         IDirect3DDevice9_AddRef(device);
  2002     }
  2003 #endif /* SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED */
  2004 
  2005     return device;
  2006 }
  2007 #endif /* __WIN32__ */
  2008 
  2009 /* vi: set ts=4 sw=4 expandtab: */