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