src/video/win32/SDL_d3drender.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 14 Jul 2006 08:22:45 +0000
changeset 1905 36d52b1f0504
parent 1904 1a713f9d1f71
child 1907 06c27a737b7a
permissions -rw-r--r--
Prefer the D3D renderer over GDI, at least for testing.
Added support for the SDL_VIDEO_RENDERER environment variable to pick the desired render driver.
Implemented WritePixels support for the D3D renderer.
     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 *SDL_D3D_CreateRenderer(SDL_Window * window,
    31                                             Uint32 flags);
    32 static int SDL_D3D_CreateTexture(SDL_Renderer * renderer,
    33                                  SDL_Texture * texture);
    34 static int SDL_D3D_SetTexturePalette(SDL_Renderer * renderer,
    35                                      SDL_Texture * texture,
    36                                      const SDL_Color * colors, int firstcolor,
    37                                      int ncolors);
    38 static int SDL_D3D_GetTexturePalette(SDL_Renderer * renderer,
    39                                      SDL_Texture * texture,
    40                                      SDL_Color * colors, int firstcolor,
    41                                      int ncolors);
    42 static int SDL_D3D_UpdateTexture(SDL_Renderer * renderer,
    43                                  SDL_Texture * texture, const SDL_Rect * rect,
    44                                  const void *pixels, int pitch);
    45 static int SDL_D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    46                                const SDL_Rect * rect, int markDirty,
    47                                void **pixels, int *pitch);
    48 static void SDL_D3D_UnlockTexture(SDL_Renderer * renderer,
    49                                   SDL_Texture * texture);
    50 static void SDL_D3D_DirtyTexture(SDL_Renderer * renderer,
    51                                  SDL_Texture * texture, int numrects,
    52                                  const SDL_Rect * rects);
    53 static void SDL_D3D_SelectRenderTexture(SDL_Renderer * renderer,
    54                                         SDL_Texture * texture);
    55 static int SDL_D3D_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect,
    56                               Uint32 color);
    57 static int SDL_D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
    58                               const SDL_Rect * srcrect,
    59                               const SDL_Rect * dstrect, int blendMode,
    60                               int scaleMode);
    61 static int SDL_D3D_RenderReadPixels(SDL_Renderer * renderer,
    62                                     const SDL_Rect * rect, void *pixels,
    63                                     int pitch);
    64 static int SDL_D3D_RenderWritePixels(SDL_Renderer * renderer,
    65                                      const SDL_Rect * rect,
    66                                      const void *pixels, int pitch);
    67 static void SDL_D3D_RenderPresent(SDL_Renderer * renderer);
    68 static void SDL_D3D_DestroyTexture(SDL_Renderer * renderer,
    69                                    SDL_Texture * texture);
    70 static void SDL_D3D_DestroyRenderer(SDL_Renderer * renderer);
    71 
    72 
    73 SDL_RenderDriver SDL_D3D_RenderDriver = {
    74     SDL_D3D_CreateRenderer,
    75     {
    76      "d3d",
    77      (SDL_Renderer_SingleBuffer | SDL_Renderer_PresentCopy |
    78       SDL_Renderer_PresentFlip2 | SDL_Renderer_PresentFlip3 |
    79       SDL_Renderer_PresentDiscard | SDL_Renderer_RenderTarget),
    80      (SDL_TextureBlendMode_None |
    81       SDL_TextureBlendMode_Mask | SDL_TextureBlendMode_Blend),
    82      (SDL_TextureScaleMode_None | SDL_TextureScaleMode_Fast),
    83      12,
    84      {
    85       SDL_PixelFormat_Index8,
    86       SDL_PixelFormat_RGB332,
    87       SDL_PixelFormat_RGB444,
    88       SDL_PixelFormat_RGB555,
    89       SDL_PixelFormat_ARGB4444,
    90       SDL_PixelFormat_ARGB1555,
    91       SDL_PixelFormat_RGB565,
    92       SDL_PixelFormat_RGB888,
    93       SDL_PixelFormat_ARGB8888,
    94       SDL_PixelFormat_ARGB2101010,
    95       SDL_PixelFormat_UYVY,
    96       SDL_PixelFormat_YUY2},
    97      0,
    98      0}
    99 };
   100 
   101 typedef struct
   102 {
   103     IDirect3DDevice9 *device;
   104     IDirect3DSurface9 *surface;
   105     IDirect3DSurface9 *offscreen;
   106     SDL_bool beginScene;
   107 } SDL_D3D_RenderData;
   108 
   109 typedef struct
   110 {
   111     IDirect3DTexture9 *texture;
   112 } SDL_D3D_TextureData;
   113 
   114 typedef struct
   115 {
   116     float x, y, z;
   117     float rhw;
   118     float u, v;
   119 } Vertex;
   120 
   121 static void
   122 D3D_SetError(const char *prefix, HRESULT result)
   123 {
   124     const char *error;
   125 
   126     switch (result) {
   127     case D3DERR_WRONGTEXTUREFORMAT:
   128         error = "WRONGTEXTUREFORMAT";
   129         break;
   130     case D3DERR_UNSUPPORTEDCOLOROPERATION:
   131         error = "UNSUPPORTEDCOLOROPERATION";
   132         break;
   133     case D3DERR_UNSUPPORTEDCOLORARG:
   134         error = "UNSUPPORTEDCOLORARG";
   135         break;
   136     case D3DERR_UNSUPPORTEDALPHAOPERATION:
   137         error = "UNSUPPORTEDALPHAOPERATION";
   138         break;
   139     case D3DERR_UNSUPPORTEDALPHAARG:
   140         error = "UNSUPPORTEDALPHAARG";
   141         break;
   142     case D3DERR_TOOMANYOPERATIONS:
   143         error = "TOOMANYOPERATIONS";
   144         break;
   145     case D3DERR_CONFLICTINGTEXTUREFILTER:
   146         error = "CONFLICTINGTEXTUREFILTER";
   147         break;
   148     case D3DERR_UNSUPPORTEDFACTORVALUE:
   149         error = "UNSUPPORTEDFACTORVALUE";
   150         break;
   151     case D3DERR_CONFLICTINGRENDERSTATE:
   152         error = "CONFLICTINGRENDERSTATE";
   153         break;
   154     case D3DERR_UNSUPPORTEDTEXTUREFILTER:
   155         error = "UNSUPPORTEDTEXTUREFILTER";
   156         break;
   157     case D3DERR_CONFLICTINGTEXTUREPALETTE:
   158         error = "CONFLICTINGTEXTUREPALETTE";
   159         break;
   160     case D3DERR_DRIVERINTERNALERROR:
   161         error = "DRIVERINTERNALERROR";
   162         break;
   163     case D3DERR_NOTFOUND:
   164         error = "NOTFOUND";
   165         break;
   166     case D3DERR_MOREDATA:
   167         error = "MOREDATA";
   168         break;
   169     case D3DERR_DEVICELOST:
   170         error = "DEVICELOST";
   171         break;
   172     case D3DERR_DEVICENOTRESET:
   173         error = "DEVICENOTRESET";
   174         break;
   175     case D3DERR_NOTAVAILABLE:
   176         error = "NOTAVAILABLE";
   177         break;
   178     case D3DERR_OUTOFVIDEOMEMORY:
   179         error = "OUTOFVIDEOMEMORY";
   180         break;
   181     case D3DERR_INVALIDDEVICE:
   182         error = "INVALIDDEVICE";
   183         break;
   184     case D3DERR_INVALIDCALL:
   185         error = "INVALIDCALL";
   186         break;
   187     case D3DERR_DRIVERINVALIDCALL:
   188         error = "DRIVERINVALIDCALL";
   189         break;
   190     case D3DERR_WASSTILLDRAWING:
   191         error = "WASSTILLDRAWING";
   192         break;
   193     default:
   194         error = "UNKNOWN";
   195         break;
   196     }
   197     SDL_SetError("%s: %s", prefix, error);
   198 }
   199 
   200 static D3DFORMAT
   201 PixelFormatToD3DFMT(Uint32 format)
   202 {
   203     switch (format) {
   204     case SDL_PixelFormat_Index8:
   205         return D3DFMT_P8;
   206     case SDL_PixelFormat_RGB332:
   207         return D3DFMT_R3G3B2;
   208     case SDL_PixelFormat_RGB444:
   209         return D3DFMT_X4R4G4B4;
   210     case SDL_PixelFormat_RGB555:
   211         return D3DFMT_X1R5G5B5;
   212     case SDL_PixelFormat_ARGB4444:
   213         return D3DFMT_A4R4G4B4;
   214     case SDL_PixelFormat_ARGB1555:
   215         return D3DFMT_A1R5G5B5;
   216     case SDL_PixelFormat_RGB565:
   217         return D3DFMT_R5G6B5;
   218     case SDL_PixelFormat_RGB888:
   219         return D3DFMT_X8R8G8B8;
   220     case SDL_PixelFormat_ARGB8888:
   221         return D3DFMT_A8R8G8B8;
   222     case SDL_PixelFormat_ARGB2101010:
   223         return D3DFMT_A2R10G10B10;
   224     case SDL_PixelFormat_UYVY:
   225         return D3DFMT_UYVY;
   226     case SDL_PixelFormat_YUY2:
   227         return D3DFMT_YUY2;
   228     default:
   229         return D3DFMT_UNKNOWN;
   230     }
   231 }
   232 
   233 void
   234 D3D_AddRenderDriver(_THIS)
   235 {
   236     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   237 
   238     if (data->d3d) {
   239         SDL_AddRenderDriver(0, &SDL_D3D_RenderDriver);
   240     }
   241 }
   242 
   243 SDL_Renderer *
   244 SDL_D3D_CreateRenderer(SDL_Window * window, Uint32 flags)
   245 {
   246     SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
   247     SDL_VideoData *videodata = (SDL_VideoData *) display->device->driverdata;
   248     SDL_WindowData *windowdata = (SDL_WindowData *) window->driverdata;
   249     SDL_Renderer *renderer;
   250     SDL_D3D_RenderData *data;
   251     HRESULT result;
   252     D3DPRESENT_PARAMETERS pparams;
   253 
   254     renderer = (SDL_Renderer *) SDL_malloc(sizeof(*renderer));
   255     if (!renderer) {
   256         SDL_OutOfMemory();
   257         return NULL;
   258     }
   259     SDL_zerop(renderer);
   260 
   261     data = (SDL_D3D_RenderData *) SDL_malloc(sizeof(*data));
   262     if (!data) {
   263         SDL_D3D_DestroyRenderer(renderer);
   264         SDL_OutOfMemory();
   265         return NULL;
   266     }
   267     SDL_zerop(data);
   268 
   269     renderer->CreateTexture = SDL_D3D_CreateTexture;
   270     renderer->SetTexturePalette = SDL_D3D_SetTexturePalette;
   271     renderer->GetTexturePalette = SDL_D3D_GetTexturePalette;
   272     renderer->UpdateTexture = SDL_D3D_UpdateTexture;
   273     renderer->LockTexture = SDL_D3D_LockTexture;
   274     renderer->UnlockTexture = SDL_D3D_UnlockTexture;
   275     renderer->DirtyTexture = SDL_D3D_DirtyTexture;
   276     renderer->SelectRenderTexture = SDL_D3D_SelectRenderTexture;
   277     renderer->RenderFill = SDL_D3D_RenderFill;
   278     renderer->RenderCopy = SDL_D3D_RenderCopy;
   279     renderer->RenderReadPixels = SDL_D3D_RenderReadPixels;
   280     renderer->RenderWritePixels = SDL_D3D_RenderWritePixels;
   281     renderer->RenderPresent = SDL_D3D_RenderPresent;
   282     renderer->DestroyTexture = SDL_D3D_DestroyTexture;
   283     renderer->DestroyRenderer = SDL_D3D_DestroyRenderer;
   284     renderer->info = SDL_D3D_RenderDriver.info;
   285     renderer->window = window->id;
   286     renderer->driverdata = data;
   287 
   288     renderer->info.flags = SDL_Renderer_RenderTarget;
   289 
   290     SDL_zero(pparams);
   291     pparams.BackBufferWidth = window->w;
   292     pparams.BackBufferHeight = window->h;
   293     if (window->flags & SDL_WINDOW_FULLSCREEN) {
   294         pparams.BackBufferFormat =
   295             PixelFormatToD3DFMT(display->fullscreen_mode->format);
   296     } else {
   297         pparams.BackBufferFormat = D3DFMT_UNKNOWN;
   298     }
   299     if (flags & SDL_Renderer_PresentFlip2) {
   300         pparams.BackBufferCount = 2;
   301         pparams.SwapEffect = D3DSWAPEFFECT_FLIP;
   302     } else if (flags & SDL_Renderer_PresentFlip3) {
   303         pparams.BackBufferCount = 3;
   304         pparams.SwapEffect = D3DSWAPEFFECT_FLIP;
   305     } else if (flags & SDL_Renderer_PresentCopy) {
   306         pparams.BackBufferCount = 1;
   307         pparams.SwapEffect = D3DSWAPEFFECT_COPY;
   308     } else {
   309         pparams.BackBufferCount = 1;
   310         pparams.SwapEffect = D3DSWAPEFFECT_DISCARD;
   311     }
   312     if (window->flags & SDL_WINDOW_FULLSCREEN) {
   313         pparams.Windowed = FALSE;
   314         pparams.FullScreen_RefreshRateInHz =
   315             display->fullscreen_mode->refresh_rate;
   316     } else {
   317         pparams.Windowed = TRUE;
   318         pparams.FullScreen_RefreshRateInHz = 0;
   319     }
   320     pparams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
   321 
   322     result = IDirect3D9_CreateDevice(videodata->d3d, D3DADAPTER_DEFAULT,        /* FIXME */
   323                                      D3DDEVTYPE_HAL,
   324                                      windowdata->hwnd,
   325                                      D3DCREATE_SOFTWARE_VERTEXPROCESSING,
   326                                      &pparams, &data->device);
   327     if (FAILED(result)) {
   328         SDL_D3D_DestroyRenderer(renderer);
   329         D3D_SetError("CreateDevice()", result);
   330         return NULL;
   331     }
   332     data->beginScene = SDL_TRUE;
   333 
   334     /* Set up parameters for rendering */
   335     IDirect3DDevice9_SetVertexShader(data->device, NULL);
   336     IDirect3DDevice9_SetFVF(data->device, D3DFVF_XYZRHW | D3DFVF_TEX1);
   337     IDirect3DDevice9_SetRenderState(data->device, D3DRS_CULLMODE,
   338                                     D3DCULL_NONE);
   339     IDirect3DDevice9_SetRenderState(data->device, D3DRS_LIGHTING, FALSE);
   340     IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
   341                                     TRUE);
   342     IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
   343                                     D3DBLEND_SRCALPHA);
   344     IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
   345                                     D3DBLEND_INVSRCALPHA);
   346 
   347     return renderer;
   348 }
   349 
   350 static int
   351 SDL_D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   352 {
   353     SDL_D3D_RenderData *renderdata =
   354         (SDL_D3D_RenderData *) renderer->driverdata;
   355     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   356     SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
   357     SDL_D3D_TextureData *data;
   358     D3DPOOL pool;
   359     HRESULT result;
   360 
   361     data = (SDL_D3D_TextureData *) SDL_malloc(sizeof(*data));
   362     if (!data) {
   363         SDL_OutOfMemory();
   364         return -1;
   365     }
   366     SDL_zerop(data);
   367 
   368     texture->driverdata = data;
   369 
   370     if (texture->access == SDL_TextureAccess_Local) {
   371         pool = D3DPOOL_MANAGED;
   372     } else {
   373         pool = D3DPOOL_DEFAULT;
   374     }
   375     result =
   376         IDirect3DDevice9_CreateTexture(renderdata->device, texture->w,
   377                                        texture->h, 1, 0,
   378                                        PixelFormatToD3DFMT(texture->format),
   379                                        pool, &data->texture, NULL);
   380     if (FAILED(result)) {
   381         SDL_free(data);
   382         D3D_SetError("CreateTexture()", result);
   383         return -1;
   384     }
   385 
   386     return 0;
   387 }
   388 
   389 static int
   390 SDL_D3D_SetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
   391                           const SDL_Color * colors, int firstcolor,
   392                           int ncolors)
   393 {
   394     SDL_D3D_RenderData *renderdata =
   395         (SDL_D3D_RenderData *) renderer->driverdata;
   396     SDL_D3D_TextureData *data = (SDL_D3D_TextureData *) texture->driverdata;
   397 
   398     return 0;
   399 }
   400 
   401 static int
   402 SDL_D3D_GetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
   403                           SDL_Color * colors, int firstcolor, int ncolors)
   404 {
   405     SDL_D3D_TextureData *data = (SDL_D3D_TextureData *) texture->driverdata;
   406 
   407     return 0;
   408 }
   409 
   410 static int
   411 SDL_D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   412                       const SDL_Rect * rect, const void *pixels, int pitch)
   413 {
   414     SDL_D3D_TextureData *data = (SDL_D3D_TextureData *) texture->driverdata;
   415     SDL_D3D_RenderData *renderdata =
   416         (SDL_D3D_RenderData *) renderer->driverdata;
   417     IDirect3DTexture9 *temp;
   418     RECT d3drect;
   419     D3DLOCKED_RECT locked;
   420     const Uint8 *src;
   421     Uint8 *dst;
   422     int row, length;
   423     HRESULT result;
   424 
   425     result =
   426         IDirect3DDevice9_CreateTexture(renderdata->device, texture->w,
   427                                        texture->h, 1, 0,
   428                                        PixelFormatToD3DFMT(texture->format),
   429                                        D3DPOOL_SYSTEMMEM, &temp, NULL);
   430     if (FAILED(result)) {
   431         D3D_SetError("CreateTexture()", result);
   432         return -1;
   433     }
   434 
   435     d3drect.left = rect->x;
   436     d3drect.right = rect->x + rect->w;
   437     d3drect.top = rect->y;
   438     d3drect.bottom = rect->y + rect->h;
   439 
   440     result = IDirect3DTexture9_LockRect(temp, 0, &locked, &d3drect, 0);
   441     if (FAILED(result)) {
   442         IDirect3DTexture9_Release(temp);
   443         D3D_SetError("LockRect()", result);
   444         return -1;
   445     }
   446 
   447     src = pixels;
   448     dst = locked.pBits;
   449     length = rect->w * SDL_BYTESPERPIXEL(texture->format);
   450     for (row = 0; row < rect->h; ++row) {
   451         SDL_memcpy(dst, src, length);
   452         src += pitch;
   453         dst += locked.Pitch;
   454     }
   455     IDirect3DTexture9_UnlockRect(temp, 0);
   456 
   457     result =
   458         IDirect3DDevice9_UpdateTexture(renderdata->device,
   459                                        (IDirect3DBaseTexture9 *) temp,
   460                                        (IDirect3DBaseTexture9 *) data->
   461                                        texture);
   462     IDirect3DTexture9_Release(temp);
   463     if (FAILED(result)) {
   464         D3D_SetError("UpdateTexture()", result);
   465         return -1;
   466     }
   467     return 0;
   468 }
   469 
   470 static int
   471 SDL_D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   472                     const SDL_Rect * rect, int markDirty, void **pixels,
   473                     int *pitch)
   474 {
   475     SDL_D3D_TextureData *data = (SDL_D3D_TextureData *) texture->driverdata;
   476     RECT d3drect;
   477     D3DLOCKED_RECT locked;
   478     HRESULT result;
   479 
   480     if (texture->access != SDL_TextureAccess_Local) {
   481         SDL_SetError("Can't lock remote video memory");
   482         return -1;
   483     }
   484 
   485     d3drect.left = rect->x;
   486     d3drect.right = rect->x + rect->w;
   487     d3drect.top = rect->y;
   488     d3drect.bottom = rect->y + rect->h;
   489 
   490     result =
   491         IDirect3DTexture9_LockRect(data->texture, 0, &locked, &d3drect,
   492                                    markDirty ? 0 : D3DLOCK_NO_DIRTY_UPDATE);
   493     if (FAILED(result)) {
   494         D3D_SetError("LockRect()", result);
   495         return -1;
   496     }
   497     *pixels = locked.pBits;
   498     *pitch = locked.Pitch;
   499     return 0;
   500 }
   501 
   502 static void
   503 SDL_D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   504 {
   505     SDL_D3D_TextureData *data = (SDL_D3D_TextureData *) texture->driverdata;
   506 
   507     IDirect3DTexture9_UnlockRect(data->texture, 0);
   508 }
   509 
   510 static void
   511 SDL_D3D_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   512                      int numrects, const SDL_Rect * rects)
   513 {
   514     SDL_D3D_TextureData *data = (SDL_D3D_TextureData *) texture->driverdata;
   515     RECT d3drect;
   516     int i;
   517 
   518     for (i = 0; i < numrects; ++i) {
   519         const SDL_Rect *rect = &rects[i];
   520 
   521         d3drect.left = rect->x;
   522         d3drect.right = rect->x + rect->w;
   523         d3drect.top = rect->y;
   524         d3drect.bottom = rect->y + rect->h;
   525 
   526         IDirect3DTexture9_AddDirtyRect(data->texture, &d3drect);
   527     }
   528 }
   529 
   530 static void
   531 SDL_D3D_SelectRenderTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   532 {
   533     SDL_D3D_RenderData *data = (SDL_D3D_RenderData *) renderer->driverdata;
   534 
   535     /* FIXME */
   536 }
   537 
   538 static int
   539 SDL_D3D_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect,
   540                    Uint32 color)
   541 {
   542     SDL_D3D_RenderData *data = (SDL_D3D_RenderData *) renderer->driverdata;
   543     D3DRECT d3drect;
   544     HRESULT result;
   545 
   546     if (data->beginScene) {
   547         IDirect3DDevice9_BeginScene(data->device);
   548         data->beginScene = SDL_FALSE;
   549     }
   550 
   551     d3drect.x1 = rect->x;
   552     d3drect.x2 = rect->x + rect->w;
   553     d3drect.y1 = rect->y;
   554     d3drect.y2 = rect->y + rect->h;
   555 
   556     result =
   557         IDirect3DDevice9_Clear(data->device, 1, &d3drect, D3DCLEAR_TARGET,
   558                                (D3DCOLOR) color, 1.0f, 0);
   559     if (FAILED(result)) {
   560         D3D_SetError("Clear()", result);
   561         return -1;
   562     }
   563     return 0;
   564 }
   565 
   566 static int
   567 SDL_D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   568                    const SDL_Rect * srcrect, const SDL_Rect * dstrect,
   569                    int blendMode, int scaleMode)
   570 {
   571     SDL_D3D_RenderData *data = (SDL_D3D_RenderData *) renderer->driverdata;
   572     SDL_D3D_TextureData *texturedata =
   573         (SDL_D3D_TextureData *) texture->driverdata;
   574     float minx, miny, maxx, maxy;
   575     float minu, maxu, minv, maxv;
   576     Vertex vertices[4];
   577     HRESULT result;
   578 
   579     if (data->beginScene) {
   580         IDirect3DDevice9_BeginScene(data->device);
   581         data->beginScene = SDL_FALSE;
   582     }
   583 
   584     minx = (float) dstrect->x - 0.5f;
   585     miny = (float) dstrect->y - 0.5f;
   586     maxx = (float) dstrect->x + dstrect->w - 0.5f;
   587     maxy = (float) dstrect->y + dstrect->h - 0.5f;
   588 
   589     minu = (float) srcrect->x / texture->w;
   590     maxu = (float) (srcrect->x + srcrect->w) / texture->w;
   591     minv = (float) srcrect->y / texture->h;
   592     maxv = (float) (srcrect->y + srcrect->h) / texture->h;
   593 
   594     vertices[0].x = minx;
   595     vertices[0].y = miny;
   596     vertices[0].z = 0.0f;
   597     vertices[0].rhw = 1.0f;
   598     vertices[0].u = minu;
   599     vertices[0].v = minv;
   600 
   601     vertices[1].x = maxx;
   602     vertices[1].y = miny;
   603     vertices[1].z = 0.0f;
   604     vertices[1].rhw = 1.0f;
   605     vertices[1].u = maxu;
   606     vertices[1].v = minv;
   607 
   608     vertices[2].x = maxx;
   609     vertices[2].y = maxy;
   610     vertices[2].z = 0.0f;
   611     vertices[2].rhw = 1.0f;
   612     vertices[2].u = maxu;
   613     vertices[2].v = maxv;
   614 
   615     vertices[3].x = minx;
   616     vertices[3].y = maxy;
   617     vertices[3].z = 0.0f;
   618     vertices[3].rhw = 1.0f;
   619     vertices[3].u = minu;
   620     vertices[3].v = maxv;
   621 
   622     result =
   623         IDirect3DDevice9_SetTexture(data->device, 0,
   624                                     (IDirect3DBaseTexture9 *) texturedata->
   625                                     texture);
   626     if (FAILED(result)) {
   627         D3D_SetError("SetTexture()", result);
   628         return -1;
   629     }
   630     result =
   631         IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2,
   632                                          vertices, sizeof(*vertices));
   633     if (FAILED(result)) {
   634         D3D_SetError("DrawPrimitiveUP()", result);
   635         return -1;
   636     }
   637     return 0;
   638 }
   639 
   640 static int
   641 SDL_D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
   642                          void *pixels, int pitch)
   643 {
   644     SDL_D3D_RenderData *data = (SDL_D3D_RenderData *) renderer->driverdata;
   645 
   646     /* FIXME */
   647     return 0;
   648 }
   649 
   650 static int
   651 SDL_D3D_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect,
   652                           const void *pixels, int pitch)
   653 {
   654     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   655     SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
   656     SDL_D3D_RenderData *data = (SDL_D3D_RenderData *) renderer->driverdata;
   657     RECT d3drect;
   658     POINT point;
   659     D3DLOCKED_RECT locked;
   660     const Uint8 *src;
   661     Uint8 *dst;
   662     int row, length;
   663     HRESULT result;
   664 
   665     if (!data->surface) {
   666         result =
   667             IDirect3DDevice9_GetBackBuffer(data->device, 0, 0,
   668                                            D3DBACKBUFFER_TYPE_MONO,
   669                                            &data->surface);
   670         if (FAILED(result)) {
   671             D3D_SetError("GetBackBuffer()", result);
   672             return -1;
   673         }
   674     }
   675     if (!data->offscreen) {
   676         result =
   677             IDirect3DDevice9_CreateOffscreenPlainSurface(data->device,
   678                                                          window->w, window->h,
   679                                                          PixelFormatToD3DFMT
   680                                                          (display->
   681                                                           current_mode.
   682                                                           format),
   683                                                          D3DPOOL_SYSTEMMEM,
   684                                                          &data->offscreen,
   685                                                          NULL);
   686         if (FAILED(result)) {
   687             D3D_SetError("CreateOffscreenPlainSurface()", result);
   688             return -1;
   689         }
   690     }
   691 
   692     d3drect.left = rect->x;
   693     d3drect.right = rect->x + rect->w;
   694     d3drect.top = rect->y;
   695     d3drect.bottom = rect->y + rect->h;
   696 
   697     result =
   698         IDirect3DSurface9_LockRect(data->offscreen, &locked, &d3drect, 0);
   699     if (FAILED(result)) {
   700         D3D_SetError("LockRect()", result);
   701         return -1;
   702     }
   703 
   704     src = pixels;
   705     dst = locked.pBits;
   706     length = rect->w * SDL_BYTESPERPIXEL(display->current_mode.format);
   707     for (row = 0; row < rect->h; ++row) {
   708         SDL_memcpy(dst, src, length);
   709         src += pitch;
   710         dst += locked.Pitch;
   711     }
   712     IDirect3DSurface9_UnlockRect(data->offscreen);
   713 
   714     point.x = rect->x;
   715     point.y = rect->y;
   716     result =
   717         IDirect3DDevice9_UpdateSurface(data->device, data->offscreen,
   718                                        &d3drect, data->surface, &point);
   719     if (FAILED(result)) {
   720         D3D_SetError("UpdateSurface()", result);
   721         return -1;
   722     }
   723 
   724     return 0;
   725 }
   726 
   727 static void
   728 SDL_D3D_RenderPresent(SDL_Renderer * renderer)
   729 {
   730     SDL_D3D_RenderData *data = (SDL_D3D_RenderData *) renderer->driverdata;
   731     HRESULT result;
   732 
   733     if (!data->beginScene) {
   734         IDirect3DDevice9_EndScene(data->device);
   735         data->beginScene = SDL_TRUE;
   736     }
   737 
   738     result = IDirect3DDevice9_Present(data->device, NULL, NULL, NULL, NULL);
   739     if (FAILED(result)) {
   740         D3D_SetError("Present()", result);
   741     }
   742 }
   743 
   744 static void
   745 SDL_D3D_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   746 {
   747     SDL_D3D_TextureData *data = (SDL_D3D_TextureData *) texture->driverdata;
   748 
   749     if (!data) {
   750         return;
   751     }
   752     if (data->texture) {
   753         IDirect3DTexture9_Release(data->texture);
   754     }
   755     SDL_free(data);
   756     texture->driverdata = NULL;
   757 }
   758 
   759 void
   760 SDL_D3D_DestroyRenderer(SDL_Renderer * renderer)
   761 {
   762     SDL_D3D_RenderData *data = (SDL_D3D_RenderData *) renderer->driverdata;
   763 
   764     if (data) {
   765         if (data->device) {
   766             IDirect3DDevice9_Release(data->device);
   767         }
   768         if (data->surface) {
   769             IDirect3DSurface9_Release(data->surface);
   770         }
   771         if (data->offscreen) {
   772             IDirect3DSurface9_Release(data->offscreen);
   773         }
   774         SDL_free(data);
   775     }
   776     SDL_free(renderer);
   777 }
   778 
   779 #endif /* SDL_VIDEO_RENDER_D3D */
   780 
   781 /* vi: set ts=4 sw=4 expandtab: */