Added ability to turn off hi-res backing surface rendering on Retina displays

High resolution backing surface is enabled by default and controlled via vid_hidpi CVAR
When it is set to false one pixel per point scale is used
This commit is contained in:
alexey.lysiuk 2014-09-12 18:35:45 +03:00
parent e60d181e87
commit 0fd84bc853
2 changed files with 111 additions and 51 deletions

View file

@ -86,13 +86,15 @@
- (NSRect)convertRectToBacking:(NSRect)aRect; - (NSRect)convertRectToBacking:(NSRect)aRect;
@end @end
#endif // NSAppKitVersionNumber10_7 #endif // !NSAppKitVersionNumber10_7
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
RenderBufferOptions rbOpts; RenderBufferOptions rbOpts;
EXTERN_CVAR(Bool, vid_hidpi)
CVAR(Bool, use_mouse, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Bool, use_mouse, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CVAR(Bool, m_noprescale, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Bool, m_noprescale, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CVAR(Bool, m_filter, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Bool, m_filter, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
@ -585,7 +587,7 @@ NSSize GetRealContentViewSize(const NSWindow* const window)
// TODO: figure out why [NSView frame] returns different values in "fullscreen" and in window // TODO: figure out why [NSView frame] returns different values in "fullscreen" and in window
// In "fullscreen" the result is multiplied by [NSScreen backingScaleFactor], but not in window // In "fullscreen" the result is multiplied by [NSScreen backingScaleFactor], but not in window
return (IsHiDPISupported() && NSNormalWindowLevel == [window level]) return (vid_hidpi && NSNormalWindowLevel == [window level])
? [view convertSizeToBacking:frameSize] ? [view convertSizeToBacking:frameSize]
: frameSize; : frameSize;
} }
@ -840,10 +842,16 @@ void ProcessMouseWheelEvent(NSEvent* theEvent)
#endif #endif
{ {
@private @private
FullscreenWindow* m_window; FullscreenWindow* m_window;
int m_multisample;
int m_width;
int m_height;
bool m_fullscreen;
bool m_hiDPI;
bool m_openGLInitialized; bool m_openGLInitialized;
int m_multisample;
} }
- (id)init; - (id)init;
@ -864,7 +872,8 @@ void ProcessMouseWheelEvent(NSEvent* theEvent)
- (int)multisample; - (int)multisample;
- (void)setMultisample:(int)multisample; - (void)setMultisample:(int)multisample;
- (void)changeVideoResolution:(bool)fullscreen width:(int)width height:(int)height; - (void)changeVideoResolution:(bool)fullscreen width:(int)width height:(int)height useHiDPI:(bool)hiDPI;
- (void)useHiDPI:(bool)hiDPI;
- (void)processEvents:(NSTimer*)timer; - (void)processEvents:(NSTimer*)timer;
@ -884,8 +893,14 @@ static ApplicationDelegate* s_applicationDelegate;
{ {
self = [super init]; self = [super init];
m_multisample = 0;
m_width = -1;
m_height = -1;
m_fullscreen = false;
m_hiDPI = false;
m_openGLInitialized = false; m_openGLInitialized = false;
m_multisample = 0;
return self; return self;
} }
@ -1052,35 +1067,30 @@ static ApplicationDelegate* s_applicationDelegate;
pixelFormat:pixelFormat]; pixelFormat:pixelFormat];
[[glView openGLContext] makeCurrentContext]; [[glView openGLContext] makeCurrentContext];
if (IsHiDPISupported())
{
[glView setWantsBestResolutionOpenGLSurface:YES];
}
[m_window setContentView:glView]; [m_window setContentView:glView];
m_openGLInitialized = true; m_openGLInitialized = true;
} }
- (void)fullscreenWithWidth:(int)width height:(int)height - (void)switchToFullscreen
{ {
NSScreen* screen = [m_window screen]; NSScreen* screen = [m_window screen];
const NSRect screenFrame = [screen frame]; const NSRect screenFrame = [screen frame];
const NSRect displayRect = IsHiDPISupported() const NSRect displayRect = vid_hidpi
? [screen convertRectToBacking:screenFrame] ? [screen convertRectToBacking:screenFrame]
: screenFrame; : screenFrame;
const float displayWidth = displayRect.size.width; const float displayWidth = displayRect.size.width;
const float displayHeight = displayRect.size.height; const float displayHeight = displayRect.size.height;
const float pixelScaleFactorX = displayWidth / static_cast< float >(width ); const float pixelScaleFactorX = displayWidth / static_cast<float>(m_width );
const float pixelScaleFactorY = displayHeight / static_cast< float >(height); const float pixelScaleFactorY = displayHeight / static_cast<float>(m_height);
rbOpts.pixelScale = std::min(pixelScaleFactorX, pixelScaleFactorY); rbOpts.pixelScale = std::min(pixelScaleFactorX, pixelScaleFactorY);
rbOpts.width = width * rbOpts.pixelScale; rbOpts.width = m_width * rbOpts.pixelScale;
rbOpts.height = height * rbOpts.pixelScale; rbOpts.height = m_height * rbOpts.pixelScale;
rbOpts.shiftX = (displayWidth - rbOpts.width ) / 2.0f; rbOpts.shiftX = (displayWidth - rbOpts.width ) / 2.0f;
rbOpts.shiftY = (displayHeight - rbOpts.height) / 2.0f; rbOpts.shiftY = (displayHeight - rbOpts.height) / 2.0f;
@ -1092,18 +1102,18 @@ static ApplicationDelegate* s_applicationDelegate;
[m_window setFrameOrigin:NSMakePoint(0.0f, 0.0f)]; [m_window setFrameOrigin:NSMakePoint(0.0f, 0.0f)];
} }
- (void)windowedWithWidth:(int)width height:(int)height - (void)switchToWindowed
{ {
rbOpts.pixelScale = 1.0f; rbOpts.pixelScale = 1.0f;
rbOpts.width = static_cast< float >(width ); rbOpts.width = static_cast<float>(m_width );
rbOpts.height = static_cast< float >(height); rbOpts.height = static_cast<float>(m_height);
rbOpts.shiftX = 0.0f; rbOpts.shiftX = 0.0f;
rbOpts.shiftY = 0.0f; rbOpts.shiftY = 0.0f;
const NSSize windowPixelSize = NSMakeSize(width, height); const NSSize windowPixelSize = NSMakeSize(m_width, m_height);
const NSSize windowSize = IsHiDPISupported() const NSSize windowSize = vid_hidpi
? [[m_window contentView] convertSizeFromBacking:windowPixelSize] ? [[m_window contentView] convertSizeFromBacking:windowPixelSize]
: windowPixelSize; : windowPixelSize;
@ -1114,19 +1124,40 @@ static ApplicationDelegate* s_applicationDelegate;
[m_window center]; [m_window center];
} }
- (void)changeVideoResolution:(bool)fullscreen width:(int)width height:(int)height - (void)changeVideoResolution:(bool)fullscreen width:(int)width height:(int)height useHiDPI:(bool)hiDPI
{ {
if (fullscreen == m_fullscreen
&& width == m_width
&& height == m_height
&& hiDPI == m_hiDPI)
{
return;
}
m_fullscreen = fullscreen;
m_width = width;
m_height = height;
m_hiDPI = hiDPI;
[self initializeOpenGL]; [self initializeOpenGL];
if (fullscreen) if (IsHiDPISupported())
{ {
[self fullscreenWithWidth:width height:height]; NSOpenGLView* const glView = [m_window contentView];
[glView setWantsBestResolutionOpenGLSurface:m_hiDPI];
}
if (m_fullscreen)
{
[self switchToFullscreen];
} }
else else
{ {
[self windowedWithWidth:width height:height]; [self switchToWindowed];
} }
rbOpts.dirty = true;
const NSSize viewSize = GetRealContentViewSize(m_window); const NSSize viewSize = GetRealContentViewSize(m_window);
glViewport(0, 0, viewSize.width, viewSize.height); glViewport(0, 0, viewSize.width, viewSize.height);
@ -1145,6 +1176,19 @@ static ApplicationDelegate* s_applicationDelegate;
} }
} }
- (void)useHiDPI:(bool)hiDPI
{
if (!m_openGLInitialized)
{
return;
}
[self changeVideoResolution:m_fullscreen
width:m_width
height:m_height
useHiDPI:hiDPI];
}
- (void)processEvents:(NSTimer*)timer - (void)processEvents:(NSTimer*)timer
{ {
@ -1230,6 +1274,22 @@ static ApplicationDelegate* s_applicationDelegate;
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
CUSTOM_CVAR(Bool, vid_hidpi, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
{
if (IsHiDPISupported())
{
[s_applicationDelegate useHiDPI:self];
}
else if (0 != self)
{
self = 0;
}
}
// ---------------------------------------------------------------------------
void I_SetMainWindowVisible(bool visible) void I_SetMainWindowVisible(bool visible)
{ {
[s_applicationDelegate setMainWindowVisible:visible]; [s_applicationDelegate setMainWindowVisible:visible];
@ -1508,7 +1568,10 @@ static SDL_PixelFormat* GetPixelFormat()
SDL_Surface* SDL_SetVideoMode(int width, int height, int, Uint32 flags) SDL_Surface* SDL_SetVideoMode(int width, int height, int, Uint32 flags)
{ {
[s_applicationDelegate changeVideoResolution:(SDL_FULLSCREEN & flags) width:width height:height]; [s_applicationDelegate changeVideoResolution:(SDL_FULLSCREEN & flags)
width:width
height:height
useHiDPI:vid_hidpi];
static SDL_Surface result; static SDL_Surface result;
@ -1554,21 +1617,6 @@ void SDL_WM_SetCaption(const char* title, const char* icon)
// Window title is set in SDL_SetVideoMode() // Window title is set in SDL_SetVideoMode()
} }
static void ResetSoftwareViewport()
{
// For an unknown reason the following call to glClear() is needed
// to avoid drawing of garbage in fullscreen mode
// when game video resolution's aspect ratio is different from display one
GLint viewport[2];
glGetIntegerv(GL_MAX_VIEWPORT_DIMS, viewport);
glViewport(0, 0, viewport[0], viewport[1]);
glClear(GL_COLOR_BUFFER_BIT);
glViewport(rbOpts.shiftX, rbOpts.shiftY, rbOpts.width, rbOpts.height);
}
int SDL_WM_ToggleFullScreen(SDL_Surface* surface) int SDL_WM_ToggleFullScreen(SDL_Surface* surface)
{ {
if (surface->flags & SDL_FULLSCREEN) if (surface->flags & SDL_FULLSCREEN)
@ -1582,8 +1630,8 @@ int SDL_WM_ToggleFullScreen(SDL_Surface* surface)
[s_applicationDelegate changeVideoResolution:(SDL_FULLSCREEN & surface->flags) [s_applicationDelegate changeVideoResolution:(SDL_FULLSCREEN & surface->flags)
width:surface->w width:surface->w
height:surface->h]; height:surface->h
ResetSoftwareViewport(); useHiDPI:vid_hidpi];
return 1; return 1;
} }
@ -1638,8 +1686,6 @@ static void SetupSoftwareRendering(SDL_Surface* screen)
glLoadIdentity(); glLoadIdentity();
glOrtho(0.0, screen->w, screen->h, 0.0, -1.0, 1.0); glOrtho(0.0, screen->w, screen->h, 0.0, -1.0, 1.0);
ResetSoftwareViewport();
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
glGenTextures(1, &s_frameBufferTexture); glGenTextures(1, &s_frameBufferTexture);
@ -1661,11 +1707,23 @@ int SDL_Flip(SDL_Surface* screen)
SetupSoftwareRendering(screen); SetupSoftwareRendering(screen);
} }
if (rbOpts.dirty)
{
glViewport(rbOpts.shiftX, rbOpts.shiftY, rbOpts.width, rbOpts.height);
// TODO: Figure out why the following glClear() call is needed
// to avoid drawing of garbage in fullscreen mode when
// in-game's aspect ratio is different from display one
glClear(GL_COLOR_BUFFER_BIT);
rbOpts.dirty = false;
}
const int width = screen->w; const int width = screen->w;
const int height = screen->h; const int height = screen->h;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,
width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, screen->pixels); width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, screen->pixels);
glBegin(GL_QUADS); glBegin(GL_QUADS);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glColor4f(1.0f, 1.0f, 1.0f, 1.0f);

View file

@ -43,6 +43,8 @@ struct RenderBufferOptions
float width; float width;
float height; float height;
bool dirty;
}; };
extern RenderBufferOptions rbOpts; extern RenderBufferOptions rbOpts;