cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

SDL_render_d3d.c (64903B)


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