src/render/direct3d/SDL_render_d3d.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 17 Aug 2014 14:44:53 -0700
changeset 9085 7cafa57c23ec
parent 9074 86a6f6d92960
child 9619 b94b6d0bff0f
permissions -rw-r--r--
Fixed bug 2685 - SDL_RenderReadPixels() doesn't work with offscreen targets

Andreas Falkenhahn

SDL_RenderReadPixels() doesn't seem to work when trying to read pixels from a texture that has been created using SDL_TEXTUREACCESS_TARGET and has been selected as the render target using SDL_SetRenderTarget().

I am attaching a small program that demonstrates the issue. I get the following result here:

READ PIXEL RETURN: 0 --- COLOR CHECK: ff000000

But it should be:

READ PIXEL RETURN: 0 --- COLOR CHECK: ffff0000

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