xref: /reactos/dll/directx/d3d9/format.c (revision 84344399)
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