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