00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "wdxGraphicsPipe9.h"
00016 #include "wdxGraphicsWindow9.h"
00017 #include "config_dxgsg9.h"
00018 #include "config_display.h"
00019 #include "keyboardButton.h"
00020 #include "mouseButton.h"
00021 #include "throw_event.h"
00022 #include "pStatTimer.h"
00023 #include "pmap.h"
00024 #include <ddraw.h>
00025 #include <errno.h>
00026 #include <time.h>
00027 #include <math.h>
00028 #include <tchar.h>
00029
00030 TypeHandle wdxGraphicsWindow9::_type_handle;
00031
00032
00033
00034
00035
00036
00037 wdxGraphicsWindow9::
00038 wdxGraphicsWindow9(GraphicsEngine *engine, GraphicsPipe *pipe,
00039 const string &name,
00040 const FrameBufferProperties &fb_prop,
00041 const WindowProperties &win_prop,
00042 int flags,
00043 GraphicsStateGuardian *gsg,
00044 GraphicsOutput *host):
00045 WinGraphicsWindow(engine, pipe, name, fb_prop, win_prop, flags, gsg, host)
00046 {
00047
00048
00049
00050
00051 _dxgsg = DCAST(DXGraphicsStateGuardian9, gsg);
00052 _depth_buffer_bpp = 0;
00053 _awaiting_restore = false;
00054 ZeroMemory(&_wcontext, sizeof(_wcontext));
00055 }
00056
00057
00058
00059
00060
00061
00062 wdxGraphicsWindow9::
00063 ~wdxGraphicsWindow9() {
00064 }
00065
00066
00067
00068
00069
00070
00071 void wdxGraphicsWindow9::
00072 make_current() {
00073 PStatTimer timer(_make_current_pcollector);
00074
00075 _dxgsg->set_context(&_wcontext);
00076
00077
00078
00079
00080
00081 _dxgsg->reset_if_new();
00082 }
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093 bool wdxGraphicsWindow9::
00094 begin_frame(FrameMode mode, Thread *current_thread) {
00095 begin_frame_spam(mode);
00096 if (_gsg == (GraphicsStateGuardian *)NULL) {
00097 return false;
00098 }
00099
00100 if (!get_unexposed_draw() && !_got_expose_event) {
00101 if (wdxdisplay9_cat.is_spam()) {
00102 wdxdisplay9_cat.spam()
00103 << "Not drawing " << this << ": unexposed.\n";
00104 }
00105 return false;
00106 }
00107
00108 if (_awaiting_restore) {
00109
00110
00111 if (!_dxgsg->check_cooperative_level()) {
00112
00113 return false;
00114 }
00115 _awaiting_restore = false;
00116 init_resized_window();
00117 }
00118
00119 make_current();
00120
00121 if (mode == FM_render) {
00122 clear_cube_map_selection();
00123 }
00124
00125 _gsg->set_current_properties(&get_fb_properties());
00126 bool return_val = _gsg->begin_frame(current_thread);
00127 _dxgsg->set_render_target();
00128 return return_val;
00129 }
00130
00131
00132
00133
00134
00135
00136
00137
00138 void wdxGraphicsWindow9::
00139 end_frame(FrameMode mode, Thread *current_thread) {
00140 end_frame_spam(mode);
00141 nassertv(_gsg != (GraphicsStateGuardian *)NULL);
00142
00143 if (mode == FM_render) {
00144 copy_to_textures();
00145 }
00146
00147 _gsg->end_frame(current_thread);
00148
00149 if (mode == FM_render) {
00150 trigger_flip();
00151 clear_cube_map_selection();
00152 }
00153 }
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165 void wdxGraphicsWindow9::
00166 end_flip() {
00167 if (_dxgsg != (DXGraphicsStateGuardian9 *)NULL && is_active()) {
00168 _dxgsg->show_frame();
00169 }
00170 WinGraphicsWindow::end_flip();
00171 }
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186 int wdxGraphicsWindow9::
00187 verify_window_sizes(int numsizes, int *dimen) {
00188
00189
00190 nassertr(IS_VALID_PTR(_dxgsg), 0);
00191
00192 int num_valid_modes = 0;
00193
00194 wdxGraphicsPipe9 *dxpipe;
00195 DCAST_INTO_R(dxpipe, _pipe, 0);
00196
00197
00198
00199
00200 int *pCurDim = dimen;
00201
00202 for (int i = 0; i < numsizes; i++, pCurDim += 2) {
00203 int x_size = pCurDim[0];
00204 int y_size = pCurDim[1];
00205
00206 bool bIsGoodMode = false;
00207 bool CouldntFindAnyValidZBuf;
00208 D3DFORMAT newPixFmt = D3DFMT_UNKNOWN;
00209
00210 if (dxpipe->special_check_fullscreen_resolution(_wcontext, x_size, y_size)) {
00211
00212 bIsGoodMode = true;
00213
00214 } else {
00215 if (_wcontext._is_low_memory_card) {
00216 bIsGoodMode = ((x_size == 640) && (y_size == 480));
00217 } else {
00218 dxpipe->search_for_valid_displaymode
00219 (_wcontext, x_size, y_size, _wcontext._presentation_params.EnableAutoDepthStencil != false,
00220 IS_STENCIL_FORMAT(_wcontext._presentation_params.AutoDepthStencilFormat),
00221 &_wcontext._supported_screen_depths_mask,
00222 &CouldntFindAnyValidZBuf, &newPixFmt, dx_force_16bpp_zbuffer, true);
00223 bIsGoodMode = (newPixFmt != D3DFMT_UNKNOWN);
00224 }
00225 }
00226
00227 if (bIsGoodMode) {
00228 num_valid_modes++;
00229 } else {
00230
00231 pCurDim[0] = 0;
00232 pCurDim[1] = 0;
00233 }
00234
00235 if (wdxdisplay9_cat.is_spam()) {
00236 wdxdisplay9_cat.spam()
00237 << "Fullscrn Mode (" << x_size << ", " << y_size << ")\t"
00238 << (bIsGoodMode ? "V" : "Inv") << "alid\n";
00239 }
00240 }
00241
00242 return num_valid_modes;
00243 }
00244
00245
00246
00247
00248
00249
00250
00251
00252 void wdxGraphicsWindow9::
00253 close_window() {
00254 if (wdxdisplay9_cat.is_debug()) {
00255 wdxdisplay9_cat.debug()
00256 << "wdxGraphicsWindow9::close_window() " << this << "\n";
00257 }
00258
00259 if (_gsg != (GraphicsStateGuardian *)NULL) {
00260 _gsg.clear();
00261 }
00262
00263 DXGraphicsStateGuardian9::set_cg_device(NULL);
00264
00265 _dxgsg->release_swap_chain(&_wcontext);
00266 WinGraphicsWindow::close_window();
00267 }
00268
00269
00270
00271
00272
00273
00274
00275
00276 bool wdxGraphicsWindow9::
00277 open_window() {
00278 PT(DXGraphicsDevice9) dxdev;
00279 WindowProperties props;
00280
00281
00282
00283
00284
00285 static ConfigVariableBool always_discard_device("always-discard-device", true);
00286 bool discard_device = always_discard_device;
00287
00288 if (_gsg == 0) {
00289 _dxgsg = new DXGraphicsStateGuardian9(_engine, _pipe);
00290 _gsg = _dxgsg;
00291 } else {
00292 DCAST_INTO_R(_dxgsg, _gsg, false);
00293 }
00294
00295 if (!choose_device()) {
00296 return false;
00297 }
00298
00299
00300
00301 {
00302 WindowProperties resized_props;
00303 resized_props.set_size(_wcontext._display_mode.Width,
00304 _wcontext._display_mode.Height);
00305 _properties.add_properties(resized_props);
00306 }
00307
00308 wdxdisplay9_cat.debug() << "_wcontext._window is " << _wcontext._window << "\n";
00309 if (!WinGraphicsWindow::open_window()) {
00310 return false;
00311 }
00312 _wcontext._window = _hWnd;
00313
00314 wdxdisplay9_cat.debug() << "_wcontext._window is " << _wcontext._window << "\n";
00315
00316
00317
00318
00319
00320 while (true) {
00321 if (_dxgsg->get_pipe()->get_device() == NULL || discard_device) {
00322 wdxdisplay9_cat.debug() << "device is null or fullscreen\n";
00323
00324
00325 if (_dxgsg->get_pipe()->get_device()) {
00326 _dxgsg->dx_cleanup();
00327 }
00328
00329 wdxdisplay9_cat.debug() << "device width " << _wcontext._display_mode.Width << "\n";
00330 if (!create_screen_buffers_and_device(_wcontext, dx_force_16bpp_zbuffer)) {
00331 wdxdisplay9_cat.error() << "Unable to create window with specified parameters.\n";
00332 close_window();
00333 return false;
00334 }
00335 _dxgsg->get_pipe()->make_device((void*)(&_wcontext));
00336 _dxgsg->copy_pres_reset(&_wcontext);
00337 _dxgsg->create_swap_chain(&_wcontext);
00338 break;
00339
00340 } else {
00341
00342
00343 wdxdisplay9_cat.debug() << "device is not null\n";
00344
00345 dxdev = (DXGraphicsDevice9*)_dxgsg->get_pipe()->get_device();
00346 memcpy(&_wcontext, &dxdev->_Scrn, sizeof(DXScreenData));
00347
00348 _wcontext._presentation_params.Windowed = !is_fullscreen();
00349 _wcontext._presentation_params.hDeviceWindow = _wcontext._window = _hWnd;
00350 _wcontext._presentation_params.BackBufferWidth = _wcontext._display_mode.Width = _properties.get_x_size();
00351 _wcontext._presentation_params.BackBufferHeight = _wcontext._display_mode.Height = _properties.get_y_size();
00352
00353 wdxdisplay9_cat.debug() << "device width " << _wcontext._presentation_params.BackBufferWidth << "\n";
00354 if (!_dxgsg->create_swap_chain(&_wcontext)) {
00355 discard_device = true;
00356 continue;
00357 }
00358 init_resized_window();
00359 break;
00360 }
00361 }
00362 wdxdisplay9_cat.debug() << "swapchain is " << _wcontext._swap_chain << "\n";
00363 return true;
00364 }
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375 void wdxGraphicsWindow9::
00376 reset_window(bool swapchain) {
00377 if (swapchain) {
00378 if (_wcontext._swap_chain) {
00379 _dxgsg->create_swap_chain(&_wcontext);
00380 wdxdisplay9_cat.debug() << "created swapchain " << _wcontext._swap_chain << "\n";
00381 }
00382 }
00383 else {
00384 if (_wcontext._swap_chain) {
00385 _dxgsg->release_swap_chain(&_wcontext);
00386 wdxdisplay9_cat.debug() << "released swapchain " << _wcontext._swap_chain << "\n";
00387 }
00388 }
00389 }
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400 void wdxGraphicsWindow9::
00401 fullscreen_restored(WindowProperties &properties) {
00402
00403
00404
00405
00406
00407 if (_dxgsg != NULL) {
00408 _awaiting_restore = true;
00409 }
00410 }
00411
00412
00413
00414
00415
00416
00417
00418
00419 void wdxGraphicsWindow9::
00420 handle_reshape() {
00421 GdiFlush();
00422 WinGraphicsWindow::handle_reshape();
00423
00424 if (_dxgsg != NULL) {
00425
00426 WindowProperties props = get_properties();
00427 int x_size = props.get_x_size();
00428 int y_size = props.get_y_size();
00429
00430 if (_wcontext._presentation_params.BackBufferWidth != x_size ||
00431 _wcontext._presentation_params.BackBufferHeight != y_size) {
00432 bool resize_succeeded = reset_device_resize_window(x_size, y_size);
00433
00434 if (wdxdisplay9_cat.is_debug()) {
00435 if (!resize_succeeded) {
00436 wdxdisplay9_cat.debug()
00437 << "windowed_resize to size: (" << x_size << ", " << y_size
00438 << ") failed due to out-of-memory\n";
00439 } else {
00440 int x_origin = props.get_x_origin();
00441 int y_origin = props.get_y_origin();
00442 wdxdisplay9_cat.debug()
00443 << "windowed_resize to origin: (" << x_origin << ", "
00444 << y_origin << "), size: (" << x_size
00445 << ", " << y_size << ")\n";
00446 }
00447 }
00448 }
00449 }
00450 }
00451
00452
00453
00454
00455
00456
00457
00458 bool wdxGraphicsWindow9::
00459 do_fullscreen_resize(int x_size, int y_size) {
00460 if (!WinGraphicsWindow::do_fullscreen_resize(x_size, y_size)) {
00461 return false;
00462 }
00463
00464 bool bCouldntFindValidZBuf;
00465 D3DFORMAT pixFmt;
00466 bool bNeedZBuffer = (_wcontext._presentation_params.EnableAutoDepthStencil != false);
00467 bool bNeedStencilBuffer = IS_STENCIL_FORMAT(_wcontext._presentation_params.AutoDepthStencilFormat);
00468
00469 wdxGraphicsPipe9 *dxpipe;
00470 DCAST_INTO_R(dxpipe, _pipe, false);
00471
00472 bool bIsGoodMode = false;
00473 bool bResizeSucceeded = false;
00474
00475 if (!dxpipe->special_check_fullscreen_resolution(_wcontext, x_size, y_size)) {
00476
00477
00478 if (_wcontext._is_low_memory_card && (!((x_size == 640) && (y_size == 480)))) {
00479 wdxdisplay9_cat.error() << "resize() failed: will not try to resize low vidmem device #" << _wcontext._card_id << " to non-640x480!\n";
00480 return bResizeSucceeded;
00481 }
00482 }
00483
00484
00485
00486 dxpipe->search_for_valid_displaymode(_wcontext, x_size, y_size,
00487 bNeedZBuffer, bNeedStencilBuffer,
00488 &_wcontext._supported_screen_depths_mask,
00489 &bCouldntFindValidZBuf,
00490 &pixFmt, dx_force_16bpp_zbuffer, true);
00491 bIsGoodMode = (pixFmt != D3DFMT_UNKNOWN);
00492
00493 if (!bIsGoodMode) {
00494 wdxdisplay9_cat.error() << "resize() failed: "
00495 << (bCouldntFindValidZBuf ? "Couldnt find valid zbuffer format to go with FullScreen mode" : "No supported FullScreen modes")
00496 << " at " << x_size << "x" << y_size << " for device #" << _wcontext._card_id << endl;
00497 return bResizeSucceeded;
00498 }
00499
00500
00501
00502 _wcontext._display_mode.Width = x_size;
00503 _wcontext._display_mode.Height = y_size;
00504 _wcontext._display_mode.Format = pixFmt;
00505 _wcontext._display_mode.RefreshRate = D3DPRESENT_RATE_DEFAULT;
00506
00507
00508 bResizeSucceeded = reset_device_resize_window(x_size, y_size);
00509
00510 if (!bResizeSucceeded) {
00511 wdxdisplay9_cat.error() << "resize() failed with OUT-OF-MEMORY error!\n";
00512
00513 if ((!IS_16BPP_DISPLAY_FORMAT(_wcontext._presentation_params.BackBufferFormat)) &&
00514 (_wcontext._supported_screen_depths_mask & (R5G6B5_FLAG|X1R5G5B5_FLAG))) {
00515
00516 _wcontext._display_mode.Format = ((_wcontext._supported_screen_depths_mask & R5G6B5_FLAG) ? D3DFMT_R5G6B5 : D3DFMT_X1R5G5B5);
00517 dx_force_16bpp_zbuffer = true;
00518 if (wdxdisplay9_cat.info())
00519 wdxdisplay9_cat.info() << "CreateDevice failed with out-of-vidmem, retrying w/16bpp buffers on device #" << _wcontext._card_id << endl;
00520
00521 bResizeSucceeded = reset_device_resize_window(x_size, y_size);
00522 }
00523 }
00524
00525 return bResizeSucceeded;
00526 }
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536 bool wdxGraphicsWindow9::
00537 create_screen_buffers_and_device(DXScreenData &display, bool force_16bpp_zbuffer) {
00538 wdxGraphicsPipe9 *dxpipe;
00539 DCAST_INTO_R(dxpipe, _pipe, false);
00540
00541 DWORD dwRenderWidth = display._display_mode.Width;
00542 DWORD dwRenderHeight = display._display_mode.Height;
00543 DWORD dwBehaviorFlags = 0x0;
00544 LPDIRECT3D9 _d3d9 = display._d3d9;
00545 D3DCAPS9 *pD3DCaps = &display._d3dcaps;
00546 D3DPRESENT_PARAMETERS* presentation_params = &display._presentation_params;
00547 RECT view_rect;
00548 UINT adapter;
00549 D3DDEVTYPE device_type;
00550 HRESULT hr;
00551
00552 adapter = display._card_id;
00553 device_type = D3DDEVTYPE_HAL;
00554
00555
00556 if (dx_use_nvperfhud) {
00557 UINT adapter_id;
00558 UINT total_adapters;
00559
00560 total_adapters = _d3d9 -> GetAdapterCount ( );
00561 for (adapter_id = 0; adapter_id < total_adapters; adapter_id++) {
00562 D3DADAPTER_IDENTIFIER9 identifier;
00563
00564 _d3d9 -> GetAdapterIdentifier (adapter_id, 0, &identifier);
00565 if (strcmp ("NVIDIA NVPerfHUD", identifier.Description) == 0) {
00566 adapter = adapter_id;
00567 device_type = D3DDEVTYPE_REF;
00568 break;
00569 }
00570 }
00571 }
00572
00573 wdxdisplay9_cat.debug() << "Display Width " << dwRenderWidth << " and PresParam Width " << _wcontext._presentation_params.BackBufferWidth << "\n";
00574
00575
00576
00577 bool bWantStencil = (_fb_properties.get_stencil_bits() > 0);
00578 bool bWantAlpha = (_fb_properties.get_alpha_bits() > 0);
00579
00580 PRINT_REFCNT(wdxdisplay9, _d3d9);
00581
00582 nassertr(_d3d9 != NULL, false);
00583 nassertr(pD3DCaps->DevCaps & D3DDEVCAPS_HWRASTERIZATION, false);
00584
00585 bool do_sync = sync_video;
00586
00587 if (do_sync && !(pD3DCaps->Caps & D3DCAPS_READ_SCANLINE)) {
00588 wdxdisplay9_cat.info()
00589 << "HW doesnt support syncing to vertical refresh, ignoring sync-video\n";
00590 do_sync = false;
00591 }
00592
00593 presentation_params->BackBufferFormat = display._display_mode.Format;
00594
00595
00596 if (bWantAlpha) {
00597 if (!FAILED(_d3d9->CheckDeviceFormat(adapter, device_type, display._display_mode.Format, D3DUSAGE_RENDERTARGET,
00598 D3DRTYPE_SURFACE, D3DFMT_A8R8G8B8))) {
00599 if (!FAILED(_d3d9->CheckDeviceType(adapter, device_type, display._display_mode.Format, D3DFMT_A8R8G8B8,
00600 is_fullscreen()))) {
00601
00602 presentation_params->BackBufferFormat = D3DFMT_A8R8G8B8;
00603 }
00604 }
00605 }
00606
00607
00608
00609 if (FAILED(_d3d9->CheckDeviceFormat(adapter, device_type, display._display_mode.Format, D3DUSAGE_RENDERTARGET,
00610 D3DRTYPE_SURFACE, presentation_params->BackBufferFormat))) {
00611 wdxdisplay9_cat.error() << "adapter #" << adapter << " CheckDeviceFmt failed for surface fmt " << D3DFormatStr(presentation_params->BackBufferFormat) << endl;
00612 goto Fallback_to_16bpp_buffers;
00613 }
00614
00615 if (FAILED(_d3d9->CheckDeviceType(adapter, device_type, display._display_mode.Format, presentation_params->BackBufferFormat,
00616 is_fullscreen()))) {
00617 wdxdisplay9_cat.error() << "adapter #" << adapter << " CheckDeviceType failed for surface fmt " << D3DFormatStr(presentation_params->BackBufferFormat) << endl;
00618 goto Fallback_to_16bpp_buffers;
00619 }
00620
00621 if (display._presentation_params.EnableAutoDepthStencil) {
00622 if (!dxpipe->find_best_depth_format(display, display._display_mode,
00623 &display._presentation_params.AutoDepthStencilFormat,
00624 bWantStencil, false)) {
00625 wdxdisplay9_cat.error()
00626 << "find_best_depth_format failed in CreateScreenBuffers for device #"
00627 << adapter << endl;
00628 goto Fallback_to_16bpp_buffers;
00629 }
00630 _depth_buffer_bpp = D3DFMT_to_DepthBits(display._presentation_params.AutoDepthStencilFormat);
00631 } else {
00632 _depth_buffer_bpp = 0;
00633 }
00634
00635 presentation_params->Windowed = !is_fullscreen();
00636
00637 int supported_multisamples = 0;
00638 if (framebuffer_multisample.get_value()){
00639 supported_multisamples = multisamples.get_value();
00640 }
00641
00642 while (supported_multisamples > 1){
00643
00644 hr = _d3d9->CheckDeviceMultiSampleType(adapter, D3DDEVTYPE_HAL, display._display_mode.Format,
00645 is_fullscreen(), D3DMULTISAMPLE_TYPE(supported_multisamples), NULL);
00646 if (FAILED(hr)) {
00647 supported_multisamples--;
00648 continue;
00649 }
00650
00651 if (display._presentation_params.EnableAutoDepthStencil) {
00652 hr = _d3d9->CheckDeviceMultiSampleType(adapter, D3DDEVTYPE_HAL, display._presentation_params.AutoDepthStencilFormat,
00653 is_fullscreen(), D3DMULTISAMPLE_TYPE(supported_multisamples), NULL);
00654 if (FAILED(hr)) {
00655 supported_multisamples--;
00656 continue;
00657 }
00658 }
00659
00660 presentation_params->MultiSampleType = D3DMULTISAMPLE_TYPE(supported_multisamples);
00661
00662 if (wdxdisplay9_cat.is_info())
00663 wdxdisplay9_cat.info() << "adapter #" << adapter << " using multisample antialiasing level: " << supported_multisamples <<
00664 ". Requested level was: " << multisamples.get_value() << endl;
00665 break;
00666 }
00667
00668 presentation_params->BackBufferCount = 1;
00669 presentation_params->Flags = 0x0;
00670 presentation_params->hDeviceWindow = display._window;
00671 presentation_params->BackBufferWidth = display._display_mode.Width;
00672 presentation_params->BackBufferHeight = display._display_mode.Height;
00673
00674 if (_wcontext._is_tnl_device) {
00675 dwBehaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
00676
00677
00678
00679
00680
00681
00682 } else {
00683 dwBehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
00684 }
00685
00686 if (dx_preserve_fpu_state)
00687 dwBehaviorFlags |= D3DCREATE_FPU_PRESERVE;
00688
00689
00690
00691
00692
00693
00694 if (!SetForegroundWindow(display._window)) {
00695 wdxdisplay9_cat.warning() << "SetForegroundWindow() failed!\n";
00696 }
00697
00698 if (dx_use_multithread) {
00699 dwBehaviorFlags |= D3DCREATE_MULTITHREADED;
00700 }
00701 if (dx_use_puredevice) {
00702 dwBehaviorFlags |= D3DCREATE_PUREDEVICE;
00703 }
00704
00705 if (dx_disable_driver_management) {
00706 dwBehaviorFlags |= D3DCREATE_DISABLE_DRIVER_MANAGEMENT;
00707 }
00708 if (dx_disable_driver_management_ex) {
00709 dwBehaviorFlags |= D3DCREATE_DISABLE_DRIVER_MANAGEMENT_EX;
00710 }
00711
00712 if (is_fullscreen()) {
00713
00714
00715 presentation_params->SwapEffect = D3DSWAPEFFECT_DISCARD;
00716 presentation_params->PresentationInterval = (do_sync ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE);
00717 presentation_params->FullScreen_RefreshRateInHz = display._display_mode.RefreshRate;
00718
00719 ClearToBlack(display._window, get_properties());
00720
00721 hr = _d3d9->CreateDevice(adapter, device_type, _hWnd,
00722 dwBehaviorFlags, presentation_params, &display._d3d_device);
00723
00724 if (FAILED(hr)) {
00725 wdxdisplay9_cat.fatal() << "D3D CreateDevice failed for adapter #" << adapter << ", " << D3DERRORSTRING(hr);
00726
00727 if (hr == D3DERR_OUTOFVIDEOMEMORY)
00728 goto Fallback_to_16bpp_buffers;
00729 else
00730 return false;
00731 }
00732
00733 SetRect(&view_rect, 0, 0, dwRenderWidth, dwRenderHeight);
00734
00735 } else {
00736
00737
00738 D3DDISPLAYMODE dispmode;
00739 hr = display._d3d9->GetAdapterDisplayMode(adapter, &dispmode);
00740
00741 if (FAILED(hr)) {
00742 wdxdisplay9_cat.fatal()
00743 << "GetAdapterDisplayMode failed" << D3DERRORSTRING(hr);
00744 return false;
00745 }
00746
00747 if (dispmode.Format == D3DFMT_P8) {
00748 wdxdisplay9_cat.fatal()
00749 << "Can't run windowed in an 8-bit or less display mode" << endl;
00750 return false;
00751 }
00752
00753
00754
00755
00756
00757
00758 presentation_params->PresentationInterval = 0;
00759
00760
00761 presentation_params->SwapEffect = D3DSWAPEFFECT_DISCARD;
00762 if (do_sync == false) {
00763 presentation_params->PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
00764 }
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789 hr = _d3d9->CreateDevice(adapter, device_type, _hWnd,
00790 dwBehaviorFlags, presentation_params, &display._d3d_device);
00791
00792 if (FAILED(hr)) {
00793 wdxdisplay9_cat.warning() << "presentation_params->BackBufferWidth : " << presentation_params->BackBufferWidth << endl;
00794 wdxdisplay9_cat.warning() << "presentation_params->BackBufferHeight : " << presentation_params->BackBufferHeight << endl;
00795 wdxdisplay9_cat.warning() << "presentation_params->BackBufferFormat : " << presentation_params->BackBufferFormat << endl;
00796 wdxdisplay9_cat.warning() << "presentation_params->BackBufferCount : " << presentation_params->BackBufferCount << endl;
00797 wdxdisplay9_cat.warning() << "D3D CreateDevice failed for adapter #" << adapter << D3DERRORSTRING(hr);
00798 goto Fallback_to_16bpp_buffers;
00799 }
00800 }
00801
00802
00803
00804 PRINT_REFCNT(wdxdisplay9, _wcontext._d3d_device);
00805
00806 if (presentation_params->EnableAutoDepthStencil) {
00807 int depth_bits;
00808 int stencil_bits;
00809
00810 depth_bits = 1;
00811 stencil_bits = 0;
00812 switch (presentation_params->AutoDepthStencilFormat)
00813 {
00814 case D3DFMT_D16_LOCKABLE:
00815 depth_bits = 16;
00816 break;
00817 case D3DFMT_D32:
00818 depth_bits = 32;
00819 break;
00820 case D3DFMT_D15S1:
00821 depth_bits = 15;
00822 stencil_bits = 1;
00823 break;
00824 case D3DFMT_D24S8:
00825 depth_bits = 24;
00826 stencil_bits = 8;
00827 break;
00828 case D3DFMT_D24X8:
00829 depth_bits = 24;
00830 break;
00831 case D3DFMT_D24X4S4:
00832 depth_bits = 24;
00833 stencil_bits = 4;
00834 break;
00835 case D3DFMT_D32F_LOCKABLE:
00836 depth_bits = 32;
00837 break;
00838 case D3DFMT_D24FS8:
00839 depth_bits = 24;
00840 stencil_bits = 8;
00841 break;
00842 case D3DFMT_D16:
00843 depth_bits = 16;
00844 break;
00845 default:
00846 wdxdisplay9_cat.error() << "unknown depth stencil format " << presentation_params->AutoDepthStencilFormat;
00847 break;
00848 }
00849
00850 _fb_properties.set_stencil_bits(stencil_bits);
00851 _fb_properties.set_depth_bits(depth_bits);
00852 } else {
00853 _fb_properties.set_depth_bits(0);
00854 _fb_properties.set_stencil_bits(0);
00855 }
00856
00857 init_resized_window();
00858
00859 return true;
00860
00861 Fallback_to_16bpp_buffers:
00862 if ((!IS_16BPP_DISPLAY_FORMAT(presentation_params->BackBufferFormat)) &&
00863 (display._supported_screen_depths_mask & (R5G6B5_FLAG|X1R5G5B5_FLAG))) {
00864
00865
00866 display._display_mode.Format = ((display._supported_screen_depths_mask & R5G6B5_FLAG) ? D3DFMT_R5G6B5 : D3DFMT_X1R5G5B5);
00867
00868 if (wdxdisplay9_cat.info()) {
00869 wdxdisplay9_cat.info()
00870 << "CreateDevice failed with out-of-vidmem or invalid BackBufferFormat, retrying w/16bpp buffers on adapter #"
00871 << adapter << endl;
00872 }
00873 return create_screen_buffers_and_device(display, true);
00874
00875
00876 } else if (!((dwRenderWidth == 640)&&(dwRenderHeight == 480))) {
00877 if (wdxdisplay9_cat.info())
00878 wdxdisplay9_cat.info() << "CreateDevice failed w/out-of-vidmem, retrying at 640x480 w/16bpp buffers on adapter #" << adapter << endl;
00879
00880 display._display_mode.Width = 640;
00881 display._display_mode.Height = 480;
00882 return create_screen_buffers_and_device(display, true);
00883
00884
00885 } else {
00886 wdxdisplay9_cat.fatal()
00887 << "Can't create any screen buffers, bailing out.\n";
00888 return false;
00889 }
00890 }
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900 bool wdxGraphicsWindow9::
00901 choose_device() {
00902 HRESULT hr;
00903
00904 wdxGraphicsPipe9 *dxpipe;
00905 DCAST_INTO_R(dxpipe, _pipe, false);
00906
00907 int num_adapters = dxpipe->__d3d9->GetAdapterCount();
00908 DXDeviceInfoVec device_infos;
00909
00910 for (int i = 0; i < num_adapters; i++) {
00911 D3DADAPTER_IDENTIFIER9 adapter_info;
00912 ZeroMemory(&adapter_info, sizeof(D3DADAPTER_IDENTIFIER9));
00913 hr = dxpipe->__d3d9->GetAdapterIdentifier(i, 0, &adapter_info);
00914 if (FAILED(hr)) {
00915 wdxdisplay9_cat.fatal()
00916 << "D3D GetAdapterID(" << i << ") failed: "
00917 << D3DERRORSTRING(hr) << endl;
00918 continue;
00919 }
00920
00921 LARGE_INTEGER *DrvVer = &adapter_info.DriverVersion;
00922
00923 wdxdisplay9_cat.info()
00924 << "D3D9." << (dxpipe->__is_dx9_1 ?"1":"0") << " Adapter[" << i << "]: " << adapter_info.Description
00925 << ", Driver: " << adapter_info.Driver << ", DriverVersion: ("
00926 << HIWORD(DrvVer->HighPart) << "." << LOWORD(DrvVer->HighPart) << "."
00927 << HIWORD(DrvVer->LowPart) << "." << LOWORD(DrvVer->LowPart)
00928 << ")\nVendorID: 0x" << (void*) adapter_info.VendorId
00929 << " DeviceID: 0x" << (void*) adapter_info.DeviceId
00930 << " SubsysID: 0x" << (void*) adapter_info.SubSysId
00931 << " Revision: 0x" << (void*) adapter_info.Revision << endl;
00932
00933 HMONITOR _monitor = dxpipe->__d3d9->GetAdapterMonitor(i);
00934 if (_monitor == NULL) {
00935 wdxdisplay9_cat.info()
00936 << "D3D9 Adapter[" << i << "]: seems to be disabled, skipping it\n";
00937 continue;
00938 }
00939
00940 DXDeviceInfo devinfo;
00941 ZeroMemory(&devinfo, sizeof(devinfo));
00942 memcpy(&devinfo.guidDeviceIdentifier, &adapter_info.DeviceIdentifier,
00943 sizeof(GUID));
00944 strncpy(devinfo.szDescription, adapter_info.Description,
00945 MAX_DEVICE_IDENTIFIER_STRING);
00946 strncpy(devinfo.szDriver, adapter_info.Driver,
00947 MAX_DEVICE_IDENTIFIER_STRING);
00948 devinfo.VendorID = adapter_info.VendorId;
00949 devinfo.DeviceID = adapter_info.DeviceId;
00950 devinfo._driver_version = adapter_info.DriverVersion;
00951 devinfo._monitor = _monitor;
00952 devinfo.cardID = i;
00953
00954 device_infos.push_back(devinfo);
00955 }
00956
00957 if (device_infos.empty()) {
00958 wdxdisplay9_cat.error()
00959 << "No available D3D9 devices found.\n";
00960 return false;
00961 }
00962
00963
00964
00965 num_adapters = (int)device_infos.size();
00966
00967
00968
00969 int adapter_num = D3DADAPTER_DEFAULT;
00970
00971
00972
00973 if (dx_preferred_device_id != -1) {
00974 if (dx_preferred_device_id < 0 || dx_preferred_device_id >= num_adapters) {
00975 wdxdisplay9_cat.error()
00976 << "invalid 'dx-preferred-device-id', valid values are 0-"
00977 << num_adapters - 1 << ", using default adapter instead.\n";
00978 } else {
00979 adapter_num = dx_preferred_device_id;
00980 }
00981 }
00982
00983
00984 if (adapter_num >= 0 && adapter_num < (int)device_infos.size()) {
00985 if (consider_device(dxpipe, &device_infos[adapter_num])) {
00986 wdxdisplay9_cat.info()
00987 << "Selected device " << adapter_num << " (of "
00988 << device_infos.size() << ", zero-based)\n";
00989 return true;
00990 }
00991 wdxdisplay9_cat.info()
00992 << "Could not select device " << adapter_num << "\n";
00993 }
00994
00995
00996
00997 for (UINT devnum = 0; devnum < device_infos.size(); ++devnum) {
00998 if (consider_device(dxpipe, &device_infos[devnum])) {
00999 wdxdisplay9_cat.info()
01000 << "Chose device " << devnum << " (of "
01001 << device_infos.size() << ", zero-based): first one that works.\n";
01002 return true;
01003 }
01004 }
01005
01006 wdxdisplay9_cat.error() << "no usable display devices.\n";
01007 return false;
01008 }
01009
01010
01011
01012
01013
01014
01015
01016
01017 bool wdxGraphicsWindow9::
01018 consider_device(wdxGraphicsPipe9 *dxpipe, DXDeviceInfo *device_info) {
01019
01020 nassertr(dxpipe != NULL, false);
01021 WindowProperties properties = get_properties();
01022 DWORD dwRenderWidth = properties.get_x_size();
01023 DWORD dwRenderHeight = properties.get_y_size();
01024 HRESULT hr;
01025 LPDIRECT3D9 _d3d9 = dxpipe->__d3d9;
01026
01027 nassertr(_dxgsg != NULL, false);
01028 _wcontext._d3d9 = _d3d9;
01029 _wcontext._is_dx9_1 = dxpipe->__is_dx9_1;
01030 _wcontext._card_id = device_info->cardID;
01031
01032 bool bWantStencil = (_fb_properties.get_stencil_bits() > 0);
01033
01034 hr = _d3d9->GetAdapterIdentifier(device_info->cardID, 0,
01035 &_wcontext._dx_device_id);
01036 if (FAILED(hr)) {
01037 wdxdisplay9_cat.error()
01038 << "D3D GetAdapterID failed" << D3DERRORSTRING(hr);
01039 return false;
01040 }
01041
01042 D3DCAPS9 _d3dcaps;
01043 hr = _d3d9->GetDeviceCaps(device_info->cardID, D3DDEVTYPE_HAL, &_d3dcaps);
01044 if (FAILED(hr)) {
01045 if ((hr == D3DERR_INVALIDDEVICE)||(hr == D3DERR_NOTAVAILABLE)) {
01046 wdxdisplay9_cat.error()
01047 << "No DirectX 9 D3D-capable 3D hardware detected for device # "
01048 << device_info->cardID << " (" << device_info->szDescription
01049 << ")!\n";
01050 } else {
01051 wdxdisplay9_cat.error()
01052 << "GetDeviceCaps failed: " << D3DERRORSTRING(hr) << endl;
01053 }
01054 return false;
01055 }
01056
01057
01058 memcpy(&_wcontext._d3dcaps, &_d3dcaps, sizeof(D3DCAPS9));
01059 _wcontext._card_id = device_info->cardID;
01060
01061 _wcontext._max_available_video_memory = UNKNOWN_VIDMEM_SIZE;
01062 _wcontext._is_low_memory_card = false;
01063
01064
01065
01066
01067 if (_d3dcaps.MaxStreams == 0) {
01068 if (wdxdisplay9_cat.is_debug()) {
01069 wdxdisplay9_cat.debug()
01070 << "checking vidmem size\n";
01071 }
01072
01073 UINT IDnum;
01074
01075
01076 for (IDnum = 0; IDnum < dxpipe->_card_ids.size(); IDnum++) {
01077 if ((device_info->VendorID == dxpipe->_card_ids[IDnum].VendorID) &&
01078 (device_info->DeviceID == dxpipe->_card_ids[IDnum].DeviceID) &&
01079 (device_info->_monitor == dxpipe->_card_ids[IDnum]._monitor))
01080 break;
01081 }
01082
01083 if (IDnum < dxpipe->_card_ids.size()) {
01084 _wcontext._max_available_video_memory = dxpipe->_card_ids[IDnum]._max_available_video_memory;
01085 _wcontext._is_low_memory_card = dxpipe->_card_ids[IDnum]._is_low_memory_card;
01086 } else {
01087 wdxdisplay9_cat.error()
01088 << "Error: couldnt find a CardID match in DX7 info, assuming card is not a lowmem card\n";
01089 }
01090 }
01091
01092 if ((bWantStencil) && (_d3dcaps.StencilCaps == 0x0)) {
01093 wdxdisplay9_cat.fatal()
01094 << "Stencil ability requested, but device #" << device_info->cardID
01095 << " (" << _wcontext._dx_device_id.Description
01096 << "), has no stencil capability!\n";
01097 return false;
01098 }
01099
01100
01101
01102
01103
01104 _wcontext._is_tnl_device =
01105 ((_d3dcaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) != 0);
01106 _wcontext._can_use_hw_vertex_shaders =
01107 (_d3dcaps.VertexShaderVersion >= D3DVS_VERSION(1, 0));
01108 _wcontext._can_use_pixel_shaders =
01109 (_d3dcaps.PixelShaderVersion >= D3DPS_VERSION(1, 0));
01110
01111 bool bNeedZBuffer =
01112 ((!(_d3dcaps.RasterCaps & D3DPRASTERCAPS_ZBUFFERLESSHSR )) &&
01113 (_fb_properties.get_depth_bits() > 0));
01114
01115 _wcontext._presentation_params.EnableAutoDepthStencil = bNeedZBuffer;
01116
01117 D3DFORMAT pixFmt = D3DFMT_UNKNOWN;
01118
01119 if (is_fullscreen()) {
01120 bool bCouldntFindValidZBuf;
01121
01122 dxpipe->search_for_valid_displaymode(_wcontext, dwRenderWidth, dwRenderHeight,
01123 bNeedZBuffer, bWantStencil,
01124 &_wcontext._supported_screen_depths_mask,
01125 &bCouldntFindValidZBuf,
01126 &pixFmt, dx_force_16bpp_zbuffer, true);
01127
01128
01129
01130
01131 if (pixFmt == D3DFMT_UNKNOWN) {
01132 wdxdisplay9_cat.error()
01133 << (bCouldntFindValidZBuf ? "Couldnt find valid zbuffer format to go with FullScreen mode" : "No supported FullScreen modes")
01134 << " at " << dwRenderWidth << "x" << dwRenderHeight << " for device #" << _wcontext._card_id << endl;
01135 return false;
01136 }
01137 } else {
01138
01139
01140 D3DDISPLAYMODE dispmode;
01141 hr = _d3d9->GetAdapterDisplayMode(device_info->cardID, &dispmode);
01142 if (FAILED(hr)) {
01143 wdxdisplay9_cat.error()
01144 << "GetAdapterDisplayMode(" << device_info->cardID
01145 << ") failed" << D3DERRORSTRING(hr);
01146 return false;
01147 }
01148 pixFmt = dispmode.Format;
01149 }
01150
01151 _wcontext._display_mode.Width = dwRenderWidth;
01152 _wcontext._display_mode.Height = dwRenderHeight;
01153 _wcontext._display_mode.Format = pixFmt;
01154 _wcontext._display_mode.RefreshRate = D3DPRESENT_RATE_DEFAULT;
01155 _wcontext._monitor = device_info->_monitor;
01156
01157 if (strcmp(device_info->szDriver, "igdumd32.dll") == 0 &&
01158 device_info->_driver_version.QuadPart <= 0x0007000e000affffLL &&
01159 dx_intel_compressed_texture_bug) {
01160
01161
01162
01163 _wcontext._intel_compressed_texture_bug = true;
01164 }
01165
01166 return true;
01167 }
01168
01169
01170
01171
01172
01173
01174
01175
01176 bool wdxGraphicsWindow9::
01177 reset_device_resize_window(UINT new_xsize, UINT new_ysize) {
01178 bool retval = true;
01179
01180 DXScreenData *screen = NULL;
01181 D3DPRESENT_PARAMETERS d3dpp;
01182 memcpy(&d3dpp, &_wcontext._presentation_params, sizeof(D3DPRESENT_PARAMETERS));
01183 _wcontext._presentation_params.BackBufferWidth = new_xsize;
01184 _wcontext._presentation_params.BackBufferHeight = new_ysize;
01185 make_current();
01186 HRESULT hr = _dxgsg->reset_d3d_device(&_wcontext._presentation_params, &screen);
01187
01188 if (FAILED(hr)) {
01189 retval = false;
01190 wdxdisplay9_cat.error()
01191 << "reset_device_resize_window Reset() failed" << D3DERRORSTRING(hr);
01192 if (hr == D3DERR_OUTOFVIDEOMEMORY) {
01193 memcpy(&_wcontext._presentation_params, &d3dpp, sizeof(D3DPRESENT_PARAMETERS));
01194 hr = _dxgsg->reset_d3d_device(&_wcontext._presentation_params, &screen);
01195 if (FAILED(hr)) {
01196 wdxdisplay9_cat.error()
01197 << "reset_device_resize_window Reset() failed OutOfVidmem, then failed again doing Reset w/original params:" << D3DERRORSTRING(hr);
01198 throw_event("panda3d-render-error");
01199 return false;
01200
01201 } else {
01202 if (wdxdisplay9_cat.is_info()) {
01203 wdxdisplay9_cat.info()
01204 << "reset of original size (" << _wcontext._presentation_params.BackBufferWidth
01205 << ", " << _wcontext._presentation_params.BackBufferHeight << ") succeeded\n";
01206 }
01207 }
01208 } else {
01209 wdxdisplay9_cat.fatal()
01210 << "Can't reset device, bailing out.\n";
01211 throw_event("panda3d-render-error");
01212 return false;
01213 }
01214 }
01215
01216 if (screen) {
01217 _wcontext._swap_chain = screen->_swap_chain;
01218 }
01219 wdxdisplay9_cat.debug() << "swapchain is " << _wcontext._swap_chain << "\n";
01220 _gsg->mark_new();
01221 init_resized_window();
01222 return retval;
01223 }
01224
01225
01226
01227
01228
01229
01230
01231
01232
01233
01234
01235 void wdxGraphicsWindow9::
01236 init_resized_window() {
01237 HRESULT hr;
01238
01239 DWORD newWidth = _wcontext._presentation_params.BackBufferWidth;
01240 DWORD newHeight = _wcontext._presentation_params.BackBufferHeight;
01241
01242 nassertv((newWidth != 0) && (newHeight != 0));
01243 nassertv(_wcontext._window != NULL);
01244
01245 if (_wcontext._presentation_params.Windowed) {
01246 POINT ul, lr;
01247 RECT client_rect;
01248
01249
01250
01251
01252 GetClientRect(_wcontext._window, &client_rect);
01253 ul.x = client_rect.left;
01254 ul.y = client_rect.top;
01255 lr.x = client_rect.right;
01256 lr.y = client_rect.bottom;
01257 ClientToScreen(_wcontext._window, &ul);
01258 ClientToScreen(_wcontext._window, &lr);
01259 client_rect.left = ul.x;
01260 client_rect.top = ul.y;
01261 client_rect.right = lr.x;
01262 client_rect.bottom = lr.y;
01263 }
01264
01265
01266 nassertv(_wcontext._window != NULL);
01267 ClearToBlack(_wcontext._window, get_properties());
01268
01269
01270 hr = _wcontext._d3d_device->EvictManagedResources ( );
01271 if (FAILED(hr)) {
01272 wdxdisplay9_cat.error()
01273 << "EvictManagedResources failed for device #"
01274 << _wcontext._card_id << D3DERRORSTRING(hr);
01275 }
01276
01277 make_current();
01278
01279
01280 _dxgsg->set_render_target ( );
01281
01282
01283 DWORD flags;
01284 D3DCOLOR clear_color;
01285
01286 flags = D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER;
01287 clear_color = 0x00000000;
01288 hr = _wcontext._d3d_device-> Clear (0, NULL, flags, clear_color, 0.0f, 0);
01289 if (FAILED(hr)) {
01290 wdxdisplay9_cat.error()
01291 << "Clear failed for device"
01292 << D3DERRORSTRING(hr);
01293 }
01294 hr = _wcontext._d3d_device-> Present (NULL, NULL, NULL, NULL);
01295 if (FAILED(hr)) {
01296 wdxdisplay9_cat.error()
01297 << "Present failed for device"
01298 << D3DERRORSTRING(hr);
01299 }
01300 hr = _wcontext._d3d_device-> Clear (0, NULL, flags, clear_color, 0.0f, 0);
01301 if (FAILED(hr)) {
01302 wdxdisplay9_cat.error()
01303 << "Clear failed for device"
01304 << D3DERRORSTRING(hr);
01305 }
01306 }
01307
01308
01309
01310
01311
01312
01313
01314 int wdxGraphicsWindow9::
01315 D3DFMT_to_DepthBits(D3DFORMAT fmt) {
01316 switch(fmt) {
01317 case D3DFMT_D16:
01318 return 16;
01319
01320 case D3DFMT_D24X8:
01321 case D3DFMT_D24X4S4:
01322 case D3DFMT_D24S8:
01323 return 24;
01324
01325 case D3DFMT_D32:
01326 return 32;
01327
01328 case D3DFMT_D15S1:
01329 return 15;
01330
01331 default:
01332 wdxdisplay9_cat.debug()
01333 << "D3DFMT_DepthBits: unhandled D3DFMT!\n";
01334 return 0;
01335 }
01336 }
01337
01338
01339
01340
01341
01342
01343
01344
01345 bool wdxGraphicsWindow9::
01346 is_badvidmem_card(D3DADAPTER_IDENTIFIER9 *pDevID) {
01347
01348 if (pDevID->VendorId == 0x00008086) {
01349 return true;
01350 }
01351
01352 return false;
01353 }
01354