sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_render_d3d.c (64582B)


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