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