src/render/direct3d/SDL_render_d3d.c
author Ryan C. Gordon <icculus@icculus.org>
Mon, 01 Oct 2018 11:32:08 -0400
branchSDL-ryan-batching-renderer
changeset 12280 412a6f2078d4
parent 12279 4b8721c990f9
child 12281 838c5562d05f
permissions -rw-r--r--
render: Set the D3D9 stream source once and choose offsets during draw calls.

This is _much_ faster than setting the offsets with SetStreamSource!
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2018 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_log.h"
    34 #include "SDL_assert.h"
    35 #include "../SDL_sysrender.h"
    36 #include "../SDL_d3dmath.h"
    37 #include "../../video/windows/SDL_windowsvideo.h"
    38 
    39 #if SDL_VIDEO_RENDER_D3D
    40 #define D3D_DEBUG_INFO
    41 #include <d3d9.h>
    42 #endif
    43 
    44 #include "SDL_shaders_d3d.h"
    45 
    46 typedef struct
    47 {
    48     SDL_Rect viewport;
    49     SDL_bool viewport_dirty;
    50     SDL_Texture *texture;
    51     SDL_BlendMode blend;
    52     SDL_bool cliprect_enabled;
    53     SDL_bool cliprect_enabled_dirty;
    54     SDL_Rect cliprect;
    55     SDL_bool cliprect_dirty;
    56     SDL_bool is_copy_ex;
    57     LPDIRECT3DPIXELSHADER9 shader;
    58 } D3D_DrawStateCache;
    59 
    60 
    61 /* Direct3D renderer implementation */
    62 
    63 typedef struct
    64 {
    65     void* d3dDLL;
    66     IDirect3D9 *d3d;
    67     IDirect3DDevice9 *device;
    68     UINT adapter;
    69     D3DPRESENT_PARAMETERS pparams;
    70     SDL_bool updateSize;
    71     SDL_bool beginScene;
    72     SDL_bool enableSeparateAlphaBlend;
    73     SDL_bool supportsStreamOffset;
    74     D3DTEXTUREFILTERTYPE scaleMode[8];
    75     IDirect3DSurface9 *defaultRenderTarget;
    76     IDirect3DSurface9 *currentRenderTarget;
    77     void* d3dxDLL;
    78     LPDIRECT3DPIXELSHADER9 shaders[NUM_SHADERS];
    79     LPDIRECT3DVERTEXBUFFER9 vertexBuffers[8];
    80     size_t vertexBufferSize[8];
    81     int currentVertexBuffer;
    82     SDL_bool reportedVboProblem;
    83     D3D_DrawStateCache drawstate;
    84 } D3D_RenderData;
    85 
    86 typedef struct
    87 {
    88     SDL_bool dirty;
    89     int w, h;
    90     DWORD usage;
    91     Uint32 format;
    92     D3DFORMAT d3dfmt;
    93     IDirect3DTexture9 *texture;
    94     IDirect3DTexture9 *staging;
    95 } D3D_TextureRep;
    96 
    97 typedef struct
    98 {
    99     D3D_TextureRep texture;
   100     D3DTEXTUREFILTERTYPE scaleMode;
   101 
   102     /* YV12 texture support */
   103     SDL_bool yuv;
   104     D3D_TextureRep utexture;
   105     D3D_TextureRep vtexture;
   106     Uint8 *pixels;
   107     int pitch;
   108     SDL_Rect locked_rect;
   109 } D3D_TextureData;
   110 
   111 typedef struct
   112 {
   113     float x, y, z;
   114     DWORD color;
   115     float u, v;
   116 } Vertex;
   117 
   118 static int
   119 D3D_SetError(const char *prefix, HRESULT result)
   120 {
   121     const char *error;
   122 
   123     switch (result) {
   124     case D3DERR_WRONGTEXTUREFORMAT:
   125         error = "WRONGTEXTUREFORMAT";
   126         break;
   127     case D3DERR_UNSUPPORTEDCOLOROPERATION:
   128         error = "UNSUPPORTEDCOLOROPERATION";
   129         break;
   130     case D3DERR_UNSUPPORTEDCOLORARG:
   131         error = "UNSUPPORTEDCOLORARG";
   132         break;
   133     case D3DERR_UNSUPPORTEDALPHAOPERATION:
   134         error = "UNSUPPORTEDALPHAOPERATION";
   135         break;
   136     case D3DERR_UNSUPPORTEDALPHAARG:
   137         error = "UNSUPPORTEDALPHAARG";
   138         break;
   139     case D3DERR_TOOMANYOPERATIONS:
   140         error = "TOOMANYOPERATIONS";
   141         break;
   142     case D3DERR_CONFLICTINGTEXTUREFILTER:
   143         error = "CONFLICTINGTEXTUREFILTER";
   144         break;
   145     case D3DERR_UNSUPPORTEDFACTORVALUE:
   146         error = "UNSUPPORTEDFACTORVALUE";
   147         break;
   148     case D3DERR_CONFLICTINGRENDERSTATE:
   149         error = "CONFLICTINGRENDERSTATE";
   150         break;
   151     case D3DERR_UNSUPPORTEDTEXTUREFILTER:
   152         error = "UNSUPPORTEDTEXTUREFILTER";
   153         break;
   154     case D3DERR_CONFLICTINGTEXTUREPALETTE:
   155         error = "CONFLICTINGTEXTUREPALETTE";
   156         break;
   157     case D3DERR_DRIVERINTERNALERROR:
   158         error = "DRIVERINTERNALERROR";
   159         break;
   160     case D3DERR_NOTFOUND:
   161         error = "NOTFOUND";
   162         break;
   163     case D3DERR_MOREDATA:
   164         error = "MOREDATA";
   165         break;
   166     case D3DERR_DEVICELOST:
   167         error = "DEVICELOST";
   168         break;
   169     case D3DERR_DEVICENOTRESET:
   170         error = "DEVICENOTRESET";
   171         break;
   172     case D3DERR_NOTAVAILABLE:
   173         error = "NOTAVAILABLE";
   174         break;
   175     case D3DERR_OUTOFVIDEOMEMORY:
   176         error = "OUTOFVIDEOMEMORY";
   177         break;
   178     case D3DERR_INVALIDDEVICE:
   179         error = "INVALIDDEVICE";
   180         break;
   181     case D3DERR_INVALIDCALL:
   182         error = "INVALIDCALL";
   183         break;
   184     case D3DERR_DRIVERINVALIDCALL:
   185         error = "DRIVERINVALIDCALL";
   186         break;
   187     case D3DERR_WASSTILLDRAWING:
   188         error = "WASSTILLDRAWING";
   189         break;
   190     default:
   191         error = "UNKNOWN";
   192         break;
   193     }
   194     return SDL_SetError("%s: %s", prefix, error);
   195 }
   196 
   197 static D3DFORMAT
   198 PixelFormatToD3DFMT(Uint32 format)
   199 {
   200     switch (format) {
   201     case SDL_PIXELFORMAT_RGB565:
   202         return D3DFMT_R5G6B5;
   203     case SDL_PIXELFORMAT_RGB888:
   204         return D3DFMT_X8R8G8B8;
   205     case SDL_PIXELFORMAT_ARGB8888:
   206         return D3DFMT_A8R8G8B8;
   207     case SDL_PIXELFORMAT_YV12:
   208     case SDL_PIXELFORMAT_IYUV:
   209     case SDL_PIXELFORMAT_NV12:
   210     case SDL_PIXELFORMAT_NV21:
   211         return D3DFMT_L8;
   212     default:
   213         return D3DFMT_UNKNOWN;
   214     }
   215 }
   216 
   217 static Uint32
   218 D3DFMTToPixelFormat(D3DFORMAT format)
   219 {
   220     switch (format) {
   221     case D3DFMT_R5G6B5:
   222         return SDL_PIXELFORMAT_RGB565;
   223     case D3DFMT_X8R8G8B8:
   224         return SDL_PIXELFORMAT_RGB888;
   225     case D3DFMT_A8R8G8B8:
   226         return SDL_PIXELFORMAT_ARGB8888;
   227     default:
   228         return SDL_PIXELFORMAT_UNKNOWN;
   229     }
   230 }
   231 
   232 static void
   233 D3D_InitRenderState(D3D_RenderData *data)
   234 {
   235     D3DMATRIX matrix;
   236 
   237     IDirect3DDevice9 *device = data->device;
   238     IDirect3DDevice9_SetFVF(device, D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);
   239     IDirect3DDevice9_SetVertexShader(device, NULL);
   240     IDirect3DDevice9_SetRenderState(device, D3DRS_ZENABLE, D3DZB_FALSE);
   241     IDirect3DDevice9_SetRenderState(device, D3DRS_CULLMODE, D3DCULL_NONE);
   242     IDirect3DDevice9_SetRenderState(device, D3DRS_LIGHTING, FALSE);
   243 
   244     /* Enable color modulation by diffuse color */
   245     IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLOROP,
   246                                           D3DTOP_MODULATE);
   247     IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLORARG1,
   248                                           D3DTA_TEXTURE);
   249     IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLORARG2,
   250                                           D3DTA_DIFFUSE);
   251 
   252     /* Enable alpha modulation by diffuse alpha */
   253     IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAOP,
   254                                           D3DTOP_MODULATE);
   255     IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAARG1,
   256                                           D3DTA_TEXTURE);
   257     IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAARG2,
   258                                           D3DTA_DIFFUSE);
   259 
   260     /* Enable separate alpha blend function, if possible */
   261     if (data->enableSeparateAlphaBlend) {
   262         IDirect3DDevice9_SetRenderState(device, D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
   263     }
   264 
   265     /* Disable second texture stage, since we're done */
   266     IDirect3DDevice9_SetTextureStageState(device, 1, D3DTSS_COLOROP,
   267                                           D3DTOP_DISABLE);
   268     IDirect3DDevice9_SetTextureStageState(device, 1, D3DTSS_ALPHAOP,
   269                                           D3DTOP_DISABLE);
   270 
   271     /* Set an identity world and view matrix */
   272     SDL_zero(matrix);
   273     matrix.m[0][0] = 1.0f;
   274     matrix.m[1][1] = 1.0f;
   275     matrix.m[2][2] = 1.0f;
   276     matrix.m[3][3] = 1.0f;
   277     IDirect3DDevice9_SetTransform(device, D3DTS_WORLD, &matrix);
   278     IDirect3DDevice9_SetTransform(device, D3DTS_VIEW, &matrix);
   279 
   280     /* Reset our current scale mode */
   281     SDL_memset(data->scaleMode, 0xFF, sizeof(data->scaleMode));
   282 
   283     /* Start the render with beginScene */
   284     data->beginScene = SDL_TRUE;
   285 }
   286 
   287 static int D3D_Reset(SDL_Renderer * renderer);
   288 
   289 static int
   290 D3D_ActivateRenderer(SDL_Renderer * renderer)
   291 {
   292     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   293     HRESULT result;
   294 
   295     if (data->updateSize) {
   296         SDL_Window *window = renderer->window;
   297         int w, h;
   298         Uint32 window_flags = SDL_GetWindowFlags(window);
   299 
   300         SDL_GetWindowSize(window, &w, &h);
   301         data->pparams.BackBufferWidth = w;
   302         data->pparams.BackBufferHeight = h;
   303         if (window_flags & SDL_WINDOW_FULLSCREEN && (window_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
   304             SDL_DisplayMode fullscreen_mode;
   305             SDL_GetWindowDisplayMode(window, &fullscreen_mode);
   306             data->pparams.Windowed = FALSE;
   307             data->pparams.BackBufferFormat = PixelFormatToD3DFMT(fullscreen_mode.format);
   308             data->pparams.FullScreen_RefreshRateInHz = fullscreen_mode.refresh_rate;
   309         } else {
   310             data->pparams.Windowed = TRUE;
   311             data->pparams.BackBufferFormat = D3DFMT_UNKNOWN;
   312             data->pparams.FullScreen_RefreshRateInHz = 0;
   313         }
   314         if (D3D_Reset(renderer) < 0) {
   315             return -1;
   316         }
   317 
   318         data->updateSize = SDL_FALSE;
   319     }
   320     if (data->beginScene) {
   321         result = IDirect3DDevice9_BeginScene(data->device);
   322         if (result == D3DERR_DEVICELOST) {
   323             if (D3D_Reset(renderer) < 0) {
   324                 return -1;
   325             }
   326             result = IDirect3DDevice9_BeginScene(data->device);
   327         }
   328         if (FAILED(result)) {
   329             return D3D_SetError("BeginScene()", result);
   330         }
   331         data->beginScene = SDL_FALSE;
   332     }
   333     return 0;
   334 }
   335 
   336 static void
   337 D3D_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
   338 {
   339     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   340 
   341     if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) {
   342         data->updateSize = SDL_TRUE;
   343     }
   344 }
   345 
   346 static D3DBLEND GetBlendFunc(SDL_BlendFactor factor)
   347 {
   348     switch (factor) {
   349     case SDL_BLENDFACTOR_ZERO:
   350         return D3DBLEND_ZERO;
   351     case SDL_BLENDFACTOR_ONE:
   352         return D3DBLEND_ONE;
   353     case SDL_BLENDFACTOR_SRC_COLOR:
   354         return D3DBLEND_SRCCOLOR;
   355     case SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR:
   356         return D3DBLEND_INVSRCCOLOR;
   357     case SDL_BLENDFACTOR_SRC_ALPHA:
   358         return D3DBLEND_SRCALPHA;
   359     case SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA:
   360         return D3DBLEND_INVSRCALPHA;
   361     case SDL_BLENDFACTOR_DST_COLOR:
   362         return D3DBLEND_DESTCOLOR;
   363     case SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR:
   364         return D3DBLEND_INVDESTCOLOR;
   365     case SDL_BLENDFACTOR_DST_ALPHA:
   366         return D3DBLEND_DESTALPHA;
   367     case SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA:
   368         return D3DBLEND_INVDESTALPHA;
   369     default:
   370         return (D3DBLEND)0;
   371     }
   372 }
   373 
   374 static SDL_bool
   375 D3D_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
   376 {
   377     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   378     SDL_BlendFactor srcColorFactor = SDL_GetBlendModeSrcColorFactor(blendMode);
   379     SDL_BlendFactor srcAlphaFactor = SDL_GetBlendModeSrcAlphaFactor(blendMode);
   380     SDL_BlendOperation colorOperation = SDL_GetBlendModeColorOperation(blendMode);
   381     SDL_BlendFactor dstColorFactor = SDL_GetBlendModeDstColorFactor(blendMode);
   382     SDL_BlendFactor dstAlphaFactor = SDL_GetBlendModeDstAlphaFactor(blendMode);
   383     SDL_BlendOperation alphaOperation = SDL_GetBlendModeAlphaOperation(blendMode);
   384 
   385     if (!GetBlendFunc(srcColorFactor) || !GetBlendFunc(srcAlphaFactor) ||
   386         !GetBlendFunc(dstColorFactor) || !GetBlendFunc(dstAlphaFactor)) {
   387         return SDL_FALSE;
   388     }
   389     if ((srcColorFactor != srcAlphaFactor || dstColorFactor != dstAlphaFactor) && !data->enableSeparateAlphaBlend) {
   390         return SDL_FALSE;
   391     }
   392     if (colorOperation != SDL_BLENDOPERATION_ADD || alphaOperation != SDL_BLENDOPERATION_ADD) {
   393         return SDL_FALSE;
   394     }
   395     return SDL_TRUE;
   396 }
   397 
   398 static int
   399 D3D_CreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWORD usage, Uint32 format, D3DFORMAT d3dfmt, int w, int h)
   400 {
   401     HRESULT result;
   402 
   403     texture->dirty = SDL_FALSE;
   404     texture->w = w;
   405     texture->h = h;
   406     texture->usage = usage;
   407     texture->format = format;
   408     texture->d3dfmt = d3dfmt;
   409 
   410     result = IDirect3DDevice9_CreateTexture(device, w, h, 1, usage,
   411         PixelFormatToD3DFMT(format),
   412         D3DPOOL_DEFAULT, &texture->texture, NULL);
   413     if (FAILED(result)) {
   414         return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
   415     }
   416     return 0;
   417 }
   418 
   419 
   420 static int
   421 D3D_CreateStagingTexture(IDirect3DDevice9 *device, D3D_TextureRep *texture)
   422 {
   423     HRESULT result;
   424 
   425     if (texture->staging == NULL) {
   426         result = IDirect3DDevice9_CreateTexture(device, texture->w, texture->h, 1, 0,
   427             texture->d3dfmt, D3DPOOL_SYSTEMMEM, &texture->staging, NULL);
   428         if (FAILED(result)) {
   429             return D3D_SetError("CreateTexture(D3DPOOL_SYSTEMMEM)", result);
   430         }
   431     }
   432     return 0;
   433 }
   434 
   435 static int
   436 D3D_RecreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture)
   437 {
   438     if (texture->texture) {
   439         IDirect3DTexture9_Release(texture->texture);
   440         texture->texture = NULL;
   441     }
   442     if (texture->staging) {
   443         IDirect3DTexture9_AddDirtyRect(texture->staging, NULL);
   444         texture->dirty = SDL_TRUE;
   445     }
   446     return 0;
   447 }
   448 
   449 static int
   450 D3D_UpdateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, int x, int y, int w, int h, const void *pixels, int pitch)
   451 {
   452     RECT d3drect;
   453     D3DLOCKED_RECT locked;
   454     const Uint8 *src;
   455     Uint8 *dst;
   456     int row, length;
   457     HRESULT result;
   458 
   459     if (D3D_CreateStagingTexture(device, texture) < 0) {
   460         return -1;
   461     }
   462 
   463     d3drect.left = x;
   464     d3drect.right = x + w;
   465     d3drect.top = y;
   466     d3drect.bottom = y + h;
   467     
   468     result = IDirect3DTexture9_LockRect(texture->staging, 0, &locked, &d3drect, 0);
   469     if (FAILED(result)) {
   470         return D3D_SetError("LockRect()", result);
   471     }
   472 
   473     src = (const Uint8 *)pixels;
   474     dst = (Uint8 *)locked.pBits;
   475     length = w * SDL_BYTESPERPIXEL(texture->format);
   476     if (length == pitch && length == locked.Pitch) {
   477         SDL_memcpy(dst, src, length*h);
   478     } else {
   479         if (length > pitch) {
   480             length = pitch;
   481         }
   482         if (length > locked.Pitch) {
   483             length = locked.Pitch;
   484         }
   485         for (row = 0; row < h; ++row) {
   486             SDL_memcpy(dst, src, length);
   487             src += pitch;
   488             dst += locked.Pitch;
   489         }
   490     }
   491     result = IDirect3DTexture9_UnlockRect(texture->staging, 0);
   492     if (FAILED(result)) {
   493         return D3D_SetError("UnlockRect()", result);
   494     }
   495     texture->dirty = SDL_TRUE;
   496 
   497     return 0;
   498 }
   499 
   500 static void
   501 D3D_DestroyTextureRep(D3D_TextureRep *texture)
   502 {
   503     if (texture->texture) {
   504         IDirect3DTexture9_Release(texture->texture);
   505         texture->texture = NULL;
   506     }
   507     if (texture->staging) {
   508         IDirect3DTexture9_Release(texture->staging);
   509         texture->staging = NULL;
   510     }
   511 }
   512 
   513 static int
   514 D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   515 {
   516     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   517     D3D_TextureData *texturedata;
   518     DWORD usage;
   519 
   520     texturedata = (D3D_TextureData *) SDL_calloc(1, sizeof(*texturedata));
   521     if (!texturedata) {
   522         return SDL_OutOfMemory();
   523     }
   524     texturedata->scaleMode = (texture->scaleMode == SDL_ScaleModeNearest) ? D3DTEXF_POINT : D3DTEXF_LINEAR;
   525 
   526     texture->driverdata = texturedata;
   527 
   528     if (texture->access == SDL_TEXTUREACCESS_TARGET) {
   529         usage = D3DUSAGE_RENDERTARGET;
   530     } else {
   531         usage = 0;
   532     }
   533 
   534     if (D3D_CreateTextureRep(data->device, &texturedata->texture, usage, texture->format, PixelFormatToD3DFMT(texture->format), texture->w, texture->h) < 0) {
   535         return -1;
   536     }
   537 
   538     if (texture->format == SDL_PIXELFORMAT_YV12 ||
   539         texture->format == SDL_PIXELFORMAT_IYUV) {
   540         texturedata->yuv = SDL_TRUE;
   541 
   542         if (D3D_CreateTextureRep(data->device, &texturedata->utexture, usage, texture->format, PixelFormatToD3DFMT(texture->format), (texture->w + 1) / 2, (texture->h + 1) / 2) < 0) {
   543             return -1;
   544         }
   545 
   546         if (D3D_CreateTextureRep(data->device, &texturedata->vtexture, usage, texture->format, PixelFormatToD3DFMT(texture->format), (texture->w + 1) / 2, (texture->h + 1) / 2) < 0) {
   547             return -1;
   548         }
   549     }
   550     return 0;
   551 }
   552 
   553 static int
   554 D3D_RecreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   555 {
   556     D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
   557     D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
   558 
   559     if (!texturedata) {
   560         return 0;
   561     }
   562 
   563     if (D3D_RecreateTextureRep(data->device, &texturedata->texture) < 0) {
   564         return -1;
   565     }
   566 
   567     if (texturedata->yuv) {
   568         if (D3D_RecreateTextureRep(data->device, &texturedata->utexture) < 0) {
   569             return -1;
   570         }
   571 
   572         if (D3D_RecreateTextureRep(data->device, &texturedata->vtexture) < 0) {
   573             return -1;
   574         }
   575     }
   576     return 0;
   577 }
   578 
   579 static int
   580 D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   581                   const SDL_Rect * rect, const void *pixels, int pitch)
   582 {
   583     D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
   584     D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata;
   585 
   586     if (!texturedata) {
   587         SDL_SetError("Texture is not currently available");
   588         return -1;
   589     }
   590 
   591     if (D3D_UpdateTextureRep(data->device, &texturedata->texture, rect->x, rect->y, rect->w, rect->h, pixels, pitch) < 0) {
   592         return -1;
   593     }
   594 
   595     if (texturedata->yuv) {
   596         /* Skip to the correct offset into the next texture */
   597         pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
   598 
   599         if (D3D_UpdateTextureRep(data->device, texture->format == SDL_PIXELFORMAT_YV12 ? &texturedata->vtexture : &texturedata->utexture, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, pixels, (pitch + 1) / 2) < 0) {
   600             return -1;
   601         }
   602 
   603         /* Skip to the correct offset into the next texture */
   604         pixels = (const void*)((const Uint8*)pixels + ((rect->h + 1) / 2) * ((pitch + 1) / 2));
   605         if (D3D_UpdateTextureRep(data->device, texture->format == SDL_PIXELFORMAT_YV12 ? &texturedata->utexture : &texturedata->vtexture, rect->x / 2, (rect->y + 1) / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, pixels, (pitch + 1) / 2) < 0) {
   606             return -1;
   607         }
   608     }
   609     return 0;
   610 }
   611 
   612 static int
   613 D3D_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
   614                      const SDL_Rect * rect,
   615                      const Uint8 *Yplane, int Ypitch,
   616                      const Uint8 *Uplane, int Upitch,
   617                      const Uint8 *Vplane, int Vpitch)
   618 {
   619     D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
   620     D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata;
   621 
   622     if (!texturedata) {
   623         SDL_SetError("Texture is not currently available");
   624         return -1;
   625     }
   626 
   627     if (D3D_UpdateTextureRep(data->device, &texturedata->texture, rect->x, rect->y, rect->w, rect->h, Yplane, Ypitch) < 0) {
   628         return -1;
   629     }
   630     if (D3D_UpdateTextureRep(data->device, &texturedata->utexture, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, Uplane, Upitch) < 0) {
   631         return -1;
   632     }
   633     if (D3D_UpdateTextureRep(data->device, &texturedata->vtexture, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, Vplane, Vpitch) < 0) {
   634         return -1;
   635     }
   636     return 0;
   637 }
   638 
   639 static int
   640 D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   641                 const SDL_Rect * rect, void **pixels, int *pitch)
   642 {
   643     D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
   644     D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
   645     IDirect3DDevice9 *device = data->device;
   646 
   647     if (!texturedata) {
   648         SDL_SetError("Texture is not currently available");
   649         return -1;
   650     }
   651 
   652     texturedata->locked_rect = *rect;
   653 
   654     if (texturedata->yuv) {
   655         /* It's more efficient to upload directly... */
   656         if (!texturedata->pixels) {
   657             texturedata->pitch = texture->w;
   658             texturedata->pixels = (Uint8 *)SDL_malloc((texture->h * texturedata->pitch * 3) / 2);
   659             if (!texturedata->pixels) {
   660                 return SDL_OutOfMemory();
   661             }
   662         }
   663         *pixels =
   664             (void *) ((Uint8 *) texturedata->pixels + rect->y * texturedata->pitch +
   665                       rect->x * SDL_BYTESPERPIXEL(texture->format));
   666         *pitch = texturedata->pitch;
   667     } else {
   668         RECT d3drect;
   669         D3DLOCKED_RECT locked;
   670         HRESULT result;
   671 
   672         if (D3D_CreateStagingTexture(device, &texturedata->texture) < 0) {
   673             return -1;
   674         }
   675 
   676         d3drect.left = rect->x;
   677         d3drect.right = rect->x + rect->w;
   678         d3drect.top = rect->y;
   679         d3drect.bottom = rect->y + rect->h;
   680 
   681         result = IDirect3DTexture9_LockRect(texturedata->texture.staging, 0, &locked, &d3drect, 0);
   682         if (FAILED(result)) {
   683             return D3D_SetError("LockRect()", result);
   684         }
   685         *pixels = locked.pBits;
   686         *pitch = locked.Pitch;
   687     }
   688     return 0;
   689 }
   690 
   691 static void
   692 D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   693 {
   694     /*D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;*/
   695     D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
   696 
   697     if (!texturedata) {
   698         return;
   699     }
   700 
   701     if (texturedata->yuv) {
   702         const SDL_Rect *rect = &texturedata->locked_rect;
   703         void *pixels =
   704             (void *) ((Uint8 *) texturedata->pixels + rect->y * texturedata->pitch +
   705                       rect->x * SDL_BYTESPERPIXEL(texture->format));
   706         D3D_UpdateTexture(renderer, texture, rect, pixels, texturedata->pitch);
   707     } else {
   708         IDirect3DTexture9_UnlockRect(texturedata->texture.staging, 0);
   709         texturedata->texture.dirty = SDL_TRUE;
   710    }
   711 }
   712 
   713 static int
   714 D3D_SetRenderTargetInternal(SDL_Renderer * renderer, SDL_Texture * texture)
   715 {
   716     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   717     D3D_TextureData *texturedata;
   718     D3D_TextureRep *texturerep;
   719     HRESULT result;
   720     IDirect3DDevice9 *device = data->device;
   721 
   722     /* Release the previous render target if it wasn't the default one */
   723     if (data->currentRenderTarget != NULL) {
   724         IDirect3DSurface9_Release(data->currentRenderTarget);
   725         data->currentRenderTarget = NULL;
   726     }
   727 
   728     if (texture == NULL) {
   729         IDirect3DDevice9_SetRenderTarget(data->device, 0, data->defaultRenderTarget);
   730         return 0;
   731     }
   732 
   733     texturedata = (D3D_TextureData *)texture->driverdata;
   734     if (!texturedata) {
   735         SDL_SetError("Texture is not currently available");
   736         return -1;
   737     }
   738 
   739     /* Make sure the render target is updated if it was locked and written to */
   740     texturerep = &texturedata->texture;
   741     if (texturerep->dirty && texturerep->staging) {
   742         if (!texturerep->texture) {
   743             result = IDirect3DDevice9_CreateTexture(device, texturerep->w, texturerep->h, 1, texturerep->usage,
   744                 PixelFormatToD3DFMT(texturerep->format), D3DPOOL_DEFAULT, &texturerep->texture, NULL);
   745             if (FAILED(result)) {
   746                 return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
   747             }
   748         }
   749 
   750         result = IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)texturerep->staging, (IDirect3DBaseTexture9 *)texturerep->texture);
   751         if (FAILED(result)) {
   752             return D3D_SetError("UpdateTexture()", result);
   753         }
   754         texturerep->dirty = SDL_FALSE;
   755     }
   756 
   757     result = IDirect3DTexture9_GetSurfaceLevel(texturedata->texture.texture, 0, &data->currentRenderTarget);
   758     if(FAILED(result)) {
   759         return D3D_SetError("GetSurfaceLevel()", result);
   760     }
   761     result = IDirect3DDevice9_SetRenderTarget(data->device, 0, data->currentRenderTarget);
   762     if(FAILED(result)) {
   763         return D3D_SetError("SetRenderTarget()", result);
   764     }
   765 
   766     return 0;
   767 }
   768 
   769 static int
   770 D3D_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
   771 {
   772     if (D3D_ActivateRenderer(renderer) < 0) {
   773         return -1;
   774     }
   775 
   776     return D3D_SetRenderTargetInternal(renderer, texture);
   777 }
   778 
   779 
   780 static int
   781 D3D_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd)
   782 {
   783     return 0;  /* nothing to do in this backend. */
   784 }
   785 
   786 static int
   787 D3D_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
   788 {
   789     const DWORD color = D3DCOLOR_ARGB(cmd->data.draw.a, cmd->data.draw.r, cmd->data.draw.g, cmd->data.draw.b);
   790     const size_t vertslen = count * sizeof (Vertex);
   791     Vertex *verts = (Vertex *) SDL_AllocateRenderVertices(renderer, vertslen, 0, &cmd->data.draw.first);
   792     size_t i;
   793 
   794     if (!verts) {
   795         return -1;
   796     }
   797 
   798     SDL_memset(verts, '\0', vertslen);
   799     cmd->data.draw.count = count;
   800 
   801     for (i = 0; i < count; i++, verts++, points++) {
   802         verts->x = points->x;
   803         verts->y = points->y;
   804         verts->color = color;
   805     }
   806 
   807     return 0;
   808 }
   809 
   810 static int
   811 D3D_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects, int count)
   812 {
   813     const DWORD color = D3DCOLOR_ARGB(cmd->data.draw.a, cmd->data.draw.r, cmd->data.draw.g, cmd->data.draw.b);
   814     const size_t vertslen = count * sizeof (Vertex) * 4;
   815     Vertex *verts = (Vertex *) SDL_AllocateRenderVertices(renderer, vertslen, 0, &cmd->data.draw.first);
   816     size_t i;
   817 
   818     if (!verts) {
   819         return -1;
   820     }
   821 
   822     SDL_memset(verts, '\0', vertslen);
   823     cmd->data.draw.count = count;
   824 
   825     for (i = 0; i < count; i++) {
   826         const SDL_FRect *rect = &rects[i];
   827         const float minx = rect->x;
   828         const float maxx = rect->x + rect->w;
   829         const float miny = rect->y;
   830         const float maxy = rect->y + rect->h;
   831 
   832         verts->x = minx;
   833         verts->y = miny;
   834         verts->color = color;
   835         verts++;
   836 
   837         verts->x = maxx;
   838         verts->y = miny;
   839         verts->color = color;
   840         verts++;
   841 
   842         verts->x = maxx;
   843         verts->y = maxy;
   844         verts->color = color;
   845         verts++;
   846 
   847         verts->x = minx;
   848         verts->y = maxy;
   849         verts->color = color;
   850         verts++;
   851     }
   852 
   853     return 0;
   854 }
   855 
   856 static int
   857 D3D_QueueCopy(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
   858                           const SDL_Rect * srcrect, const SDL_FRect * dstrect)
   859 {
   860     const DWORD color = D3DCOLOR_ARGB(cmd->data.draw.a, cmd->data.draw.r, cmd->data.draw.g, cmd->data.draw.b);
   861     float minx, miny, maxx, maxy;
   862     float minu, maxu, minv, maxv;
   863     const size_t vertslen = sizeof (Vertex) * 4;
   864     Vertex *verts = (Vertex *) SDL_AllocateRenderVertices(renderer, vertslen, 0, &cmd->data.draw.first);
   865 
   866     if (!verts) {
   867         return -1;
   868     }
   869 
   870     cmd->data.draw.count = 1;
   871 
   872     minx = dstrect->x - 0.5f;
   873     miny = dstrect->y - 0.5f;
   874     maxx = dstrect->x + dstrect->w - 0.5f;
   875     maxy = dstrect->y + dstrect->h - 0.5f;
   876 
   877     minu = (float) srcrect->x / texture->w;
   878     maxu = (float) (srcrect->x + srcrect->w) / texture->w;
   879     minv = (float) srcrect->y / texture->h;
   880     maxv = (float) (srcrect->y + srcrect->h) / texture->h;
   881 
   882     verts->x = minx;
   883     verts->y = miny;
   884     verts->z = 0.0f;
   885     verts->color = color;
   886     verts->u = minu;
   887     verts->v = minv;
   888     verts++;
   889 
   890     verts->x = maxx;
   891     verts->y = miny;
   892     verts->z = 0.0f;
   893     verts->color = color;
   894     verts->u = maxu;
   895     verts->v = minv;
   896     verts++;
   897 
   898     verts->x = maxx;
   899     verts->y = maxy;
   900     verts->z = 0.0f;
   901     verts->color = color;
   902     verts->u = maxu;
   903     verts->v = maxv;
   904     verts++;
   905 
   906     verts->x = minx;
   907     verts->y = maxy;
   908     verts->z = 0.0f;
   909     verts->color = color;
   910     verts->u = minu;
   911     verts->v = maxv;
   912     verts++;
   913 
   914     return 0;
   915 }
   916 
   917 static int
   918 D3D_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
   919                         const SDL_Rect * srcquad, const SDL_FRect * dstrect,
   920                         const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
   921 {
   922     const DWORD color = D3DCOLOR_ARGB(cmd->data.draw.a, cmd->data.draw.r, cmd->data.draw.g, cmd->data.draw.b);
   923     float minx, miny, maxx, maxy;
   924     float minu, maxu, minv, maxv;
   925     const size_t vertslen = sizeof (Vertex) * 5;
   926     Vertex *verts = (Vertex *) SDL_AllocateRenderVertices(renderer, vertslen, 0, &cmd->data.draw.first);
   927 
   928     if (!verts) {
   929         return -1;
   930     }
   931 
   932     cmd->data.draw.count = 1;
   933 
   934     minx = -center->x;
   935     maxx = dstrect->w - center->x;
   936     miny = -center->y;
   937     maxy = dstrect->h - center->y;
   938 
   939     if (flip & SDL_FLIP_HORIZONTAL) {
   940         minu = (float) (srcquad->x + srcquad->w) / texture->w;
   941         maxu = (float) srcquad->x / texture->w;
   942     } else {
   943         minu = (float) srcquad->x / texture->w;
   944         maxu = (float) (srcquad->x + srcquad->w) / texture->w;
   945     }
   946 
   947     if (flip & SDL_FLIP_VERTICAL) {
   948         minv = (float) (srcquad->y + srcquad->h) / texture->h;
   949         maxv = (float) srcquad->y / texture->h;
   950     } else {
   951         minv = (float) srcquad->y / texture->h;
   952         maxv = (float) (srcquad->y + srcquad->h) / texture->h;
   953     }
   954 
   955     verts->x = minx;
   956     verts->y = miny;
   957     verts->z = 0.0f;
   958     verts->color = color;
   959     verts->u = minu;
   960     verts->v = minv;
   961     verts++;
   962 
   963     verts->x = maxx;
   964     verts->y = miny;
   965     verts->z = 0.0f;
   966     verts->color = color;
   967     verts->u = maxu;
   968     verts->v = minv;
   969     verts++;
   970 
   971     verts->x = maxx;
   972     verts->y = maxy;
   973     verts->z = 0.0f;
   974     verts->color = color;
   975     verts->u = maxu;
   976     verts->v = maxv;
   977     verts++;
   978 
   979     verts->x = minx;
   980     verts->y = maxy;
   981     verts->z = 0.0f;
   982     verts->color = color;
   983     verts->u = minu;
   984     verts->v = maxv;
   985     verts++;
   986 
   987     verts->x = dstrect->x + center->x - 0.5f;  /* X translation */
   988     verts->y = dstrect->y + center->y - 0.5f;  /* Y translation */
   989     verts->z = (float)(M_PI * (float) angle / 180.0f);  /* rotation */
   990     verts->color = 0;
   991     verts->u = 0.0f;
   992     verts->v = 0.0f;
   993     verts++;
   994 
   995     return 0;
   996 }
   997 
   998 static int
   999 BindTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWORD sampler)
  1000 {
  1001     HRESULT result;
  1002 
  1003     if (texture->dirty && texture->staging) {
  1004         if (!texture->texture) {
  1005             result = IDirect3DDevice9_CreateTexture(device, texture->w, texture->h, 1, texture->usage,
  1006                 PixelFormatToD3DFMT(texture->format), D3DPOOL_DEFAULT, &texture->texture, NULL);
  1007             if (FAILED(result)) {
  1008                 return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
  1009             }
  1010         }
  1011 
  1012         result = IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)texture->staging, (IDirect3DBaseTexture9 *)texture->texture);
  1013         if (FAILED(result)) {
  1014             return D3D_SetError("UpdateTexture()", result);
  1015         }
  1016         texture->dirty = SDL_FALSE;
  1017     }
  1018     result = IDirect3DDevice9_SetTexture(device, sampler, (IDirect3DBaseTexture9 *)texture->texture);
  1019     if (FAILED(result)) {
  1020         return D3D_SetError("SetTexture()", result);
  1021     }
  1022     return 0;
  1023 }
  1024 
  1025 static void
  1026 UpdateTextureScaleMode(D3D_RenderData *data, D3D_TextureData *texturedata, unsigned index)
  1027 {
  1028     if (texturedata->scaleMode != data->scaleMode[index]) {
  1029         IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MINFILTER,
  1030                                          texturedata->scaleMode);
  1031         IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MAGFILTER,
  1032                                          texturedata->scaleMode);
  1033         IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_ADDRESSU,
  1034                                          D3DTADDRESS_CLAMP);
  1035         IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_ADDRESSV,
  1036                                          D3DTADDRESS_CLAMP);
  1037         data->scaleMode[index] = texturedata->scaleMode;
  1038     }
  1039 }
  1040 
  1041 static int
  1042 SetupTextureState(D3D_RenderData *data, SDL_Texture * texture, LPDIRECT3DPIXELSHADER9 *shader)
  1043 {
  1044     D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
  1045 
  1046     SDL_assert(*shader == NULL);
  1047 
  1048     if (!texturedata) {
  1049         SDL_SetError("Texture is not currently available");
  1050         return -1;
  1051     }
  1052 
  1053     UpdateTextureScaleMode(data, texturedata, 0);
  1054 
  1055     if (BindTextureRep(data->device, &texturedata->texture, 0) < 0) {
  1056         return -1;
  1057     }
  1058 
  1059     if (texturedata->yuv) {
  1060         switch (SDL_GetYUVConversionModeForResolution(texture->w, texture->h)) {
  1061         case SDL_YUV_CONVERSION_JPEG:
  1062             *shader = data->shaders[SHADER_YUV_JPEG];
  1063             break;
  1064         case SDL_YUV_CONVERSION_BT601:
  1065             *shader = data->shaders[SHADER_YUV_BT601];
  1066             break;
  1067         case SDL_YUV_CONVERSION_BT709:
  1068             *shader = data->shaders[SHADER_YUV_BT709];
  1069             break;
  1070         default:
  1071             return SDL_SetError("Unsupported YUV conversion mode");
  1072         }
  1073 
  1074         UpdateTextureScaleMode(data, texturedata, 1);
  1075         UpdateTextureScaleMode(data, texturedata, 2);
  1076 
  1077         if (BindTextureRep(data->device, &texturedata->utexture, 1) < 0) {
  1078             return -1;
  1079         }
  1080         if (BindTextureRep(data->device, &texturedata->vtexture, 2) < 0) {
  1081             return -1;
  1082         }
  1083     }
  1084     return 0;
  1085 }
  1086 
  1087 static int
  1088 SetDrawState(D3D_RenderData *data, const SDL_RenderCommand *cmd)
  1089 {
  1090     const SDL_bool was_copy_ex = data->drawstate.is_copy_ex;
  1091     const SDL_bool is_copy_ex = (cmd->command == SDL_RENDERCMD_COPY_EX);
  1092     SDL_Texture *texture = cmd->data.draw.texture;
  1093     const SDL_BlendMode blend = cmd->data.draw.blend;
  1094 
  1095     if (texture != data->drawstate.texture) {
  1096         D3D_TextureData *oldtexturedata = data->drawstate.texture ? (D3D_TextureData *) data->drawstate.texture->driverdata : NULL;
  1097         D3D_TextureData *newtexturedata = texture ? (D3D_TextureData *) texture->driverdata : NULL;
  1098         LPDIRECT3DPIXELSHADER9 shader = NULL;
  1099 
  1100         /* disable any enabled textures we aren't going to use, let SetupTextureState() do the rest. */
  1101         if (texture == NULL) {
  1102             IDirect3DDevice9_SetTexture(data->device, 0, NULL);
  1103         }
  1104         if ((!newtexturedata || !newtexturedata->yuv) && (oldtexturedata && oldtexturedata->yuv)) {
  1105             IDirect3DDevice9_SetTexture(data->device, 1, NULL);
  1106             IDirect3DDevice9_SetTexture(data->device, 2, NULL);
  1107         }
  1108         if (texture && SetupTextureState(data, texture, &shader) < 0) {
  1109             return -1;
  1110         }
  1111 
  1112         if (shader != data->drawstate.shader) {
  1113             const HRESULT result = IDirect3DDevice9_SetPixelShader(data->device, shader);
  1114             if (FAILED(result)) {
  1115                 return D3D_SetError("IDirect3DDevice9_SetPixelShader()", result);
  1116             }
  1117             data->drawstate.shader = shader;
  1118         }
  1119 
  1120         data->drawstate.texture = texture;
  1121     }
  1122 
  1123     if (blend != data->drawstate.blend) {
  1124         if (blend == SDL_BLENDMODE_NONE) {
  1125             IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, FALSE);
  1126         } else {
  1127             IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, TRUE);
  1128             IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
  1129                                             GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blend)));
  1130             IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
  1131                                             GetBlendFunc(SDL_GetBlendModeDstColorFactor(blend)));
  1132             if (data->enableSeparateAlphaBlend) {
  1133                 IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA,
  1134                                                 GetBlendFunc(SDL_GetBlendModeSrcAlphaFactor(blend)));
  1135                 IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA,
  1136                                                 GetBlendFunc(SDL_GetBlendModeDstAlphaFactor(blend)));
  1137             }
  1138         }
  1139 
  1140         data->drawstate.blend = blend;
  1141     }
  1142 
  1143     if (is_copy_ex != was_copy_ex) {
  1144         if (!is_copy_ex) {  /* SDL_RENDERCMD_COPY_EX will set this, we only want to reset it here if necessary. */
  1145             const Float4X4 d3dmatrix = MatrixIdentity();
  1146             IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*) &d3dmatrix);
  1147         }
  1148         data->drawstate.is_copy_ex = is_copy_ex;
  1149     }
  1150 
  1151     if (data->drawstate.viewport_dirty) {
  1152         const SDL_Rect *viewport = &data->drawstate.viewport;
  1153         const D3DVIEWPORT9 d3dviewport = { viewport->x, viewport->y, viewport->w, viewport->h, 0.0f, 1.0f };
  1154         IDirect3DDevice9_SetViewport(data->device, &d3dviewport);
  1155 
  1156         /* Set an orthographic projection matrix */
  1157         if (viewport->w && viewport->h) {
  1158             D3DMATRIX d3dmatrix;
  1159             SDL_zero(d3dmatrix);
  1160             d3dmatrix.m[0][0] = 2.0f / viewport->w;
  1161             d3dmatrix.m[1][1] = -2.0f / viewport->h;
  1162             d3dmatrix.m[2][2] = 1.0f;
  1163             d3dmatrix.m[3][0] = -1.0f;
  1164             d3dmatrix.m[3][1] = 1.0f;
  1165             d3dmatrix.m[3][3] = 1.0f;
  1166             IDirect3DDevice9_SetTransform(data->device, D3DTS_PROJECTION, &d3dmatrix);
  1167         }
  1168 
  1169         data->drawstate.viewport_dirty = SDL_FALSE;
  1170     }
  1171 
  1172     if (data->drawstate.cliprect_enabled_dirty) {
  1173         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, data->drawstate.cliprect_enabled ? TRUE : FALSE);
  1174         data->drawstate.cliprect_enabled_dirty = SDL_FALSE;
  1175     }
  1176 
  1177     if (data->drawstate.cliprect_dirty) {
  1178         const SDL_Rect *viewport = &data->drawstate.viewport;
  1179         const SDL_Rect *rect = &cmd->data.cliprect.rect;
  1180         const RECT d3drect = { viewport->x + rect->x, viewport->y + rect->y, viewport->x + rect->x + rect->w, viewport->y + rect->y + rect->h };
  1181         IDirect3DDevice9_SetScissorRect(data->device, &d3drect);
  1182         data->drawstate.cliprect_dirty = SDL_FALSE;
  1183     }
  1184 
  1185     return 0;
  1186 }
  1187 
  1188 static int
  1189 D3D_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
  1190 {
  1191     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1192     const int vboidx = data->currentVertexBuffer;
  1193     IDirect3DVertexBuffer9 *vbo = NULL;
  1194     const SDL_bool istarget = renderer->target != NULL;
  1195     size_t i;
  1196 
  1197     if (D3D_ActivateRenderer(renderer) < 0) {
  1198         return -1;
  1199     }
  1200 
  1201     /* upload the new VBO data for this set of commands. */
  1202     if (data->supportsStreamOffset) {
  1203         vbo = data->vertexBuffers[vboidx];
  1204         if (!vbo || (data->vertexBufferSize[vboidx] < vertsize)) {
  1205             const DWORD usage = D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY;
  1206             const DWORD fvf = D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1;
  1207             if (vbo) {
  1208                 IDirect3DVertexBuffer9_Release(vbo);
  1209             }
  1210 
  1211             if (FAILED(IDirect3DDevice9_CreateVertexBuffer(data->device, vertsize, usage, fvf, D3DPOOL_DEFAULT, &vbo, NULL))) {
  1212                 vbo = NULL;
  1213             }
  1214             data->vertexBuffers[vboidx] = vbo;
  1215             data->vertexBufferSize[vboidx] = vbo ? vertsize : 0;
  1216         }
  1217 
  1218         if (vbo) {
  1219             void *ptr;
  1220             if (FAILED(IDirect3DVertexBuffer9_Lock(vbo, 0, vertsize, &ptr, D3DLOCK_DISCARD))) {
  1221                 vbo = NULL;  /* oh well, we'll do immediate mode drawing.  :(  */
  1222             } else {
  1223                 SDL_memcpy(ptr, vertices, vertsize);
  1224                 if (FAILED(IDirect3DVertexBuffer9_Unlock(vbo))) {
  1225                     vbo = NULL;  /* oh well, we'll do immediate mode drawing.  :(  */
  1226                 }
  1227             }
  1228         }
  1229 
  1230         /* cycle through a few VBOs so D3D has some time with the data before we replace it. */
  1231         if (vbo) {
  1232             data->currentVertexBuffer++;
  1233             if (data->currentVertexBuffer >= SDL_arraysize(data->vertexBuffers)) {
  1234                 data->currentVertexBuffer = 0;
  1235             }
  1236         }
  1237     }
  1238 
  1239     if (!vbo && !data->reportedVboProblem) {
  1240         SDL_LogError(SDL_LOG_CATEGORY_RENDER, "SDL failed to get a vertex buffer for this Direct3D 9 rendering batch!");
  1241         SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Dropping back to a slower method.");
  1242         SDL_LogError(SDL_LOG_CATEGORY_RENDER, "This might be a brief hiccup, but if performance is bad, this is probably why.");
  1243         SDL_LogError(SDL_LOG_CATEGORY_RENDER, "This error will not be logged again for this renderer.");
  1244         data->reportedVboProblem = SDL_TRUE;
  1245     }
  1246 
  1247     IDirect3DDevice9_SetStreamSource(data->device, 0, vbo, 0, sizeof (Vertex));
  1248 
  1249     while (cmd) {
  1250         switch (cmd->command) {
  1251             case SDL_RENDERCMD_SETDRAWCOLOR: {
  1252                 /* currently this is sent with each vertex, but if we move to
  1253                    shaders, we can put this in a uniform here and reduce vertex
  1254                    buffer bandwidth */
  1255                 break;
  1256             }
  1257 
  1258             case SDL_RENDERCMD_SETVIEWPORT: {
  1259                 SDL_Rect *viewport = &data->drawstate.viewport;
  1260                 if (SDL_memcmp(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect)) != 0) {
  1261                     SDL_memcpy(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect));
  1262                     data->drawstate.viewport_dirty = SDL_TRUE;
  1263                 }
  1264                 break;
  1265             }
  1266 
  1267             case SDL_RENDERCMD_SETCLIPRECT: {
  1268                 const SDL_Rect *rect = &cmd->data.cliprect.rect;
  1269                 if (data->drawstate.cliprect_enabled != cmd->data.cliprect.enabled) {
  1270                     data->drawstate.cliprect_enabled = cmd->data.cliprect.enabled;
  1271                     data->drawstate.cliprect_enabled_dirty = SDL_TRUE;
  1272                 }
  1273 
  1274                 if (SDL_memcmp(&data->drawstate.cliprect, rect, sizeof (SDL_Rect)) != 0) {
  1275                     SDL_memcpy(&data->drawstate.cliprect, rect, sizeof (SDL_Rect));
  1276                     data->drawstate.cliprect_dirty = SDL_TRUE;
  1277                 }
  1278                 break;
  1279             }
  1280 
  1281             case SDL_RENDERCMD_CLEAR: {
  1282                 const DWORD color = D3DCOLOR_ARGB(cmd->data.color.a, cmd->data.color.r, cmd->data.color.g, cmd->data.color.b);
  1283                 const SDL_Rect *viewport = &data->drawstate.viewport;
  1284                 const int backw = istarget ? renderer->target->w : data->pparams.BackBufferWidth;
  1285                 const int backh = istarget ? renderer->target->h : data->pparams.BackBufferHeight;
  1286 
  1287                 if (data->drawstate.cliprect_enabled) {
  1288                     IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, FALSE);
  1289                     data->drawstate.cliprect_enabled_dirty = SDL_TRUE;
  1290                 }
  1291 
  1292                 /* Don't reset the viewport if we don't have to! */
  1293                 if (!viewport->x && !viewport->y && (viewport->w == backw) && (viewport->h == backh)) {
  1294                     IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
  1295                 } else {
  1296                     /* Clear is defined to clear the entire render target */
  1297                     const D3DVIEWPORT9 wholeviewport = { 0, 0, backw, backh, 0.0f, 1.0f };
  1298                     IDirect3DDevice9_SetViewport(data->device, &wholeviewport);
  1299                     data->drawstate.viewport_dirty = SDL_TRUE;
  1300                     IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
  1301                 }
  1302 
  1303                 break;
  1304             }
  1305 
  1306             case SDL_RENDERCMD_DRAW_POINTS: {
  1307                 const size_t count = cmd->data.draw.count;
  1308                 const size_t first = cmd->data.draw.first;
  1309                 SetDrawState(data, cmd);
  1310                 if (vbo) {
  1311                     IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_POINTLIST, first / sizeof (Vertex), count);
  1312                 } else {
  1313                     const Vertex *verts = (Vertex *) (((Uint8 *) vertices) + first);
  1314                     IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, count, vertices, sizeof (Vertex));
  1315                 }
  1316                 break;
  1317             }
  1318 
  1319             case SDL_RENDERCMD_DRAW_LINES: {
  1320                 const size_t count = cmd->data.draw.count;
  1321                 const size_t first = cmd->data.draw.first;
  1322                 const Vertex *verts = (Vertex *) (((Uint8 *) vertices) + first);
  1323 
  1324                 /* DirectX 9 has the same line rasterization semantics as GDI,
  1325                    so we need to close the endpoint of the line with a second draw call. */
  1326                 const SDL_bool close_endpoint = ((count == 2) || (verts[0].x != verts[count-1].x) || (verts[0].y != verts[count-1].y));
  1327 
  1328                 SetDrawState(data, cmd);
  1329 
  1330                 if (vbo) {
  1331                     IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_LINESTRIP, first / sizeof (Vertex), count - 1);
  1332                     if (close_endpoint) {
  1333                         IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_POINTLIST, (first / sizeof (Vertex)) + (count - 1), 1);
  1334                     }
  1335                 } else {
  1336                     IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_LINESTRIP, count - 1, verts, sizeof (Vertex));
  1337                     if (close_endpoint) {
  1338                         IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, 1, &verts[count-1], sizeof (Vertex));
  1339                     }
  1340                 }
  1341                 break;
  1342             }
  1343 
  1344             case SDL_RENDERCMD_FILL_RECTS: {
  1345                 const size_t count = cmd->data.draw.count;
  1346                 const size_t first = cmd->data.draw.first;
  1347                 SetDrawState(data, cmd);
  1348                 if (vbo) {
  1349                     size_t offset = 0;
  1350                     for (i = 0; i < count; ++i, offset += 4) {
  1351                         IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_TRIANGLEFAN, (first / sizeof (Vertex)) + offset, 2);
  1352                     }
  1353                 } else {
  1354                     const Vertex *verts = (Vertex *) (((Uint8 *) vertices) + first);
  1355                     for (i = 0; i < count; ++i, verts += 4) {
  1356                         IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2, verts, sizeof (Vertex));
  1357                     }
  1358                 }
  1359                 break;
  1360             }
  1361 
  1362             case SDL_RENDERCMD_COPY: {
  1363                 const size_t count = cmd->data.draw.count;
  1364                 const size_t first = cmd->data.draw.first;
  1365                 SetDrawState(data, cmd);
  1366                 if (vbo) {
  1367                     size_t offset = 0;
  1368                     for (i = 0; i < count; ++i, offset += 4) {
  1369                         IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_TRIANGLEFAN, (first / sizeof (Vertex)) + offset, 2);
  1370                     }
  1371                 } else {
  1372                     const Vertex *verts = (Vertex *) (((Uint8 *) vertices) + first);
  1373                     for (i = 0; i < count; ++i, verts += 4) {
  1374                         IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2, verts, sizeof (Vertex));
  1375                     }
  1376                 }
  1377                 break;
  1378             }
  1379 
  1380             case SDL_RENDERCMD_COPY_EX: {
  1381                 const size_t first = cmd->data.draw.first;
  1382                 const Vertex *verts = (Vertex *) (((Uint8 *) vertices) + first);
  1383                 const Vertex *transvert = verts + 4;
  1384                 const float translatex = transvert->x;
  1385                 const float translatey = transvert->y;
  1386                 const float rotation = transvert->z;
  1387                 const Float4X4 d3dmatrix = MatrixMultiply(MatrixRotationZ(rotation), MatrixTranslation(translatex, translatey, 0));
  1388                 SetDrawState(data, cmd);
  1389 
  1390                 IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)&d3dmatrix);
  1391 
  1392                 if (vbo) {
  1393                     IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_TRIANGLEFAN, first / sizeof (Vertex), 2);
  1394                 } else {
  1395                     IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2, verts, sizeof (Vertex));
  1396                 }
  1397                 break;
  1398             }
  1399 
  1400             case SDL_RENDERCMD_NO_OP:
  1401                 break;
  1402         }
  1403 
  1404         cmd = cmd->next;
  1405     }
  1406 
  1407     return 0;
  1408 }
  1409 
  1410 
  1411 static int
  1412 D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
  1413                      Uint32 format, void * pixels, int pitch)
  1414 {
  1415     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1416     D3DSURFACE_DESC desc;
  1417     LPDIRECT3DSURFACE9 backBuffer;
  1418     LPDIRECT3DSURFACE9 surface;
  1419     RECT d3drect;
  1420     D3DLOCKED_RECT locked;
  1421     HRESULT result;
  1422 
  1423     if (data->currentRenderTarget) {
  1424         backBuffer = data->currentRenderTarget;
  1425     } else {
  1426         backBuffer = data->defaultRenderTarget;
  1427     }
  1428 
  1429     result = IDirect3DSurface9_GetDesc(backBuffer, &desc);
  1430     if (FAILED(result)) {
  1431         IDirect3DSurface9_Release(backBuffer);
  1432         return D3D_SetError("GetDesc()", result);
  1433     }
  1434 
  1435     result = IDirect3DDevice9_CreateOffscreenPlainSurface(data->device, desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surface, NULL);
  1436     if (FAILED(result)) {
  1437         IDirect3DSurface9_Release(backBuffer);
  1438         return D3D_SetError("CreateOffscreenPlainSurface()", result);
  1439     }
  1440 
  1441     result = IDirect3DDevice9_GetRenderTargetData(data->device, backBuffer, surface);
  1442     if (FAILED(result)) {
  1443         IDirect3DSurface9_Release(surface);
  1444         IDirect3DSurface9_Release(backBuffer);
  1445         return D3D_SetError("GetRenderTargetData()", result);
  1446     }
  1447 
  1448     d3drect.left = rect->x;
  1449     d3drect.right = rect->x + rect->w;
  1450     d3drect.top = rect->y;
  1451     d3drect.bottom = rect->y + rect->h;
  1452 
  1453     result = IDirect3DSurface9_LockRect(surface, &locked, &d3drect, D3DLOCK_READONLY);
  1454     if (FAILED(result)) {
  1455         IDirect3DSurface9_Release(surface);
  1456         IDirect3DSurface9_Release(backBuffer);
  1457         return D3D_SetError("LockRect()", result);
  1458     }
  1459 
  1460     SDL_ConvertPixels(rect->w, rect->h,
  1461                       D3DFMTToPixelFormat(desc.Format), locked.pBits, locked.Pitch,
  1462                       format, pixels, pitch);
  1463 
  1464     IDirect3DSurface9_UnlockRect(surface);
  1465 
  1466     IDirect3DSurface9_Release(surface);
  1467 
  1468     return 0;
  1469 }
  1470 
  1471 static void
  1472 D3D_RenderPresent(SDL_Renderer * renderer)
  1473 {
  1474     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1475     HRESULT result;
  1476 
  1477     if (!data->beginScene) {
  1478         IDirect3DDevice9_EndScene(data->device);
  1479         data->beginScene = SDL_TRUE;
  1480     }
  1481 
  1482     result = IDirect3DDevice9_TestCooperativeLevel(data->device);
  1483     if (result == D3DERR_DEVICELOST) {
  1484         /* We'll reset later */
  1485         return;
  1486     }
  1487     if (result == D3DERR_DEVICENOTRESET) {
  1488         D3D_Reset(renderer);
  1489     }
  1490     result = IDirect3DDevice9_Present(data->device, NULL, NULL, NULL, NULL);
  1491     if (FAILED(result)) {
  1492         D3D_SetError("Present()", result);
  1493     }
  1494 }
  1495 
  1496 static void
  1497 D3D_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  1498 {
  1499     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
  1500 
  1501     if (!data) {
  1502         return;
  1503     }
  1504     D3D_DestroyTextureRep(&data->texture);
  1505     D3D_DestroyTextureRep(&data->utexture);
  1506     D3D_DestroyTextureRep(&data->vtexture);
  1507     SDL_free(data->pixels);
  1508     SDL_free(data);
  1509     texture->driverdata = NULL;
  1510 }
  1511 
  1512 static void
  1513 D3D_DestroyRenderer(SDL_Renderer * renderer)
  1514 {
  1515     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1516 
  1517     if (data) {
  1518         int i;
  1519 
  1520         /* Release the render target */
  1521         if (data->defaultRenderTarget) {
  1522             IDirect3DSurface9_Release(data->defaultRenderTarget);
  1523             data->defaultRenderTarget = NULL;
  1524         }
  1525         if (data->currentRenderTarget != NULL) {
  1526             IDirect3DSurface9_Release(data->currentRenderTarget);
  1527             data->currentRenderTarget = NULL;
  1528         }
  1529         for (i = 0; i < SDL_arraysize(data->shaders); ++i) {
  1530             if (data->shaders[i]) {
  1531                 IDirect3DPixelShader9_Release(data->shaders[i]);
  1532                 data->shaders[i] = NULL;
  1533             }
  1534         }
  1535         if (data->device) {
  1536             IDirect3DDevice9_Release(data->device);
  1537             data->device = NULL;
  1538         }
  1539         if (data->d3d) {
  1540             IDirect3D9_Release(data->d3d);
  1541             SDL_UnloadObject(data->d3dDLL);
  1542         }
  1543         SDL_free(data);
  1544     }
  1545     SDL_free(renderer);
  1546 }
  1547 
  1548 static int
  1549 D3D_Reset(SDL_Renderer * renderer)
  1550 {
  1551     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1552     HRESULT result;
  1553     SDL_Texture *texture;
  1554 
  1555     /* Release the default render target before reset */
  1556     if (data->defaultRenderTarget) {
  1557         IDirect3DSurface9_Release(data->defaultRenderTarget);
  1558         data->defaultRenderTarget = NULL;
  1559     }
  1560     if (data->currentRenderTarget != NULL) {
  1561         IDirect3DSurface9_Release(data->currentRenderTarget);
  1562         data->currentRenderTarget = NULL;
  1563     }
  1564 
  1565     /* Release application render targets */
  1566     for (texture = renderer->textures; texture; texture = texture->next) {
  1567         if (texture->access == SDL_TEXTUREACCESS_TARGET) {
  1568             D3D_DestroyTexture(renderer, texture);
  1569         } else {
  1570             D3D_RecreateTexture(renderer, texture);
  1571         }
  1572     }
  1573 
  1574     result = IDirect3DDevice9_Reset(data->device, &data->pparams);
  1575     if (FAILED(result)) {
  1576         if (result == D3DERR_DEVICELOST) {
  1577             /* Don't worry about it, we'll reset later... */
  1578             return 0;
  1579         } else {
  1580             return D3D_SetError("Reset()", result);
  1581         }
  1582     }
  1583 
  1584     /* Allocate application render targets */
  1585     for (texture = renderer->textures; texture; texture = texture->next) {
  1586         if (texture->access == SDL_TEXTUREACCESS_TARGET) {
  1587             D3D_CreateTexture(renderer, texture);
  1588         }
  1589     }
  1590 
  1591     IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget);
  1592     D3D_InitRenderState(data);
  1593     D3D_SetRenderTargetInternal(renderer, renderer->target);
  1594     data->drawstate.viewport_dirty = SDL_TRUE;
  1595 
  1596     /* Let the application know that render targets were reset */
  1597     {
  1598         SDL_Event event;
  1599         event.type = SDL_RENDER_TARGETS_RESET;
  1600         SDL_PushEvent(&event);
  1601     }
  1602 
  1603     return 0;
  1604 }
  1605 
  1606 SDL_Renderer *
  1607 D3D_CreateRenderer(SDL_Window * window, Uint32 flags)
  1608 {
  1609     SDL_Renderer *renderer;
  1610     D3D_RenderData *data;
  1611     SDL_SysWMinfo windowinfo;
  1612     HRESULT result;
  1613     D3DPRESENT_PARAMETERS pparams;
  1614     IDirect3DSwapChain9 *chain;
  1615     D3DCAPS9 caps;
  1616     DWORD device_flags;
  1617     Uint32 window_flags;
  1618     int w, h;
  1619     SDL_DisplayMode fullscreen_mode;
  1620     int displayIndex;
  1621 
  1622     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
  1623     if (!renderer) {
  1624         SDL_OutOfMemory();
  1625         return NULL;
  1626     }
  1627 
  1628     data = (D3D_RenderData *) SDL_calloc(1, sizeof(*data));
  1629     if (!data) {
  1630         SDL_free(renderer);
  1631         SDL_OutOfMemory();
  1632         return NULL;
  1633     }
  1634 
  1635     if (!D3D_LoadDLL(&data->d3dDLL, &data->d3d)) {
  1636         SDL_free(renderer);
  1637         SDL_free(data);
  1638         SDL_SetError("Unable to create Direct3D interface");
  1639         return NULL;
  1640     }
  1641 
  1642     renderer->WindowEvent = D3D_WindowEvent;
  1643     renderer->SupportsBlendMode = D3D_SupportsBlendMode;
  1644     renderer->CreateTexture = D3D_CreateTexture;
  1645     renderer->UpdateTexture = D3D_UpdateTexture;
  1646     renderer->UpdateTextureYUV = D3D_UpdateTextureYUV;
  1647     renderer->LockTexture = D3D_LockTexture;
  1648     renderer->UnlockTexture = D3D_UnlockTexture;
  1649     renderer->SetRenderTarget = D3D_SetRenderTarget;
  1650     renderer->QueueSetViewport = D3D_QueueSetViewport;
  1651     renderer->QueueSetDrawColor = D3D_QueueSetViewport;  /* SetViewport and SetDrawColor are (currently) no-ops. */
  1652     renderer->QueueDrawPoints = D3D_QueueDrawPoints;
  1653     renderer->QueueDrawLines = D3D_QueueDrawPoints;  /* lines and points queue vertices the same way. */
  1654     renderer->QueueFillRects = D3D_QueueFillRects;
  1655     renderer->QueueCopy = D3D_QueueCopy;
  1656     renderer->QueueCopyEx = D3D_QueueCopyEx;
  1657     renderer->RunCommandQueue = D3D_RunCommandQueue;
  1658     renderer->RenderReadPixels = D3D_RenderReadPixels;
  1659     renderer->RenderPresent = D3D_RenderPresent;
  1660     renderer->DestroyTexture = D3D_DestroyTexture;
  1661     renderer->DestroyRenderer = D3D_DestroyRenderer;
  1662     renderer->info = D3D_RenderDriver.info;
  1663     renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
  1664     renderer->driverdata = data;
  1665 
  1666     SDL_VERSION(&windowinfo.version);
  1667     SDL_GetWindowWMInfo(window, &windowinfo);
  1668 
  1669     window_flags = SDL_GetWindowFlags(window);
  1670     SDL_GetWindowSize(window, &w, &h);
  1671     SDL_GetWindowDisplayMode(window, &fullscreen_mode);
  1672 
  1673     SDL_zero(pparams);
  1674     pparams.hDeviceWindow = windowinfo.info.win.window;
  1675     pparams.BackBufferWidth = w;
  1676     pparams.BackBufferHeight = h;
  1677     pparams.BackBufferCount = 1;
  1678     pparams.SwapEffect = D3DSWAPEFFECT_DISCARD;
  1679 
  1680     if (window_flags & SDL_WINDOW_FULLSCREEN && (window_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
  1681         pparams.Windowed = FALSE;
  1682         pparams.BackBufferFormat = PixelFormatToD3DFMT(fullscreen_mode.format);
  1683         pparams.FullScreen_RefreshRateInHz = fullscreen_mode.refresh_rate;
  1684     } else {
  1685         pparams.Windowed = TRUE;
  1686         pparams.BackBufferFormat = D3DFMT_UNKNOWN;
  1687         pparams.FullScreen_RefreshRateInHz = 0;
  1688     }
  1689     if (flags & SDL_RENDERER_PRESENTVSYNC) {
  1690         pparams.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
  1691     } else {
  1692         pparams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
  1693     }
  1694 
  1695     /* Get the adapter for the display that the window is on */
  1696     displayIndex = SDL_GetWindowDisplayIndex(window);
  1697     data->adapter = SDL_Direct3D9GetAdapterIndex(displayIndex);
  1698 
  1699     IDirect3D9_GetDeviceCaps(data->d3d, data->adapter, D3DDEVTYPE_HAL, &caps);
  1700 
  1701     device_flags = D3DCREATE_FPU_PRESERVE;
  1702     if (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) {
  1703         device_flags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
  1704     } else {
  1705         device_flags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  1706     }
  1707 
  1708     if (SDL_GetHintBoolean(SDL_HINT_RENDER_DIRECT3D_THREADSAFE, SDL_FALSE)) {
  1709         device_flags |= D3DCREATE_MULTITHREADED;
  1710     }
  1711 
  1712     data->supportsStreamOffset = ((caps.DevCaps2 & D3DDEVCAPS2_STREAMOFFSET) == D3DDEVCAPS2_STREAMOFFSET);
  1713 
  1714     result = IDirect3D9_CreateDevice(data->d3d, data->adapter,
  1715                                      D3DDEVTYPE_HAL,
  1716                                      pparams.hDeviceWindow,
  1717                                      device_flags,
  1718                                      &pparams, &data->device);
  1719     if (FAILED(result)) {
  1720         D3D_DestroyRenderer(renderer);
  1721         D3D_SetError("CreateDevice()", result);
  1722         return NULL;
  1723     }
  1724 
  1725     /* Get presentation parameters to fill info */
  1726     result = IDirect3DDevice9_GetSwapChain(data->device, 0, &chain);
  1727     if (FAILED(result)) {
  1728         D3D_DestroyRenderer(renderer);
  1729         D3D_SetError("GetSwapChain()", result);
  1730         return NULL;
  1731     }
  1732     result = IDirect3DSwapChain9_GetPresentParameters(chain, &pparams);
  1733     if (FAILED(result)) {
  1734         IDirect3DSwapChain9_Release(chain);
  1735         D3D_DestroyRenderer(renderer);
  1736         D3D_SetError("GetPresentParameters()", result);
  1737         return NULL;
  1738     }
  1739     IDirect3DSwapChain9_Release(chain);
  1740     if (pparams.PresentationInterval == D3DPRESENT_INTERVAL_ONE) {
  1741         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
  1742     }
  1743     data->pparams = pparams;
  1744 
  1745     IDirect3DDevice9_GetDeviceCaps(data->device, &caps);
  1746     renderer->info.max_texture_width = caps.MaxTextureWidth;
  1747     renderer->info.max_texture_height = caps.MaxTextureHeight;
  1748     if (caps.NumSimultaneousRTs >= 2) {
  1749         renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE;
  1750     }
  1751 
  1752     if (caps.PrimitiveMiscCaps & D3DPMISCCAPS_SEPARATEALPHABLEND) {
  1753         data->enableSeparateAlphaBlend = SDL_TRUE;
  1754     }
  1755 
  1756     /* Store the default render target */
  1757     IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget);
  1758     data->currentRenderTarget = NULL;
  1759 
  1760     /* Set up parameters for rendering */
  1761     D3D_InitRenderState(data);
  1762 
  1763     if (caps.MaxSimultaneousTextures >= 3) {
  1764         int i;
  1765         for (i = 0; i < SDL_arraysize(data->shaders); ++i) {
  1766             result = D3D9_CreatePixelShader(data->device, (D3D9_Shader)i, &data->shaders[i]);
  1767             if (FAILED(result)) {
  1768                 D3D_SetError("CreatePixelShader()", result);
  1769             }
  1770         }
  1771         if (data->shaders[SHADER_YUV_JPEG] && data->shaders[SHADER_YUV_BT601] && data->shaders[SHADER_YUV_BT709]) {
  1772             renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;
  1773             renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
  1774         }
  1775     }
  1776 
  1777     data->drawstate.blend = SDL_BLENDMODE_INVALID;
  1778 
  1779     return renderer;
  1780 }
  1781 
  1782 SDL_RenderDriver D3D_RenderDriver = {
  1783     D3D_CreateRenderer,
  1784     {
  1785      "direct3d",
  1786      (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
  1787      1,
  1788      {SDL_PIXELFORMAT_ARGB8888},
  1789      0,
  1790      0}
  1791 };
  1792 #endif /* SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED */
  1793 
  1794 #ifdef __WIN32__
  1795 /* This function needs to always exist on Windows, for the Dynamic API. */
  1796 IDirect3DDevice9 *
  1797 SDL_RenderGetD3D9Device(SDL_Renderer * renderer)
  1798 {
  1799     IDirect3DDevice9 *device = NULL;
  1800 
  1801 #if SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED
  1802     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1803 
  1804     /* Make sure that this is a D3D renderer */
  1805     if (renderer->DestroyRenderer != D3D_DestroyRenderer) {
  1806         SDL_SetError("Renderer is not a D3D renderer");
  1807         return NULL;
  1808     }
  1809 
  1810     device = data->device;
  1811     if (device) {
  1812         IDirect3DDevice9_AddRef(device);
  1813     }
  1814 #endif /* SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED */
  1815 
  1816     return device;
  1817 }
  1818 #endif /* __WIN32__ */
  1819 
  1820 /* vi: set ts=4 sw=4 expandtab: */