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
IsBackBufferFormat(D3DFORMAT Format)14 BOOL IsBackBufferFormat(D3DFORMAT Format)
15 {
16 return ((Format >= D3DFMT_A8R8G8B8) && (Format < D3DFMT_A1R5G5B5)) ||
17 (IsExtendedFormat(Format));
18 }
19
IsExtendedFormat(D3DFORMAT Format)20 BOOL IsExtendedFormat(D3DFORMAT Format)
21 {
22 return (Format == D3DFMT_A2R10G10B10);
23 }
24
IsZBufferFormat(D3DFORMAT Format)25 BOOL IsZBufferFormat(D3DFORMAT Format)
26 {
27 UNIMPLEMENTED
28
29 return TRUE;
30 }
31
IsMultiElementFormat(D3DFORMAT Format)32 BOOL IsMultiElementFormat(D3DFORMAT Format)
33 {
34 return (Format == D3DFMT_MULTI2_ARGB8);
35 }
36
IsFourCCFormat(D3DFORMAT Format)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
IsStencilFormat(D3DFORMAT Format)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
GetBytesPerPixel(D3DFORMAT Format)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
GetPixelStride(D3DFORMAT Format)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
IsSupportedFormatOp(LPD3D9_DRIVERCAPS pDriverCaps,D3DFORMAT DisplayFormat,DWORD FormatOp)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
CheckDeviceType(LPD3D9_DRIVERCAPS pDriverCaps,D3DFORMAT DisplayFormat,D3DFORMAT BackBufferFormat,BOOL Windowed)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
GetStencilFormat(LPD3D9_DRIVERCAPS pDriverCaps,D3DFORMAT CheckFormat)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
RemoveAlphaChannel(D3DFORMAT CheckFormat)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
CheckDeviceFormat(LPD3D9_DRIVERCAPS pDriverCaps,D3DFORMAT AdapterFormat,DWORD Usage,D3DRESOURCETYPE RType,D3DFORMAT CheckFormat)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
CheckDeviceFormatConversion(LPD3D9_DRIVERCAPS pDriverCaps,D3DFORMAT SourceFormat,D3DFORMAT TargetFormat)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
CheckDepthStencilMatch(LPD3D9_DRIVERCAPS pDriverCaps,D3DFORMAT AdapterFormat,D3DFORMAT RenderTargetFormat,D3DFORMAT DepthStencilFormat)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