src/render/direct3d/SDL_render_d3d.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 29 May 2020 21:26:32 -0700
changeset 13884 ba1ed72249c0
parent 13696 ea20a7434b98
permissions -rw-r--r--
Fixed bug 5113 - SDL_UpdateWindowSurfaceRects BitBlt the entire surface on Win32

Ryan C. Gordon

As discussed here:
https://discourse.libsdl.org/t/question-about-implementation-of-sdl-updatewindowsurfacerects/27561

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