XJDHDR wrote on 2022-08-02, 20:40:
What API calls do DirectX/Draw 9 or below games make to start the game in fullscreen vs. windowed mode? What API calls allow a game to switch between the two while running?
It's not so simple regarding those old API's...
DirectDraw was so low-level to the hw that fullscreen and windowed mode required 2 different presenting paths in the application and you couldn't just switch between them with a single API call.
- Full screen required "exclusive" mode, to own the display hw for the rendering. After you set it with IDirectDraw*::SetCooperativeLevel, you could create (IDirectDraw*::CreateSurface) a complex "primary" surface with one or more backbuffers that formed a "flipping chain" (the old term for swapchains). You could flip to the next backbuffer by calling IDirectDrawSurface*::Flip on the primary one in the chain and that flip was true hw flipping.
Also worth to mention that exclusive mode was tied to a window. If that window lost the focus (e.g. Alt-Tab out from fullscreen) then all the hw resources not backed by system memory got lost and they had to be restored or recreated when returning (Alt-Tabbing back) to exclusive full screen.
- Windowed mode could work in "normal" cooperating mode, even without a dedicated window, but you could only create a single primary surface representing the current dekstop. You could arbitrarily draw to it, even drawing into windows of another apps were possible. You rendered into an offscreen buffer and then copied the result into the client area of a window (IDirectDrawSurface*::Blt). To make sure that the copy only overwrites the visible parts of your window client area, you had to attach a clipper (IDirectDrawClipper) representing the visible region of the window, to the primary surface.
You could also change and restore the display mode (IDirectDraw*::SetDisplayMode and IDirectDraw*::RestoreDisplayMode) but it was not required and it was independent on the cooperative level. If your application rendered at the current desktop resolution (be it windowed or fullscreen) then it could be omitted. Since not all pixel formats were compatible with all of the display modes, when the display mode was changed then hw resources (textures, offscreens) could also got into lost state which weren't necessarily restorable but only re-creatable with another pixel format(s).
So, how to switch between windowed and fullscreen? Basically you have to release all your resources, and re-initialize your application (at least partially) to run on the other presenting path...
D3D8/9 made this all somewhat easier because a lot of this process, including setting the cooperative level, the display mode, the 2 different techniques to present a backbuffer in a window, was made implicitly inside a few API calls.
The term of swapchain (windowed or fullscreen) appeared here, a D3D8/9 device always had one implicit swapchain that were created when the device was created (IDirect3D8/9::CreateDevice) or recreated (IDirect3DDevice8/9::Reset). (But you could create additional ones in windowed mode (IDirect3DDevice8/9::CreateAdditionalSwapchain) if you wanted to render into multiple windows.)
Those API calls accepted a presentation descriptor that contained the window used for the presentation, the display mode, whether fullscreen or windowed mode was required, and so on, and the API made all the tedious work needed with DDraw in the background. Once initialized, you just had to call IDirect3DDevice8/9::Present to present the next backbuffer from the implicit swapchain.
One problem however remained: these API's (except D3D9Ex) still relied on non-virtual video memory unlike modern ones, so if the rendering window lost the focus in fullscreen then the device object itself (not particular resource objects like in DD) got into lost state and all resources backed only by pure hw memory had to be released before and re-created after resetting the device with IDirect3DDevice8/9::Reset with either the old or a new presentation descriptor.
To solve the problem of compatibility of certain resource pixel formats and display formats, the API proved general query methods for them (IDirect3D8/9::Check* methods).
How to switch between windowed and fullscreen? You can call IDirect3DDevice8/9::Reset with another presentation descriptor. But, as I wrote, it involves re-creating certain resources on your part, using the Check* methods to pick up usable pixel formats. It still makes the process elaborate. Not so easy like with a DXGI swapchain where you can just switch with literally one API call.