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