/* Starshatter: The Open Source Project Copyright (c) 2021-2024, Starshatter: The Open Source Project Contributors Copyright (c) 2011-2012, Starshatter OpenSource Distribution Contributors Copyright (c) 1997-2006, Destroyer Studios LLC. AUTHOR: John DiCamillo OVERVIEW ======== Direct3D Video class for DirectX 9 */ #include "VideoDX9Enum.h" #include "VideoSettings.h" #include "Color.h" #include "Utils.h" // +--------------------------------------------------------------------+ char* DDErrStr(HRESULT dderr); void VideoDX9Error(const char* msg, HRESULT dderr); int VD3D_describe_things; #ifndef RELEASE #define RELEASE(x) if (x) { x->Release(); x=NULL; } #endif // +--------------------------------------------------------------------+ static UINT GetBitsPerPixel(D3DFORMAT fmt) { switch (fmt) { case D3DFMT_A8R8G8B8: return 32; case D3DFMT_X8R8G8B8: return 32; case D3DFMT_A2B10G10R10: return 32; case D3DFMT_A2R10G10B10: return 32; case D3DFMT_R8G8B8: return 24; case D3DFMT_R5G6B5: return 16; case D3DFMT_X1R5G5B5: return 16; case D3DFMT_A1R5G5B5: return 16; case D3DFMT_A4R4G4B4: return 16; case D3DFMT_A8R3G3B2: return 16; case D3DFMT_X4R4G4B4: return 16; case D3DFMT_R3G3B2: return 8; default: return 0; } } // +--------------------------------------------------------------------+ static UINT GetColorChannelBits(D3DFORMAT fmt) { switch (fmt) { case D3DFMT_A2B10G10R10: return 10; case D3DFMT_A2R10G10B10: return 10; case D3DFMT_R8G8B8: return 8; case D3DFMT_A8R8G8B8: return 8; case D3DFMT_X8R8G8B8: return 8; case D3DFMT_R5G6B5: return 6; case D3DFMT_X1R5G5B5: return 5; case D3DFMT_A1R5G5B5: return 5; case D3DFMT_A4R4G4B4: return 4; case D3DFMT_R3G3B2: return 2; case D3DFMT_A8R3G3B2: return 2; case D3DFMT_X4R4G4B4: return 4; default: return 0; } } // +--------------------------------------------------------------------+ static UINT GetAlphaChannelBits(D3DFORMAT fmt) { switch (fmt) { case D3DFMT_R8G8B8: return 0; case D3DFMT_A8R8G8B8: return 8; case D3DFMT_X8R8G8B8: return 0; case D3DFMT_R5G6B5: return 0; case D3DFMT_X1R5G5B5: return 0; case D3DFMT_A1R5G5B5: return 1; case D3DFMT_A4R4G4B4: return 4; case D3DFMT_R3G3B2: return 0; case D3DFMT_A8R3G3B2: return 8; case D3DFMT_X4R4G4B4: return 0; case D3DFMT_A2B10G10R10: return 2; case D3DFMT_A2R10G10B10: return 2; default: return 0; } } // +--------------------------------------------------------------------+ static UINT GetDepthBits(D3DFORMAT fmt) { switch (fmt) { case D3DFMT_D16: return 16; case D3DFMT_D15S1: return 15; case D3DFMT_D24X8: return 24; case D3DFMT_D24S8: return 24; case D3DFMT_D24X4S4: return 24; case D3DFMT_D32: return 32; default: return 0; } } // +--------------------------------------------------------------------+ static UINT GetStencilBits(D3DFORMAT fmt) { switch (fmt) { case D3DFMT_D16: return 0; case D3DFMT_D15S1: return 1; case D3DFMT_D24X8: return 0; case D3DFMT_D24S8: return 8; case D3DFMT_D24X4S4: return 4; case D3DFMT_D32: return 0; default: return 0; } } // +--------------------------------------------------------------------+ // // This routine prints a text description of the indicated driver // into the error log file. static void DescribeGUID(GUID* lpGUID) { if (lpGUID) Print(" GUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", lpGUID->Data1, lpGUID->Data2, lpGUID->Data3, lpGUID->Data4[0], lpGUID->Data4[1], lpGUID->Data4[2], lpGUID->Data4[3], lpGUID->Data4[4], lpGUID->Data4[5], lpGUID->Data4[6], lpGUID->Data4[7]); else Print(" GUID IS NULL!\n"); } // +--------------------------------------------------------------------+ VideoDX9Enum::VideoDX9Enum(IDirect3D9* d3d9) { if (d3d9) { d3d = d3d9; d3d->AddRef(); } min_width = 640; min_height = 480; min_color_bits = 5; min_alpha_bits = 0; min_depth_bits = 16; min_stencil_bits = 0; uses_depth_buffer = false; uses_mixed_vp = false; req_windowed = false; req_fullscreen = false; adapter_index = 0; } VideoDX9Enum::~VideoDX9Enum() { adapter_info_list.destroy(); RELEASE(d3d); } void VideoDX9Enum::SetDirect3D9(IDirect3D9* d3d9) { RELEASE(d3d); if (d3d9) { d3d = d3d9; d3d->AddRef(); } } // +--------------------------------------------------------------------+ void VideoDX9Enum::SelectAdapter(int index) { if (index >= 0 && index < adapter_info_list.size()) adapter_index = index; } VideoDX9AdapterInfo* VideoDX9Enum::GetAdapterInfo() { if (adapter_index >= 0 && adapter_index < adapter_info_list.size()) return adapter_info_list[adapter_index]; return 0; } VideoDX9DeviceInfo* VideoDX9Enum::GetDeviceInfo(DWORD devtype) { if (adapter_index >= 0 && adapter_index < adapter_info_list.size()) { VideoDX9AdapterInfo* adapter = adapter_info_list[adapter_index]; if (adapter) { ListIter iter = adapter->device_info_list; while (++iter) { VideoDX9DeviceInfo* dev_info = iter.value(); if (dev_info->device_type == (D3DDEVTYPE) devtype) return dev_info; } } } return 0; } bool VideoDX9Enum::IsModeSupported(int w, int h, int b) const { if (adapter_index >= 0 && adapter_index < adapter_info_list.size()) { VideoDX9AdapterInfo* adapter = adapter_info_list[adapter_index]; ListIter mode_iter = adapter->display_mode_list; while (++mode_iter) { VideoDX9DisplayMode* mode = mode_iter.value(); if (mode->width == (UINT) w && mode->height == (UINT) h && GetBitsPerPixel(mode->format) == (UINT) b) { return true; } } } return false; } // +--------------------------------------------------------------------+ HRESULT VideoDX9Enum::Enumerate() { HRESULT hr = E_FAIL; if (!d3d) return hr; if (VD3D_describe_things > 0) { Print("Video DX9 Enumerate Adapters and Devices\n"); Print("----------------------------------------\n\n"); } allowed_adapter_format_list.push_back(D3DFMT_X8R8G8B8); allowed_adapter_format_list.push_back(D3DFMT_X1R5G5B5); allowed_adapter_format_list.push_back(D3DFMT_R5G6B5); allowed_adapter_format_list.push_back(D3DFMT_A2R10G10B10); VideoDX9AdapterInfo* adapter_info = 0; std::vector adapter_format_list; UINT num_adapters = d3d->GetAdapterCount(); for (UINT ordinal = 0; ordinal < num_adapters; ordinal++) { adapter_info = new VideoDX9AdapterInfo; if (!adapter_info) return E_OUTOFMEMORY; adapter_info->adapter_ordinal = ordinal; d3d->GetAdapterIdentifier(ordinal, 0, &adapter_info->adapter_identifier); // Get list of all display modes on this adapter. // Also build a temporary list of all display adapter formats. adapter_format_list.clear(); for (size_t iaaf = 0; iaaf < allowed_adapter_format_list.size(); iaaf++) { D3DFORMAT allowed_adapter_format = allowed_adapter_format_list[iaaf]; UINT num_adapter_modes = d3d->GetAdapterModeCount(ordinal, allowed_adapter_format); for (UINT mode = 0; mode < num_adapter_modes; mode++) { D3DDISPLAYMODE display_mode; d3d->EnumAdapterModes(ordinal, allowed_adapter_format, mode, &display_mode); if (display_mode.Width < min_width || display_mode.Height < min_height || GetColorChannelBits(display_mode.Format) < min_color_bits) { continue; } VideoDX9DisplayMode* dx9_display_mode = new VideoDX9DisplayMode(display_mode); if (!dx9_display_mode) { delete adapter_info; return E_OUTOFMEMORY; } adapter_info->display_mode_list.append(dx9_display_mode); bool contains_display_mode = false; for (auto afli = adapter_format_list.begin(); afli != adapter_format_list.end(); ++afli) { if (*afli == display_mode.Format) { contains_display_mode = true; break; } } if (!contains_display_mode) adapter_format_list.push_back(display_mode.Format); } } // Sort displaymode list adapter_info->display_mode_list.sort(); if (VD3D_describe_things > 0) { Print("Adapter %d. %s\n", ordinal, adapter_info->adapter_identifier.Description); DescribeGUID(&adapter_info->adapter_identifier.DeviceIdentifier); if (VD3D_describe_things > 4) { ListIter m_iter = adapter_info->display_mode_list; while (++m_iter) { VideoDX9DisplayMode* m = m_iter.value(); Print(" Mode %3d %s\n", m_iter.index(), m->GetDescription()); } Print("\n"); } } // Get info for each device on this adapter if (FAILED(hr = EnumerateDevices(adapter_info, adapter_format_list))) { delete adapter_info; return hr; } // If at least one device on this adapter is available and compatible // with the app, add the adapterInfo to the list if (adapter_info->device_info_list.size() == 0) delete adapter_info; else adapter_info_list.append(adapter_info); if (VD3D_describe_things > 0) { Print("\n"); } } return S_OK; } // +--------------------------------------------------------------------+ HRESULT VideoDX9Enum::EnumerateDevices(VideoDX9AdapterInfo* adapter_info, std::vector& adapter_format_list) { HRESULT hr = E_FAIL; const D3DDEVTYPE dtypes[3] = { D3DDEVTYPE_HAL, D3DDEVTYPE_SW, D3DDEVTYPE_REF }; const char* dtypestr[3] = { "D3DDEVTYPE_HAL", "D3DDEVTYPE_SW", "D3DDEVTYPE_REF" }; VideoDX9DeviceInfo* device_info = 0; for (int i = 0; i < 3; i++ ) { device_info = new VideoDX9DeviceInfo; if (!device_info) return E_OUTOFMEMORY; device_info->adapter_ordinal = adapter_info->adapter_ordinal; device_info->device_type = dtypes[i]; if (FAILED(d3d->GetDeviceCaps(adapter_info->adapter_ordinal, device_info->device_type, &device_info->caps))) { delete device_info; continue; } if (VD3D_describe_things > 1) { Print(" Device %d - %s\n", i, dtypestr[i]); Print(" Max Texture Width: %d\n", device_info->caps.MaxTextureWidth); Print(" Max Texture Height: %d\n", device_info->caps.MaxTextureHeight); } // Get info for each device combo on this device if (FAILED(hr = EnumerateDeviceCombos(device_info, adapter_format_list))) { delete device_info; return hr; } // make sure at least one devicecombo for this device was found if (device_info->device_combo_list.size() < 1) { delete device_info; continue; } adapter_info->device_info_list.append(device_info); } return S_OK; } // +--------------------------------------------------------------------+ HRESULT VideoDX9Enum::EnumerateDeviceCombos(VideoDX9DeviceInfo* device_info, std::vector& adapter_format_list) { const D3DFORMAT back_buffer_formats[] = { D3DFMT_A8R8G8B8, D3DFMT_X8R8G8B8, D3DFMT_R8G8B8, D3DFMT_R5G6B5, D3DFMT_A1R5G5B5, D3DFMT_X1R5G5B5 }; bool is_windowed[] = { false, true }; // See which adapter formats are supported by this device D3DFORMAT a_fmt; for (size_t i = 0; i < adapter_format_list.size(); i++) { a_fmt = adapter_format_list[i]; D3DFORMAT b_fmt; for (int n = 0; n < 6; n++) { b_fmt = back_buffer_formats[n]; if (GetAlphaChannelBits(b_fmt) < min_alpha_bits) continue; bool win; for (int w = 0; w < 2; w++) { win = is_windowed[w]; if (!win && req_windowed) continue; if (win && req_fullscreen) continue; if (FAILED(d3d->CheckDeviceType(device_info->adapter_ordinal, device_info->device_type, a_fmt, b_fmt, win))) { continue; } // At this point, we have an adapter/device/adapterformat/backbufferformat/iswindowed // DeviceCombo that is supported by the system. We still need to confirm that it's // compatible with the app, and find one or more suitable depth/stencil buffer format, // multisample type, vertex processing type, and present interval. VideoDX9DeviceCombo* device_combo = 0; device_combo = new VideoDX9DeviceCombo; if (!device_combo) return E_OUTOFMEMORY; device_combo->adapter_ordinal = device_info->adapter_ordinal; device_combo->device_type = device_info->device_type; device_combo->adapter_format = a_fmt; device_combo->back_buffer_format = b_fmt; device_combo->is_windowed = win; if (uses_depth_buffer) { BuildDepthStencilFormatList(device_combo); if (device_combo->depth_stencil_fmt_list.size() < 1) { delete device_combo; continue; } } BuildMultiSampleTypeList(device_combo); if (device_combo->multisample_type_list.size() < 1) { delete device_combo; continue; } BuildDSMSConflictList(device_combo); BuildVertexProcessingTypeList(device_info, device_combo); if (device_combo->vertex_processing_list.size() < 1) { delete device_combo; continue; } BuildPresentIntervalList(device_info, device_combo); device_info->device_combo_list.append(device_combo); } } } return S_OK; } void VideoDX9Enum::BuildDepthStencilFormatList(VideoDX9DeviceCombo* device_combo) { const D3DFORMAT depth_stencil_formats[] = { D3DFMT_D32, D3DFMT_D24S8, D3DFMT_D24X4S4, D3DFMT_D24X8, D3DFMT_D16, D3DFMT_D15S1, }; for (int i = 0; i < 6; i++) { D3DFORMAT fmt = depth_stencil_formats[i]; if (GetDepthBits(fmt) < min_depth_bits) continue; if (GetStencilBits(fmt) < min_stencil_bits) continue; if (SUCCEEDED(d3d->CheckDeviceFormat(device_combo->adapter_ordinal, device_combo->device_type, device_combo->adapter_format, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, fmt))) { if (SUCCEEDED(d3d->CheckDepthStencilMatch(device_combo->adapter_ordinal, device_combo->device_type, device_combo->adapter_format, device_combo->back_buffer_format, fmt))) { device_combo->depth_stencil_fmt_list.push_back(fmt); } } } } void VideoDX9Enum::BuildMultiSampleTypeList(VideoDX9DeviceCombo* device_combo) { const D3DMULTISAMPLE_TYPE multisample_type_array[] = { D3DMULTISAMPLE_NONE, D3DMULTISAMPLE_NONMASKABLE, D3DMULTISAMPLE_2_SAMPLES, D3DMULTISAMPLE_3_SAMPLES, D3DMULTISAMPLE_4_SAMPLES, D3DMULTISAMPLE_5_SAMPLES, D3DMULTISAMPLE_6_SAMPLES, D3DMULTISAMPLE_7_SAMPLES, D3DMULTISAMPLE_8_SAMPLES, D3DMULTISAMPLE_9_SAMPLES, D3DMULTISAMPLE_10_SAMPLES, D3DMULTISAMPLE_11_SAMPLES, D3DMULTISAMPLE_12_SAMPLES, D3DMULTISAMPLE_13_SAMPLES, D3DMULTISAMPLE_14_SAMPLES, D3DMULTISAMPLE_15_SAMPLES, D3DMULTISAMPLE_16_SAMPLES, }; for (int i = 0; i < 17; i++) { D3DMULTISAMPLE_TYPE multisample_type = multisample_type_array[i]; DWORD multisample_qual = 0; if (SUCCEEDED(d3d->CheckDeviceMultiSampleType(device_combo->adapter_ordinal, device_combo->device_type, device_combo->back_buffer_format, device_combo->is_windowed, multisample_type, &multisample_qual))) { device_combo->multisample_type_list.push_back(multisample_type); device_combo->multisample_qual_list.push_back(multisample_qual); } } } void VideoDX9Enum::BuildDSMSConflictList(VideoDX9DeviceCombo* device_combo) { for (size_t i = 0; i < device_combo->depth_stencil_fmt_list.size(); i++) { D3DFORMAT depth_format = (D3DFORMAT) device_combo->depth_stencil_fmt_list[i]; for (size_t n = 0; n < device_combo->multisample_type_list.size(); n++) { D3DMULTISAMPLE_TYPE multisample_type = (D3DMULTISAMPLE_TYPE) device_combo->multisample_type_list[n]; if (FAILED(d3d->CheckDeviceMultiSampleType(device_combo->adapter_ordinal, device_combo->device_type, depth_format, device_combo->is_windowed, multisample_type, NULL))) { VideoDX9FormatConflict* conflict = new VideoDX9FormatConflict; conflict->ds_format = depth_format; conflict->multisample_type = multisample_type; device_combo->conflict_list.append(conflict); } } } } void VideoDX9Enum::BuildVertexProcessingTypeList(VideoDX9DeviceInfo* device_info, VideoDX9DeviceCombo* device_combo) { if ((device_info->caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) != 0) { if ((device_info->caps.DevCaps & D3DDEVCAPS_PUREDEVICE) != 0) { device_combo->vertex_processing_list.push_back(PURE_HARDWARE_VP); } device_combo->vertex_processing_list.push_back(HARDWARE_VP); if (uses_mixed_vp) { device_combo->vertex_processing_list.push_back(MIXED_VP); } } device_combo->vertex_processing_list.push_back(SOFTWARE_VP); } void VideoDX9Enum::BuildPresentIntervalList(VideoDX9DeviceInfo* device_info, VideoDX9DeviceCombo* device_combo) { const DWORD present_interval_array[] = { D3DPRESENT_INTERVAL_IMMEDIATE, D3DPRESENT_INTERVAL_DEFAULT, D3DPRESENT_INTERVAL_ONE, D3DPRESENT_INTERVAL_TWO, D3DPRESENT_INTERVAL_THREE, D3DPRESENT_INTERVAL_FOUR, }; for (int i = 0; i < 6; i++) { DWORD interval = present_interval_array[i]; if (device_combo->is_windowed && i > 2) { // none of the remaining intervals are supported in windowed mode. break; } // Note that D3DPRESENT_INTERVAL_DEFAULT is zero, so you // can't do a caps check for it -- it is always available. if (interval == D3DPRESENT_INTERVAL_DEFAULT || (device_info->caps.PresentationIntervals & interval)) { device_combo->present_interval_list.push_back(interval); } } } bool VideoDX9Enum::SuggestWindowSettings(VideoSettings* vs) { if (!vs) return false; // Get display mode of primary adapter (which is assumed to be where the window // will appear) D3DDISPLAYMODE desktop_display_mode; d3d->GetAdapterDisplayMode(0, &desktop_display_mode); VideoDX9AdapterInfo* best_adapter_info = 0; VideoDX9DeviceInfo* best_device_info = 0; VideoDX9DeviceCombo* best_device_combo = 0; int best_adapter_index = 0; int best_device_index = 0; ListIter a_iter = adapter_info_list; while (++a_iter) { VideoDX9AdapterInfo* adapter_info = a_iter.value(); ListIter d_iter = adapter_info->device_info_list; while (++d_iter) { VideoDX9DeviceInfo* device_info = d_iter.value(); ListIter c_iter = device_info->device_combo_list; while (++c_iter) { VideoDX9DeviceCombo* device_combo = c_iter.value(); bool formats_match = (device_combo->back_buffer_format == device_combo->adapter_format); if (!device_combo->is_windowed) continue; if (device_combo->adapter_format != desktop_display_mode.Format) continue; // If we haven't found a compatible DeviceCombo yet, or if this set // is better (because it's a HAL, and/or because formats match better), // save it if (best_device_combo == NULL || best_device_combo->device_type != D3DDEVTYPE_HAL && device_combo->device_type == D3DDEVTYPE_HAL || device_combo->device_type == D3DDEVTYPE_HAL && formats_match) { best_adapter_info = adapter_info; best_adapter_index = a_iter.index(); best_device_info = device_info; best_device_index = d_iter.index(); best_device_combo = device_combo; if (device_combo->device_type == D3DDEVTYPE_HAL && formats_match) { // This windowed device combo looks great -- take it goto EndWindowedDeviceComboSearch; } // Otherwise keep looking for a better windowed device combo } } } } EndWindowedDeviceComboSearch: if (best_device_combo == NULL) return false; VideoDeviceInfo* win_device = &vs->windowed_device; vs->is_windowed = true; vs->windowed_mode.width = desktop_display_mode.Width; vs->windowed_mode.height = desktop_display_mode.Height; vs->windowed_mode.refresh = desktop_display_mode.RefreshRate; vs->windowed_mode.format = desktop_display_mode.Format; win_device->adapter_index = best_adapter_index; win_device->device_index = best_device_index; win_device->device_type = best_device_info->device_type; win_device->back_buffer_format = best_device_combo->back_buffer_format; win_device->depth_buffer_bits = GetDepthBits((D3DFORMAT) best_device_combo->depth_stencil_fmt_list[0]); win_device->depth_stencil_format = best_device_combo->depth_stencil_fmt_list[0]; win_device->multisample_type = best_device_combo->multisample_type_list[0]; win_device->multisample_qual = best_device_combo->multisample_qual_list[0]; win_device->vertex_processing = best_device_combo->vertex_processing_list[0]; return true; } bool VideoDX9Enum::SuggestFullscreenSettings(VideoSettings* vs) { if (!vs) return false; WORD desired_width = vs->fullscreen_mode.width; WORD desired_height = vs->fullscreen_mode.height; // For fullscreen, default to first HAL DeviceCombo that supports the current desktop // display mode, or any display mode if HAL is not compatible with the desktop mode, or // non-HAL if no HAL is available D3DDISPLAYMODE desktop_display_mode; D3DDISPLAYMODE best_desktop_display_mode; best_desktop_display_mode.Width = 0; best_desktop_display_mode.Height = 0; best_desktop_display_mode.Format = D3DFMT_UNKNOWN; best_desktop_display_mode.RefreshRate = 0; VideoDX9AdapterInfo* best_adapter_info = 0; VideoDX9DeviceInfo* best_device_info = 0; VideoDX9DeviceCombo* best_device_combo = 0; int best_adapter_index = 0; int best_device_index = 0; ListIter a_iter = adapter_info_list; while (++a_iter) { VideoDX9AdapterInfo* adapter_info = a_iter.value(); d3d->GetAdapterDisplayMode(adapter_info->adapter_ordinal, &desktop_display_mode); ListIter d_iter = adapter_info->device_info_list; while (++d_iter) { VideoDX9DeviceInfo* device_info = d_iter.value(); ListIter c_iter = device_info->device_combo_list; while (++c_iter) { VideoDX9DeviceCombo* device_combo = c_iter.value(); bool bAdapterMatchesBB = (device_combo->back_buffer_format == device_combo->adapter_format); bool bAdapterMatchesDesktop = (device_combo->adapter_format == desktop_display_mode.Format); if (device_combo->is_windowed) continue; // If we haven't found a compatible set yet, or if this set // is better (because it's a HAL, and/or because formats match better), // save it if (best_device_combo == NULL || best_device_combo->device_type != D3DDEVTYPE_HAL && device_info->device_type == D3DDEVTYPE_HAL || device_combo->device_type == D3DDEVTYPE_HAL && best_device_combo->adapter_format != desktop_display_mode.Format && bAdapterMatchesDesktop || device_combo->device_type == D3DDEVTYPE_HAL && bAdapterMatchesDesktop && bAdapterMatchesBB ) { best_desktop_display_mode = desktop_display_mode; best_adapter_info = adapter_info; best_device_info = device_info; best_device_combo = device_combo; if (device_info->device_type == D3DDEVTYPE_HAL && bAdapterMatchesDesktop && bAdapterMatchesBB) { // This fullscreen device combo looks great -- take it goto EndFullscreenDeviceComboSearch; } // Otherwise keep looking for a better fullscreen device combo } } } } EndFullscreenDeviceComboSearch: if (best_device_combo == NULL) return false; // Need to find a display mode on the best adapter that uses best_device_combo->adapter_format // and is as close to best_desktop_display_mode's res as possible VideoDX9DisplayMode best_display_mode; ListIter m_iter = best_adapter_info->display_mode_list; while (++m_iter) { VideoDX9DisplayMode* display_mode = m_iter.value(); if (display_mode->format != best_device_combo->adapter_format) continue; if (display_mode->width == desired_width && //best_desktop_display_mode.Width && display_mode->height == desired_height && //best_desktop_display_mode.Height && display_mode->refresh == best_desktop_display_mode.RefreshRate) { // found a perfect match, so stop best_display_mode = *display_mode; break; } else if (display_mode->width == desired_width && //best_desktop_display_mode.Width && display_mode->height == desired_height && //best_desktop_display_mode.Height && display_mode->refresh > best_desktop_display_mode.RefreshRate) { // refresh rate doesn't match, but width/height match, so keep this // and keep looking best_display_mode = *display_mode; } else if (display_mode->width == desired_width) { //best_desktop_display_mode.Width) { // width matches, so keep this and keep looking best_display_mode = *display_mode; } else if (best_display_mode.width == 0) { // we don't have anything better yet, so keep this and keep looking best_display_mode = *display_mode; } } VideoDeviceInfo* fs_device = &vs->fullscreen_device; vs->is_windowed = false; vs->fullscreen_mode.width = best_display_mode.width; vs->fullscreen_mode.height = best_display_mode.height; vs->fullscreen_mode.refresh = best_display_mode.refresh; vs->fullscreen_mode.format = best_display_mode.format; fs_device->adapter_index = best_adapter_index; fs_device->device_index = best_device_index; fs_device->device_type = best_device_info->device_type; fs_device->back_buffer_format = best_device_combo->back_buffer_format; fs_device->depth_buffer_bits = GetDepthBits((D3DFORMAT) best_device_combo->depth_stencil_fmt_list[0]); fs_device->depth_stencil_format = best_device_combo->depth_stencil_fmt_list[0]; fs_device->multisample_type = best_device_combo->multisample_type_list[0]; fs_device->multisample_qual = best_device_combo->multisample_qual_list[0]; fs_device->vertex_processing = best_device_combo->vertex_processing_list[0]; return true; } // +--------------------------------------------------------------------+ // +--------------------------------------------------------------------+ // +--------------------------------------------------------------------+ VideoDX9DisplayMode::VideoDX9DisplayMode() : width(0), height(0), refresh(0), format(D3DFMT_UNKNOWN) { } VideoDX9DisplayMode::VideoDX9DisplayMode(const VideoDX9DisplayMode& m) : width(m.width), height(m.height), refresh(m.refresh), format(m.format) { } VideoDX9DisplayMode::VideoDX9DisplayMode(const D3DDISPLAYMODE& m) : width(m.Width), height(m.Height), refresh(m.RefreshRate), format(m.Format) { } int VideoDX9DisplayMode::operator<(const VideoDX9DisplayMode& m) const { if (width < m.width) return 1; if (width > m.width) return 0; if (height < m.height) return 1; if (height > m.height) return 0; if (format < m.format) return 1; if (format > m.format) return 0; if (refresh < m.refresh) return 1; return 0; } int VideoDX9DisplayMode::operator<=(const VideoDX9DisplayMode& m) const { // if less than ... if (*this < m) return 1; // ... or equal to ... if (width == m.width && height == m.height && format == m.format && refresh == m.refresh) return 1; // must be greater than return 0; } const char* VideoDX9DisplayMode::GetDescription() const { static char desc[32]; sprintf_s(desc, "%4d x %4d %-12s %d Hz", //-V576 width, height, D3DFormatToString(format), refresh); return desc; } const char* VideoDX9DisplayMode::D3DFormatToString(D3DFORMAT format) { const char* str = "Unknown Format"; switch (format) { case D3DFMT_UNKNOWN: str = "UNKNOWN"; break; case D3DFMT_R8G8B8: str = "R8G8B8"; break; case D3DFMT_A8R8G8B8: str = "A8R8G8B8"; break; case D3DFMT_X8R8G8B8: str = "X8R8G8B8"; break; case D3DFMT_R5G6B5: str = "R5G6B5"; break; case D3DFMT_X1R5G5B5: str = "X1R5G5B5"; break; case D3DFMT_A1R5G5B5: str = "A1R5G5B5"; break; case D3DFMT_A4R4G4B4: str = "A4R4G4B4"; break; case D3DFMT_R3G3B2: str = "R3G3B2"; break; case D3DFMT_A8: str = "A8"; break; case D3DFMT_A8R3G3B2: str = "A8R3G3B2"; break; case D3DFMT_X4R4G4B4: str = "X4R4G4B4"; break; case D3DFMT_A2B10G10R10: str = "A2B10G10R10"; break; case D3DFMT_A8B8G8R8: str = "A8B8G8R8"; break; case D3DFMT_X8B8G8R8: str = "X8B8G8R8"; break; case D3DFMT_G16R16: str = "G16R16"; break; case D3DFMT_A2R10G10B10: str = "A2R10G10B10"; break; case D3DFMT_A16B16G16R16: str = "A16B16G16R16"; break; case D3DFMT_A8P8: str = "A8P8"; break; case D3DFMT_P8: str = "P8"; break; case D3DFMT_L8: str = "L8"; break; case D3DFMT_A8L8: str = "A8L8"; break; case D3DFMT_A4L4: str = "A4L4"; break; case D3DFMT_V8U8: str = "V8U8"; break; case D3DFMT_L6V5U5: str = "L6V5U5"; break; case D3DFMT_X8L8V8U8: str = "X8L8V8U8"; break; case D3DFMT_Q8W8V8U8: str = "Q8W8V8U8"; break; case D3DFMT_V16U16: str = "V16U16"; break; case D3DFMT_A2W10V10U10: str = "A2W10V10U10"; break; case D3DFMT_UYVY: str = "UYVY"; break; case D3DFMT_YUY2: str = "YUY2"; break; case D3DFMT_DXT1: str = "DXT1"; break; case D3DFMT_DXT2: str = "DXT2"; break; case D3DFMT_DXT3: str = "DXT3"; break; case D3DFMT_DXT4: str = "DXT4"; break; case D3DFMT_DXT5: str = "DXT5"; break; case D3DFMT_D16_LOCKABLE: str = "D16_LOCKABLE"; break; case D3DFMT_D32: str = "D32"; break; case D3DFMT_D15S1: str = "D15S1"; break; case D3DFMT_D24S8: str = "D24S8"; break; case D3DFMT_D24X8: str = "D24X8"; break; case D3DFMT_D24X4S4: str = "D24X4S4"; break; case D3DFMT_D16: str = "D16"; break; case D3DFMT_L16: str = "L16"; break; case D3DFMT_VERTEXDATA: str = "VERTEXDATA"; break; case D3DFMT_INDEX16: str = "INDEX16"; break; case D3DFMT_INDEX32: str = "INDEX32"; break; case D3DFMT_Q16W16V16U16: str = "Q16W16V16U16"; break; case D3DFMT_MULTI2_ARGB8: str = "MULTI2_ARGB8"; break; case D3DFMT_R16F: str = "R16F"; break; case D3DFMT_G16R16F: str = "G16R16F"; break; case D3DFMT_A16B16G16R16F: str = "A16B16G16R16F"; break; case D3DFMT_R32F: str = "R32F"; break; case D3DFMT_G32R32F: str = "G32R32F"; break; case D3DFMT_A32B32G32R32F: str = "A32B32G32R32F"; break; case D3DFMT_CxV8U8: str = "CxV8U8"; break; default: str = "Unknown format"; break; } return str; } // +--------------------------------------------------------------------+ VideoDX9AdapterInfo::VideoDX9AdapterInfo() : adapter_ordinal(0) { ZeroMemory(&adapter_identifier, sizeof(adapter_identifier)); } VideoDX9AdapterInfo::~VideoDX9AdapterInfo() { display_mode_list.destroy(); device_info_list.destroy(); } const char* VideoDX9AdapterInfo::GetDescription() const { return adapter_identifier.Description; } // +--------------------------------------------------------------------+ VideoDX9DeviceInfo::VideoDX9DeviceInfo() : adapter_ordinal(0), device_type(D3DDEVTYPE_HAL) { ZeroMemory(&caps, sizeof(caps)); } VideoDX9DeviceInfo::~VideoDX9DeviceInfo() { device_combo_list.destroy(); } // +--------------------------------------------------------------------+ VideoDX9DeviceCombo::VideoDX9DeviceCombo() : adapter_ordinal(0), device_type(D3DDEVTYPE_HAL), adapter_format((D3DFORMAT) 0), back_buffer_format((D3DFORMAT) 0), is_windowed(false) { } VideoDX9DeviceCombo::~VideoDX9DeviceCombo() { conflict_list.destroy(); }