1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS ReactX 4 * FILE: dll/directx/d3d9/format.c 5 * PURPOSE: d3d9.dll D3DFORMAT helper functions 6 * PROGRAMERS: Gregor Brunmar <gregor (dot) brunmar (at) home (dot) se> 7 */ 8 9 #include "format.h" 10 #include <ddrawi.h> 11 #include <debug.h> 12 #include <d3d9types.h> 13 14 BOOL IsBackBufferFormat(D3DFORMAT Format) 15 { 16 return ((Format >= D3DFMT_A8R8G8B8) && (Format < D3DFMT_A1R5G5B5)) || 17 (IsExtendedFormat(Format)); 18 } 19 20 BOOL IsExtendedFormat(D3DFORMAT Format) 21 { 22 return (Format == D3DFMT_A2R10G10B10); 23 } 24 25 BOOL IsZBufferFormat(D3DFORMAT Format) 26 { 27 UNIMPLEMENTED 28 29 return TRUE; 30 } 31 32 BOOL IsMultiElementFormat(D3DFORMAT Format) 33 { 34 return (Format == D3DFMT_MULTI2_ARGB8); 35 } 36 37 BOOL IsFourCCFormat(D3DFORMAT Format) 38 { 39 CHAR* cFormat = (CHAR*)&Format; 40 if (isalnum(cFormat[0]) && 41 isalnum(cFormat[1]) && 42 isalnum(cFormat[2]) && 43 isalnum(cFormat[3])) 44 { 45 return TRUE; 46 } 47 48 return FALSE; 49 } 50 51 BOOL IsStencilFormat(D3DFORMAT Format) 52 { 53 switch (Format) 54 { 55 case D3DFMT_D15S1: 56 case D3DFMT_D24S8: 57 case D3DFMT_D24X4S4: 58 case D3DFMT_D24FS8: 59 return TRUE; 60 61 default: 62 return FALSE; 63 } 64 } 65 66 DWORD GetBytesPerPixel(D3DFORMAT Format) 67 { 68 switch (Format) 69 { 70 case D3DFMT_R3G3B2: 71 case D3DFMT_A8: 72 return 1; 73 74 case D3DFMT_R5G6B5: 75 case D3DFMT_X1R5G5B5: 76 case D3DFMT_A1R5G5B5: 77 case D3DFMT_A4R4G4B4: 78 case D3DFMT_A8R3G3B2: 79 case D3DFMT_X4R4G4B4: 80 return 2; 81 82 case D3DFMT_R8G8B8: 83 return 3; 84 85 case D3DFMT_A8R8G8B8: 86 case D3DFMT_X8R8G8B8: 87 case D3DFMT_A2B10G10R10: 88 case D3DFMT_A8B8G8R8: 89 case D3DFMT_X8B8G8R8: 90 case D3DFMT_G16R16: 91 case D3DFMT_A2R10G10B10: 92 return 4; 93 94 case D3DFMT_A16B16G16R16: 95 return 8; 96 97 98 case D3DFMT_P8: 99 case D3DFMT_L8: 100 case D3DFMT_A4L4: 101 return 1; 102 103 case D3DFMT_A8P8: 104 case D3DFMT_A8L8: 105 return 2; 106 107 108 case D3DFMT_V8U8: 109 case D3DFMT_L6V5U5: 110 return 2; 111 112 case D3DFMT_X8L8V8U8: 113 case D3DFMT_Q8W8V8U8: 114 case D3DFMT_V16U16: 115 case D3DFMT_A2W10V10U10: 116 return 4; 117 118 119 case D3DFMT_S8_LOCKABLE: 120 return 1; 121 122 case D3DFMT_D16_LOCKABLE: 123 case D3DFMT_D15S1: 124 case D3DFMT_D16: 125 return 2; 126 127 case D3DFMT_D32: 128 case D3DFMT_D24S8: 129 case D3DFMT_D24X8: 130 case D3DFMT_D24X4S4: 131 case D3DFMT_D32F_LOCKABLE: 132 case D3DFMT_D24FS8: 133 case D3DFMT_D32_LOCKABLE: 134 return 4; 135 136 137 case D3DFMT_L16: 138 return 2; 139 140 /* TODO: Handle D3DFMT_VERTEXDATA? */ 141 case D3DFMT_INDEX16: 142 return 2; 143 case D3DFMT_INDEX32: 144 return 4; 145 146 147 case D3DFMT_Q16W16V16U16: 148 return 8; 149 150 151 case D3DFMT_R16F: 152 return 2; 153 case D3DFMT_G16R16F: 154 return 4; 155 case D3DFMT_A16B16G16R16F: 156 return 8; 157 158 159 case D3DFMT_R32F: 160 return 4; 161 case D3DFMT_G32R32F: 162 return 8; 163 case D3DFMT_A32B32G32R32F: 164 return 16; 165 166 case D3DFMT_CxV8U8: 167 return 2; 168 169 170 /* Known FourCC formats */ 171 case D3DFMT_UYVY: 172 case D3DFMT_R8G8_B8G8: 173 case D3DFMT_YUY2: 174 case D3DFMT_G8R8_G8B8: 175 return 2; 176 177 case D3DFMT_DXT1: 178 return 0xFFFFFFF8; 179 180 case D3DFMT_DXT2: 181 case D3DFMT_DXT3: 182 case D3DFMT_DXT4: 183 case D3DFMT_DXT5: 184 return 0xFFFFFFF0; 185 186 case D3DFMT_MULTI2_ARGB8: 187 return 8; 188 189 default: 190 return 0; 191 } 192 } 193 194 DWORD GetPixelStride(D3DFORMAT Format) 195 { 196 DWORD Bpp = GetBytesPerPixel(Format); 197 198 if (0 == Bpp) 199 { 200 /* TODO: Handle unknown formats here */ 201 } 202 203 return Bpp; 204 } 205 206 BOOL IsSupportedFormatOp(LPD3D9_DRIVERCAPS pDriverCaps, D3DFORMAT DisplayFormat, DWORD FormatOp) 207 { 208 const DWORD NumFormatOps = pDriverCaps->NumSupportedFormatOps; 209 DWORD FormatOpIndex; 210 211 for (FormatOpIndex = 0; FormatOpIndex < NumFormatOps; FormatOpIndex++) 212 { 213 const LPDDSURFACEDESC pSurfaceDesc = &pDriverCaps->pSupportedFormatOps[FormatOpIndex]; 214 if (pSurfaceDesc->ddpfPixelFormat.dwFourCC == DisplayFormat && 215 (pSurfaceDesc->ddpfPixelFormat.dwOperations & FormatOp) == FormatOp) 216 { 217 return TRUE; 218 } 219 } 220 221 return FALSE; 222 } 223 224 HRESULT CheckDeviceType(LPD3D9_DRIVERCAPS pDriverCaps, D3DFORMAT DisplayFormat, D3DFORMAT BackBufferFormat, BOOL Windowed) 225 { 226 if (FALSE == IsSupportedFormatOp(pDriverCaps, DisplayFormat, D3DFORMAT_OP_DISPLAYMODE | D3DFORMAT_OP_3DACCELERATION)) 227 { 228 return D3DERR_NOTAVAILABLE; 229 } 230 231 if (DisplayFormat != BackBufferFormat) 232 { 233 D3DFORMAT AdjustedDisplayFormat = DisplayFormat; 234 235 if (DisplayFormat == D3DFMT_X8R8G8B8) 236 { 237 DisplayFormat = D3DFMT_A8R8G8B8; 238 } 239 else if (DisplayFormat == D3DFMT_X1R5G5B5) 240 { 241 DisplayFormat = D3DFMT_A1R5G5B5; 242 } 243 244 if (AdjustedDisplayFormat == BackBufferFormat) 245 { 246 if (FALSE == IsSupportedFormatOp(pDriverCaps, AdjustedDisplayFormat, D3DFORMAT_OP_SAME_FORMAT_UP_TO_ALPHA_RENDERTARGET)) 247 { 248 return D3DERR_NOTAVAILABLE; 249 } 250 251 return D3D_OK; 252 } 253 else if (FALSE == Windowed) 254 { 255 return D3DERR_NOTAVAILABLE; 256 } 257 258 if (FALSE == IsSupportedFormatOp(pDriverCaps, BackBufferFormat, D3DFORMAT_OP_OFFSCREEN_RENDERTARGET) || 259 FALSE == IsSupportedFormatOp(pDriverCaps, BackBufferFormat, D3DFORMAT_OP_CONVERT_TO_ARGB) || 260 FALSE == IsSupportedFormatOp(pDriverCaps, BackBufferFormat, D3DFORMAT_MEMBEROFGROUP_ARGB)) 261 { 262 return D3DERR_NOTAVAILABLE; 263 } 264 } 265 else 266 { 267 if (FALSE == IsSupportedFormatOp(pDriverCaps, DisplayFormat, D3DFORMAT_OP_SAME_FORMAT_RENDERTARGET)) 268 { 269 return D3DERR_NOTAVAILABLE; 270 } 271 } 272 273 return D3D_OK; 274 } 275 276 static D3DFORMAT GetStencilFormat(LPD3D9_DRIVERCAPS pDriverCaps, D3DFORMAT CheckFormat) 277 { 278 switch (CheckFormat) 279 { 280 case D3DFMT_D15S1: 281 case D3DFMT_D24S8: 282 case D3DFMT_D24X8: 283 case D3DFMT_D24X4S4: 284 if (IsSupportedFormatOp(pDriverCaps, CheckFormat - 1, 0)) 285 return CheckFormat - 1; 286 break; 287 288 case D3DFMT_D16: 289 if (IsSupportedFormatOp(pDriverCaps, CheckFormat, 0)) 290 return CheckFormat; 291 else 292 return D3DFMT_D16_LOCKABLE; 293 294 default: 295 /* StencilFormat same as CheckFormat */ 296 break; 297 } 298 299 return CheckFormat; 300 } 301 302 static D3DFORMAT RemoveAlphaChannel(D3DFORMAT CheckFormat) 303 { 304 switch (CheckFormat) 305 { 306 case D3DFMT_A8R8G8B8: 307 return D3DFMT_X8R8G8B8; 308 309 case D3DFMT_A1R5G5B5: 310 return D3DFMT_X1R5G5B5; 311 312 case D3DFMT_A4R4G4B4: 313 return D3DFMT_X4R4G4B4; 314 315 case D3DFMT_A8B8G8R8: 316 return D3DFMT_X8B8G8R8; 317 318 default: 319 /* CheckFormat has not relevant alpha channel */ 320 break; 321 } 322 323 return CheckFormat; 324 } 325 326 HRESULT CheckDeviceFormat(LPD3D9_DRIVERCAPS pDriverCaps, D3DFORMAT AdapterFormat, DWORD Usage, D3DRESOURCETYPE RType, D3DFORMAT CheckFormat) 327 { 328 const DWORD NumFormatOps = pDriverCaps->NumSupportedFormatOps; 329 DWORD NonCompatibleOperations = 0, MustSupportOperations = 0; 330 BOOL bSupportedWithAutogen = FALSE; 331 DWORD FormatOpIndex; 332 333 if (FALSE == IsSupportedFormatOp(pDriverCaps, AdapterFormat, D3DFORMAT_OP_DISPLAYMODE | D3DFORMAT_OP_3DACCELERATION)) 334 { 335 return D3DERR_NOTAVAILABLE; 336 } 337 338 /* Check for driver auto generated mip map support if requested */ 339 if ((Usage & (D3DUSAGE_AUTOGENMIPMAP)) != 0) 340 { 341 switch (RType) 342 { 343 case D3DRTYPE_TEXTURE: 344 if ((pDriverCaps->DriverCaps9.TextureCaps & D3DPTEXTURECAPS_MIPMAP) == 0) 345 return D3DERR_NOTAVAILABLE; 346 347 break; 348 349 case D3DRTYPE_VOLUME: 350 case D3DRTYPE_VOLUMETEXTURE: 351 if ((pDriverCaps->DriverCaps9.TextureCaps & D3DPTEXTURECAPS_MIPVOLUMEMAP) == 0) 352 return D3DERR_NOTAVAILABLE; 353 354 break; 355 356 case D3DRTYPE_CUBETEXTURE: 357 if ((pDriverCaps->DriverCaps9.TextureCaps & D3DPTEXTURECAPS_MIPCUBEMAP) == 0) 358 return D3DERR_NOTAVAILABLE; 359 360 break; 361 362 default: 363 /* Do nothing */ 364 break; 365 } 366 367 MustSupportOperations |= D3DFORMAT_OP_AUTOGENMIPMAP; 368 } 369 370 /* Translate from RType and Usage parameters to FormatOps */ 371 switch (RType) 372 { 373 case D3DRTYPE_TEXTURE: 374 MustSupportOperations |= D3DFORMAT_OP_TEXTURE; 375 break; 376 377 case D3DRTYPE_VOLUME: 378 case D3DRTYPE_VOLUMETEXTURE: 379 MustSupportOperations |= D3DFORMAT_OP_VOLUMETEXTURE; 380 break; 381 382 case D3DRTYPE_CUBETEXTURE: 383 MustSupportOperations |= D3DFORMAT_OP_CUBETEXTURE; 384 break; 385 386 default: 387 /* Do nothing */ 388 break; 389 } 390 391 if (Usage == 0 && RType == D3DRTYPE_SURFACE) 392 { 393 MustSupportOperations |= D3DFORMAT_OP_OFFSCREENPLAIN; 394 } 395 396 if ((Usage & D3DUSAGE_DEPTHSTENCIL) != 0) 397 { 398 MustSupportOperations |= D3DFORMAT_OP_ZSTENCIL; 399 } 400 401 if ((Usage & D3DUSAGE_DMAP) != 0) 402 { 403 MustSupportOperations |= D3DFORMAT_OP_DMAP; 404 } 405 406 if ((Usage & D3DUSAGE_QUERY_LEGACYBUMPMAP) != 0) 407 { 408 MustSupportOperations |= D3DFORMAT_OP_BUMPMAP; 409 } 410 411 if ((Usage & D3DUSAGE_QUERY_SRGBREAD) != 0) 412 { 413 MustSupportOperations |= D3DFORMAT_OP_SRGBREAD; 414 } 415 416 if ((Usage & D3DUSAGE_QUERY_SRGBWRITE) != 0) 417 { 418 MustSupportOperations |= D3DFORMAT_OP_SRGBWRITE; 419 } 420 421 if ((Usage & D3DUSAGE_QUERY_VERTEXTEXTURE) != 0) 422 { 423 MustSupportOperations |= D3DFORMAT_OP_VERTEXTEXTURE; 424 } 425 426 CheckFormat = GetStencilFormat(pDriverCaps, CheckFormat); 427 428 if ((Usage & D3DUSAGE_RENDERTARGET) != 0) 429 { 430 if (AdapterFormat == CheckFormat) 431 { 432 MustSupportOperations |= D3DFORMAT_OP_SAME_FORMAT_RENDERTARGET; 433 } 434 else 435 { 436 D3DFORMAT NonAlphaAdapterFormat; 437 D3DFORMAT NonAlphaCheckFormat; 438 439 NonAlphaAdapterFormat = RemoveAlphaChannel(AdapterFormat); 440 NonAlphaCheckFormat = RemoveAlphaChannel(CheckFormat); 441 442 if (NonAlphaAdapterFormat == NonAlphaCheckFormat && 443 NonAlphaCheckFormat != D3DFMT_UNKNOWN) 444 { 445 MustSupportOperations |= D3DFORMAT_OP_SAME_FORMAT_UP_TO_ALPHA_RENDERTARGET; 446 } 447 else 448 { 449 MustSupportOperations |= D3DFORMAT_OP_OFFSCREEN_RENDERTARGET; 450 } 451 } 452 } 453 454 if ((Usage & D3DUSAGE_QUERY_FILTER) != 0) 455 { 456 NonCompatibleOperations |= D3DFORMAT_OP_OFFSCREENPLAIN; 457 } 458 459 if ((Usage & D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING) != 0) 460 { 461 NonCompatibleOperations |= D3DFORMAT_OP_NOALPHABLEND; 462 } 463 464 if ((Usage & D3DUSAGE_QUERY_WRAPANDMIP) != 0) 465 { 466 NonCompatibleOperations |= D3DFORMAT_OP_NOTEXCOORDWRAPNORMIP; 467 } 468 469 for (FormatOpIndex = 0; FormatOpIndex < NumFormatOps; FormatOpIndex++) 470 { 471 DWORD dwOperations; 472 LPDDSURFACEDESC pSurfaceDesc = &pDriverCaps->pSupportedFormatOps[FormatOpIndex]; 473 474 if (pSurfaceDesc->ddpfPixelFormat.dwFourCC != CheckFormat) 475 continue; 476 477 dwOperations = pSurfaceDesc->ddpfPixelFormat.dwOperations; 478 479 if ((dwOperations & NonCompatibleOperations) != 0) 480 continue; 481 482 if ((dwOperations & MustSupportOperations) == MustSupportOperations) 483 return D3D_OK; 484 485 if (((dwOperations & MustSupportOperations) | D3DFORMAT_OP_AUTOGENMIPMAP) == MustSupportOperations) 486 bSupportedWithAutogen = TRUE; 487 } 488 489 if (TRUE == bSupportedWithAutogen) 490 return D3DOK_NOAUTOGEN; 491 492 return D3DERR_NOTAVAILABLE; 493 } 494 495 HRESULT CheckDeviceFormatConversion(LPD3D9_DRIVERCAPS pDriverCaps, D3DFORMAT SourceFormat, D3DFORMAT TargetFormat) 496 { 497 D3DFORMAT NonAlphaSourceFormat; 498 D3DFORMAT NonAlphaTargetFormat; 499 500 NonAlphaSourceFormat = RemoveAlphaChannel(SourceFormat); 501 NonAlphaTargetFormat = RemoveAlphaChannel(TargetFormat); 502 503 if (NonAlphaSourceFormat == NonAlphaTargetFormat) 504 { 505 return D3D_OK; 506 } 507 508 if (FALSE == IsFourCCFormat(SourceFormat)) 509 { 510 switch (SourceFormat) 511 { 512 case D3DFMT_A8R8G8B8: 513 case D3DFMT_X8R8G8B8: 514 case D3DFMT_R5G6B5: 515 case D3DFMT_X1R5G5B5: 516 case D3DFMT_A1R5G5B5: 517 case D3DFMT_A2R10G10B10: 518 /* Do nothing, valid SourceFormat */ 519 break; 520 521 default: 522 return D3DERR_NOTAVAILABLE; 523 } 524 } 525 else if (pDriverCaps->DriverCaps9.DevCaps2 == 0) 526 { 527 return D3D_OK; 528 } 529 530 if (FALSE == IsSupportedFormatOp(pDriverCaps, SourceFormat, D3DFORMAT_OP_CONVERT_TO_ARGB) || 531 FALSE == IsSupportedFormatOp(pDriverCaps, TargetFormat, D3DFORMAT_MEMBEROFGROUP_ARGB)) 532 { 533 return D3DERR_NOTAVAILABLE; 534 } 535 536 return D3D_OK; 537 } 538 539 HRESULT CheckDepthStencilMatch(LPD3D9_DRIVERCAPS pDriverCaps, D3DFORMAT AdapterFormat, D3DFORMAT RenderTargetFormat, D3DFORMAT DepthStencilFormat) 540 { 541 const DWORD NumFormatOps = pDriverCaps->NumSupportedFormatOps; 542 BOOL bRenderTargetAvailable = FALSE; 543 BOOL bDepthStencilAvailable = FALSE; 544 BOOL bForceSameDepthStencilBits = FALSE; 545 DWORD FormatIndex; 546 547 if (FALSE == IsSupportedFormatOp(pDriverCaps, AdapterFormat, D3DFORMAT_OP_DISPLAYMODE | D3DFORMAT_OP_3DACCELERATION)) 548 { 549 return D3DERR_NOTAVAILABLE; 550 } 551 552 if (DepthStencilFormat != D3DFMT_D16_LOCKABLE && 553 DepthStencilFormat != D3DFMT_D32F_LOCKABLE) 554 { 555 if (TRUE == IsStencilFormat(DepthStencilFormat)) 556 { 557 bForceSameDepthStencilBits = TRUE; 558 } 559 } 560 561 if (FALSE == bForceSameDepthStencilBits && 562 (DepthStencilFormat == D3DFMT_D32 || DepthStencilFormat == D3DFMT_D24X8)) 563 { 564 bForceSameDepthStencilBits = TRUE; 565 } 566 567 DepthStencilFormat = GetStencilFormat(pDriverCaps, DepthStencilFormat); 568 569 /* Observe the multiple conditions */ 570 for (FormatIndex = 0; FormatIndex < NumFormatOps && (bRenderTargetAvailable == FALSE || bDepthStencilAvailable == FALSE); FormatIndex++) 571 { 572 const LPDDSURFACEDESC pSurfaceDesc = &pDriverCaps->pSupportedFormatOps[FormatIndex]; 573 const DWORD FourCC = pSurfaceDesc->ddpfPixelFormat.dwFourCC; 574 const DWORD FormatOperations = pSurfaceDesc->ddpfPixelFormat.dwOperations; 575 576 if (FALSE == bRenderTargetAvailable && 577 FourCC == RenderTargetFormat && 578 (FormatOperations & D3DFORMAT_OP_SAME_FORMAT_RENDERTARGET) != 0) 579 { 580 bRenderTargetAvailable = TRUE; 581 } 582 583 if (FALSE == bDepthStencilAvailable && 584 FourCC == DepthStencilFormat && 585 (FormatOperations & D3DFORMAT_OP_ZSTENCIL) != 0) 586 { 587 bDepthStencilAvailable = TRUE; 588 589 if ((FormatOperations & D3DFORMAT_OP_ZSTENCIL_WITH_ARBITRARY_COLOR_DEPTH) != 0) 590 { 591 bForceSameDepthStencilBits = FALSE; 592 } 593 } 594 } 595 596 if (FALSE == bRenderTargetAvailable || FALSE == bDepthStencilAvailable) 597 { 598 return D3DERR_INVALIDCALL; 599 } 600 601 if (TRUE == bForceSameDepthStencilBits) 602 { 603 if (GetPixelStride(RenderTargetFormat) != GetPixelStride(DepthStencilFormat)) 604 return D3DERR_NOTAVAILABLE; 605 } 606 607 return D3D_OK; 608 } 609