diff --git a/src/citra/config.cpp b/src/citra/config.cpp
index ef1229912..a4162e9ad 100644
--- a/src/citra/config.cpp
+++ b/src/citra/config.cpp
@@ -94,6 +94,23 @@ void Config::ReadValues() {
     Settings::values.layout_option =
         static_cast<Settings::LayoutOption>(sdl2_config->GetInteger("Layout", "layout_option", 0));
     Settings::values.swap_screen = sdl2_config->GetBoolean("Layout", "swap_screen", false);
+    Settings::values.custom_layout = sdl2_config->GetBoolean("Layout", "custom_layout", false);
+    Settings::values.custom_top_left =
+        static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_top_left", 0));
+    Settings::values.custom_top_top =
+        static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_top_top", 0));
+    Settings::values.custom_top_right =
+        static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_top_right", 400));
+    Settings::values.custom_top_bottom =
+        static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_top_bottom", 240));
+    Settings::values.custom_bottom_left =
+        static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_bottom_left", 40));
+    Settings::values.custom_bottom_top =
+        static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_bottom_top", 240));
+    Settings::values.custom_bottom_right =
+        static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_bottom_right", 360));
+    Settings::values.custom_bottom_bottom =
+        static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_bottom_bottom", 480));
 
     // Audio
     Settings::values.sink_id = sdl2_config->Get("Audio", "output_engine", "auto");
diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h
index af9f7aa2a..084372df4 100644
--- a/src/citra/default_ini.h
+++ b/src/citra/default_ini.h
@@ -84,6 +84,21 @@ bg_green =
 # 0 (default): Default Top Bottom Screen, 1: Single Screen Only, 2: Large Screen Small Screen
 layout_option =
 
+# Toggle custom layout (using the settings below) on or off.
+# 0 (default): Off , 1: On
+custom_layout =
+
+# Screen placement when using Custom layout option
+# 0x, 0y is the top left corner of the render window.
+custom_top_left =
+custom_top_top =
+custom_top_right =
+custom_top_bottom =
+custom_bottom_left =
+custom_bottom_top =
+custom_bottom_right =
+custom_bottom_bottom =
+
 #Whether to toggle frame limiter on or off.
 # 0: Off , 1  (default): On
 toggle_framelimit =
diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp
index 6ccfa1577..bf0ac7c66 100644
--- a/src/citra_qt/config.cpp
+++ b/src/citra_qt/config.cpp
@@ -79,6 +79,15 @@ void Config::ReadValues() {
     Settings::values.layout_option =
         static_cast<Settings::LayoutOption>(qt_config->value("layout_option").toInt());
     Settings::values.swap_screen = qt_config->value("swap_screen", false).toBool();
+    Settings::values.custom_layout = qt_config->value("custom_layout", false).toBool();
+    Settings::values.custom_top_left = qt_config->value("custom_top_left", 0).toInt();
+    Settings::values.custom_top_top = qt_config->value("custom_top_top", 0).toInt();
+    Settings::values.custom_top_right = qt_config->value("custom_top_right", 400).toInt();
+    Settings::values.custom_top_bottom = qt_config->value("custom_top_bottom", 240).toInt();
+    Settings::values.custom_bottom_left = qt_config->value("custom_bottom_left", 40).toInt();
+    Settings::values.custom_bottom_top = qt_config->value("custom_bottom_top", 240).toInt();
+    Settings::values.custom_bottom_right = qt_config->value("custom_bottom_right", 360).toInt();
+    Settings::values.custom_bottom_bottom = qt_config->value("custom_bottom_bottom", 480).toInt();
     qt_config->endGroup();
 
     qt_config->beginGroup("Audio");
@@ -207,6 +216,15 @@ void Config::SaveValues() {
     qt_config->beginGroup("Layout");
     qt_config->setValue("layout_option", static_cast<int>(Settings::values.layout_option));
     qt_config->setValue("swap_screen", Settings::values.swap_screen);
+    qt_config->setValue("custom_layout", Settings::values.custom_layout);
+    qt_config->setValue("custom_top_left", Settings::values.custom_top_left);
+    qt_config->setValue("custom_top_top", Settings::values.custom_top_top);
+    qt_config->setValue("custom_top_right", Settings::values.custom_top_right);
+    qt_config->setValue("custom_top_bottom", Settings::values.custom_top_bottom);
+    qt_config->setValue("custom_bottom_left", Settings::values.custom_bottom_left);
+    qt_config->setValue("custom_bottom_top", Settings::values.custom_bottom_top);
+    qt_config->setValue("custom_bottom_right", Settings::values.custom_bottom_right);
+    qt_config->setValue("custom_bottom_bottom", Settings::values.custom_bottom_bottom);
     qt_config->endGroup();
 
     qt_config->beginGroup("Audio");
diff --git a/src/citra_qt/configure_graphics.cpp b/src/citra_qt/configure_graphics.cpp
index 54f799b47..4c0bd4246 100644
--- a/src/citra_qt/configure_graphics.cpp
+++ b/src/citra_qt/configure_graphics.cpp
@@ -14,6 +14,8 @@ ConfigureGraphics::ConfigureGraphics(QWidget* parent)
     this->setConfiguration();
 
     ui->toggle_vsync->setEnabled(!Core::System::GetInstance().IsPoweredOn());
+
+    ui->layoutBox->setEnabled(!Settings::values.custom_layout);
 }
 
 ConfigureGraphics::~ConfigureGraphics() {}
diff --git a/src/citra_qt/configure_graphics.ui b/src/citra_qt/configure_graphics.ui
index a091f4c60..228f2a869 100644
--- a/src/citra_qt/configure_graphics.ui
+++ b/src/citra_qt/configure_graphics.ui
@@ -126,7 +126,7 @@
     </layout>
    </item>
    <item>
-    <widget class="QGroupBox" name="groupBox2">
+    <widget class="QGroupBox" name="layoutBox">
      <property name="title">
       <string>Layout</string>
      </property>
diff --git a/src/common/framebuffer_layout.cpp b/src/common/framebuffer_layout.cpp
index 46c008d9c..a2a0e7dad 100644
--- a/src/common/framebuffer_layout.cpp
+++ b/src/common/framebuffer_layout.cpp
@@ -6,6 +6,7 @@
 
 #include "common/assert.h"
 #include "common/framebuffer_layout.h"
+#include "core/settings.h"
 #include "video_core/video_core.h"
 
 namespace Layout {
@@ -135,4 +136,22 @@ FramebufferLayout LargeFrameLayout(unsigned width, unsigned height, bool swapped
     res.bottom_screen = swapped ? large_screen : small_screen;
     return res;
 }
+
+FramebufferLayout CustomFrameLayout(unsigned width, unsigned height) {
+    ASSERT(width > 0);
+    ASSERT(height > 0);
+
+    FramebufferLayout res{width, height, true, true, {}, {}};
+
+    MathUtil::Rectangle<unsigned> top_screen{
+        Settings::values.custom_top_left, Settings::values.custom_top_top,
+        Settings::values.custom_top_right, Settings::values.custom_top_bottom};
+    MathUtil::Rectangle<unsigned> bot_screen{
+        Settings::values.custom_bottom_left, Settings::values.custom_bottom_top,
+        Settings::values.custom_bottom_right, Settings::values.custom_bottom_bottom};
+
+    res.top_screen = top_screen;
+    res.bottom_screen = bot_screen;
+    return res;
+}
 }
diff --git a/src/common/framebuffer_layout.h b/src/common/framebuffer_layout.h
index a125646a3..f1df5c55a 100644
--- a/src/common/framebuffer_layout.h
+++ b/src/common/framebuffer_layout.h
@@ -44,4 +44,12 @@ FramebufferLayout SingleFrameLayout(unsigned width, unsigned height, bool is_swa
  * @return Newly created FramebufferLayout object with default screen regions initialized
  */
 FramebufferLayout LargeFrameLayout(unsigned width, unsigned height, bool is_swapped);
+
+/**
+ * Factory method for constructing a custom FramebufferLayout
+ * @param width Window framebuffer width in pixels
+ * @param height Window framebuffer height in pixels
+ * @return Newly created FramebufferLayout object with default screen regions initialized
+ */
+FramebufferLayout CustomFrameLayout(unsigned width, unsigned height);
 }
diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp
index 73a44bfe7..5fdb3a7e8 100644
--- a/src/core/frontend/emu_window.cpp
+++ b/src/core/frontend/emu_window.cpp
@@ -89,17 +89,21 @@ void EmuWindow::GyroscopeChanged(float x, float y, float z) {
 
 void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height) {
     Layout::FramebufferLayout layout;
-    switch (Settings::values.layout_option) {
-    case Settings::LayoutOption::SingleScreen:
-        layout = Layout::SingleFrameLayout(width, height, Settings::values.swap_screen);
-        break;
-    case Settings::LayoutOption::LargeScreen:
-        layout = Layout::LargeFrameLayout(width, height, Settings::values.swap_screen);
-        break;
-    case Settings::LayoutOption::Default:
-    default:
-        layout = Layout::DefaultFrameLayout(width, height, Settings::values.swap_screen);
-        break;
+    if (Settings::values.custom_layout == true) {
+        layout = Layout::CustomFrameLayout(width, height);
+    } else {
+        switch (Settings::values.layout_option) {
+        case Settings::LayoutOption::SingleScreen:
+            layout = Layout::SingleFrameLayout(width, height, Settings::values.swap_screen);
+            break;
+        case Settings::LayoutOption::LargeScreen:
+            layout = Layout::LargeFrameLayout(width, height, Settings::values.swap_screen);
+            break;
+        case Settings::LayoutOption::Default:
+        default:
+            layout = Layout::DefaultFrameLayout(width, height, Settings::values.swap_screen);
+            break;
+        }
     }
     NotifyFramebufferLayoutChanged(layout);
 }
diff --git a/src/core/settings.h b/src/core/settings.h
index d1a9f0da8..03c64c94c 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -15,7 +15,6 @@ enum class LayoutOption {
     Default,
     SingleScreen,
     LargeScreen,
-    Custom,
 };
 
 namespace NativeButton {
@@ -99,6 +98,15 @@ struct Values {
 
     LayoutOption layout_option;
     bool swap_screen;
+    bool custom_layout;
+    u16 custom_top_left;
+    u16 custom_top_top;
+    u16 custom_top_right;
+    u16 custom_top_bottom;
+    u16 custom_bottom_left;
+    u16 custom_bottom_top;
+    u16 custom_bottom_right;
+    u16 custom_bottom_bottom;
 
     float bg_red;
     float bg_green;