3804: HiDPI-aware Resolution List r=def- a=TsFreddie

This is a version of https://github.com/teeworlds/teeworlds/pull/2827

Which gives you a resolution list that allows you to select appropriate window size (which is saved in config and used to initialize videos), while showing the canvas size (which is the drawing resolution), at least on MacOS.

This also fixes incorrect clips that happens without HiDPI enabled, because `Graphics()->ScreenWidth()` (in canvas size) was reported incorrectly before, which is now fixed.

Also, I noticed that `m_DesktopScreenWidth` and `m_DesktopScreenHeight` (in window size in MacOS) is used incorrectly or differently from what it was used during initialization:

* During initialization, DesktopScreenWidth is the "screen width of your desktop", but it was used as the "game window size on your desktop" when checking whether to resize window. I added a separate window size calculation to use during resize.

Also, god, I hope SDL's different sizes and stuff is reported consistently at least in Wayland or X, so please test. I know in Windows they are always in pixel/canvas size so it might not be a huge issue there.

## Checklist

- [x] Tested the change ~~ingame~~ on MacOS
- [ ] Provided screenshots if it is a visual change
- [x] Tested in combination with possibly related configuration options (again, on MacOS, with both HiDPI and non-HiDPI settings)
- [ ] Written a unit test if it works standalone, system.c especially
- [ ] Considered possible null pointers and out of bounds array indexing
- [ ] Changed no physics that affect existing maps
- [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional)


Co-authored-by: Freddie Wang <tsfreddiewang@gmail.com>
This commit is contained in:
bors[bot] 2021-05-22 09:56:09 +00:00 committed by GitHub
commit 502711541e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 89 additions and 50 deletions

View file

@ -190,18 +190,29 @@ void CCommandProcessorFragment_SDL::Cmd_VideoModes(const CCommandBuffer::SComman
int maxModes = SDL_GetNumDisplayModes(pCommand->m_Screen),
numModes = 0;
for(int i = 0; i < maxModes; i++)
for(int i = -1; i < maxModes; i++)
{
if(SDL_GetDisplayMode(pCommand->m_Screen, i, &mode) < 0)
if(i == -1)
{
dbg_msg("gfx", "unable to get display mode: %s", SDL_GetError());
continue;
if(SDL_GetDesktopDisplayMode(pCommand->m_Screen, &mode) < 0)
{
dbg_msg("gfx", "unable to get display mode: %s", SDL_GetError());
continue;
}
}
else
{
if(SDL_GetDisplayMode(pCommand->m_Screen, i, &mode) < 0)
{
dbg_msg("gfx", "unable to get display mode: %s", SDL_GetError());
continue;
}
}
bool AlreadyFound = false;
for(int j = 0; j < numModes; j++)
{
if(pCommand->m_pModes[j].m_Width == mode.w && pCommand->m_pModes[j].m_Height == mode.h)
if(pCommand->m_pModes[j].m_CanvasWidth == mode.w && pCommand->m_pModes[j].m_CanvasHeight == mode.h)
{
AlreadyFound = true;
break;
@ -210,8 +221,13 @@ void CCommandProcessorFragment_SDL::Cmd_VideoModes(const CCommandBuffer::SComman
if(AlreadyFound)
continue;
pCommand->m_pModes[numModes].m_Width = mode.w;
pCommand->m_pModes[numModes].m_Height = mode.h;
if(mode.w > pCommand->m_MaxWindowWidth || mode.h > pCommand->m_MaxWindowHeight)
continue;
pCommand->m_pModes[numModes].m_CanvasWidth = mode.w * pCommand->m_HiDPIScale;
pCommand->m_pModes[numModes].m_CanvasHeight = mode.h * pCommand->m_HiDPIScale;
pCommand->m_pModes[numModes].m_WindowWidth = mode.w;
pCommand->m_pModes[numModes].m_WindowHeight = mode.h;
pCommand->m_pModes[numModes].m_Red = 8;
pCommand->m_pModes[numModes].m_Green = 8;
pCommand->m_pModes[numModes].m_Blue = 8;
@ -740,11 +756,14 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *Screen, int *pWidt
dbg_msg("gfx", "unable to get desktop resolution: %s", SDL_GetError());
return EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_SDL_SCREEN_RESOLUTION_REQUEST_FAILED;
}
bool IsDesktopChanged = *pDesktopWidth == 0 || *pDesktopHeight == 0 || *pDesktopWidth != DisplayMode.w || *pDesktopHeight != DisplayMode.h;
*pDesktopWidth = DisplayMode.w;
*pDesktopHeight = DisplayMode.h;
// use desktop resolution as default resolution
if(*pWidth == 0 || *pHeight == 0)
// use desktop resolution as default resolution, clamp resolution if users's display is smaller than we remembered
if(*pWidth == 0 || *pHeight == 0 || (IsDesktopChanged && (*pWidth > *pDesktopWidth || *pHeight > *pDesktopHeight)))
{
*pWidth = *pDesktopWidth;
*pHeight = *pDesktopHeight;
@ -845,7 +864,12 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *Screen, int *pWidt
InitError = IsVersionSupportedGlew(m_BackendType, g_Config.m_GfxOpenGLMajor, g_Config.m_GfxOpenGLMinor, g_Config.m_GfxOpenGLPatch, GlewMajor, GlewMinor, GlewPatch);
SDL_GL_GetDrawableSize(m_pWindow, pCurrentWidth, pCurrentHeight);
// SDL_GL_GetDrawableSize reports HiDPI resolution even with SDL_WINDOW_ALLOW_HIGHDPI not set, which is wrong
if(SdlFlags & SDL_WINDOW_ALLOW_HIGHDPI)
SDL_GL_GetDrawableSize(m_pWindow, pCurrentWidth, pCurrentHeight);
else
SDL_GetWindowSize(m_pWindow, pCurrentWidth, pCurrentHeight);
SDL_GL_SetSwapInterval(Flags & IGraphicsBackend::INITFLAG_VSYNC ? 1 : 0);
SDL_GL_MakeCurrent(NULL, NULL);

View file

@ -33,31 +33,31 @@
#include "graphics_threaded.h"
static CVideoMode g_aFakeModes[] = {
{8192, 4320, 8, 8, 8}, {7680, 4320, 8, 8, 8}, {5120, 2880, 8, 8, 8},
{4096, 2160, 8, 8, 8}, {3840, 2160, 8, 8, 8}, {2560, 1440, 8, 8, 8},
{2048, 1536, 8, 8, 8}, {1920, 2400, 8, 8, 8}, {1920, 1440, 8, 8, 8},
{1920, 1200, 8, 8, 8}, {1920, 1080, 8, 8, 8}, {1856, 1392, 8, 8, 8},
{1800, 1440, 8, 8, 8}, {1792, 1344, 8, 8, 8}, {1680, 1050, 8, 8, 8},
{1600, 1200, 8, 8, 8}, {1600, 1000, 8, 8, 8}, {1440, 1050, 8, 8, 8},
{1440, 900, 8, 8, 8}, {1400, 1050, 8, 8, 8}, {1368, 768, 8, 8, 8},
{1280, 1024, 8, 8, 8}, {1280, 960, 8, 8, 8}, {1280, 800, 8, 8, 8},
{1280, 768, 8, 8, 8}, {1152, 864, 8, 8, 8}, {1024, 768, 8, 8, 8},
{1024, 600, 8, 8, 8}, {800, 600, 8, 8, 8}, {768, 576, 8, 8, 8},
{720, 400, 8, 8, 8}, {640, 480, 8, 8, 8}, {400, 300, 8, 8, 8},
{320, 240, 8, 8, 8},
{8192, 4320, 8192, 4320, 8, 8, 8}, {7680, 4320, 7680, 4320, 8, 8, 8}, {5120, 2880, 5120, 2880, 8, 8, 8},
{4096, 2160, 4096, 2160, 8, 8, 8}, {3840, 2160, 3840, 2160, 8, 8, 8}, {2560, 1440, 2560, 1440, 8, 8, 8},
{2048, 1536, 2048, 1536, 8, 8, 8}, {1920, 2400, 1920, 2400, 8, 8, 8}, {1920, 1440, 1920, 1440, 8, 8, 8},
{1920, 1200, 1920, 1200, 8, 8, 8}, {1920, 1080, 1920, 1080, 8, 8, 8}, {1856, 1392, 1856, 1392, 8, 8, 8},
{1800, 1440, 1800, 1440, 8, 8, 8}, {1792, 1344, 1792, 1344, 8, 8, 8}, {1680, 1050, 1680, 1050, 8, 8, 8},
{1600, 1200, 1600, 1200, 8, 8, 8}, {1600, 1000, 1600, 1000, 8, 8, 8}, {1440, 1050, 1440, 1050, 8, 8, 8},
{1440, 900, 1440, 900, 8, 8, 8}, {1400, 1050, 1400, 1050, 8, 8, 8}, {1368, 768, 1368, 768, 8, 8, 8},
{1280, 1024, 1280, 1024, 8, 8, 8}, {1280, 960, 1280, 960, 8, 8, 8}, {1280, 800, 1280, 800, 8, 8, 8},
{1280, 768, 1280, 768, 8, 8, 8}, {1152, 864, 1152, 864, 8, 8, 8}, {1024, 768, 1024, 768, 8, 8, 8},
{1024, 600, 1024, 600, 8, 8, 8}, {800, 600, 800, 600, 8, 8, 8}, {768, 576, 768, 576, 8, 8, 8},
{720, 400, 720, 400, 8, 8, 8}, {640, 480, 640, 480, 8, 8, 8}, {400, 300, 400, 300, 8, 8, 8},
{320, 240, 320, 240, 8, 8, 8},
{8192, 4320, 5, 6, 5}, {7680, 4320, 5, 6, 5}, {5120, 2880, 5, 6, 5},
{4096, 2160, 5, 6, 5}, {3840, 2160, 5, 6, 5}, {2560, 1440, 5, 6, 5},
{2048, 1536, 5, 6, 5}, {1920, 2400, 5, 6, 5}, {1920, 1440, 5, 6, 5},
{1920, 1200, 5, 6, 5}, {1920, 1080, 5, 6, 5}, {1856, 1392, 5, 6, 5},
{1800, 1440, 5, 6, 5}, {1792, 1344, 5, 6, 5}, {1680, 1050, 5, 6, 5},
{1600, 1200, 5, 6, 5}, {1600, 1000, 5, 6, 5}, {1440, 1050, 5, 6, 5},
{1440, 900, 5, 6, 5}, {1400, 1050, 5, 6, 5}, {1368, 768, 5, 6, 5},
{1280, 1024, 5, 6, 5}, {1280, 960, 5, 6, 5}, {1280, 800, 5, 6, 5},
{1280, 768, 5, 6, 5}, {1152, 864, 5, 6, 5}, {1024, 768, 5, 6, 5},
{1024, 600, 5, 6, 5}, {800, 600, 5, 6, 5}, {768, 576, 5, 6, 5},
{720, 400, 5, 6, 5}, {640, 480, 5, 6, 5}, {400, 300, 5, 6, 5},
{320, 240, 5, 6, 5}};
{8192, 4320, 8192, 4320, 5, 6, 5}, {7680, 4320, 7680, 4320, 5, 6, 5}, {5120, 2880, 5120, 2880, 5, 6, 5},
{4096, 2160, 4096, 2160, 5, 6, 5}, {3840, 2160, 3840, 2160, 5, 6, 5}, {2560, 1440, 2560, 1440, 5, 6, 5},
{2048, 1536, 2048, 1536, 5, 6, 5}, {1920, 2400, 1920, 2400, 5, 6, 5}, {1920, 1440, 1920, 1440, 5, 6, 5},
{1920, 1200, 1920, 1200, 5, 6, 5}, {1920, 1080, 1920, 1080, 5, 6, 5}, {1856, 1392, 1856, 1392, 5, 6, 5},
{1800, 1440, 1800, 1440, 5, 6, 5}, {1792, 1344, 1792, 1344, 5, 6, 5}, {1680, 1050, 1680, 1050, 5, 6, 5},
{1600, 1200, 1600, 1200, 5, 6, 5}, {1600, 1000, 1600, 1000, 5, 6, 5}, {1440, 1050, 1440, 1050, 5, 6, 5},
{1440, 900, 1440, 900, 5, 6, 5}, {1400, 1050, 1400, 1050, 5, 6, 5}, {1368, 768, 1368, 768, 5, 6, 5},
{1280, 1024, 1280, 1024, 5, 6, 5}, {1280, 960, 1280, 960, 5, 6, 5}, {1280, 800, 1280, 800, 5, 6, 5},
{1280, 768, 1280, 768, 5, 6, 5}, {1152, 864, 1152, 864, 5, 6, 5}, {1024, 768, 1024, 768, 5, 6, 5},
{1024, 600, 1024, 600, 5, 6, 5}, {800, 600, 800, 600, 5, 6, 5}, {768, 576, 768, 576, 5, 6, 5},
{720, 400, 720, 400, 5, 6, 5}, {640, 480, 640, 480, 5, 6, 5}, {400, 300, 400, 300, 5, 6, 5},
{320, 240, 320, 240, 5, 6, 5}};
void CGraphics_Threaded::FlushVertices(bool KeepVertices)
{
@ -2083,7 +2083,7 @@ int CGraphics_Threaded::IssueInit()
if(g_Config.m_GfxResizable)
Flags |= IGraphicsBackend::INITFLAG_RESIZABLE;
int r = m_pBackend->Init("DDNet Client", &g_Config.m_GfxScreen, &g_Config.m_GfxScreenWidth, &g_Config.m_GfxScreenHeight, g_Config.m_GfxFsaaSamples, Flags, &m_DesktopScreenWidth, &m_DesktopScreenHeight, &m_ScreenWidth, &m_ScreenHeight, m_pStorage);
int r = m_pBackend->Init("DDNet Client", &g_Config.m_GfxScreen, &g_Config.m_GfxScreenWidth, &g_Config.m_GfxScreenHeight, g_Config.m_GfxFsaaSamples, Flags, &g_Config.m_GfxDesktopWidth, &g_Config.m_GfxDesktopHeight, &m_ScreenWidth, &m_ScreenHeight, m_pStorage);
AddBackEndWarningIfExists();
m_IsNewOpenGL = m_pBackend->IsNewOpenGL();
m_OpenGLTileBufferingEnabled = m_IsNewOpenGL || m_pBackend->HasTileBuffering();
@ -2091,6 +2091,7 @@ int CGraphics_Threaded::IssueInit()
m_OpenGLQuadContainerBufferingEnabled = m_IsNewOpenGL || m_pBackend->HasQuadContainerBuffering();
m_OpenGLTextBufferingEnabled = m_IsNewOpenGL || (m_OpenGLQuadContainerBufferingEnabled && m_pBackend->HasTextBuffering());
m_OpenGLHasTextureArrays = m_IsNewOpenGL || m_pBackend->Has2DTextureArrays();
m_ScreenHiDPIScale = m_ScreenWidth / (float)g_Config.m_GfxScreenWidth;
return r;
}
@ -2239,6 +2240,12 @@ int CGraphics_Threaded::Init()
if(InitWindow() != 0)
return -1;
for(auto &FakeMode : g_aFakeModes)
{
FakeMode.m_WindowWidth = FakeMode.m_CanvasWidth / m_ScreenHiDPIScale;
FakeMode.m_WindowHeight = FakeMode.m_CanvasHeight / m_ScreenHiDPIScale;
}
// create command buffers
for(auto &pCommandBuffer : m_apCommandBuffers)
pCommandBuffer = new CCommandBuffer(CMD_BUFFER_CMD_BUFFER_SIZE, CMD_BUFFER_DATA_BUFFER_SIZE);
@ -2313,15 +2320,12 @@ void CGraphics_Threaded::Resize(int w, int h, bool SetWindowSize)
return;
#endif
if(m_DesktopScreenWidth == w && m_DesktopScreenHeight == h)
if(WindowWidth() == w && WindowHeight() == h)
return;
if(SetWindowSize)
m_pBackend->ResizeWindow(w, h);
m_DesktopScreenWidth = w;
m_DesktopScreenHeight = h;
m_pBackend->GetViewportSize(m_ScreenWidth, m_ScreenHeight);
// adjust the viewport to only allow certain aspect ratios
@ -2530,6 +2534,9 @@ int CGraphics_Threaded::GetVideoModes(CVideoMode *pModes, int MaxModes, int Scre
Cmd.m_pModes = pModes;
Cmd.m_MaxModes = MaxModes;
Cmd.m_pNumModes = &NumModes;
Cmd.m_HiDPIScale = m_ScreenHiDPIScale;
Cmd.m_MaxWindowWidth = g_Config.m_GfxDesktopWidth;
Cmd.m_MaxWindowHeight = g_Config.m_GfxDesktopHeight;
Cmd.m_Screen = Screen;
if(!AddCmd(

View file

@ -497,6 +497,9 @@ public:
CVideoMode *m_pModes; // processor will fill this in
int m_MaxModes; // maximum of modes the processor can write to the m_pModes
int *m_pNumModes; // processor will write to this pointer
int m_HiDPIScale;
int m_MaxWindowWidth;
int m_MaxWindowHeight;
int m_Screen;
};
@ -1162,8 +1165,8 @@ public:
int GetVideoModes(CVideoMode *pModes, int MaxModes, int Screen) override;
virtual int GetDesktopScreenWidth() const { return m_DesktopScreenWidth; }
virtual int GetDesktopScreenHeight() const { return m_DesktopScreenHeight; }
virtual int GetDesktopScreenWidth() const { return g_Config.m_GfxScreenWidth; }
virtual int GetDesktopScreenHeight() const { return g_Config.m_GfxScreenHeight; }
// synchronization
void InsertSignal(CSemaphore *pSemaphore) override;

View file

@ -93,7 +93,8 @@ public:
class CVideoMode
{
public:
int m_Width, m_Height;
int m_CanvasWidth, m_CanvasHeight;
int m_WindowWidth, m_WindowHeight;
int m_Red, m_Green, m_Blue;
};
@ -166,8 +167,7 @@ class IGraphics : public IInterface
protected:
int m_ScreenWidth;
int m_ScreenHeight;
int m_DesktopScreenWidth;
int m_DesktopScreenHeight;
float m_ScreenHiDPIScale;
public:
enum
@ -198,6 +198,9 @@ public:
int ScreenWidth() const { return m_ScreenWidth; }
int ScreenHeight() const { return m_ScreenHeight; }
float ScreenAspect() const { return (float)ScreenWidth() / (float)ScreenHeight(); }
float ScreenHiDPIScale() const { return m_ScreenHiDPIScale; }
int WindowWidth() const { return m_ScreenWidth / m_ScreenHiDPIScale; }
int WindowHeight() const { return m_ScreenHeight / m_ScreenHiDPIScale; }
virtual void SetWindowParams(int FullscreenMode, bool IsBorderless) = 0;
virtual bool SetWindowScreen(int Index) = 0;

View file

@ -98,6 +98,8 @@ MACRO_CONFIG_INT(SndHighlight, snd_highlight, 1, 0, 1, CFGFLAG_SAVE | CFGFLAG_CL
MACRO_CONFIG_INT(GfxScreen, gfx_screen, 0, 0, 15, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Screen index")
MACRO_CONFIG_INT(GfxScreenWidth, gfx_screen_width, 0, 0, 0, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Screen resolution width")
MACRO_CONFIG_INT(GfxScreenHeight, gfx_screen_height, 0, 0, 0, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Screen resolution height")
MACRO_CONFIG_INT(GfxDesktopWidth, gfx_desktop_height, 0, 0, 0, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Desktop resolution width for detecting display changes (not recommended to change manually)")
MACRO_CONFIG_INT(GfxDesktopHeight, gfx_desktop_height, 0, 0, 0, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Desktop resolution height for detecting display changes (not recommended to change manually)")
#if !defined(CONF_PLATFORM_MACOS)
MACRO_CONFIG_INT(GfxBorderless, gfx_borderless, 0, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Borderless window (not to be used with fullscreen)")
MACRO_CONFIG_INT(GfxFullscreen, gfx_fullscreen, 1, 0, 2, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Set fullscreen mode: 0=no fullscreen, 1=pure fullscreen, 2=desktop fullscreen")

View file

@ -1105,8 +1105,8 @@ void CMenus::RenderSettingsGraphics(CUIRect MainView)
{
const int Depth = s_aModes[i].m_Red + s_aModes[i].m_Green + s_aModes[i].m_Blue > 16 ? 24 : 16;
if(g_Config.m_GfxColorDepth == Depth &&
g_Config.m_GfxScreenWidth == s_aModes[i].m_Width &&
g_Config.m_GfxScreenHeight == s_aModes[i].m_Height)
g_Config.m_GfxScreenWidth == s_aModes[i].m_WindowWidth &&
g_Config.m_GfxScreenHeight == s_aModes[i].m_WindowHeight)
{
OldSelected = i;
}
@ -1114,8 +1114,8 @@ void CMenus::RenderSettingsGraphics(CUIRect MainView)
CListboxItem Item = UiDoListboxNextItem(&s_aModes[i], OldSelected == i);
if(Item.m_Visible)
{
int G = gcd(s_aModes[i].m_Width, s_aModes[i].m_Height);
str_format(aBuf, sizeof(aBuf), " %dx%d %d bit (%d:%d)", s_aModes[i].m_Width, s_aModes[i].m_Height, Depth, s_aModes[i].m_Width / G, s_aModes[i].m_Height / G);
int G = gcd(s_aModes[i].m_CanvasWidth, s_aModes[i].m_CanvasHeight);
str_format(aBuf, sizeof(aBuf), " %dx%d %d bit (%d:%d)", s_aModes[i].m_CanvasWidth, s_aModes[i].m_CanvasHeight, Depth, s_aModes[i].m_CanvasWidth / G, s_aModes[i].m_CanvasHeight / G);
UI()->DoLabelScaled(&Item.m_Rect, aBuf, 16.0f, -1);
}
}
@ -1125,8 +1125,8 @@ void CMenus::RenderSettingsGraphics(CUIRect MainView)
{
const int Depth = s_aModes[NewSelected].m_Red + s_aModes[NewSelected].m_Green + s_aModes[NewSelected].m_Blue > 16 ? 24 : 16;
g_Config.m_GfxColorDepth = Depth;
g_Config.m_GfxScreenWidth = s_aModes[NewSelected].m_Width;
g_Config.m_GfxScreenHeight = s_aModes[NewSelected].m_Height;
g_Config.m_GfxScreenWidth = s_aModes[NewSelected].m_WindowWidth;
g_Config.m_GfxScreenHeight = s_aModes[NewSelected].m_WindowHeight;
Graphics()->Resize(g_Config.m_GfxScreenWidth, g_Config.m_GfxScreenHeight, true);
}