src/video/win32/SDL_d3drender.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 17 Jul 2006 06:47:33 +0000
changeset 1913 83420da906a5
parent 1907 06c27a737b7a
child 1916 c773b0c0ac89
permissions -rw-r--r--
Implemented Windows OpenGL support
Fixed slowdown enumerating display modes, which was hosing OpenGL as well...
Removed SDL_ from the render driver prefixes
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 #if SDL_VIDEO_RENDER_D3D
    25 
    26 #include "SDL_win32video.h"
    27 
    28 /* Direct3D renderer implementation */
    29 
    30 static SDL_Renderer *D3D_CreateRenderer(SDL_Window * window, Uint32 flags);
    31 static int D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    32 static int D3D_SetTexturePalette(SDL_Renderer * renderer,
    33                                  SDL_Texture * texture,
    34                                  const SDL_Color * colors, int firstcolor,
    35                                  int ncolors);
    36 static int D3D_GetTexturePalette(SDL_Renderer * renderer,
    37                                  SDL_Texture * texture, SDL_Color * colors,
    38                                  int firstcolor, int ncolors);
    39 static int D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    40                              const SDL_Rect * rect, const void *pixels,
    41                              int pitch);
    42 static int D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    43                            const SDL_Rect * rect, int markDirty,
    44                            void **pixels, int *pitch);
    45 static void D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    46 static void D3D_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    47                              int numrects, const SDL_Rect * rects);
    48 static int D3D_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect,
    49                           Uint32 color);
    50 static int D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
    51                           const SDL_Rect * srcrect, const SDL_Rect * dstrect,
    52                           int blendMode, int scaleMode);
    53 static void D3D_RenderPresent(SDL_Renderer * renderer);
    54 static void D3D_DestroyTexture(SDL_Renderer * renderer,
    55                                SDL_Texture * texture);
    56 static void D3D_DestroyRenderer(SDL_Renderer * renderer);
    57 
    58 
    59 SDL_RenderDriver D3D_RenderDriver = {
    60     D3D_CreateRenderer,
    61     {
    62      "d3d",
    63      (SDL_Renderer_SingleBuffer | SDL_Renderer_PresentCopy |
    64       SDL_Renderer_PresentFlip2 | SDL_Renderer_PresentFlip3 |
    65       SDL_Renderer_PresentDiscard | SDL_Renderer_PresentVSync),
    66      (SDL_TextureBlendMode_None | SDL_TextureBlendMode_Mask | SDL_TextureBlendMode_Blend),      /* FIXME */
    67      (SDL_TextureScaleMode_None | SDL_TextureScaleMode_Fast),   /* FIXME */
    68      12,
    69      {
    70       SDL_PixelFormat_Index8,
    71       SDL_PixelFormat_RGB332,
    72       SDL_PixelFormat_RGB444,
    73       SDL_PixelFormat_RGB555,
    74       SDL_PixelFormat_ARGB4444,
    75       SDL_PixelFormat_ARGB1555,
    76       SDL_PixelFormat_RGB565,
    77       SDL_PixelFormat_RGB888,
    78       SDL_PixelFormat_ARGB8888,
    79       SDL_PixelFormat_ARGB2101010,
    80       SDL_PixelFormat_UYVY,
    81       SDL_PixelFormat_YUY2},
    82      0,
    83      0}
    84 };
    85 
    86 typedef struct
    87 {
    88     IDirect3DDevice9 *device;
    89     SDL_bool beginScene;
    90 } D3D_RenderData;
    91 
    92 typedef struct
    93 {
    94     IDirect3DTexture9 *texture;
    95 } D3D_TextureData;
    96 
    97 typedef struct
    98 {
    99     float x, y, z;
   100     float rhw;
   101     float u, v;
   102 } Vertex;
   103 
   104 static void
   105 D3D_SetError(const char *prefix, HRESULT result)
   106 {
   107     const char *error;
   108 
   109     switch (result) {
   110     case D3DERR_WRONGTEXTUREFORMAT:
   111         error = "WRONGTEXTUREFORMAT";
   112         break;
   113     case D3DERR_UNSUPPORTEDCOLOROPERATION:
   114         error = "UNSUPPORTEDCOLOROPERATION";
   115         break;
   116     case D3DERR_UNSUPPORTEDCOLORARG:
   117         error = "UNSUPPORTEDCOLORARG";
   118         break;
   119     case D3DERR_UNSUPPORTEDALPHAOPERATION:
   120         error = "UNSUPPORTEDALPHAOPERATION";
   121         break;
   122     case D3DERR_UNSUPPORTEDALPHAARG:
   123         error = "UNSUPPORTEDALPHAARG";
   124         break;
   125     case D3DERR_TOOMANYOPERATIONS:
   126         error = "TOOMANYOPERATIONS";
   127         break;
   128     case D3DERR_CONFLICTINGTEXTUREFILTER:
   129         error = "CONFLICTINGTEXTUREFILTER";
   130         break;
   131     case D3DERR_UNSUPPORTEDFACTORVALUE:
   132         error = "UNSUPPORTEDFACTORVALUE";
   133         break;
   134     case D3DERR_CONFLICTINGRENDERSTATE:
   135         error = "CONFLICTINGRENDERSTATE";
   136         break;
   137     case D3DERR_UNSUPPORTEDTEXTUREFILTER:
   138         error = "UNSUPPORTEDTEXTUREFILTER";
   139         break;
   140     case D3DERR_CONFLICTINGTEXTUREPALETTE:
   141         error = "CONFLICTINGTEXTUREPALETTE";
   142         break;
   143     case D3DERR_DRIVERINTERNALERROR:
   144         error = "DRIVERINTERNALERROR";
   145         break;
   146     case D3DERR_NOTFOUND:
   147         error = "NOTFOUND";
   148         break;
   149     case D3DERR_MOREDATA:
   150         error = "MOREDATA";
   151         break;
   152     case D3DERR_DEVICELOST:
   153         error = "DEVICELOST";
   154         break;
   155     case D3DERR_DEVICENOTRESET:
   156         error = "DEVICENOTRESET";
   157         break;
   158     case D3DERR_NOTAVAILABLE:
   159         error = "NOTAVAILABLE";
   160         break;
   161     case D3DERR_OUTOFVIDEOMEMORY:
   162         error = "OUTOFVIDEOMEMORY";
   163         break;
   164     case D3DERR_INVALIDDEVICE:
   165         error = "INVALIDDEVICE";
   166         break;
   167     case D3DERR_INVALIDCALL:
   168         error = "INVALIDCALL";
   169         break;
   170     case D3DERR_DRIVERINVALIDCALL:
   171         error = "DRIVERINVALIDCALL";
   172         break;
   173     case D3DERR_WASSTILLDRAWING:
   174         error = "WASSTILLDRAWING";
   175         break;
   176     default:
   177         error = "UNKNOWN";
   178         break;
   179     }
   180     SDL_SetError("%s: %s", prefix, error);
   181 }
   182 
   183 static D3DFORMAT
   184 PixelFormatToD3DFMT(Uint32 format)
   185 {
   186     switch (format) {
   187     case SDL_PixelFormat_Index8:
   188         return D3DFMT_P8;
   189     case SDL_PixelFormat_RGB332:
   190         return D3DFMT_R3G3B2;
   191     case SDL_PixelFormat_RGB444:
   192         return D3DFMT_X4R4G4B4;
   193     case SDL_PixelFormat_RGB555:
   194         return D3DFMT_X1R5G5B5;
   195     case SDL_PixelFormat_ARGB4444:
   196         return D3DFMT_A4R4G4B4;
   197     case SDL_PixelFormat_ARGB1555:
   198         return D3DFMT_A1R5G5B5;
   199     case SDL_PixelFormat_RGB565:
   200         return D3DFMT_R5G6B5;
   201     case SDL_PixelFormat_RGB888:
   202         return D3DFMT_X8R8G8B8;
   203     case SDL_PixelFormat_ARGB8888:
   204         return D3DFMT_A8R8G8B8;
   205     case SDL_PixelFormat_ARGB2101010:
   206         return D3DFMT_A2R10G10B10;
   207     case SDL_PixelFormat_UYVY:
   208         return D3DFMT_UYVY;
   209     case SDL_PixelFormat_YUY2:
   210         return D3DFMT_YUY2;
   211     default:
   212         return D3DFMT_UNKNOWN;
   213     }
   214 }
   215 
   216 void
   217 D3D_AddRenderDriver(_THIS)
   218 {
   219     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   220 
   221     if (data->d3d) {
   222         SDL_AddRenderDriver(0, &D3D_RenderDriver);
   223     }
   224 }
   225 
   226 SDL_Renderer *
   227 D3D_CreateRenderer(SDL_Window * window, Uint32 flags)
   228 {
   229     SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
   230     SDL_VideoData *videodata = (SDL_VideoData *) display->device->driverdata;
   231     SDL_WindowData *windowdata = (SDL_WindowData *) window->driverdata;
   232     SDL_Renderer *renderer;
   233     D3D_RenderData *data;
   234     HRESULT result;
   235     D3DPRESENT_PARAMETERS pparams;
   236     IDirect3DSwapChain9 *chain;
   237 
   238     renderer = (SDL_Renderer *) SDL_malloc(sizeof(*renderer));
   239     if (!renderer) {
   240         SDL_OutOfMemory();
   241         return NULL;
   242     }
   243     SDL_zerop(renderer);
   244 
   245     data = (D3D_RenderData *) SDL_malloc(sizeof(*data));
   246     if (!data) {
   247         D3D_DestroyRenderer(renderer);
   248         SDL_OutOfMemory();
   249         return NULL;
   250     }
   251     SDL_zerop(data);
   252 
   253     renderer->CreateTexture = D3D_CreateTexture;
   254     renderer->SetTexturePalette = D3D_SetTexturePalette;
   255     renderer->GetTexturePalette = D3D_GetTexturePalette;
   256     renderer->UpdateTexture = D3D_UpdateTexture;
   257     renderer->LockTexture = D3D_LockTexture;
   258     renderer->UnlockTexture = D3D_UnlockTexture;
   259     renderer->DirtyTexture = D3D_DirtyTexture;
   260     renderer->RenderFill = D3D_RenderFill;
   261     renderer->RenderCopy = D3D_RenderCopy;
   262     renderer->RenderPresent = D3D_RenderPresent;
   263     renderer->DestroyTexture = D3D_DestroyTexture;
   264     renderer->DestroyRenderer = D3D_DestroyRenderer;
   265     renderer->info = D3D_RenderDriver.info;
   266     renderer->window = window->id;
   267     renderer->driverdata = data;
   268 
   269     renderer->info.flags = SDL_Renderer_Accelerated;
   270 
   271     SDL_zero(pparams);
   272     pparams.BackBufferWidth = window->w;
   273     pparams.BackBufferHeight = window->h;
   274     if (window->flags & SDL_WINDOW_FULLSCREEN) {
   275         pparams.BackBufferFormat =
   276             PixelFormatToD3DFMT(display->fullscreen_mode->format);
   277     } else {
   278         pparams.BackBufferFormat = D3DFMT_UNKNOWN;
   279     }
   280     if (flags & SDL_Renderer_PresentFlip2) {
   281         pparams.BackBufferCount = 2;
   282         pparams.SwapEffect = D3DSWAPEFFECT_FLIP;
   283     } else if (flags & SDL_Renderer_PresentFlip3) {
   284         pparams.BackBufferCount = 3;
   285         pparams.SwapEffect = D3DSWAPEFFECT_FLIP;
   286     } else if (flags & SDL_Renderer_PresentCopy) {
   287         pparams.BackBufferCount = 1;
   288         pparams.SwapEffect = D3DSWAPEFFECT_COPY;
   289     } else {
   290         pparams.BackBufferCount = 1;
   291         pparams.SwapEffect = D3DSWAPEFFECT_DISCARD;
   292     }
   293     if (window->flags & SDL_WINDOW_FULLSCREEN) {
   294         pparams.Windowed = FALSE;
   295         pparams.FullScreen_RefreshRateInHz =
   296             display->fullscreen_mode->refresh_rate;
   297     } else {
   298         pparams.Windowed = TRUE;
   299         pparams.FullScreen_RefreshRateInHz = 0;
   300     }
   301     if (flags & SDL_Renderer_PresentVSync) {
   302         pparams.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
   303     } else {
   304         pparams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
   305     }
   306 
   307     result = IDirect3D9_CreateDevice(videodata->d3d, D3DADAPTER_DEFAULT,        /* FIXME */
   308                                      D3DDEVTYPE_HAL,
   309                                      windowdata->hwnd,
   310                                      D3DCREATE_SOFTWARE_VERTEXPROCESSING,
   311                                      &pparams, &data->device);
   312     if (FAILED(result)) {
   313         D3D_DestroyRenderer(renderer);
   314         D3D_SetError("CreateDevice()", result);
   315         return NULL;
   316     }
   317     data->beginScene = SDL_TRUE;
   318 
   319     /* Get presentation parameters to fill info */
   320     result = IDirect3DDevice9_GetSwapChain(data->device, 0, &chain);
   321     if (FAILED(result)) {
   322         D3D_DestroyRenderer(renderer);
   323         D3D_SetError("GetSwapChain()", result);
   324         return NULL;
   325     }
   326     result = IDirect3DSwapChain9_GetPresentParameters(chain, &pparams);
   327     if (FAILED(result)) {
   328         IDirect3DSwapChain9_Release(chain);
   329         D3D_DestroyRenderer(renderer);
   330         D3D_SetError("GetPresentParameters()", result);
   331         return NULL;
   332     }
   333     IDirect3DSwapChain9_Release(chain);
   334     switch (pparams.SwapEffect) {
   335     case D3DSWAPEFFECT_COPY:
   336         renderer->info.flags |= SDL_Renderer_PresentCopy;
   337         break;
   338     case D3DSWAPEFFECT_FLIP:
   339         switch (pparams.BackBufferCount) {
   340         case 2:
   341             renderer->info.flags |= SDL_Renderer_PresentFlip2;
   342             break;
   343         case 3:
   344             renderer->info.flags |= SDL_Renderer_PresentFlip3;
   345             break;
   346         }
   347         break;
   348     case D3DSWAPEFFECT_DISCARD:
   349         renderer->info.flags |= SDL_Renderer_PresentDiscard;
   350         break;
   351     }
   352     if (pparams.PresentationInterval == D3DPRESENT_INTERVAL_ONE) {
   353         renderer->info.flags |= SDL_Renderer_PresentVSync;
   354     }
   355 
   356     /* Set up parameters for rendering */
   357     IDirect3DDevice9_SetVertexShader(data->device, NULL);
   358     IDirect3DDevice9_SetFVF(data->device, D3DFVF_XYZRHW | D3DFVF_TEX1);
   359     IDirect3DDevice9_SetRenderState(data->device, D3DRS_CULLMODE,
   360                                     D3DCULL_NONE);
   361     IDirect3DDevice9_SetRenderState(data->device, D3DRS_LIGHTING, FALSE);
   362     IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
   363                                     TRUE);
   364     IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
   365                                     D3DBLEND_SRCALPHA);
   366     IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
   367                                     D3DBLEND_INVSRCALPHA);
   368 
   369     return renderer;
   370 }
   371 
   372 static int
   373 D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   374 {
   375     D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata;
   376     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   377     SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
   378     D3D_TextureData *data;
   379     D3DPOOL pool;
   380     HRESULT result;
   381 
   382     data = (D3D_TextureData *) SDL_malloc(sizeof(*data));
   383     if (!data) {
   384         SDL_OutOfMemory();
   385         return -1;
   386     }
   387     SDL_zerop(data);
   388 
   389     texture->driverdata = data;
   390 
   391     if (texture->access == SDL_TextureAccess_Local) {
   392         pool = D3DPOOL_MANAGED;
   393     } else {
   394         pool = D3DPOOL_DEFAULT;
   395     }
   396     result =
   397         IDirect3DDevice9_CreateTexture(renderdata->device, texture->w,
   398                                        texture->h, 1, 0,
   399                                        PixelFormatToD3DFMT(texture->format),
   400                                        pool, &data->texture, NULL);
   401     if (FAILED(result)) {
   402         SDL_free(data);
   403         D3D_SetError("CreateTexture()", result);
   404         return -1;
   405     }
   406 
   407     return 0;
   408 }
   409 
   410 static int
   411 D3D_SetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
   412                       const SDL_Color * colors, int firstcolor, int ncolors)
   413 {
   414     D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata;
   415     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
   416 
   417     return 0;
   418 }
   419 
   420 static int
   421 D3D_GetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
   422                       SDL_Color * colors, int firstcolor, int ncolors)
   423 {
   424     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
   425 
   426     return 0;
   427 }
   428 
   429 static int
   430 D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   431                   const SDL_Rect * rect, const void *pixels, int pitch)
   432 {
   433     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
   434     D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata;
   435     IDirect3DTexture9 *temp;
   436     RECT d3drect;
   437     D3DLOCKED_RECT locked;
   438     const Uint8 *src;
   439     Uint8 *dst;
   440     int row, length;
   441     HRESULT result;
   442 
   443     result =
   444         IDirect3DDevice9_CreateTexture(renderdata->device, texture->w,
   445                                        texture->h, 1, 0,
   446                                        PixelFormatToD3DFMT(texture->format),
   447                                        D3DPOOL_SYSTEMMEM, &temp, NULL);
   448     if (FAILED(result)) {
   449         D3D_SetError("CreateTexture()", result);
   450         return -1;
   451     }
   452 
   453     d3drect.left = rect->x;
   454     d3drect.right = rect->x + rect->w;
   455     d3drect.top = rect->y;
   456     d3drect.bottom = rect->y + rect->h;
   457 
   458     result = IDirect3DTexture9_LockRect(temp, 0, &locked, &d3drect, 0);
   459     if (FAILED(result)) {
   460         IDirect3DTexture9_Release(temp);
   461         D3D_SetError("LockRect()", result);
   462         return -1;
   463     }
   464 
   465     src = pixels;
   466     dst = locked.pBits;
   467     length = rect->w * SDL_BYTESPERPIXEL(texture->format);
   468     for (row = 0; row < rect->h; ++row) {
   469         SDL_memcpy(dst, src, length);
   470         src += pitch;
   471         dst += locked.Pitch;
   472     }
   473     IDirect3DTexture9_UnlockRect(temp, 0);
   474 
   475     result =
   476         IDirect3DDevice9_UpdateTexture(renderdata->device,
   477                                        (IDirect3DBaseTexture9 *) temp,
   478                                        (IDirect3DBaseTexture9 *) data->
   479                                        texture);
   480     IDirect3DTexture9_Release(temp);
   481     if (FAILED(result)) {
   482         D3D_SetError("UpdateTexture()", result);
   483         return -1;
   484     }
   485     return 0;
   486 }
   487 
   488 static int
   489 D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   490                 const SDL_Rect * rect, int markDirty, void **pixels,
   491                 int *pitch)
   492 {
   493     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
   494     RECT d3drect;
   495     D3DLOCKED_RECT locked;
   496     HRESULT result;
   497 
   498     if (texture->access != SDL_TextureAccess_Local) {
   499         SDL_SetError("Can't lock remote video memory");
   500         return -1;
   501     }
   502 
   503     d3drect.left = rect->x;
   504     d3drect.right = rect->x + rect->w;
   505     d3drect.top = rect->y;
   506     d3drect.bottom = rect->y + rect->h;
   507 
   508     result =
   509         IDirect3DTexture9_LockRect(data->texture, 0, &locked, &d3drect,
   510                                    markDirty ? 0 : D3DLOCK_NO_DIRTY_UPDATE);
   511     if (FAILED(result)) {
   512         D3D_SetError("LockRect()", result);
   513         return -1;
   514     }
   515     *pixels = locked.pBits;
   516     *pitch = locked.Pitch;
   517     return 0;
   518 }
   519 
   520 static void
   521 D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   522 {
   523     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
   524 
   525     IDirect3DTexture9_UnlockRect(data->texture, 0);
   526 }
   527 
   528 static void
   529 D3D_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture, int numrects,
   530                  const SDL_Rect * rects)
   531 {
   532     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
   533     RECT d3drect;
   534     int i;
   535 
   536     for (i = 0; i < numrects; ++i) {
   537         const SDL_Rect *rect = &rects[i];
   538 
   539         d3drect.left = rect->x;
   540         d3drect.right = rect->x + rect->w;
   541         d3drect.top = rect->y;
   542         d3drect.bottom = rect->y + rect->h;
   543 
   544         IDirect3DTexture9_AddDirtyRect(data->texture, &d3drect);
   545     }
   546 }
   547 
   548 static int
   549 D3D_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect, Uint32 color)
   550 {
   551     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   552     D3DRECT d3drect;
   553     HRESULT result;
   554 
   555     if (data->beginScene) {
   556         IDirect3DDevice9_BeginScene(data->device);
   557         data->beginScene = SDL_FALSE;
   558     }
   559 
   560     d3drect.x1 = rect->x;
   561     d3drect.x2 = rect->x + rect->w;
   562     d3drect.y1 = rect->y;
   563     d3drect.y2 = rect->y + rect->h;
   564 
   565     result =
   566         IDirect3DDevice9_Clear(data->device, 1, &d3drect, D3DCLEAR_TARGET,
   567                                (D3DCOLOR) color, 1.0f, 0);
   568     if (FAILED(result)) {
   569         D3D_SetError("Clear()", result);
   570         return -1;
   571     }
   572     return 0;
   573 }
   574 
   575 static int
   576 D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   577                const SDL_Rect * srcrect, const SDL_Rect * dstrect,
   578                int blendMode, int scaleMode)
   579 {
   580     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   581     D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata;
   582     float minx, miny, maxx, maxy;
   583     float minu, maxu, minv, maxv;
   584     Vertex vertices[4];
   585     HRESULT result;
   586 
   587     if (data->beginScene) {
   588         IDirect3DDevice9_BeginScene(data->device);
   589         data->beginScene = SDL_FALSE;
   590     }
   591 
   592     minx = (float) dstrect->x - 0.5f;
   593     miny = (float) dstrect->y - 0.5f;
   594     maxx = (float) dstrect->x + dstrect->w - 0.5f;
   595     maxy = (float) dstrect->y + dstrect->h - 0.5f;
   596 
   597     minu = (float) srcrect->x / texture->w;
   598     maxu = (float) (srcrect->x + srcrect->w) / texture->w;
   599     minv = (float) srcrect->y / texture->h;
   600     maxv = (float) (srcrect->y + srcrect->h) / texture->h;
   601 
   602     vertices[0].x = minx;
   603     vertices[0].y = miny;
   604     vertices[0].z = 0.0f;
   605     vertices[0].rhw = 1.0f;
   606     vertices[0].u = minu;
   607     vertices[0].v = minv;
   608 
   609     vertices[1].x = maxx;
   610     vertices[1].y = miny;
   611     vertices[1].z = 0.0f;
   612     vertices[1].rhw = 1.0f;
   613     vertices[1].u = maxu;
   614     vertices[1].v = minv;
   615 
   616     vertices[2].x = maxx;
   617     vertices[2].y = maxy;
   618     vertices[2].z = 0.0f;
   619     vertices[2].rhw = 1.0f;
   620     vertices[2].u = maxu;
   621     vertices[2].v = maxv;
   622 
   623     vertices[3].x = minx;
   624     vertices[3].y = maxy;
   625     vertices[3].z = 0.0f;
   626     vertices[3].rhw = 1.0f;
   627     vertices[3].u = minu;
   628     vertices[3].v = maxv;
   629 
   630     result =
   631         IDirect3DDevice9_SetTexture(data->device, 0,
   632                                     (IDirect3DBaseTexture9 *) texturedata->
   633                                     texture);
   634     if (FAILED(result)) {
   635         D3D_SetError("SetTexture()", result);
   636         return -1;
   637     }
   638     result =
   639         IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2,
   640                                          vertices, sizeof(*vertices));
   641     if (FAILED(result)) {
   642         D3D_SetError("DrawPrimitiveUP()", result);
   643         return -1;
   644     }
   645     return 0;
   646 }
   647 
   648 static void
   649 D3D_RenderPresent(SDL_Renderer * renderer)
   650 {
   651     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   652     HRESULT result;
   653 
   654     if (!data->beginScene) {
   655         IDirect3DDevice9_EndScene(data->device);
   656         data->beginScene = SDL_TRUE;
   657     }
   658 
   659     result = IDirect3DDevice9_Present(data->device, NULL, NULL, NULL, NULL);
   660     if (FAILED(result)) {
   661         D3D_SetError("Present()", result);
   662     }
   663 }
   664 
   665 static void
   666 D3D_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   667 {
   668     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
   669 
   670     if (!data) {
   671         return;
   672     }
   673     if (data->texture) {
   674         IDirect3DTexture9_Release(data->texture);
   675     }
   676     SDL_free(data);
   677     texture->driverdata = NULL;
   678 }
   679 
   680 void
   681 D3D_DestroyRenderer(SDL_Renderer * renderer)
   682 {
   683     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   684 
   685     if (data) {
   686         if (data->device) {
   687             IDirect3DDevice9_Release(data->device);
   688         }
   689         SDL_free(data);
   690     }
   691     SDL_free(renderer);
   692 }
   693 
   694 #endif /* SDL_VIDEO_RENDER_D3D */
   695 
   696 /* vi: set ts=4 sw=4 expandtab: */