src/video/win32/SDL_d3drender.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 28 Aug 2006 03:17:39 +0000
changeset 1985 8055185ae4ed
parent 1976 b1620a317791
child 1987 36a08379b3f2
permissions -rw-r--r--
Added source color and alpha modulation support.
Added perl script to generate optimized render copy functions.
     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_DisplayModeChanged(SDL_Renderer * renderer);
    32 static int D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    33 static int D3D_SetTexturePalette(SDL_Renderer * renderer,
    34                                  SDL_Texture * texture,
    35                                  const SDL_Color * colors, int firstcolor,
    36                                  int ncolors);
    37 static int D3D_GetTexturePalette(SDL_Renderer * renderer,
    38                                  SDL_Texture * texture, SDL_Color * colors,
    39                                  int firstcolor, int ncolors);
    40 static int D3D_SetTextureColorMod(SDL_Renderer * renderer,
    41                                   SDL_Texture * texture);
    42 static int D3D_SetTextureAlphaMod(SDL_Renderer * renderer,
    43                                   SDL_Texture * texture);
    44 static int D3D_SetTextureBlendMode(SDL_Renderer * renderer,
    45                                    SDL_Texture * texture);
    46 static int D3D_SetTextureScaleMode(SDL_Renderer * renderer,
    47                                    SDL_Texture * texture);
    48 static int D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    49                              const SDL_Rect * rect, const void *pixels,
    50                              int pitch);
    51 static int D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    52                            const SDL_Rect * rect, int markDirty,
    53                            void **pixels, int *pitch);
    54 static void D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    55 static void D3D_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    56                              int numrects, const SDL_Rect * rects);
    57 static int D3D_RenderFill(SDL_Renderer * renderer, Uint8 r, Uint8 g, Uint8 b,
    58                           Uint8 a, const SDL_Rect * rect);
    59 static int D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
    60                           const SDL_Rect * srcrect, const SDL_Rect * dstrect);
    61 static void D3D_RenderPresent(SDL_Renderer * renderer);
    62 static void D3D_DestroyTexture(SDL_Renderer * renderer,
    63                                SDL_Texture * texture);
    64 static void D3D_DestroyRenderer(SDL_Renderer * renderer);
    65 
    66 
    67 SDL_RenderDriver D3D_RenderDriver = {
    68     D3D_CreateRenderer,
    69     {
    70      "d3d",
    71      (SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_PRESENTCOPY |
    72       SDL_RENDERER_PRESENTFLIP2 | SDL_RENDERER_PRESENTFLIP3 |
    73       SDL_RENDERER_PRESENTDISCARD | SDL_RENDERER_PRESENTVSYNC |
    74       SDL_RENDERER_ACCELERATED),
    75      (SDL_TEXTUREMODULATE_NONE | SDL_TEXTUREMODULATE_COLOR |
    76       SDL_TEXTUREMODULATE_ALPHA),
    77      (SDL_TEXTUREBLENDMODE_NONE | SDL_TEXTUREBLENDMODE_MASK |
    78       SDL_TEXTUREBLENDMODE_BLEND | SDL_TEXTUREBLENDMODE_ADD |
    79       SDL_TEXTUREBLENDMODE_MOD),
    80      (SDL_TEXTURESCALEMODE_NONE | SDL_TEXTURESCALEMODE_FAST |
    81       SDL_TEXTURESCALEMODE_SLOW | SDL_TEXTURESCALEMODE_BEST),
    82      12,
    83      {
    84       SDL_PIXELFORMAT_INDEX8,
    85       SDL_PIXELFORMAT_RGB332,
    86       SDL_PIXELFORMAT_RGB444,
    87       SDL_PIXELFORMAT_RGB555,
    88       SDL_PIXELFORMAT_ARGB4444,
    89       SDL_PIXELFORMAT_ARGB1555,
    90       SDL_PIXELFORMAT_RGB565,
    91       SDL_PIXELFORMAT_RGB888,
    92       SDL_PIXELFORMAT_ARGB8888,
    93       SDL_PIXELFORMAT_ARGB2101010,
    94       SDL_PIXELFORMAT_UYVY,
    95       SDL_PIXELFORMAT_YUY2},
    96      0,
    97      0}
    98 };
    99 
   100 typedef struct
   101 {
   102     IDirect3DDevice9 *device;
   103     D3DPRESENT_PARAMETERS pparams;
   104     SDL_bool beginScene;
   105 } D3D_RenderData;
   106 
   107 typedef struct
   108 {
   109     IDirect3DTexture9 *texture;
   110 } D3D_TextureData;
   111 
   112 typedef struct
   113 {
   114     float x, y, z;
   115     float rhw;
   116     float u, v;
   117 } Vertex;
   118 
   119 static void
   120 D3D_SetError(const char *prefix, HRESULT result)
   121 {
   122     const char *error;
   123 
   124     switch (result) {
   125     case D3DERR_WRONGTEXTUREFORMAT:
   126         error = "WRONGTEXTUREFORMAT";
   127         break;
   128     case D3DERR_UNSUPPORTEDCOLOROPERATION:
   129         error = "UNSUPPORTEDCOLOROPERATION";
   130         break;
   131     case D3DERR_UNSUPPORTEDCOLORARG:
   132         error = "UNSUPPORTEDCOLORARG";
   133         break;
   134     case D3DERR_UNSUPPORTEDALPHAOPERATION:
   135         error = "UNSUPPORTEDALPHAOPERATION";
   136         break;
   137     case D3DERR_UNSUPPORTEDALPHAARG:
   138         error = "UNSUPPORTEDALPHAARG";
   139         break;
   140     case D3DERR_TOOMANYOPERATIONS:
   141         error = "TOOMANYOPERATIONS";
   142         break;
   143     case D3DERR_CONFLICTINGTEXTUREFILTER:
   144         error = "CONFLICTINGTEXTUREFILTER";
   145         break;
   146     case D3DERR_UNSUPPORTEDFACTORVALUE:
   147         error = "UNSUPPORTEDFACTORVALUE";
   148         break;
   149     case D3DERR_CONFLICTINGRENDERSTATE:
   150         error = "CONFLICTINGRENDERSTATE";
   151         break;
   152     case D3DERR_UNSUPPORTEDTEXTUREFILTER:
   153         error = "UNSUPPORTEDTEXTUREFILTER";
   154         break;
   155     case D3DERR_CONFLICTINGTEXTUREPALETTE:
   156         error = "CONFLICTINGTEXTUREPALETTE";
   157         break;
   158     case D3DERR_DRIVERINTERNALERROR:
   159         error = "DRIVERINTERNALERROR";
   160         break;
   161     case D3DERR_NOTFOUND:
   162         error = "NOTFOUND";
   163         break;
   164     case D3DERR_MOREDATA:
   165         error = "MOREDATA";
   166         break;
   167     case D3DERR_DEVICELOST:
   168         error = "DEVICELOST";
   169         break;
   170     case D3DERR_DEVICENOTRESET:
   171         error = "DEVICENOTRESET";
   172         break;
   173     case D3DERR_NOTAVAILABLE:
   174         error = "NOTAVAILABLE";
   175         break;
   176     case D3DERR_OUTOFVIDEOMEMORY:
   177         error = "OUTOFVIDEOMEMORY";
   178         break;
   179     case D3DERR_INVALIDDEVICE:
   180         error = "INVALIDDEVICE";
   181         break;
   182     case D3DERR_INVALIDCALL:
   183         error = "INVALIDCALL";
   184         break;
   185     case D3DERR_DRIVERINVALIDCALL:
   186         error = "DRIVERINVALIDCALL";
   187         break;
   188     case D3DERR_WASSTILLDRAWING:
   189         error = "WASSTILLDRAWING";
   190         break;
   191     default:
   192         error = "UNKNOWN";
   193         break;
   194     }
   195     SDL_SetError("%s: %s", prefix, error);
   196 }
   197 
   198 static D3DFORMAT
   199 PixelFormatToD3DFMT(Uint32 format)
   200 {
   201     switch (format) {
   202     case SDL_PIXELFORMAT_INDEX8:
   203         return D3DFMT_P8;
   204     case SDL_PIXELFORMAT_RGB332:
   205         return D3DFMT_R3G3B2;
   206     case SDL_PIXELFORMAT_RGB444:
   207         return D3DFMT_X4R4G4B4;
   208     case SDL_PIXELFORMAT_RGB555:
   209         return D3DFMT_X1R5G5B5;
   210     case SDL_PIXELFORMAT_ARGB4444:
   211         return D3DFMT_A4R4G4B4;
   212     case SDL_PIXELFORMAT_ARGB1555:
   213         return D3DFMT_A1R5G5B5;
   214     case SDL_PIXELFORMAT_RGB565:
   215         return D3DFMT_R5G6B5;
   216     case SDL_PIXELFORMAT_RGB888:
   217         return D3DFMT_X8R8G8B8;
   218     case SDL_PIXELFORMAT_ARGB8888:
   219         return D3DFMT_A8R8G8B8;
   220     case SDL_PIXELFORMAT_ARGB2101010:
   221         return D3DFMT_A2R10G10B10;
   222     case SDL_PIXELFORMAT_UYVY:
   223         return D3DFMT_UYVY;
   224     case SDL_PIXELFORMAT_YUY2:
   225         return D3DFMT_YUY2;
   226     default:
   227         return D3DFMT_UNKNOWN;
   228     }
   229 }
   230 
   231 void
   232 D3D_AddRenderDriver(_THIS)
   233 {
   234     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   235 
   236     if (data->d3d) {
   237         SDL_AddRenderDriver(0, &D3D_RenderDriver);
   238     }
   239 }
   240 
   241 SDL_Renderer *
   242 D3D_CreateRenderer(SDL_Window * window, Uint32 flags)
   243 {
   244     SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
   245     SDL_VideoData *videodata = (SDL_VideoData *) display->device->driverdata;
   246     SDL_WindowData *windowdata = (SDL_WindowData *) window->driverdata;
   247     SDL_Renderer *renderer;
   248     D3D_RenderData *data;
   249     HRESULT result;
   250     D3DPRESENT_PARAMETERS pparams;
   251     IDirect3DSwapChain9 *chain;
   252     D3DCAPS9 caps;
   253 
   254     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   255     if (!renderer) {
   256         SDL_OutOfMemory();
   257         return NULL;
   258     }
   259 
   260     data = (D3D_RenderData *) SDL_calloc(1, sizeof(*data));
   261     if (!data) {
   262         D3D_DestroyRenderer(renderer);
   263         SDL_OutOfMemory();
   264         return NULL;
   265     }
   266 
   267     renderer->DisplayModeChanged = D3D_DisplayModeChanged;
   268     renderer->CreateTexture = D3D_CreateTexture;
   269     renderer->SetTexturePalette = D3D_SetTexturePalette;
   270     renderer->GetTexturePalette = D3D_GetTexturePalette;
   271     renderer->SetTextureColorMod = D3D_SetTextureColorMod;
   272     renderer->SetTextureAlphaMod = D3D_SetTextureAlphaMod;
   273     renderer->SetTextureBlendMode = D3D_SetTextureBlendMode;
   274     renderer->SetTextureScaleMode = D3D_SetTextureScaleMode;
   275     renderer->UpdateTexture = D3D_UpdateTexture;
   276     renderer->LockTexture = D3D_LockTexture;
   277     renderer->UnlockTexture = D3D_UnlockTexture;
   278     renderer->DirtyTexture = D3D_DirtyTexture;
   279     renderer->RenderFill = D3D_RenderFill;
   280     renderer->RenderCopy = D3D_RenderCopy;
   281     renderer->RenderPresent = D3D_RenderPresent;
   282     renderer->DestroyTexture = D3D_DestroyTexture;
   283     renderer->DestroyRenderer = D3D_DestroyRenderer;
   284     renderer->info = D3D_RenderDriver.info;
   285     renderer->window = window->id;
   286     renderer->driverdata = data;
   287 
   288     renderer->info.flags = SDL_RENDERER_ACCELERATED;
   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     if (flags & SDL_RENDERER_PRESENTVSYNC) {
   321         pparams.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
   322     } else {
   323         pparams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
   324     }
   325 
   326     result = IDirect3D9_CreateDevice(videodata->d3d, D3DADAPTER_DEFAULT,        /* FIXME */
   327                                      D3DDEVTYPE_HAL,
   328                                      windowdata->hwnd,
   329                                      D3DCREATE_SOFTWARE_VERTEXPROCESSING,
   330                                      &pparams, &data->device);
   331     if (FAILED(result)) {
   332         D3D_DestroyRenderer(renderer);
   333         D3D_SetError("CreateDevice()", result);
   334         return NULL;
   335     }
   336     data->beginScene = SDL_TRUE;
   337 
   338     /* Get presentation parameters to fill info */
   339     result = IDirect3DDevice9_GetSwapChain(data->device, 0, &chain);
   340     if (FAILED(result)) {
   341         D3D_DestroyRenderer(renderer);
   342         D3D_SetError("GetSwapChain()", result);
   343         return NULL;
   344     }
   345     result = IDirect3DSwapChain9_GetPresentParameters(chain, &pparams);
   346     if (FAILED(result)) {
   347         IDirect3DSwapChain9_Release(chain);
   348         D3D_DestroyRenderer(renderer);
   349         D3D_SetError("GetPresentParameters()", result);
   350         return NULL;
   351     }
   352     IDirect3DSwapChain9_Release(chain);
   353     switch (pparams.SwapEffect) {
   354     case D3DSWAPEFFECT_COPY:
   355         renderer->info.flags |= SDL_RENDERER_PRESENTCOPY;
   356         break;
   357     case D3DSWAPEFFECT_FLIP:
   358         switch (pparams.BackBufferCount) {
   359         case 2:
   360             renderer->info.flags |= SDL_RENDERER_PRESENTFLIP2;
   361             break;
   362         case 3:
   363             renderer->info.flags |= SDL_RENDERER_PRESENTFLIP3;
   364             break;
   365         }
   366         break;
   367     case D3DSWAPEFFECT_DISCARD:
   368         renderer->info.flags |= SDL_RENDERER_PRESENTDISCARD;
   369         break;
   370     }
   371     if (pparams.PresentationInterval == D3DPRESENT_INTERVAL_ONE) {
   372         renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
   373     }
   374     data->pparams = pparams;
   375 
   376     IDirect3DDevice9_GetDeviceCaps(data->device, &caps);
   377     renderer->info.max_texture_width = caps.MaxTextureWidth;
   378     renderer->info.max_texture_height = caps.MaxTextureHeight;
   379 
   380     /* Set up parameters for rendering */
   381     IDirect3DDevice9_SetVertexShader(data->device, NULL);
   382     IDirect3DDevice9_SetFVF(data->device, D3DFVF_XYZRHW | D3DFVF_TEX1);
   383     IDirect3DDevice9_SetRenderState(data->device, D3DRS_CULLMODE,
   384                                     D3DCULL_NONE);
   385     IDirect3DDevice9_SetRenderState(data->device, D3DRS_LIGHTING, FALSE);
   386 
   387     return renderer;
   388 }
   389 
   390 static int
   391 D3D_Reset(SDL_Renderer * renderer)
   392 {
   393     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   394     HRESULT result;
   395 
   396     result = IDirect3DDevice9_Reset(data->device, &data->pparams);
   397     if (FAILED(result)) {
   398         if (result == D3DERR_DEVICELOST) {
   399             /* Don't worry about it, we'll reset later... */
   400             return 0;
   401         } else {
   402             D3D_SetError("Reset()", result);
   403             return -1;
   404         }
   405     }
   406     IDirect3DDevice9_SetVertexShader(data->device, NULL);
   407     IDirect3DDevice9_SetFVF(data->device, D3DFVF_XYZRHW | D3DFVF_TEX1);
   408     IDirect3DDevice9_SetRenderState(data->device, D3DRS_CULLMODE,
   409                                     D3DCULL_NONE);
   410     IDirect3DDevice9_SetRenderState(data->device, D3DRS_LIGHTING, FALSE);
   411     return 0;
   412 }
   413 
   414 static int
   415 D3D_DisplayModeChanged(SDL_Renderer * renderer)
   416 {
   417     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   418     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   419     SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
   420 
   421     data->pparams.BackBufferWidth = window->w;
   422     data->pparams.BackBufferHeight = window->h;
   423     if (window->flags & SDL_WINDOW_FULLSCREEN) {
   424         data->pparams.BackBufferFormat =
   425             PixelFormatToD3DFMT(display->fullscreen_mode.format);
   426     } else {
   427         data->pparams.BackBufferFormat = D3DFMT_UNKNOWN;
   428     }
   429     return D3D_Reset(renderer);
   430 }
   431 
   432 static int
   433 D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   434 {
   435     D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata;
   436     SDL_Window *window = SDL_GetWindowFromID(renderer->window);
   437     SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
   438     D3D_TextureData *data;
   439     D3DPOOL pool;
   440     HRESULT result;
   441 
   442     data = (D3D_TextureData *) SDL_calloc(1, sizeof(*data));
   443     if (!data) {
   444         SDL_OutOfMemory();
   445         return -1;
   446     }
   447 
   448     texture->driverdata = data;
   449 
   450 #if 1
   451     /* FIXME: Do we want non-managed textures?
   452        They need to be freed on device reset and then reloaded by the app...
   453      */
   454     texture->access = SDL_TEXTUREACCESS_LOCAL;
   455 #endif
   456     if (texture->access == SDL_TEXTUREACCESS_LOCAL) {
   457         pool = D3DPOOL_MANAGED;
   458     } else {
   459         pool = D3DPOOL_DEFAULT;
   460     }
   461     result =
   462         IDirect3DDevice9_CreateTexture(renderdata->device, texture->w,
   463                                        texture->h, 1, 0,
   464                                        PixelFormatToD3DFMT(texture->format),
   465                                        pool, &data->texture, NULL);
   466     if (FAILED(result)) {
   467         D3D_SetError("CreateTexture()", result);
   468         return -1;
   469     }
   470 
   471     return 0;
   472 }
   473 
   474 static int
   475 D3D_SetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
   476                       const SDL_Color * colors, int firstcolor, int ncolors)
   477 {
   478     D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata;
   479     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
   480 
   481     return 0;
   482 }
   483 
   484 static int
   485 D3D_GetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
   486                       SDL_Color * colors, int firstcolor, int ncolors)
   487 {
   488     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
   489 
   490     return 0;
   491 }
   492 
   493 static int
   494 D3D_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture)
   495 {
   496     /* FIXME: implement vertex coloring */
   497     return -1;
   498 }
   499 
   500 static int
   501 D3D_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture)
   502 {
   503     /* FIXME: implement vertex coloring */
   504     return -1;
   505 }
   506 
   507 static int
   508 D3D_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture)
   509 {
   510     switch (texture->blendMode) {
   511     case SDL_TEXTUREBLENDMODE_NONE:
   512     case SDL_TEXTUREBLENDMODE_MASK:
   513     case SDL_TEXTUREBLENDMODE_BLEND:
   514     case SDL_TEXTUREBLENDMODE_ADD:
   515     case SDL_TEXTUREBLENDMODE_MOD:
   516         return 0;
   517     default:
   518         SDL_Unsupported();
   519         texture->blendMode = SDL_TEXTUREBLENDMODE_NONE;
   520         return -1;
   521     }
   522 }
   523 
   524 static int
   525 D3D_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture)
   526 {
   527     switch (texture->scaleMode) {
   528     case SDL_TEXTURESCALEMODE_NONE:
   529     case SDL_TEXTURESCALEMODE_FAST:
   530     case SDL_TEXTURESCALEMODE_SLOW:
   531     case SDL_TEXTURESCALEMODE_BEST:
   532         return 0;
   533     default:
   534         SDL_Unsupported();
   535         texture->scaleMode = SDL_TEXTURESCALEMODE_NONE;
   536         return -1;
   537     }
   538     return 0;
   539 }
   540 
   541 static int
   542 D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   543                   const SDL_Rect * rect, const void *pixels, int pitch)
   544 {
   545     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
   546     D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata;
   547     IDirect3DTexture9 *temp;
   548     RECT d3drect;
   549     D3DLOCKED_RECT locked;
   550     const Uint8 *src;
   551     Uint8 *dst;
   552     int row, length;
   553     HRESULT result;
   554 
   555     result =
   556         IDirect3DDevice9_CreateTexture(renderdata->device, texture->w,
   557                                        texture->h, 1, 0,
   558                                        PixelFormatToD3DFMT(texture->format),
   559                                        D3DPOOL_SYSTEMMEM, &temp, NULL);
   560     if (FAILED(result)) {
   561         D3D_SetError("CreateTexture()", result);
   562         return -1;
   563     }
   564 
   565     d3drect.left = rect->x;
   566     d3drect.right = rect->x + rect->w;
   567     d3drect.top = rect->y;
   568     d3drect.bottom = rect->y + rect->h;
   569 
   570     result = IDirect3DTexture9_LockRect(temp, 0, &locked, &d3drect, 0);
   571     if (FAILED(result)) {
   572         IDirect3DTexture9_Release(temp);
   573         D3D_SetError("LockRect()", result);
   574         return -1;
   575     }
   576 
   577     src = pixels;
   578     dst = locked.pBits;
   579     length = rect->w * SDL_BYTESPERPIXEL(texture->format);
   580     for (row = 0; row < rect->h; ++row) {
   581         SDL_memcpy(dst, src, length);
   582         src += pitch;
   583         dst += locked.Pitch;
   584     }
   585     IDirect3DTexture9_UnlockRect(temp, 0);
   586 
   587     result =
   588         IDirect3DDevice9_UpdateTexture(renderdata->device,
   589                                        (IDirect3DBaseTexture9 *) temp,
   590                                        (IDirect3DBaseTexture9 *) data->
   591                                        texture);
   592     IDirect3DTexture9_Release(temp);
   593     if (FAILED(result)) {
   594         D3D_SetError("UpdateTexture()", result);
   595         return -1;
   596     }
   597     return 0;
   598 }
   599 
   600 static int
   601 D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   602                 const SDL_Rect * rect, int markDirty, void **pixels,
   603                 int *pitch)
   604 {
   605     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
   606     RECT d3drect;
   607     D3DLOCKED_RECT locked;
   608     HRESULT result;
   609 
   610     if (texture->access != SDL_TEXTUREACCESS_LOCAL) {
   611         SDL_SetError("Can't lock remote video memory");
   612         return -1;
   613     }
   614 
   615     d3drect.left = rect->x;
   616     d3drect.right = rect->x + rect->w;
   617     d3drect.top = rect->y;
   618     d3drect.bottom = rect->y + rect->h;
   619 
   620     result =
   621         IDirect3DTexture9_LockRect(data->texture, 0, &locked, &d3drect,
   622                                    markDirty ? 0 : D3DLOCK_NO_DIRTY_UPDATE);
   623     if (FAILED(result)) {
   624         D3D_SetError("LockRect()", result);
   625         return -1;
   626     }
   627     *pixels = locked.pBits;
   628     *pitch = locked.Pitch;
   629     return 0;
   630 }
   631 
   632 static void
   633 D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   634 {
   635     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
   636 
   637     IDirect3DTexture9_UnlockRect(data->texture, 0);
   638 }
   639 
   640 static void
   641 D3D_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture, int numrects,
   642                  const SDL_Rect * rects)
   643 {
   644     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
   645     RECT d3drect;
   646     int i;
   647 
   648     for (i = 0; i < numrects; ++i) {
   649         const SDL_Rect *rect = &rects[i];
   650 
   651         d3drect.left = rect->x;
   652         d3drect.right = rect->x + rect->w;
   653         d3drect.top = rect->y;
   654         d3drect.bottom = rect->y + rect->h;
   655 
   656         IDirect3DTexture9_AddDirtyRect(data->texture, &d3drect);
   657     }
   658 }
   659 
   660 static int
   661 D3D_RenderFill(SDL_Renderer * renderer, Uint8 r, Uint8 g, Uint8 b, Uint8 a,
   662                const SDL_Rect * rect)
   663 {
   664     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   665     D3DRECT d3drect;
   666     HRESULT result;
   667 
   668     if (data->beginScene) {
   669         IDirect3DDevice9_BeginScene(data->device);
   670         data->beginScene = SDL_FALSE;
   671     }
   672 
   673     d3drect.x1 = rect->x;
   674     d3drect.x2 = rect->x + rect->w;
   675     d3drect.y1 = rect->y;
   676     d3drect.y2 = rect->y + rect->h;
   677 
   678     result =
   679         IDirect3DDevice9_Clear(data->device, 1, &d3drect, D3DCLEAR_TARGET,
   680                                D3DCOLOR_ARGB(a, r, g, b), 1.0f, 0);
   681     if (FAILED(result)) {
   682         D3D_SetError("Clear()", result);
   683         return -1;
   684     }
   685     return 0;
   686 }
   687 
   688 static int
   689 D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   690                const SDL_Rect * srcrect, const SDL_Rect * dstrect)
   691 {
   692     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   693     D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata;
   694     float minx, miny, maxx, maxy;
   695     float minu, maxu, minv, maxv;
   696     Vertex vertices[4];
   697     HRESULT result;
   698 
   699     if (data->beginScene) {
   700         IDirect3DDevice9_BeginScene(data->device);
   701         data->beginScene = SDL_FALSE;
   702     }
   703 
   704     minx = (float) dstrect->x - 0.5f;
   705     miny = (float) dstrect->y - 0.5f;
   706     maxx = (float) dstrect->x + dstrect->w - 0.5f;
   707     maxy = (float) dstrect->y + dstrect->h - 0.5f;
   708 
   709     minu = (float) srcrect->x / texture->w;
   710     maxu = (float) (srcrect->x + srcrect->w) / texture->w;
   711     minv = (float) srcrect->y / texture->h;
   712     maxv = (float) (srcrect->y + srcrect->h) / texture->h;
   713 
   714     vertices[0].x = minx;
   715     vertices[0].y = miny;
   716     vertices[0].z = 0.0f;
   717     vertices[0].rhw = 1.0f;
   718     vertices[0].u = minu;
   719     vertices[0].v = minv;
   720 
   721     vertices[1].x = maxx;
   722     vertices[1].y = miny;
   723     vertices[1].z = 0.0f;
   724     vertices[1].rhw = 1.0f;
   725     vertices[1].u = maxu;
   726     vertices[1].v = minv;
   727 
   728     vertices[2].x = maxx;
   729     vertices[2].y = maxy;
   730     vertices[2].z = 0.0f;
   731     vertices[2].rhw = 1.0f;
   732     vertices[2].u = maxu;
   733     vertices[2].v = maxv;
   734 
   735     vertices[3].x = minx;
   736     vertices[3].y = maxy;
   737     vertices[3].z = 0.0f;
   738     vertices[3].rhw = 1.0f;
   739     vertices[3].u = minu;
   740     vertices[3].v = maxv;
   741 
   742     switch (texture->blendMode) {
   743     case SDL_TEXTUREBLENDMODE_NONE:
   744         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
   745                                         FALSE);
   746         break;
   747     case SDL_TEXTUREBLENDMODE_MASK:
   748     case SDL_TEXTUREBLENDMODE_BLEND:
   749         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
   750                                         TRUE);
   751         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
   752                                         D3DBLEND_SRCALPHA);
   753         IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
   754                                         D3DBLEND_INVSRCALPHA);
   755         break;
   756     case SDL_TEXTUREBLENDMODE_ADD:
   757         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
   758                                         TRUE);
   759         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
   760                                         D3DBLEND_SRCALPHA);
   761         IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
   762                                         D3DBLEND_ONE);
   763         break;
   764     case SDL_TEXTUREBLENDMODE_MOD:
   765         IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
   766                                         TRUE);
   767         IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
   768                                         D3DBLEND_ZERO);
   769         IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
   770                                         D3DBLEND_SRCCOLOR);
   771         break;
   772     }
   773 
   774     switch (texture->scaleMode) {
   775     case SDL_TEXTURESCALEMODE_NONE:
   776     case SDL_TEXTURESCALEMODE_FAST:
   777         IDirect3DDevice9_SetSamplerState(data->device, 0, D3DSAMP_MINFILTER,
   778                                          D3DTEXF_POINT);
   779         IDirect3DDevice9_SetSamplerState(data->device, 0, D3DSAMP_MAGFILTER,
   780                                          D3DTEXF_POINT);
   781         break;
   782     case SDL_TEXTURESCALEMODE_SLOW:
   783         IDirect3DDevice9_SetSamplerState(data->device, 0, D3DSAMP_MINFILTER,
   784                                          D3DTEXF_LINEAR);
   785         IDirect3DDevice9_SetSamplerState(data->device, 0, D3DSAMP_MAGFILTER,
   786                                          D3DTEXF_LINEAR);
   787         break;
   788     case SDL_TEXTURESCALEMODE_BEST:
   789         IDirect3DDevice9_SetSamplerState(data->device, 0, D3DSAMP_MINFILTER,
   790                                          D3DTEXF_GAUSSIANQUAD);
   791         IDirect3DDevice9_SetSamplerState(data->device, 0, D3DSAMP_MAGFILTER,
   792                                          D3DTEXF_GAUSSIANQUAD);
   793         break;
   794     }
   795 
   796     result =
   797         IDirect3DDevice9_SetTexture(data->device, 0,
   798                                     (IDirect3DBaseTexture9 *) texturedata->
   799                                     texture);
   800     if (FAILED(result)) {
   801         D3D_SetError("SetTexture()", result);
   802         return -1;
   803     }
   804     result =
   805         IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2,
   806                                          vertices, sizeof(*vertices));
   807     if (FAILED(result)) {
   808         D3D_SetError("DrawPrimitiveUP()", result);
   809         return -1;
   810     }
   811     return 0;
   812 }
   813 
   814 static void
   815 D3D_RenderPresent(SDL_Renderer * renderer)
   816 {
   817     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   818     HRESULT result;
   819 
   820     if (!data->beginScene) {
   821         IDirect3DDevice9_EndScene(data->device);
   822         data->beginScene = SDL_TRUE;
   823     }
   824 
   825     result = IDirect3DDevice9_TestCooperativeLevel(data->device);
   826     if (result == D3DERR_DEVICELOST) {
   827         /* We'll reset later */
   828         return;
   829     }
   830     if (result == D3DERR_DEVICENOTRESET) {
   831         D3D_Reset(renderer);
   832     }
   833     result = IDirect3DDevice9_Present(data->device, NULL, NULL, NULL, NULL);
   834     if (FAILED(result)) {
   835         D3D_SetError("Present()", result);
   836     }
   837 }
   838 
   839 static void
   840 D3D_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   841 {
   842     D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
   843 
   844     if (!data) {
   845         return;
   846     }
   847     if (data->texture) {
   848         IDirect3DTexture9_Release(data->texture);
   849     }
   850     SDL_free(data);
   851     texture->driverdata = NULL;
   852 }
   853 
   854 static void
   855 D3D_DestroyRenderer(SDL_Renderer * renderer)
   856 {
   857     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   858 
   859     if (data) {
   860         if (data->device) {
   861             IDirect3DDevice9_Release(data->device);
   862         }
   863         SDL_free(data);
   864     }
   865     SDL_free(renderer);
   866 }
   867 
   868 #endif /* SDL_VIDEO_RENDER_D3D */
   869 
   870 /* vi: set ts=4 sw=4 expandtab: */