static void initialize_display_settings( HWND desktop ) { static const WCHAR display_device_guid_propW[] = { '_','_','w','i','n','e','_','d','i','s','p','l','a','y','_', 'd','e','v','i','c','e','_','g','u','i','d',0 }; GUID guid; RPC_CSTR guid_str; ATOM guid_atom; DEVMODEW dmW; UuidCreate( &guid ); UuidToStringA( &guid, &guid_str ); WINE_TRACE( "display guid %s\n", guid_str ); guid_atom = GlobalAddAtomA( (LPCSTR)guid_str ); SetPropW( desktop, display_device_guid_propW, ULongToHandle(guid_atom) ); RpcStringFreeA( &guid_str ); /* Store current display mode in the registry */ if (EnumDisplaySettingsExW( NULL, ENUM_CURRENT_SETTINGS, &dmW, 0 )) { WINE_TRACE( "Current display mode %ux%u %u bpp %u Hz\n", dmW.dmPelsWidth, dmW.dmPelsHeight, dmW.dmBitsPerPel, dmW.dmDisplayFrequency ); ChangeDisplaySettingsExW( NULL, &dmW, 0, CDS_GLOBAL | CDS_NORESET | CDS_UPDATEREGISTRY, NULL ); } }
bool DisplayManagerWin::setDisplayMode(int display, int mode) { DEVMODEW modeInfo; if (!isValidDisplayMode(display, mode)) return false; if (getModeInfo(display, mode, modeInfo)) { modeInfo.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY | DM_DISPLAYFLAGS; LONG rc = ChangeDisplaySettingsExW((LPCWSTR)m_displayAdapters[display].utf16(), &modeInfo, NULL, CDS_FULLSCREEN, NULL); if (rc != DISP_CHANGE_SUCCESSFUL) { QLOG_ERROR() << "Failed to changed DisplayMode, error" << rc; return false; } else { return true; } } return false; }
// Change the current video mode // GLFWbool _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired) { GLFWvidmode current; const GLFWvidmode* best; DEVMODEW dm; LONG result; best = _glfwChooseVideoMode(monitor, desired); _glfwPlatformGetVideoMode(monitor, ¤t); if (_glfwCompareVideoModes(¤t, best) == 0) return GLFW_TRUE; ZeroMemory(&dm, sizeof(dm)); dm.dmSize = sizeof(dm); dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY; dm.dmPelsWidth = best->width; dm.dmPelsHeight = best->height; dm.dmBitsPerPel = best->redBits + best->greenBits + best->blueBits; dm.dmDisplayFrequency = best->refreshRate; if (dm.dmBitsPerPel < 15 || dm.dmBitsPerPel >= 24) dm.dmBitsPerPel = 32; result = ChangeDisplaySettingsExW(monitor->win32.adapterName, &dm, NULL, CDS_FULLSCREEN, NULL); if (result != DISP_CHANGE_SUCCESSFUL) { const char* description = "Unknown error"; if (result == DISP_CHANGE_BADDUALVIEW) description = "The system uses DualView"; else if (result == DISP_CHANGE_BADFLAGS) description = "Invalid flags"; else if (result == DISP_CHANGE_BADMODE) description = "Graphics mode not supported"; else if (result == DISP_CHANGE_BADPARAM) description = "Invalid parameter"; else if (result == DISP_CHANGE_FAILED) description = "Graphics mode failed"; else if (result == DISP_CHANGE_NOTUPDATED) description = "Failed to write to registry"; else if (result == DISP_CHANGE_RESTART) description = "Computer restart required"; _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to set video mode: %s", description); return GLFW_FALSE; } monitor->win32.modeChanged = GLFW_TRUE; return GLFW_TRUE; }
// Restore the previously saved (original) video mode // void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor) { if (monitor->win32.modeChanged) { ChangeDisplaySettingsExW(monitor->win32.adapterName, NULL, NULL, CDS_FULLSCREEN, NULL); monitor->win32.modeChanged = GLFW_FALSE; } }
static void initialize_display_settings(void) { DEVMODEW dmW; /* Store current display mode in the registry */ if (EnumDisplaySettingsExW( NULL, ENUM_CURRENT_SETTINGS, &dmW, 0 )) { WINE_TRACE( "Current display mode %ux%u %u bpp %u Hz\n", dmW.dmPelsWidth, dmW.dmPelsHeight, dmW.dmBitsPerPel, dmW.dmDisplayFrequency ); ChangeDisplaySettingsExW( NULL, &dmW, 0, CDS_GLOBAL | CDS_NORESET | CDS_UPDATEREGISTRY, NULL ); } }
/*! * \brief Set the primary display to _disp * * \param[in] _disp The display to set primary * * \note This function will change the primary display IMMEDIATELY; Calling applyNewSettings() will *have no effect to this. * * \returns true if everything went fine */ bool iRandR::setPrimary( const iDisplays &_disp ) { DEVMODEW lNotReallyNeeded; lNotReallyNeeded.dmSize = sizeof( DEVMODEW ); lNotReallyNeeded.dmFields = DM_POSITION; // Set the primary position lNotReallyNeeded.dmPosition.x = 0; lNotReallyNeeded.dmPosition.y = 0; switch ( ChangeDisplaySettingsExW( _disp.getDisplayDevice().DeviceName, &lNotReallyNeeded, NULL, CDS_SET_PRIMARY, NULL ) ) { case DISP_CHANGE_SUCCESSFUL: iLOG( "Successfully set the primary display to ", _disp.getDisplayDevice().DeviceName ); return true; case DISP_CHANGE_BADDUALVIEW: wLOG( "ChangeDisplaySettingsEx returned DISP_CHANGE_BADDUALVIEW [setPrimary]" ); return false; case DISP_CHANGE_BADFLAGS: wLOG( "ChangeDisplaySettingsEx returned DISP_CHANGE_BADFLAGS [setPrimary]" ); return false; case DISP_CHANGE_BADMODE: wLOG( "ChangeDisplaySettingsEx returned DISP_CHANGE_BADMODE [setPrimary]" ); return false; case DISP_CHANGE_BADPARAM: wLOG( "ChangeDisplaySettingsEx returned DISP_CHANGE_BADPARAM [setPrimary]" ); return false; case DISP_CHANGE_FAILED: wLOG( "ChangeDisplaySettingsEx returned DISP_CHANGE_FAILED [setPrimary]" ); return false; case DISP_CHANGE_NOTUPDATED: wLOG( "ChangeDisplaySettingsEx returned DISP_CHANGE_NOTUPDATED [setPrimary]" ); return false; case DISP_CHANGE_RESTART: wLOG( "ChangeDisplaySettingsEx returned DISP_CHANGE_FAILED [setPrimary] (You need to " "restart yout PC because you have Windows)" ); return false; default: eLOG( "ChangeDisplaySettingsEx returned a unknown error [setPrimary]" ); return false; } return false; }
// Change the current video mode // GLFWbool _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired) { GLFWvidmode current; const GLFWvidmode* best; DEVMODEW dm; best = _glfwChooseVideoMode(monitor, desired); _glfwPlatformGetVideoMode(monitor, ¤t); if (_glfwCompareVideoModes(¤t, best) == 0) return GLFW_TRUE; ZeroMemory(&dm, sizeof(dm)); dm.dmSize = sizeof(DEVMODEW); dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY; dm.dmPelsWidth = best->width; dm.dmPelsHeight = best->height; dm.dmBitsPerPel = best->redBits + best->greenBits + best->blueBits; dm.dmDisplayFrequency = best->refreshRate; if (dm.dmBitsPerPel < 15 || dm.dmBitsPerPel >= 24) dm.dmBitsPerPel = 32; if (ChangeDisplaySettingsExW(monitor->win32.adapterName, &dm, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL) { _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to set video mode"); return GLFW_FALSE; } monitor->win32.modeChanged = GLFW_TRUE; return GLFW_TRUE; }
/* Do not call while under the GL lock. */ static HRESULT swapchain_init(struct wined3d_swapchain *swapchain, enum wined3d_surface_type surface_type, struct wined3d_device *device, struct wined3d_swapchain_desc *desc, void *parent, const struct wined3d_parent_ops *parent_ops) { const struct wined3d_adapter *adapter = device->adapter; const struct wined3d_format *format; struct wined3d_display_mode mode; BOOL displaymode_set = FALSE; RECT client_rect; HWND window; HRESULT hr; UINT i; if (desc->backbuffer_count > WINED3DPRESENT_BACK_BUFFER_MAX) { FIXME("The application requested %u back buffers, this is not supported.\n", desc->backbuffer_count); return WINED3DERR_INVALIDCALL; } if (desc->backbuffer_count > 1) { FIXME("The application requested more than one back buffer, this is not properly supported.\n" "Please configure the application to use double buffering (1 back buffer) if possible.\n"); } switch (surface_type) { case WINED3D_SURFACE_TYPE_GDI: swapchain->swapchain_ops = &swapchain_gdi_ops; break; case WINED3D_SURFACE_TYPE_OPENGL: swapchain->swapchain_ops = &swapchain_gl_ops; break; default: ERR("Invalid surface type %#x.\n", surface_type); return WINED3DERR_INVALIDCALL; } window = desc->device_window ? desc->device_window : device->create_parms.focus_window; swapchain->device = device; swapchain->parent = parent; swapchain->parent_ops = parent_ops; swapchain->ref = 1; swapchain->win_handle = window; swapchain->device_window = window; wined3d_get_adapter_display_mode(device->wined3d, adapter->ordinal, &mode); swapchain->orig_width = mode.width; swapchain->orig_height = mode.height; swapchain->orig_fmt = mode.format_id; format = wined3d_get_format(&adapter->gl_info, mode.format_id); GetClientRect(window, &client_rect); if (desc->windowed && (!desc->backbuffer_width || !desc->backbuffer_height || desc->backbuffer_format == WINED3DFMT_UNKNOWN)) { if (!desc->backbuffer_width) { desc->backbuffer_width = client_rect.right; TRACE("Updating width to %u.\n", desc->backbuffer_width); } if (!desc->backbuffer_height) { desc->backbuffer_height = client_rect.bottom; TRACE("Updating height to %u.\n", desc->backbuffer_height); } if (desc->backbuffer_format == WINED3DFMT_UNKNOWN) { desc->backbuffer_format = swapchain->orig_fmt; TRACE("Updating format to %s.\n", debug_d3dformat(swapchain->orig_fmt)); } } swapchain->desc = *desc; swapchain_update_render_to_fbo(swapchain); TRACE("Creating front buffer.\n"); hr = device->device_parent->ops->create_rendertarget(device->device_parent, parent, swapchain->desc.backbuffer_width, swapchain->desc.backbuffer_height, swapchain->desc.backbuffer_format, swapchain->desc.multisample_type, swapchain->desc.multisample_quality, TRUE /* Lockable */, &swapchain->front_buffer); if (FAILED(hr)) { WARN("Failed to create front buffer, hr %#x.\n", hr); goto err; } surface_set_container(swapchain->front_buffer, WINED3D_CONTAINER_SWAPCHAIN, swapchain); if (surface_type == WINED3D_SURFACE_TYPE_OPENGL) surface_modify_location(swapchain->front_buffer, SFLAG_INDRAWABLE, TRUE); /* MSDN says we're only allowed a single fullscreen swapchain per device, * so we should really check to see if there is a fullscreen swapchain * already. Does a single head count as full screen? */ if (!desc->windowed) { struct wined3d_display_mode mode; /* Change the display settings */ mode.width = desc->backbuffer_width; mode.height = desc->backbuffer_height; mode.format_id = desc->backbuffer_format; mode.refresh_rate = desc->refresh_rate; hr = wined3d_device_set_display_mode(device, 0, &mode); if (FAILED(hr)) { WARN("Failed to set display mode, hr %#x.\n", hr); goto err; } displaymode_set = TRUE; } if (surface_type == WINED3D_SURFACE_TYPE_OPENGL) { static const enum wined3d_format_id formats[] = { WINED3DFMT_D24_UNORM_S8_UINT, WINED3DFMT_D32_UNORM, WINED3DFMT_R24_UNORM_X8_TYPELESS, WINED3DFMT_D16_UNORM, WINED3DFMT_S1_UINT_D15_UNORM }; const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context)); if (!swapchain->context) { ERR("Failed to create the context array.\n"); hr = E_OUTOFMEMORY; goto err; } swapchain->num_contexts = 1; /* In WGL both color, depth and stencil are features of a pixel format. In case of D3D they are separate. * You are able to add a depth + stencil surface at a later stage when you need it. * In order to support this properly in WineD3D we need the ability to recreate the opengl context and * drawable when this is required. This is very tricky as we need to reapply ALL opengl states for the new * context, need torecreate shaders, textures and other resources. * * The context manager already takes care of the state problem and for the other tasks code from Reset * can be used. These changes are way to risky during the 1.0 code freeze which is taking place right now. * Likely a lot of other new bugs will be exposed. For that reason request a depth stencil surface all the * time. It can cause a slight performance hit but fixes a lot of regressions. A fixme reminds of that this * issue needs to be fixed. */ for (i = 0; i < (sizeof(formats) / sizeof(*formats)); i++) { swapchain->ds_format = wined3d_get_format(gl_info, formats[i]); swapchain->context[0] = context_create(swapchain, swapchain->front_buffer, swapchain->ds_format); if (swapchain->context[0]) break; TRACE("Depth stencil format %s is not supported, trying next format\n", debug_d3dformat(formats[i])); } if (!swapchain->context[0]) { WARN("Failed to create context.\n"); hr = WINED3DERR_NOTAVAILABLE; goto err; } if (wined3d_settings.offscreen_rendering_mode != ORM_FBO && (!desc->enable_auto_depth_stencil || swapchain->desc.auto_depth_stencil_format != swapchain->ds_format->id)) { FIXME("Add OpenGL context recreation support to context_validate_onscreen_formats\n"); } context_release(swapchain->context[0]); } if (swapchain->desc.backbuffer_count > 0) { swapchain->back_buffers = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->back_buffers) * swapchain->desc.backbuffer_count); if (!swapchain->back_buffers) { ERR("Failed to allocate backbuffer array memory.\n"); hr = E_OUTOFMEMORY; goto err; } for (i = 0; i < swapchain->desc.backbuffer_count; ++i) { TRACE("Creating back buffer %u.\n", i); hr = device->device_parent->ops->create_rendertarget(device->device_parent, parent, swapchain->desc.backbuffer_width, swapchain->desc.backbuffer_height, swapchain->desc.backbuffer_format, swapchain->desc.multisample_type, swapchain->desc.multisample_quality, TRUE /* Lockable */, &swapchain->back_buffers[i]); if (FAILED(hr)) { WARN("Failed to create back buffer %u, hr %#x.\n", i, hr); goto err; } surface_set_container(swapchain->back_buffers[i], WINED3D_CONTAINER_SWAPCHAIN, swapchain); } } /* Swapchains share the depth/stencil buffer, so only create a single depthstencil surface. */ if (desc->enable_auto_depth_stencil && surface_type == WINED3D_SURFACE_TYPE_OPENGL) { TRACE("Creating depth/stencil buffer.\n"); if (!device->auto_depth_stencil) { hr = device->device_parent->ops->create_depth_stencil(device->device_parent, swapchain->desc.backbuffer_width, swapchain->desc.backbuffer_height, swapchain->desc.auto_depth_stencil_format, swapchain->desc.multisample_type, swapchain->desc.multisample_quality, FALSE /* FIXME: Discard */, &device->auto_depth_stencil); if (FAILED(hr)) { WARN("Failed to create the auto depth stencil, hr %#x.\n", hr); goto err; } surface_set_container(device->auto_depth_stencil, WINED3D_CONTAINER_NONE, NULL); } } wined3d_swapchain_get_gamma_ramp(swapchain, &swapchain->orig_gamma); return WINED3D_OK; err: if (displaymode_set) { DEVMODEW devmode; ClipCursor(NULL); /* Change the display settings */ memset(&devmode, 0, sizeof(devmode)); devmode.dmSize = sizeof(devmode); devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; devmode.dmBitsPerPel = format->byte_count * CHAR_BIT; devmode.dmPelsWidth = swapchain->orig_width; devmode.dmPelsHeight = swapchain->orig_height; ChangeDisplaySettingsExW(adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL); } if (swapchain->back_buffers) { for (i = 0; i < swapchain->desc.backbuffer_count; ++i) { if (swapchain->back_buffers[i]) { surface_set_container(swapchain->back_buffers[i], WINED3D_CONTAINER_NONE, NULL); wined3d_surface_decref(swapchain->back_buffers[i]); } } HeapFree(GetProcessHeap(), 0, swapchain->back_buffers); } if (swapchain->context) { if (swapchain->context[0]) { context_release(swapchain->context[0]); context_destroy(device, swapchain->context[0]); swapchain->num_contexts = 0; } HeapFree(GetProcessHeap(), 0, swapchain->context); } if (swapchain->front_buffer) { surface_set_container(swapchain->front_buffer, WINED3D_CONTAINER_NONE, NULL); wined3d_surface_decref(swapchain->front_buffer); } return hr; }
bool CWinSystemWin32::ChangeResolution(const RESOLUTION_INFO& res, bool forceChange /*= false*/) { const MONITOR_DETAILS* details = GetMonitor(res.iScreen); if (!details) return false; DEVMODEW sDevMode; ZeroMemory(&sDevMode, sizeof(sDevMode)); sDevMode.dmSize = sizeof(sDevMode); // If we can't read the current resolution or any detail of the resolution is different than res if (!EnumDisplaySettingsW(details->DeviceNameW.c_str(), ENUM_CURRENT_SETTINGS, &sDevMode) || sDevMode.dmPelsWidth != res.iWidth || sDevMode.dmPelsHeight != res.iHeight || sDevMode.dmDisplayFrequency != (int)res.fRefreshRate || ((sDevMode.dmDisplayFlags & DM_INTERLACED) && !(res.dwFlags & D3DPRESENTFLAG_INTERLACED)) || (!(sDevMode.dmDisplayFlags & DM_INTERLACED) && (res.dwFlags & D3DPRESENTFLAG_INTERLACED)) || forceChange) { ZeroMemory(&sDevMode, sizeof(sDevMode)); sDevMode.dmSize = sizeof(sDevMode); sDevMode.dmDriverExtra = 0; sDevMode.dmPelsWidth = res.iWidth; sDevMode.dmPelsHeight = res.iHeight; sDevMode.dmDisplayFrequency = (int)res.fRefreshRate; sDevMode.dmDisplayFlags = (res.dwFlags & D3DPRESENTFLAG_INTERLACED) ? DM_INTERLACED : 0; sDevMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY | DM_DISPLAYFLAGS; LONG rc = DISP_CHANGE_SUCCESSFUL; bool bResChanged = false; // Windows 8 refresh rate workaround for 24.0, 48.0 and 60.0 Hz if (CSysInfo::IsWindowsVersionAtLeast(CSysInfo::WindowsVersionWin8) && (res.fRefreshRate == 24.0 || res.fRefreshRate == 48.0 || res.fRefreshRate == 60.0)) { CLog::Log(LOGDEBUG, "%s : Using Windows 8+ workaround for refresh rate %d Hz", __FUNCTION__, (int)res.fRefreshRate); // Get current resolution stored in registry DEVMODEW sDevModeRegistry; ZeroMemory(&sDevModeRegistry, sizeof(sDevModeRegistry)); sDevModeRegistry.dmSize = sizeof(sDevModeRegistry); if (EnumDisplaySettingsW(details->DeviceNameW.c_str(), ENUM_REGISTRY_SETTINGS, &sDevModeRegistry)) { // Set requested mode in registry without actually changing resolution rc = ChangeDisplaySettingsExW(details->DeviceNameW.c_str(), &sDevMode, NULL, CDS_UPDATEREGISTRY | CDS_NORESET, NULL); if (rc == DISP_CHANGE_SUCCESSFUL) { // Change resolution based on registry setting rc = ChangeDisplaySettingsExW(details->DeviceNameW.c_str(), NULL, NULL, CDS_FULLSCREEN, NULL); if (rc == DISP_CHANGE_SUCCESSFUL) bResChanged = true; else CLog::Log(LOGERROR, "%s : ChangeDisplaySettingsEx (W8+ change resolution) failed with %d, using fallback", __FUNCTION__, rc); // Restore registry with original values sDevModeRegistry.dmSize = sizeof(sDevModeRegistry); sDevModeRegistry.dmDriverExtra = 0; sDevModeRegistry.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY | DM_DISPLAYFLAGS; rc = ChangeDisplaySettingsExW(details->DeviceNameW.c_str(), &sDevModeRegistry, NULL, CDS_UPDATEREGISTRY | CDS_NORESET, NULL); if (rc != DISP_CHANGE_SUCCESSFUL) CLog::Log(LOGERROR, "%s : ChangeDisplaySettingsEx (W8+ restore registry) failed with %d", __FUNCTION__, rc); } else CLog::Log(LOGERROR, "%s : ChangeDisplaySettingsEx (W8+ set registry) failed with %d, using fallback", __FUNCTION__, rc); } else CLog::Log(LOGERROR, "%s : Unable to retrieve registry settings for Windows 8+ workaround, using fallback", __FUNCTION__); } // Standard resolution change/fallback for Windows 8+ workaround if (!bResChanged) { // CDS_FULLSCREEN is for temporary fullscreen mode and prevents icons and windows from moving // to fit within the new dimensions of the desktop rc = ChangeDisplaySettingsExW(details->DeviceNameW.c_str(), &sDevMode, NULL, CDS_FULLSCREEN, NULL); if (rc == DISP_CHANGE_SUCCESSFUL) bResChanged = true; else CLog::Log(LOGERROR, "%s : ChangeDisplaySettingsEx failed with %d", __FUNCTION__, rc); } if (bResChanged) ResolutionChanged(); return bResChanged; } // nothing to do, return success return true; }
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count) { int modeIndex = 0, size = 0; GLFWvidmode* result = NULL; *count = 0; for (;;) { int i; GLFWvidmode mode; DEVMODEW dm; ZeroMemory(&dm, sizeof(dm)); dm.dmSize = sizeof(dm); if (!EnumDisplaySettingsW(monitor->win32.adapterName, modeIndex, &dm)) break; modeIndex++; // Skip modes with less than 15 BPP if (dm.dmBitsPerPel < 15) continue; mode.width = dm.dmPelsWidth; mode.height = dm.dmPelsHeight; mode.refreshRate = dm.dmDisplayFrequency; _glfwSplitBPP(dm.dmBitsPerPel, &mode.redBits, &mode.greenBits, &mode.blueBits); for (i = 0; i < *count; i++) { if (_glfwCompareVideoModes(result + i, &mode) == 0) break; } // Skip duplicate modes if (i < *count) continue; if (monitor->win32.modesPruned) { // Skip modes not supported by the connected displays if (ChangeDisplaySettingsExW(monitor->win32.adapterName, &dm, NULL, CDS_TEST, NULL) != DISP_CHANGE_SUCCESSFUL) { continue; } } if (*count == size) { size += 128; result = (GLFWvidmode*) realloc(result, size * sizeof(GLFWvidmode)); } (*count)++; result[*count - 1] = mode; } if (!*count) { // HACK: Report the current mode if no valid modes were found result = calloc(1, sizeof(GLFWvidmode)); _glfwPlatformGetVideoMode(monitor, result); *count = 1; } return result; }
/*! * \brief Applies the settings set with setDisplaySizes * \returns true is everything went fine and false if not */ bool iRandR::applyNewRandRSettings() { vPreviousConfig_eD = vCurrentConfig_eD; bool lRetrunValue_B = false; for ( iDisplays const &disp : vDisplaysToChange_eD ) { DEVMODEW lDevmodeToChange_win32 = disp.getSelectedDevmode(); iLOG( "Change ", disp.getDisplayDevice().DeviceName, " to: ", (int32_t)lDevmodeToChange_win32.dmPelsWidth, "x", (int32_t)lDevmodeToChange_win32.dmPelsHeight ); switch ( ChangeDisplaySettingsExW( disp.getDisplayDevice().DeviceName, &lDevmodeToChange_win32, NULL, ( CDS_UPDATEREGISTRY | CDS_NORESET ), // We will apply the settings later NULL ) ) { case DISP_CHANGE_SUCCESSFUL: iLOG( "Successfully changed display ", disp.getDisplayDevice().DeviceName, " [set]" ); lRetrunValue_B = true; break; case DISP_CHANGE_BADDUALVIEW: wLOG( "ChangeDisplaySettingsEx returned DISP_CHANGE_BADDUALVIEW [set]" ); break; case DISP_CHANGE_BADFLAGS: wLOG( "ChangeDisplaySettingsEx returned DISP_CHANGE_BADFLAGS [set]" ); break; case DISP_CHANGE_BADMODE: wLOG( "ChangeDisplaySettingsEx returned DISP_CHANGE_BADMODE [set]" ); break; case DISP_CHANGE_BADPARAM: wLOG( "ChangeDisplaySettingsEx returned DISP_CHANGE_BADPARAM [set]" ); break; case DISP_CHANGE_FAILED: wLOG( "ChangeDisplaySettingsEx returned DISP_CHANGE_FAILED [set]" ); break; case DISP_CHANGE_NOTUPDATED: wLOG( "ChangeDisplaySettingsEx returned DISP_CHANGE_NOTUPDATED [set]" ); break; case DISP_CHANGE_RESTART: wLOG( "ChangeDisplaySettingsEx returned DISP_CHANGE_FAILED [set] (You need to restart " "yout PC because you have Windows)" ); break; default: eLOG( "ChangeDisplaySettingsEx returned a unknown error [set]" ); break; } } // Now really apply the settings switch ( ChangeDisplaySettingsExW( NULL, NULL, NULL, 0, NULL ) ) { case DISP_CHANGE_SUCCESSFUL: iLOG( "Successfully applyed display changes [apply]" ); lRetrunValue_B = true; break; case DISP_CHANGE_BADDUALVIEW: wLOG( "ChangeDisplaySettingsEx returned DISP_CHANGE_BADDUALVIEW [apply]" ); break; case DISP_CHANGE_BADFLAGS: wLOG( "ChangeDisplaySettingsEx returned DISP_CHANGE_BADFLAGS [apply]" ); break; case DISP_CHANGE_BADMODE: wLOG( "ChangeDisplaySettingsEx returned DISP_CHANGE_BADMODE [apply]" ); break; case DISP_CHANGE_BADPARAM: wLOG( "ChangeDisplaySettingsEx returned DISP_CHANGE_BADPARAM [apply]" ); break; case DISP_CHANGE_FAILED: wLOG( "ChangeDisplaySettingsEx returned DISP_CHANGE_FAILED [apply]" ); break; case DISP_CHANGE_NOTUPDATED: wLOG( "ChangeDisplaySettingsEx returned DISP_CHANGE_NOTUPDATED [apply]" ); break; case DISP_CHANGE_RESTART: wLOG( "ChangeDisplaySettingsEx returned DISP_CHANGE_FAILED [apply] (You need to restart " "yout PC because you have Windows)" ); break; default: eLOG( "ChangeDisplaySettingsEx returned a unknown error [apply]" ); break; } vDisplaysToChange_eD.clear(); reload(); return lRetrunValue_B; }
HRESULT swapchain_init(IWineD3DSwapChainImpl *swapchain, WINED3DSURFTYPE surface_type, IWineD3DDeviceImpl *device, WINED3DPRESENT_PARAMETERS *present_parameters, IUnknown *parent) { const struct wined3d_adapter *adapter = device->adapter; const struct wined3d_format_desc *format_desc; BOOL displaymode_set = FALSE; WINED3DDISPLAYMODE mode; RECT client_rect; HWND window = NULL; #ifdef VBOX_WITH_WDDM IWineD3DSwapChainImpl *overridenSwapchain = NULL; HDC hDC = NULL; #endif HRESULT hr; UINT i; if (present_parameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) { ERR("The application requested %u back buffers, this is not supported.\n", present_parameters->BackBufferCount); return WINED3DERR_INVALIDCALL; } if (present_parameters->BackBufferCount > 1) { FIXME("The application requested more than one back buffer, this is not properly supported.\n" "Please configure the application to use double buffering (1 back buffer) if possible.\n"); } switch (surface_type) { case SURFACE_GDI: swapchain->lpVtbl = &IWineGDISwapChain_Vtbl; break; case SURFACE_OPENGL: swapchain->lpVtbl = &IWineD3DSwapChain_Vtbl; break; case SURFACE_UNKNOWN: FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain.\n"); return WINED3DERR_INVALIDCALL; } #ifdef VBOX_WITH_WDDM if (present_parameters->hDeviceWindow) { overridenSwapchain = swapchain_find(device, present_parameters->hDeviceWindow); if (!overridenSwapchain) { ERR("invalid window handle supplied"); return E_FAIL; } window = overridenSwapchain->win_handle; hDC = overridenSwapchain->hDC; } else { hr = VBoxExtWndCreate(present_parameters->BackBufferWidth, present_parameters->BackBufferHeight, &window, &hDC); if (FAILED(hr)) { ERR("VBoxExtWndCreate failed, hr 0x%x", hr); return hr; } } Assert(window); Assert(hDC); present_parameters->hDeviceWindow = window; #else window = present_parameters->hDeviceWindow ? present_parameters->hDeviceWindow : device->createParms.hFocusWindow; #endif swapchain->device = device; swapchain->parent = parent; swapchain->ref = 1; swapchain->win_handle = window; #ifndef VBOX_WITH_WDDM swapchain->device_window = window; #else Assert(window); swapchain->hDC = hDC; swapchain->presentRt = NULL; #endif if (!present_parameters->Windowed && window) { swapchain_setup_fullscreen_window(swapchain, present_parameters->BackBufferWidth, present_parameters->BackBufferHeight); } IWineD3D_GetAdapterDisplayMode(device->wined3d, adapter->ordinal, &mode); swapchain->orig_width = mode.Width; swapchain->orig_height = mode.Height; swapchain->orig_fmt = mode.Format; format_desc = getFormatDescEntry(mode.Format, &adapter->gl_info); #ifndef VBOX_WITH_WDDM GetClientRect(window, &client_rect); #else client_rect.left = 0; client_rect.top = 0; client_rect.right = present_parameters->BackBufferWidth; client_rect.bottom = present_parameters->BackBufferHeight; #endif if (present_parameters->Windowed && (!present_parameters->BackBufferWidth || !present_parameters->BackBufferHeight || present_parameters->BackBufferFormat == WINED3DFMT_UNKNOWN)) { if (!present_parameters->BackBufferWidth) { present_parameters->BackBufferWidth = client_rect.right; TRACE("Updating width to %u.\n", present_parameters->BackBufferWidth); } if (!present_parameters->BackBufferHeight) { present_parameters->BackBufferHeight = client_rect.bottom; TRACE("Updating height to %u.\n", present_parameters->BackBufferHeight); } if (present_parameters->BackBufferFormat == WINED3DFMT_UNKNOWN) { present_parameters->BackBufferFormat = swapchain->orig_fmt; TRACE("Updating format to %s.\n", debug_d3dformat(swapchain->orig_fmt)); } } swapchain->presentParms = *present_parameters; if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && present_parameters->BackBufferCount && (present_parameters->BackBufferWidth != client_rect.right || present_parameters->BackBufferHeight != client_rect.bottom)) { TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u.\n", present_parameters->BackBufferWidth, present_parameters->BackBufferHeight, client_rect.right, client_rect.bottom); swapchain->render_to_fbo = TRUE; } TRACE("Creating front buffer.\n"); hr = IWineD3DDeviceParent_CreateRenderTarget(device->device_parent, parent, swapchain->presentParms.BackBufferWidth, swapchain->presentParms.BackBufferHeight, swapchain->presentParms.BackBufferFormat, swapchain->presentParms.MultiSampleType, swapchain->presentParms.MultiSampleQuality, TRUE /* Lockable */, &swapchain->frontBuffer); if (FAILED(hr)) { WARN("Failed to create front buffer, hr %#x.\n", hr); goto err; } IWineD3DSurface_SetContainer(swapchain->frontBuffer, (IWineD3DBase *)swapchain); ((IWineD3DSurfaceImpl *)swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN; if (surface_type == SURFACE_OPENGL) { IWineD3DSurface_ModifyLocation(swapchain->frontBuffer, SFLAG_INDRAWABLE, TRUE); } /* MSDN says we're only allowed a single fullscreen swapchain per device, * so we should really check to see if there is a fullscreen swapchain * already. Does a single head count as full screen? */ if (!present_parameters->Windowed) { WINED3DDISPLAYMODE mode; /* Change the display settings */ mode.Width = present_parameters->BackBufferWidth; mode.Height = present_parameters->BackBufferHeight; mode.Format = present_parameters->BackBufferFormat; mode.RefreshRate = present_parameters->FullScreen_RefreshRateInHz; hr = IWineD3DDevice_SetDisplayMode((IWineD3DDevice *)device, 0, &mode); if (FAILED(hr)) { WARN("Failed to set display mode, hr %#x.\n", hr); goto err; } displaymode_set = TRUE; } #ifndef VBOX_WITH_WDDM swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(swapchain->context)); if (!swapchain->context) { ERR("Failed to create the context array.\n"); hr = E_OUTOFMEMORY; goto err; } swapchain->num_contexts = 1; #endif if (surface_type == SURFACE_OPENGL) { #ifdef VBOX_WITH_WDDM struct wined3d_context * swapchainContext; #endif const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; /* In WGL both color, depth and stencil are features of a pixel format. In case of D3D they are separate. * You are able to add a depth + stencil surface at a later stage when you need it. * In order to support this properly in WineD3D we need the ability to recreate the opengl context and * drawable when this is required. This is very tricky as we need to reapply ALL opengl states for the new * context, need torecreate shaders, textures and other resources. * * The context manager already takes care of the state problem and for the other tasks code from Reset * can be used. These changes are way to risky during the 1.0 code freeze which is taking place right now. * Likely a lot of other new bugs will be exposed. For that reason request a depth stencil surface all the * time. It can cause a slight performance hit but fixes a lot of regressions. A fixme reminds of that this * issue needs to be fixed. */ if (!present_parameters->EnableAutoDepthStencil || swapchain->presentParms.AutoDepthStencilFormat != WINED3DFMT_D24_UNORM_S8_UINT) { FIXME("Add OpenGL context recreation support to context_validate_onscreen_formats\n"); } swapchain->ds_format = getFormatDescEntry(WINED3DFMT_D24_UNORM_S8_UINT, gl_info); #ifdef VBOX_WITH_WDDM swapchainContext = context_find_create(device, swapchain, (IWineD3DSurfaceImpl *)swapchain->frontBuffer, swapchain->ds_format); if (!swapchainContext) #else swapchain->context[0] = context_create(swapchain, (IWineD3DSurfaceImpl *)swapchain->frontBuffer, swapchain->ds_format); if (!swapchain->context[0]) #endif { WARN("Failed to create context.\n"); hr = WINED3DERR_NOTAVAILABLE; goto err; } #ifdef VBOX_WITH_WDDM context_release(swapchainContext); #else context_release(swapchain->context[0]); #endif } else { #ifndef VBOX_WITH_WDDM swapchain->context[0] = NULL; #endif } if (swapchain->presentParms.BackBufferCount > 0) { swapchain->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->backBuffer) * swapchain->presentParms.BackBufferCount); if (!swapchain->backBuffer) { ERR("Failed to allocate backbuffer array memory.\n"); hr = E_OUTOFMEMORY; goto err; } for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i) { TRACE("Creating back buffer %u.\n", i); hr = IWineD3DDeviceParent_CreateRenderTarget(device->device_parent, parent, swapchain->presentParms.BackBufferWidth, swapchain->presentParms.BackBufferHeight, swapchain->presentParms.BackBufferFormat, swapchain->presentParms.MultiSampleType, swapchain->presentParms.MultiSampleQuality, TRUE /* Lockable */, &swapchain->backBuffer[i]); if (FAILED(hr)) { WARN("Failed to create back buffer %u, hr %#x.\n", i, hr); goto err; } IWineD3DSurface_SetContainer(swapchain->backBuffer[i], (IWineD3DBase *)swapchain); ((IWineD3DSurfaceImpl *)swapchain->backBuffer[i])->Flags |= SFLAG_SWAPCHAIN; } } /* Swapchains share the depth/stencil buffer, so only create a single depthstencil surface. */ if (present_parameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) { TRACE("Creating depth/stencil buffer.\n"); if (!device->auto_depth_stencil_buffer) { hr = IWineD3DDeviceParent_CreateDepthStencilSurface(device->device_parent, parent, swapchain->presentParms.BackBufferWidth, swapchain->presentParms.BackBufferHeight, swapchain->presentParms.AutoDepthStencilFormat, swapchain->presentParms.MultiSampleType, swapchain->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */, &device->auto_depth_stencil_buffer); if (FAILED(hr)) { WARN("Failed to create the auto depth stencil, hr %#x.\n", hr); goto err; } IWineD3DSurface_SetContainer(device->auto_depth_stencil_buffer, NULL); } } IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *)swapchain, &swapchain->orig_gamma); #ifdef VBOX_WITH_WDDM if (overridenSwapchain) { swapchain_invalidate(overridenSwapchain); } #endif return WINED3D_OK; err: if (displaymode_set) { DEVMODEW devmode; ClipCursor(NULL); /* Change the display settings */ memset(&devmode, 0, sizeof(devmode)); devmode.dmSize = sizeof(devmode); devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; devmode.dmBitsPerPel = format_desc->byte_count * 8; devmode.dmPelsWidth = swapchain->orig_width; devmode.dmPelsHeight = swapchain->orig_height; ChangeDisplaySettingsExW(adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL); } if (swapchain->backBuffer) { for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i) { if (swapchain->backBuffer[i]) IWineD3DSurface_Release(swapchain->backBuffer[i]); } HeapFree(GetProcessHeap(), 0, swapchain->backBuffer); } #ifdef VBOX_WITH_WDDM if (!device->NumberOfSwapChains) { while (device->numContexts) { context_destroy(device, device->contexts[0]); } } #else if (swapchain->context) { if (swapchain->context[0]) { context_release(swapchain->context[0]); context_destroy(device, swapchain->context[0]); swapchain->num_contexts = 0; } HeapFree(GetProcessHeap(), 0, swapchain->context); } #endif if (swapchain->frontBuffer) IWineD3DSurface_Release(swapchain->frontBuffer); #ifdef VBOX_WITH_WDDM if (!overridenSwapchain && swapchain->win_handle) { VBoxExtWndDestroy(swapchain->win_handle, swapchain->hDC); } swapchain_invalidate(swapchain); #endif return hr; }
/*********************************************************************** * ChangeDisplaySettingsW (USER32.@) */ LONG WINAPI ChangeDisplaySettingsW( LPDEVMODEW devmode, DWORD flags ) { TRACE_(system)("%p,0x%08lx\n", devmode, flags); return ChangeDisplaySettingsExW( NULL, devmode, 0, flags, 0 ); }