aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Kevin Hartman <kevin@hart.mn>2014-08-29 22:23:12 -0700
committerGravatar Tony Wasserka <NeoBrainX@gmail.com>2014-11-18 13:06:05 +0100
commit221a9b023d8c9ca55c093823e9efd6d13d0a54a2 (patch)
tree57a26a0e11416b366688d00c4a2c9216fa0cde78 /src
parentc8d933a14211ce6ee02659ecef758a1f303bc87f (diff)
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.
Diffstat (limited to 'src')
-rw-r--r--src/citra/emu_window/emu_window_glfw.cpp5
-rw-r--r--src/citra/emu_window/emu_window_glfw.h5
-rw-r--r--src/citra_qt/bootmanager.cpp24
-rw-r--r--src/citra_qt/bootmanager.hxx1
-rw-r--r--src/common/emu_window.h7
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp36
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.h15
7 files changed, 89 insertions, 4 deletions
diff --git a/src/citra/emu_window/emu_window_glfw.cpp b/src/citra/emu_window/emu_window_glfw.cpp
index 0c774bbc..d0f6e9a9 100644
--- a/src/citra/emu_window/emu_window_glfw.cpp
+++ b/src/citra/emu_window/emu_window_glfw.cpp
@@ -34,6 +34,10 @@ const bool EmuWindow_GLFW::IsOpen() {
return glfwWindowShouldClose(m_render_window) == 0;
}
+void EmuWindow_GLFW::GetFramebufferSize(int* fbWidth, int* fbHeight) {
+ glfwGetFramebufferSize(m_render_window, fbWidth, fbHeight);
+}
+
/// EmuWindow_GLFW constructor
EmuWindow_GLFW::EmuWindow_GLFW() {
keyboard_id = KeyMap::NewDeviceId();
@@ -64,6 +68,7 @@ EmuWindow_GLFW::EmuWindow_GLFW() {
glfwSetWindowUserPointer(m_render_window, this);
glfwSetKeyCallback(m_render_window, OnKeyEvent);
+
DoneCurrent();
}
diff --git a/src/citra/emu_window/emu_window_glfw.h b/src/citra/emu_window/emu_window_glfw.h
index 7c307214..e9622876 100644
--- a/src/citra/emu_window/emu_window_glfw.h
+++ b/src/citra/emu_window/emu_window_glfw.h
@@ -21,7 +21,7 @@ public:
/// Makes the graphics context current for the caller thread
void MakeCurrent() override;
-
+
/// Releases (dunno if this is the "right" word) the GLFW context from the caller thread
void DoneCurrent() override;
@@ -32,6 +32,9 @@ public:
void ReloadSetKeymaps() override;
+ /// Gets the size of the window in pixels
+ void GetFramebufferSize(int* fbWidth, int* fbHeight);
+
private:
GLFWwindow* m_render_window; ///< Internal GLFW render window
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp
index 20824692..516e115f 100644
--- a/src/citra_qt/bootmanager.cpp
+++ b/src/citra_qt/bootmanager.cpp
@@ -2,6 +2,12 @@
#include <QKeyEvent>
#include <QApplication>
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
+// Required for screen DPI information
+#include <QScreen>
+#include <QWindow>
+#endif
+
#include "common/common.h"
#include "bootmanager.hxx"
@@ -176,6 +182,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()
{
geometry = ((QGLWidget*)this)->saveGeometry();
diff --git a/src/citra_qt/bootmanager.hxx b/src/citra_qt/bootmanager.hxx
index f8afc403..ec3e1fe7 100644
--- a/src/citra_qt/bootmanager.hxx
+++ b/src/citra_qt/bootmanager.hxx
@@ -96,6 +96,7 @@ public:
void MakeCurrent() override;
void DoneCurrent() override;
void PollEvents() override;
+ void GetFramebufferSize(int* fbWidth, int* fbHeight) override;
void BackupGeometry();
void RestoreGeometry();
diff --git a/src/common/emu_window.h b/src/common/emu_window.h
index 6c2b598f..ba9d4fa7 100644
--- a/src/common/emu_window.h
+++ b/src/common/emu_window.h
@@ -49,8 +49,11 @@ public:
void SetConfig(const WindowConfig& val) {
m_config = val;
}
-
- int GetClientAreaWidth() const {
+
+ /// Gets the size of the window in pixels
+ virtual void GetFramebufferSize(int* fbWidth, int* fbHeight) = 0;
+
+ int GetClientAreaWidth() const {
return m_client_area_width;
}
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 8483f79b..3757482d 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -191,7 +191,8 @@ void RendererOpenGL::DrawSingleScreenRotated(const TextureInfo& texture, float x
* Draws the emulated screens to the emulator window.
*/
void RendererOpenGL::DrawScreens() {
- 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);
glUseProgram(program_id);
@@ -228,6 +229,39 @@ void RendererOpenGL::SetWindow(EmuWindow* window) {
render_window = window;
}
+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;
+ }
+
+ framebuffer_size.width = width_in_pixels;
+ framebuffer_size.height = height_in_pixels;
+
+ float window_aspect_ratio = static_cast<float>(height_in_pixels) / width_in_pixels;
+ float emulation_aspect_ratio = static_cast<float>(resolution_height) / resolution_width;
+
+ if (window_aspect_ratio > emulation_aspect_ratio) {
+ // If the window is more narrow than the emulation content, borders are applied on the
+ // top and bottom of the window.
+ viewport_extent.width = width_in_pixels;
+ viewport_extent.height = emulation_aspect_ratio * viewport_extent.width;
+ viewport_extent.x = 0;
+ viewport_extent.y = (height_in_pixels - viewport_extent.height) / 2;
+ } else {
+ // Otherwise, borders are applied on the left and right sides of the window.
+ viewport_extent.height = height_in_pixels;
+ viewport_extent.width = (1 / emulation_aspect_ratio) * viewport_extent.height;
+ viewport_extent.x = (width_in_pixels - viewport_extent.width) / 2;
+ viewport_extent.y = 0;
+ }
+}
+
/// Initialize the renderer
void RendererOpenGL::Init() {
render_window->MakeCurrent();
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h
index eed201a9..d440e2bc 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.h
+++ b/src/video_core/renderer_opengl/renderer_opengl.h
@@ -52,12 +52,27 @@ private:
static void LoadFBToActiveGLTexture(const GPU::Regs::FramebufferConfig& framebuffer,
const TextureInfo& texture);
+ /// Updates the viewport rectangle
+ void UpdateViewportExtent();
+
EmuWindow* render_window; ///< Handle to render window
u32 last_mode; ///< Last render mode
int resolution_width; ///< Current resolution width
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 object IDs
GLuint vertex_array_handle;
GLuint vertex_buffer_handle;