Panda3D
Loading...
Searching...
No Matches
wdxGraphicsPipe9.cxx
Go to the documentation of this file.
1/**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file wdxGraphicsPipe9.cxx
10 * @author drose
11 * @date 2002-12-20
12 */
13
14#include "wdxGraphicsPipe9.h"
15#include "dxGraphicsDevice9.h"
16#include "wdxGraphicsWindow9.h"
17#include "wdxGraphicsBuffer9.h"
18#include "config_dxgsg9.h"
19
20using std::endl;
21
22TypeHandle wdxGraphicsPipe9::_type_handle;
23
24static bool MyGetProcAddr(HINSTANCE hDLL, FARPROC *pFn, const char *szExportedFnName) {
25 *pFn = (FARPROC) GetProcAddress(hDLL, szExportedFnName);
26 if (*pFn == nullptr) {
27 wdxdisplay9_cat.error()
28 << "GetProcAddr failed for " << szExportedFnName << ", error=" << GetLastError() <<endl;
29 return false;
30 }
31 return true;
32}
33
34#define LOWVIDMEMTHRESHOLD 5700000 // 4MB cards should fall below this
35#define CRAPPY_DRIVER_IS_LYING_VIDMEMTHRESHOLD 1000000 // if # is > 1MB, card is lying and I cant tell what it is
36#define UNKNOWN_VIDMEM_SIZE 0xFFFFFFFF
37
38/**
39 *
40 */
41wdxGraphicsPipe9::
42wdxGraphicsPipe9() {
43 _hDDrawDLL = nullptr;
44 _hD3D9_DLL = nullptr;
45 __d3d9 = nullptr;
46 _is_valid = init();
47}
48
49/**
50 *
51 */
52wdxGraphicsPipe9::
53~wdxGraphicsPipe9() {
54 RELEASE(__d3d9, wdxdisplay9, "ID3D9", RELEASE_DOWN_TO_ZERO);
55 SAFE_FREELIB(_hD3D9_DLL);
56 SAFE_FREELIB(_hDDrawDLL);
57}
58
59/**
60 * Returns the name of the rendering interface associated with this
61 * GraphicsPipe. This is used to present to the user to allow him/her to
62 * choose between several possible GraphicsPipes available on a particular
63 * platform, so the name should be meaningful and unique for a given platform.
64 */
66get_interface_name() const {
67 return "DirectX9";
68}
69
70/**
71 * This function is passed to the GraphicsPipeSelection object to allow the
72 * user to make a default wdxGraphicsPipe9.
73 */
74PT(GraphicsPipe) wdxGraphicsPipe9::
75pipe_constructor() {
76 return new wdxGraphicsPipe9;
77}
78
79/**
80 * Creates a new window on the pipe, if possible.
81 */
82PT(GraphicsOutput) wdxGraphicsPipe9::
83make_output(const std::string &name,
84 const FrameBufferProperties &fb_prop,
85 const WindowProperties &win_prop,
86 int flags,
87 GraphicsEngine *engine,
89 GraphicsOutput *host,
90 int retry,
91 bool &precertify) {
92
93 if (!_is_valid) {
94 return nullptr;
95 }
96
97 DXGraphicsStateGuardian9 *wdxgsg = 0;
98 if (gsg != 0) {
99 DCAST_INTO_R(wdxgsg, gsg, nullptr);
100 }
101
102 // First thing to try: a visible window.
103
104 if (retry == 0) {
105 if (((flags&BF_require_parasite)!=0)||
106 ((flags&BF_refuse_window)!=0)||
107 ((flags&BF_resizeable)!=0)||
108 ((flags&BF_size_track_host)!=0)||
109 ((flags&BF_rtt_cumulative)!=0)||
110 ((flags&BF_can_bind_color)!=0)||
111 ((flags&BF_can_bind_every)!=0)) {
112 return nullptr;
113 }
114 // Early failure - if we are sure that this buffer WONT meet specs, we can
115 // bail out early.
116 if ((flags & BF_fb_props_optional) == 0) {
117 if ((fb_prop.get_aux_rgba() > 0)||
118 (fb_prop.get_aux_rgba() > 0)||
119 (fb_prop.get_aux_float() > 0)) {
120 return nullptr;
121 }
122 }
123 return new wdxGraphicsWindow9(engine, this, name, fb_prop, win_prop,
124 flags, gsg, host);
125 }
126
127 // Second thing to try: a wdxGraphicsBuffer9
128
129 if (retry == 1) {
130 if ((!support_render_texture)||
131 ((flags&BF_require_parasite)!=0)||
132 ((flags&BF_require_window)!=0)||
133 ((flags&BF_rtt_cumulative)!=0)||
134 ((flags&BF_can_bind_every)!=0)) {
135 return nullptr;
136 }
137 // Early failure - if we are sure that this buffer WONT meet specs, we can
138 // bail out early.
139 if ((flags & BF_fb_props_optional) == 0) {
140 if (fb_prop.get_indexed_color() ||
141 (fb_prop.get_back_buffers() > 0)||
142 (fb_prop.get_accum_bits() > 0)||
143 (fb_prop.get_multisamples() > 0)) {
144 return nullptr;
145 }
146 }
147
148 // Early success - if we are sure that this buffer WILL meet specs, we can
149 // precertify it. This looks rather overly optimistic -- ie, buggy.
150 if ((wdxgsg != nullptr) && wdxgsg->is_valid() && !wdxgsg->needs_reset() &&
151 wdxgsg->get_supports_render_texture()) {
152 precertify = true;
153 }
154 return new wdxGraphicsBuffer9(engine, this, name, fb_prop, win_prop,
155 flags, gsg, host);
156 }
157
158 // Nothing else left to try.
159 return nullptr;
160}
161
162/**
163 * Performs some initialization steps to load up function pointers from the
164 * relevant DLL's, and determine the number and type of available graphics
165 * adapters, etc. Returns true on success, false on failure.
166 */
167bool wdxGraphicsPipe9::
168init() {
169 _hDDrawDLL = LoadLibrary("ddraw.dll");
170 if (_hDDrawDLL == nullptr) {
171 wdxdisplay9_cat.error()
172 << "LoadLibrary failed for ddraw.dll, error=" << GetLastError() <<endl;
173 goto error;
174 }
175
176 if (!MyGetProcAddr(_hDDrawDLL, (FARPROC*)&_DirectDrawCreateEx, "DirectDrawCreateEx")) {
177 goto error;
178 }
179
180 if (!MyGetProcAddr(_hDDrawDLL, (FARPROC*)&_DirectDrawEnumerateExA, "DirectDrawEnumerateExA")) {
181 goto error;
182 }
183
184 _hD3D9_DLL = LoadLibrary("d3d9.dll");
185 if (_hD3D9_DLL == nullptr) {
186 wdxdisplay9_cat.error()
187 << "LoadLibrary failed for d3d9.dll, error=" << GetLastError() <<endl;
188 goto error;
189 }
190
191 if (!MyGetProcAddr(_hD3D9_DLL, (FARPROC*)&_Direct3DCreate9, "Direct3DCreate9")) {
192 goto error;
193 }
194
195 // Create a Direct3D object.
196 __d3d9 = (*_Direct3DCreate9)(D3D_SDK_VERSION);
197
198 if (__d3d9 == nullptr) {
199 wdxdisplay9_cat.error() << "Direct3DCreate9 failed!, error = " << GetLastError() << endl;
200 // release_gsg();
201 goto error;
202 }
203
204 Init_D3DFORMAT_map();
205
206 if (dx_count_all_cards_memory){
207 return find_all_card_memavails();
208 }
209
210 return true;
211
212 error:
213 return false;
214}
215
216/**
217 * Uses DX7 calls to determine how much video memory is available for each
218 * video adapter in the system. Returns true on success, false on failure.
219 */
220bool wdxGraphicsPipe9::
221find_all_card_memavails() {
222 HRESULT hr;
223
224 hr = (*_DirectDrawEnumerateExA)(dx7_driver_enum_callback, this,
225 DDENUM_ATTACHEDSECONDARYDEVICES | DDENUM_NONDISPLAYDEVICES);
226 if (FAILED(hr)) {
227 wdxdisplay9_cat.fatal()
228 << "DirectDrawEnumerateEx failed" << D3DERRORSTRING(hr);
229 return false;
230 }
231
232 if (_card_ids.empty()) {
233 wdxdisplay9_cat.error()
234 << "DirectDrawEnumerateEx enum'ed no devices!\n";
235 return false;
236 }
237
238 GUID ZeroGUID;
239 ZeroMemory(&ZeroGUID, sizeof(GUID));
240
241 if (_card_ids.size() > 1) {
242 assert(IsEqualGUID(ZeroGUID, _card_ids[0].DX7_DeviceGUID));
243 // delete enum of primary display (always the first), since it is
244 // duplicated by explicit entry
245 _card_ids.erase(_card_ids.begin());
246 }
247
248 for (UINT i = 0; i < _card_ids.size(); i++) {
249 LPDIRECTDRAW7 pDD;
250 BYTE ddd_space[sizeof(DDDEVICEIDENTIFIER2)+4]; //bug in DX7 requires 4 extra bytes for GetDeviceID
251 DDDEVICEIDENTIFIER2 *pDX7DeviceID = (DDDEVICEIDENTIFIER2 *)&ddd_space[0];
252 GUID *pGUID = &(_card_ids[i].DX7_DeviceGUID);
253
254 if (IsEqualGUID(*pGUID, ZeroGUID)) {
255 pGUID = nullptr;
256 }
257
258 // Create the Direct Draw Object
259 hr = (*_DirectDrawCreateEx)(pGUID, (void **)&pDD, IID_IDirectDraw7, nullptr);
260 if (FAILED(hr)) {
261 wdxdisplay9_cat.error()
262 << "DirectDrawCreateEx failed for device (" << i
263 << ")" << D3DERRORSTRING(hr);
264 continue;
265 }
266
267 ZeroMemory(ddd_space, sizeof(DDDEVICEIDENTIFIER2));
268
269 hr = pDD->GetDeviceIdentifier(pDX7DeviceID, 0x0);
270 if (FAILED(hr)) {
271 wdxdisplay9_cat.error()
272 << "GetDeviceID failed for device (" << i << ")" << D3DERRORSTRING(hr);
273 continue;
274 }
275
276 _card_ids[i].DeviceID = pDX7DeviceID->dwDeviceId;
277 _card_ids[i].VendorID = pDX7DeviceID->dwVendorId;
278
279 // Get Current VidMem avail. Note this is only an estimate, when we
280 // switch to fullscreen mode from desktop, more vidmem will be available
281 // (typically 1.2 meg). I don't want to switch to fullscreen more than
282 // once due to the annoying monitor flicker, so try to figure out optimal
283 // mode using this estimate
284 DDSCAPS2 ddsGAVMCaps;
285 DWORD dwVidMemTotal, dwVidMemFree;
286 dwVidMemTotal = dwVidMemFree = 0;
287 {
288 // print out total INCLUDING AGP just for information purposes and
289 // future use. The real value I'm interested in for purposes of
290 // measuring possible valid screen sizes shouldnt include AGP.
291 ZeroMemory(&ddsGAVMCaps, sizeof(DDSCAPS2));
292 ddsGAVMCaps.dwCaps = DDSCAPS_VIDEOMEMORY;
293
294 hr = pDD->GetAvailableVidMem(&ddsGAVMCaps, &dwVidMemTotal, &dwVidMemFree);
295 if (FAILED(hr)) {
296 wdxdisplay9_cat.error()
297 << "GetAvailableVidMem failed for device #" << i
298 << D3DERRORSTRING(hr);
299 // goto skip_device; exit(1); probably want to exit, since it may be
300 // my fault
301 }
302 }
303
304 wdxdisplay9_cat.info()
305 << "DX 9.0c GetAvailableVidMem (including AGP) returns Total: "
306 << dwVidMemTotal <<", Free: " << dwVidMemFree
307 << " for device #" << i << endl;
308
309 ZeroMemory(&ddsGAVMCaps, sizeof(DDSCAPS2));
310
311 // just want to measure localvidmem, not AGP texmem
312 ddsGAVMCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM;
313
314 hr = pDD->GetAvailableVidMem(&ddsGAVMCaps, &dwVidMemTotal, &dwVidMemFree);
315 if (FAILED(hr)) {
316 wdxdisplay9_cat.error() << "GetAvailableVidMem failed for device #" << i<< D3DERRORSTRING(hr);
317 // sometimes GetAvailableVidMem fails with hr = DDERR_NODIRECTDRAWHW for
318 // some unknown reason (bad drivers?) see bugs: 15327, 18122, others.
319 // is it because D3D9 object has already been created?
320 if (hr == DDERR_NODIRECTDRAWHW)
321 continue;
322 exit(1); // probably want to exit, since it may be my fault
323 }
324
325 wdxdisplay9_cat.info()
326 << "GetAvailableVidMem (no AGP) returns Total: " << dwVidMemTotal
327 << ", Free: " << dwVidMemFree << " for device #" << i<< endl;
328
329 pDD->Release(); // release DD obj, since this is all we needed it for
330
331 if (!dx_do_vidmemsize_check) {
332 // still calling the DD stuff to get deviceID, etc. is this necessary?
333 _card_ids[i]._max_available_video_memory = UNKNOWN_VIDMEM_SIZE;
334 _card_ids[i]._is_low_memory_card = false;
335 continue;
336 }
337
338 if (dwVidMemTotal == 0) { // unreliable driver
339 dwVidMemTotal = UNKNOWN_VIDMEM_SIZE;
340 } else {
341 if (!ISPOW2(dwVidMemTotal)) {
342 // assume they wont return a proper max value, so round up to next pow
343 // of 2
344 int count = get_next_higher_bit((uint32_t)(dwVidMemTotal - 1u));
345 if (count >= 32u) {
346 // Maximum value that fits in a UINT.
347 dwVidMemTotal = 0xffffffffu;
348 } else {
349 dwVidMemTotal = (1u << count);
350 }
351 }
352 }
353
354 // after Set_display_mode, GetAvailVidMem totalmem seems to go down by 1.2
355 // meg (contradicting above comment and what I think would be correct
356 // behavior (shouldnt FS mode release the desktop vidmem?), so this is the
357 // true value
358 _card_ids[i]._max_available_video_memory = dwVidMemTotal;
359
360 // I can never get this stuff to work reliably, so I'm just rounding up to
361 // nearest pow2. Could try to get HardwareInformation.Memory_size MB
362 // number from registry like video control panel, but its not clear how to
363 // find the proper registry location for a given card
364
365 // assume buggy drivers (this means you, FireGL2) may return zero (or
366 // small amts) for dwVidMemTotal, so ignore value if its <
367 // CRAPPY_DRIVER_IS_LYING_VIDMEMTHRESHOLD
368 bool bLowVidMemFlag =
369 ((dwVidMemTotal > CRAPPY_DRIVER_IS_LYING_VIDMEMTHRESHOLD) &&
370 (dwVidMemTotal< LOWVIDMEMTHRESHOLD));
371
372 _card_ids[i]._is_low_memory_card = bLowVidMemFlag;
373 wdxdisplay9_cat.info()
374 << "SetLowVidMem flag to " << bLowVidMemFlag
375 << " based on adjusted VidMemTotal: " << dwVidMemTotal << endl;
376 }
377 return true;
378}
379
380/**
381 *
382 */
383BOOL WINAPI wdxGraphicsPipe9::
384dx7_driver_enum_callback(GUID *pGUID, TCHAR *strDesc, TCHAR *strName,
385 VOID *argptr, HMONITOR hm) {
386 wdxGraphicsPipe9 *self = (wdxGraphicsPipe9 *)argptr;
387
388 CardID card_id;
389 ZeroMemory(&card_id, sizeof(CardID));
390
391 if (hm == nullptr) {
392 card_id._monitor = MonitorFromWindow(GetDesktopWindow(),
393 MONITOR_DEFAULTTOPRIMARY);
394 } else {
395 card_id._monitor = hm;
396 }
397
398 if (pGUID != nullptr) {
399 memcpy(&card_id.DX7_DeviceGUID, pGUID, sizeof(GUID));
400 }
401
402 card_id._max_available_video_memory = UNKNOWN_VIDMEM_SIZE;
403
404 self->_card_ids.push_back(card_id);
405
406 return DDENUMRET_OK;
407}
408
409/**
410 *
411 */
412bool wdxGraphicsPipe9::
413find_best_depth_format(DXScreenData &Display, D3DDISPLAYMODE &Test_display_mode,
414 D3DFORMAT *pBestFmt, bool bWantStencil,
415 bool bForce16bpp, bool bVerboseMode) const {
416 if (dxgsg9_cat.is_debug()) {
417 bVerboseMode = true;
418 }
419
420 // list formats to try in order of preference.
421
422#define NUM_TEST_ZFMTS 6
423#define FIRST_NON_STENCIL_ZFMT 3
424 static D3DFORMAT FormatPrefList[NUM_TEST_ZFMTS] = {
425 D3DFMT_D24S8, D3DFMT_D24X4S4, D3DFMT_D15S1, // with stencil
426 D3DFMT_D32, D3DFMT_D24X8, D3DFMT_D16 // without stencil
427 };
428
429 // do not use Display._display_mode since that is probably not set yet, use
430 // Test_display_mode instead
431
432 *pBestFmt = D3DFMT_UNKNOWN;
433 HRESULT hr;
434
435 // nvidia likes zbuf depth to match rendertarget depth
436 bool bOnlySelect16bpp = (bForce16bpp ||
437 (IS_NVIDIA(Display._dx_device_id) && IS_16BPP_DISPLAY_FORMAT(Test_display_mode.Format)));
438
439 if (bVerboseMode) {
440 wdxdisplay9_cat.info()
441 << "FindBestDepthFmt: bSelectOnly16bpp: " << bOnlySelect16bpp << endl;
442 }
443
444 int first_format = (bWantStencil ? 0 : FIRST_NON_STENCIL_ZFMT);
445 for (int i = first_format; i < NUM_TEST_ZFMTS; i++) {
446 D3DFORMAT TestDepthFmt = FormatPrefList[i];
447
448 if (bOnlySelect16bpp && !IS_16BPP_ZBUFFER(TestDepthFmt)) {
449 continue;
450 }
451
452 hr = Display._d3d9->CheckDeviceFormat(Display._card_id,
453 D3DDEVTYPE_HAL,
454 Test_display_mode.Format,
455 D3DUSAGE_DEPTHSTENCIL,
456 D3DRTYPE_SURFACE, TestDepthFmt);
457
458 if (FAILED(hr)) {
459 if (hr == D3DERR_NOTAVAILABLE) {
460 if (bVerboseMode)
461 wdxdisplay9_cat.info()
462 << "FindBestDepthFmt: ChkDevFmt returns NotAvail for "
463 << D3DFormatStr(TestDepthFmt) << endl;
464 continue;
465 }
466
467 wdxdisplay9_cat.error()
468 << "unexpected CheckDeviceFormat failure" << D3DERRORSTRING(hr)
469 << endl;
470 exit(1);
471 }
472
473 hr = Display._d3d9->CheckDepthStencilMatch(Display._card_id,
474 D3DDEVTYPE_HAL,
475 Test_display_mode.Format, // adapter format
476 Test_display_mode.Format, // backbuffer fmt (should be the same in my apps)
477 TestDepthFmt);
478 if (SUCCEEDED(hr)) {
479 *pBestFmt = TestDepthFmt;
480 break;
481 } else {
482 if (hr == D3DERR_NOTAVAILABLE) {
483 if (bVerboseMode) {
484 wdxdisplay9_cat.info()
485 << "FindBestDepthFmt: ChkDepMatch returns NotAvail for "
486 << D3DFormatStr(Test_display_mode.Format) << ", "
487 << D3DFormatStr(TestDepthFmt) << endl;
488 }
489 } else {
490 wdxdisplay9_cat.error()
491 << "unexpected CheckDepthStencilMatch failure for "
492 << D3DFormatStr(Test_display_mode.Format) << ", "
493 << D3DFormatStr(TestDepthFmt) << endl;
494 exit(1);
495 }
496 }
497 }
498
499 if (bVerboseMode) {
500 wdxdisplay9_cat.info()
501 << "FindBestDepthFmt returns fmt " << D3DFormatStr(*pBestFmt) << endl;
502 }
503
504 return (*pBestFmt != D3DFMT_UNKNOWN);
505}
506
507
508/**
509 * overrides of the general estimator for known working cases
510 */
512special_check_fullscreen_resolution(DXScreenData &scrn, UINT x_size, UINT y_size) {
513 DWORD VendorId = scrn._dx_device_id.VendorId;
514 DWORD DeviceId = scrn._dx_device_id.DeviceId;
515
516 switch (VendorId) {
517 case 0x8086: // Intel
518 if ((x_size == 640) && (y_size == 480)) {
519 return true;
520 }
521 if ((x_size == 800) && (y_size == 600)) {
522 return true;
523 }
524 if ((x_size == 1024) && (y_size == 768)) {
525 return true;
526 }
527 break;
528 }
529
530 return false;
531}
532
533/**
534 * All ptr args are output parameters. If no valid mode found, returns
535 * *pSuggestedPixFmt = D3DFMT_UNKNOWN;
536 */
539 UINT RequestedX_Size, UINT RequestedY_Size,
540 bool bWantZBuffer, bool bWantStencil,
541 UINT *p_supported_screen_depths_mask,
542 bool *pCouldntFindAnyValidZBuf,
543 D3DFORMAT *pSuggestedPixFmt,
544 bool bForce16bppZBuffer,
545 bool bVerboseMode) {
546 if (dxgsg9_cat.is_debug()) {
547 bVerboseMode = true;
548 }
549
550 assert(IS_VALID_PTR(scrn._d3d9));
551
552 HRESULT hr;
553
554 *pSuggestedPixFmt = D3DFMT_UNKNOWN;
555 *p_supported_screen_depths_mask = 0x0;
556 *pCouldntFindAnyValidZBuf = false;
557
558 #define TOTAL_D3D_FORMATS 5
559 static D3DFORMAT d3d_format_array [TOTAL_D3D_FORMATS] =
560 {
561 D3DFMT_X8R8G8B8,
562 D3DFMT_A8R8G8B8,
563 D3DFMT_R5G6B5,
564 D3DFMT_X1R5G5B5,
565 D3DFMT_A2R10G10B10, // we may want this first in the list for XBOX 360 or HDR
566 };
567
568 // search for an adapter with a valid D3DFORMAT
569 int format_index;
570 for (format_index = 0; format_index < TOTAL_D3D_FORMATS; format_index++) {
571 D3DFORMAT d3d_format;
572
573 d3d_format = d3d_format_array [format_index];
574
575 int cNumModes = scrn._d3d9->GetAdapterModeCount(scrn._card_id, d3d_format);
576
577 D3DDISPLAYMODE BestDispMode;
578 ZeroMemory(&BestDispMode, sizeof(BestDispMode));
579
580 if (bVerboseMode) {
581 wdxdisplay9_cat.info()
582 << "searching for valid display modes at res: ("
583 << RequestedX_Size << ", " << RequestedY_Size
584 << "), TotalModes: " << cNumModes << endl;
585 }
586
587 // ignore memory based checks for min res 640x480. some cards just don't
588 // give accurate memavails. (should I do the check anyway for 640x480
589 // 32bpp?)
590 bool bDoMemBasedChecks =
591 ((!((RequestedX_Size == 640)&&(RequestedY_Size == 480))) &&
592 (scrn._max_available_video_memory != UNKNOWN_VIDMEM_SIZE) &&
593 (!special_check_fullscreen_resolution(scrn, RequestedX_Size, RequestedY_Size)));
594
595 if (bVerboseMode) {
596 wdxdisplay9_cat.info()
597 << "DoMemBasedChecks = " << bDoMemBasedChecks << endl;
598 }
599
600 for (int i = 0; i < cNumModes; i++) {
601 D3DDISPLAYMODE dispmode;
602 hr = scrn._d3d9->EnumAdapterModes(scrn._card_id, d3d_format, i, &dispmode);
603 if (FAILED(hr)) {
604 wdxdisplay9_cat.error()
605 << "EnumAdapter_display_mode failed for device #"
606 << scrn._card_id << D3DERRORSTRING(hr);
607 continue;
608 }
609
610 if ((dispmode.Width != RequestedX_Size) ||
611 (dispmode.Height != RequestedY_Size)) {
612 if (bVerboseMode) {
613 wdxdisplay9_cat.info()
614 << "Mode dimension " << dispmode.Width << "x" << dispmode.Height
615 << "; format " << D3DFormatStr(dispmode.Format)
616 << ": onto next mode\n";
617 }
618 continue;
619 }
620
621 // disable refresh rate checking since SLI video cards may use refresh
622 // rates less than 60
623 if (0) {
624 if ((dispmode.RefreshRate<60) && (dispmode.RefreshRate>1)) {
625 // don't want refresh rates under 60Hz, but 0 or 1 might indicate a
626 // default refresh rate, which is usually > = 60
627 if (bVerboseMode) {
628 wdxdisplay9_cat.info()
629 << "skipping mode[" << i << "], bad refresh rate: "
630 << dispmode.RefreshRate << endl;
631 }
632 continue;
633 }
634 }
635
636 // Note no attempt is made to verify if format will work at requested
637 // size, so even if this call succeeds, could still get an out-of-video-
638 // mem error
639
640 hr = scrn._d3d9->CheckDeviceFormat(scrn._card_id, D3DDEVTYPE_HAL, dispmode.Format,
641 D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE,
642 dispmode.Format);
643 if (FAILED(hr)) {
644 if (hr == D3DERR_NOTAVAILABLE) {
645 if (bVerboseMode) {
646 wdxdisplay9_cat.info()
647 << "skipping mode[" << i
648 << "], CheckDevFmt returns NotAvail for fmt: "
649 << D3DFormatStr(dispmode.Format) << endl;
650 }
651 continue;
652 } else {
653 wdxdisplay9_cat.error()
654 << "CheckDeviceFormat failed for device #"
655 << scrn._card_id << D3DERRORSTRING(hr);
656 continue;
657 }
658 }
659
660 bool bIs16bppRenderTgt = IS_16BPP_DISPLAY_FORMAT(dispmode.Format);
661 PN_stdfloat RendTgtMinMemReqmt = 0.0f;
662
663 // if we have a valid memavail value, try to determine if we have enough
664 // space
665 if (bDoMemBasedChecks) {
666 // assume user is testing fullscreen, not windowed, so use the dwTotal
667 // value see if 3 scrnbufs (frontbackz)at 16bpp at x_size*y_size will
668 // fit with a few extra megs for texmem
669
670 // 8MB Rage Pro says it has 6.8 megs Total free and will run at
671 // 1024x768, so formula makes it so that is OK
672
673 #define REQD_TEXMEM 1800000
674
675 PN_stdfloat bytes_per_pixel = (bIs16bppRenderTgt ? 2 : 4);
676
677 // *2 for double buffer
678
679 RendTgtMinMemReqmt =
680 ((PN_stdfloat)RequestedX_Size) * ((PN_stdfloat)RequestedY_Size) *
681 bytes_per_pixel * 2 + REQD_TEXMEM;
682
683 if (bVerboseMode)
684 wdxdisplay9_cat.info()
685 << "Testing Mode (" <<RequestedX_Size<<"x" << RequestedY_Size
686 << ", " << D3DFormatStr(dispmode.Format) << ")\nReqdVidMem: "
687 << (int)RendTgtMinMemReqmt << " AvailVidMem: "
688 << scrn._max_available_video_memory << endl;
689
690 if (RendTgtMinMemReqmt > scrn._max_available_video_memory) {
691 if (bVerboseMode)
692 wdxdisplay9_cat.info()
693 << "not enough VidMem for render tgt, skipping display fmt "
694 << D3DFormatStr(dispmode.Format) << " ("
695 << (int)RendTgtMinMemReqmt << " > "
696 << scrn._max_available_video_memory << ")\n";
697 continue;
698 }
699 }
700
701 if (bWantZBuffer) {
702 D3DFORMAT zformat;
703 if (!find_best_depth_format(scrn, dispmode, &zformat,
704 bWantStencil, bForce16bppZBuffer)) {
705 *pCouldntFindAnyValidZBuf = true;
706 continue;
707 }
708
709 PN_stdfloat MinMemReqmt = 0.0f;
710
711 if (bDoMemBasedChecks) {
712 // test memory again, this time including zbuf size
713 PN_stdfloat zbytes_per_pixel = (IS_16BPP_ZBUFFER(zformat) ? 2 : 4);
714 PN_stdfloat MinMemReqmt = RendTgtMinMemReqmt + ((PN_stdfloat)RequestedX_Size)*((PN_stdfloat)RequestedY_Size)*zbytes_per_pixel;
715
716 if (bVerboseMode)
717 wdxdisplay9_cat.info()
718 << "Testing Mode w/Z (" << RequestedX_Size << "x"
719 << RequestedY_Size << ", " << D3DFormatStr(dispmode.Format)
720 << ")\nReqdVidMem: " << (int)MinMemReqmt << " AvailVidMem: "
721 << scrn._max_available_video_memory << endl;
722
723 if (MinMemReqmt > scrn._max_available_video_memory) {
724 if (bVerboseMode)
725 wdxdisplay9_cat.info()
726 << "not enough VidMem for RendTgt+zbuf, skipping display fmt "
727 << D3DFormatStr(dispmode.Format) << " (" << (int)MinMemReqmt
728 << " > " << scrn._max_available_video_memory << ")\n";
729 continue;
730 }
731 }
732
733// Optimizing for 16-bit depth does not work in all cases so turn it off.
734 if (false) {
735 if ((!bDoMemBasedChecks) || (MinMemReqmt<scrn._max_available_video_memory)) {
736 if (!IS_16BPP_ZBUFFER(zformat)) {
737 // see if things fit with a 16bpp zbuffer
738
739 if (!find_best_depth_format(scrn, dispmode, &zformat,
740 bWantStencil, true, bVerboseMode)) {
741 if (bVerboseMode)
742 wdxdisplay9_cat.info()
743 << "FindBestDepthFmt rejected Mode[" << i << "] ("
744 << RequestedX_Size << "x" << RequestedY_Size
745 << ", " << D3DFormatStr(dispmode.Format) << endl;
746 *pCouldntFindAnyValidZBuf = true;
747 continue;
748 }
749
750 // right now I'm not going to use these flags, just let the
751 // create fail out-of-mem and retry at 16bpp
752 *p_supported_screen_depths_mask |=
753 (IS_16BPP_DISPLAY_FORMAT(dispmode.Format) ? DISPLAY_16BPP_REQUIRES_16BPP_ZBUFFER_FLAG : DISPLAY_32BPP_REQUIRES_16BPP_ZBUFFER_FLAG);
754 }
755 }
756 }
757 }
758
759 if (bVerboseMode)
760 wdxdisplay9_cat.info()
761 << "Validated Mode (" << RequestedX_Size << "x"
762 << RequestedY_Size << ", " << D3DFormatStr(dispmode.Format) << endl;
763
764 /*
765 // dx9 valid display modes for render targets.
766 D3DFMT_X1R5G5B5, D3DFMT_R5G6B5, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A2R10G10B10
767 */
768
769 switch (dispmode.Format) {
770 case D3DFMT_X1R5G5B5:
771 *p_supported_screen_depths_mask |= X1R5G5B5_FLAG;
772 break;
773 case D3DFMT_X8R8G8B8:
774 *p_supported_screen_depths_mask |= X8R8G8B8_FLAG;
775 break;
776 case D3DFMT_A8R8G8B8:
777 *p_supported_screen_depths_mask |= A8R8G8B8_FLAG;
778 break;
779 case D3DFMT_R5G6B5:
780 *p_supported_screen_depths_mask |= R5G6B5_FLAG;
781 break;
782 case D3DFMT_A2R10G10B10:
783 *p_supported_screen_depths_mask |= A2B10G10R10_FLAG;
784 break;
785 default:
786 wdxdisplay9_cat.error()
787 << "unrecognized supported fmt " << D3DFormatStr(dispmode.Format)
788 << " returned by EnumAdapter_display_modes!\n";
789 }
790 }
791
792 // note: this chooses 32bpp, which may not be preferred over 16 for memory
793 // & speed reasons on some older cards in particular
794 if (*p_supported_screen_depths_mask & X8R8G8B8_FLAG) {
795 *pSuggestedPixFmt = D3DFMT_X8R8G8B8;
796 } else if (*p_supported_screen_depths_mask & A8R8G8B8_FLAG) {
797 *pSuggestedPixFmt = D3DFMT_A8R8G8B8;
798 } else if (*p_supported_screen_depths_mask & R5G6B5_FLAG) {
799 *pSuggestedPixFmt = D3DFMT_R5G6B5;
800 } else if (*p_supported_screen_depths_mask & X1R5G5B5_FLAG) {
801 *pSuggestedPixFmt = D3DFMT_X1R5G5B5;
802 } else if (*p_supported_screen_depths_mask & A2B10G10R10_FLAG) {
803 *pSuggestedPixFmt = D3DFMT_A2R10G10B10;
804 }
805
806 if (bVerboseMode) {
807 wdxdisplay9_cat.info()
808 << "search_for_valid_device returns fmt: "
809 << D3DFormatStr(*pSuggestedPixFmt) << endl;
810 }
811
812 if (*pSuggestedPixFmt != D3DFMT_UNKNOWN) {
813 break;
814 }
815 }
816}
817
818/**
819 * Creates a new reference to a particular hardware device and associates it
820 * with the pipe.
821 */
822PT(GraphicsDevice) wdxGraphicsPipe9::
823make_device(void *scrn) {
824 PT(DXGraphicsDevice9) device = new DXGraphicsDevice9(this);
825 memcpy(&device->_Scrn, scrn, sizeof(device->_Scrn));
826 device->_d3d_device = device->_Scrn._d3d_device;
827
828 _device = device;
829 wdxdisplay9_cat.info() << "walla: device" << device << "\n";
830
831 return device;
832}
833
835
836void Init_D3DFORMAT_map() {
837 if (g_D3DFORMATmap.size() != 0)
838 return;
839
840#define INSERT_ELEM(XX) g_D3DFORMATmap[XX##_FLAG] = D3DFMT_##XX;
841
842 INSERT_ELEM(R8G8B8);
843 INSERT_ELEM(A8R8G8B8);
844 INSERT_ELEM(X8R8G8B8);
845 INSERT_ELEM(R5G6B5);
846 INSERT_ELEM(X1R5G5B5);
847 INSERT_ELEM(A1R5G5B5);
848 INSERT_ELEM(A4R4G4B4);
849 INSERT_ELEM(R3G3B2);
850 INSERT_ELEM(A8);
851 INSERT_ELEM(A8R3G3B2);
852 INSERT_ELEM(X4R4G4B4);
853 INSERT_ELEM(A2B10G10R10);
854 INSERT_ELEM(G16R16);
855 INSERT_ELEM(A8P8);
856 INSERT_ELEM(P8);
857 INSERT_ELEM(L8);
858 INSERT_ELEM(A8L8);
859 INSERT_ELEM(A4L4);
860 INSERT_ELEM(D16);
861 INSERT_ELEM(D24X8);
862 INSERT_ELEM(D24S8);
863 INSERT_ELEM(D32);
864 INSERT_ELEM(INTZ);
865// NOT IN DX9 INSERT_ELEM(W11V11U10);
866 INSERT_ELEM(A2W10V10U10);
867 INSERT_ELEM(ATI1);
868 INSERT_ELEM(ATI2);
869 INSERT_ELEM(DXT1);
870 INSERT_ELEM(DXT2);
871 INSERT_ELEM(DXT3);
872 INSERT_ELEM(DXT4);
873 INSERT_ELEM(DXT5);
874}
875
876
877
878const char *D3DFormatStr(D3DFORMAT fmt) {
879
880#define CASESTR(XX) case XX: return #XX;
881 switch(fmt) {
882 CASESTR(D3DFMT_UNKNOWN);
883 CASESTR(D3DFMT_R8G8B8);
884 CASESTR(D3DFMT_A8R8G8B8);
885 CASESTR(D3DFMT_X8R8G8B8);
886 CASESTR(D3DFMT_R5G6B5);
887 CASESTR(D3DFMT_X1R5G5B5);
888 CASESTR(D3DFMT_A1R5G5B5);
889 CASESTR(D3DFMT_A4R4G4B4);
890 CASESTR(D3DFMT_R3G3B2);
891 CASESTR(D3DFMT_A8);
892 CASESTR(D3DFMT_A8R3G3B2);
893 CASESTR(D3DFMT_X4R4G4B4);
894 CASESTR(D3DFMT_A2B10G10R10);
895 CASESTR(D3DFMT_G16R16);
896 CASESTR(D3DFMT_A8P8);
897 CASESTR(D3DFMT_P8);
898 CASESTR(D3DFMT_L8);
899 CASESTR(D3DFMT_A8L8);
900 CASESTR(D3DFMT_A4L4);
901 CASESTR(D3DFMT_V8U8);
902 CASESTR(D3DFMT_L6V5U5);
903 CASESTR(D3DFMT_X8L8V8U8);
904 CASESTR(D3DFMT_Q8W8V8U8);
905 CASESTR(D3DFMT_V16U16);
906// NOT IN DX9 CASESTR(D3DFMT_W11V11U10);
907 CASESTR(D3DFMT_A2W10V10U10);
908 CASESTR(D3DFMT_ATI1);
909 CASESTR(D3DFMT_ATI2);
910 CASESTR(D3DFMT_DXT1);
911 CASESTR(D3DFMT_DXT2);
912 CASESTR(D3DFMT_DXT3);
913 CASESTR(D3DFMT_DXT4);
914 CASESTR(D3DFMT_DXT5);
915 CASESTR(D3DFMT_D16_LOCKABLE);
916 CASESTR(D3DFMT_D32);
917 CASESTR(D3DFMT_D15S1);
918 CASESTR(D3DFMT_D24S8);
919 CASESTR(D3DFMT_D16);
920 CASESTR(D3DFMT_D24X8);
921 CASESTR(D3DFMT_D24X4S4);
922 CASESTR(D3DFMT_INTZ);
923 CASESTR(D3DFMT_VERTEXDATA);
924 CASESTR(D3DFMT_INDEX16);
925 CASESTR(D3DFMT_INDEX32);
926 CASESTR(D3DFMT_A16B16G16R16F);
927 CASESTR(D3DFMT_A32B32G32R32F);
928 }
929
930 return "Invalid D3DFORMAT";
931}
A GraphicsDevice necessary for multi-window rendering in DX.
A GraphicsStateGuardian for rendering into DirectX9 contexts.
bool get_supports_render_texture() const
Returns true if this particular GSG can render from a wdxGraphicsBuffer9 directly into a texture,...
A container for the various kinds of properties we might ask to have on a graphics frameBuffer before...
An abstract device object that is part of Graphics Pipe.
This class is the main interface to controlling the render process.
This is a base class for the various different classes that represent the result of a frame of render...
An object to create GraphicsOutputs that share a particular 3-D API.
Encapsulates all the communication with a particular instance of a given rendering backend.
is_valid
Returns true if the GSG has been correctly initialized within a graphics context, false if there has ...
bool needs_reset() const
Returns true if the gsg is marked as needing a reset.
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
A container for the various kinds of properties we might ask to have on a graphics window before we o...
This is our own Panda specialization on the default STL map.
Definition pmap.h:49
An offscreen render buffer.
This graphics pipe represents the interface for creating DirectX9 graphics windows.
virtual std::string get_interface_name() const
Returns the name of the rendering interface associated with this GraphicsPipe.
bool special_check_fullscreen_resolution(DXScreenData &scrn, UINT x_size, UINT y_size)
overrides of the general estimator for known working cases
void search_for_valid_displaymode(DXScreenData &scrn, UINT RequestedX_Size, UINT RequestedY_Size, bool bWantZBuffer, bool bWantStencil, UINT *p_supported_screen_depths_mask, bool *pCouldntFindAnyValidZBuf, D3DFORMAT *pSuggestedPixFmt, bool bForce16bppZBuffer, bool bVerboseMode=false)
All ptr args are output parameters.
A single graphics window for rendering DirectX under Microsoft Windows.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int get_next_higher_bit(unsigned short x)
Returns the smallest power of 2 greater than x.
Definition pbitops.I:328
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.