Viewport scaling and display density independence
The view is scaled to be as large as possible, without changing the aspect, within the bounds of the window. On "retina" displays, or other displays where window units != pixels, the view should no longer draw incorrectly.
This commit is contained in:
parent
335082e74e
commit
fea4505dda
7 changed files with 85 additions and 2 deletions
|
@ -18,6 +18,10 @@ static void OnWindowSizeEvent(GLFWwindow* win, int width, int height) {
|
||||||
emu_window->SetClientAreaHeight(height);
|
emu_window->SetClientAreaHeight(height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmuWindow_GLFW::GetFramebufferSize(int* fbWidth, int* fbHeight) {
|
||||||
|
glfwGetFramebufferSize(m_render_window, fbWidth, fbHeight);
|
||||||
|
}
|
||||||
|
|
||||||
/// EmuWindow_GLFW constructor
|
/// EmuWindow_GLFW constructor
|
||||||
EmuWindow_GLFW::EmuWindow_GLFW() {
|
EmuWindow_GLFW::EmuWindow_GLFW() {
|
||||||
// Initialize the window
|
// Initialize the window
|
||||||
|
@ -48,6 +52,7 @@ EmuWindow_GLFW::EmuWindow_GLFW() {
|
||||||
//glfwSetKeyCallback(m_render_window, OnKeyEvent);
|
//glfwSetKeyCallback(m_render_window, OnKeyEvent);
|
||||||
//glfwSetWindowSizeCallback(m_render_window, OnWindowSizeEvent);
|
//glfwSetWindowSizeCallback(m_render_window, OnWindowSizeEvent);
|
||||||
|
|
||||||
|
|
||||||
DoneCurrent();
|
DoneCurrent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ public:
|
||||||
void SwapBuffers();
|
void SwapBuffers();
|
||||||
|
|
||||||
/// Polls window events
|
/// Polls window events
|
||||||
void PollEvents();
|
void PollEvents();
|
||||||
|
|
||||||
/// Makes the graphics context current for the caller thread
|
/// Makes the graphics context current for the caller thread
|
||||||
void MakeCurrent();
|
void MakeCurrent();
|
||||||
|
@ -25,6 +25,9 @@ public:
|
||||||
/// Releases (dunno if this is the "right" word) the GLFW context from the caller thread
|
/// Releases (dunno if this is the "right" word) the GLFW context from the caller thread
|
||||||
void DoneCurrent();
|
void DoneCurrent();
|
||||||
|
|
||||||
|
/// Gets the size of the window in pixels
|
||||||
|
void GetFramebufferSize(int* fbWidth, int* fbHeight);
|
||||||
|
|
||||||
GLFWwindow* m_render_window; ///< Internal GLFW render window
|
GLFWwindow* m_render_window; ///< Internal GLFW render window
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -179,6 +179,24 @@ void GRenderWindow::PollEvents() {
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// On Qt 5.1+, this correctly gets the size of the framebuffer (pixels).
|
||||||
|
//
|
||||||
|
// Older versions get the window size (density independent pixels),
|
||||||
|
// and hence, do not support DPI scaling ("retina" displays).
|
||||||
|
// The result will be a viewport that is smaller than the extent of the window.
|
||||||
|
void GRenderWindow::GetFramebufferSize(int* fbWidth, int* fbHeight)
|
||||||
|
{
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
|
||||||
|
int pixelRatio = child->QPaintDevice::devicePixelRatio();
|
||||||
|
|
||||||
|
*fbWidth = child->QPaintDevice::width() * pixelRatio;
|
||||||
|
*fbHeight = child->QPaintDevice::height() * pixelRatio;
|
||||||
|
#else
|
||||||
|
*fbWidth = child->QPaintDevice::width();
|
||||||
|
*fbHeight = child->QPaintDevice::height();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void GRenderWindow::BackupGeometry()
|
void GRenderWindow::BackupGeometry()
|
||||||
{
|
{
|
||||||
geometry = ((QGLWidget*)this)->saveGeometry();
|
geometry = ((QGLWidget*)this)->saveGeometry();
|
||||||
|
|
|
@ -96,6 +96,7 @@ public:
|
||||||
void MakeCurrent();
|
void MakeCurrent();
|
||||||
void DoneCurrent();
|
void DoneCurrent();
|
||||||
void PollEvents();
|
void PollEvents();
|
||||||
|
void GetFramebufferSize(int* fbWidth, int* fbHeight);
|
||||||
|
|
||||||
void BackupGeometry();
|
void BackupGeometry();
|
||||||
void RestoreGeometry();
|
void RestoreGeometry();
|
||||||
|
|
|
@ -32,6 +32,9 @@ public:
|
||||||
/// Releases (dunno if this is the "right" word) the GLFW context from the caller thread
|
/// Releases (dunno if this is the "right" word) the GLFW context from the caller thread
|
||||||
virtual void DoneCurrent() = 0;
|
virtual void DoneCurrent() = 0;
|
||||||
|
|
||||||
|
/// Gets the size of the window in pixels
|
||||||
|
virtual void GetFramebufferSize(int* fbWidth, int* fbHeight) = 0;
|
||||||
|
|
||||||
Config GetConfig() const {
|
Config GetConfig() const {
|
||||||
return m_config;
|
return m_config;
|
||||||
}
|
}
|
||||||
|
|
|
@ -191,7 +191,8 @@ void RendererOpenGL::InitFramebuffer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RendererOpenGL::RenderFramebuffer() {
|
void RendererOpenGL::RenderFramebuffer() {
|
||||||
glViewport(0, 0, resolution_width, resolution_height);
|
UpdateViewportExtent();
|
||||||
|
glViewport(viewport_extent.x, viewport_extent.y, viewport_extent.width, viewport_extent.height);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
glUseProgram(program_id);
|
glUseProgram(program_id);
|
||||||
|
@ -243,6 +244,43 @@ void RendererOpenGL::SetWindow(EmuWindow* window) {
|
||||||
render_window = window;
|
render_window = window;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: This should happen on window resize callback from EmuWindow.
|
||||||
|
// It should be done when EmuWindow is refactored.
|
||||||
|
void RendererOpenGL::UpdateViewportExtent() {
|
||||||
|
int width_in_pixels;
|
||||||
|
int height_in_pixels;
|
||||||
|
|
||||||
|
render_window->GetFramebufferSize(&width_in_pixels, &height_in_pixels);
|
||||||
|
|
||||||
|
// No update needed if framebuffer size hasn't changed
|
||||||
|
if (width_in_pixels == framebuffer_size.width && height_in_pixels == framebuffer_size.height) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Letterbox the emulation content into the window
|
||||||
|
framebuffer_size.width = width_in_pixels;
|
||||||
|
framebuffer_size.height = height_in_pixels;
|
||||||
|
|
||||||
|
float windowRatio = static_cast<float>(height_in_pixels) / width_in_pixels;
|
||||||
|
float emulationRatio = static_cast<float>(resolution_height) / resolution_width;
|
||||||
|
|
||||||
|
// If the window is more narrow than the emulation content, borders are applied on the
|
||||||
|
// top and bottom of the window
|
||||||
|
if (windowRatio > emulationRatio) {
|
||||||
|
viewport_extent.width = width_in_pixels;
|
||||||
|
viewport_extent.height = emulationRatio * viewport_extent.width;
|
||||||
|
viewport_extent.x = 0;
|
||||||
|
viewport_extent.y = (height_in_pixels - viewport_extent.height) / 2;
|
||||||
|
|
||||||
|
// Otherwise, borders are applied on the left and right sides of the window
|
||||||
|
} else {
|
||||||
|
viewport_extent.height = height_in_pixels;
|
||||||
|
viewport_extent.width = (1 / emulationRatio) * viewport_extent.height;
|
||||||
|
viewport_extent.x = (width_in_pixels - viewport_extent.width) / 2;
|
||||||
|
viewport_extent.y = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Initialize the renderer
|
/// Initialize the renderer
|
||||||
void RendererOpenGL::Init() {
|
void RendererOpenGL::Init() {
|
||||||
render_window->MakeCurrent();
|
render_window->MakeCurrent();
|
||||||
|
|
|
@ -52,6 +52,9 @@ private:
|
||||||
/// Updates the framerate
|
/// Updates the framerate
|
||||||
void UpdateFramerate();
|
void UpdateFramerate();
|
||||||
|
|
||||||
|
/// Updates the viewport rectangle
|
||||||
|
void UpdateViewportExtent();
|
||||||
|
|
||||||
/// Structure used for storing information for rendering each 3DS screen
|
/// Structure used for storing information for rendering each 3DS screen
|
||||||
struct ScreenInfo {
|
struct ScreenInfo {
|
||||||
// Properties
|
// Properties
|
||||||
|
@ -81,6 +84,18 @@ private:
|
||||||
int resolution_width; ///< Current resolution width
|
int resolution_width; ///< Current resolution width
|
||||||
int resolution_height; ///< Current resolution height
|
int resolution_height; ///< Current resolution height
|
||||||
|
|
||||||
|
struct {
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
} framebuffer_size; ///< Current framebuffer size
|
||||||
|
|
||||||
|
struct {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
} viewport_extent; ///< Current viewport rectangle
|
||||||
|
|
||||||
// OpenGL global object IDs
|
// OpenGL global object IDs
|
||||||
GLuint vertex_array_id;
|
GLuint vertex_array_id;
|
||||||
GLuint program_id;
|
GLuint program_id;
|
||||||
|
|
Loading…
Reference in a new issue