From 874cb42e704f81cbb4c2dd88e25283828c4d7a87 Mon Sep 17 00:00:00 2001
From: wwylele <wwylele@gmail.com>
Date: Mon, 28 May 2018 14:28:03 +0300
Subject: [PATCH 01/19] shader/jit: preserve integer & condition register
 across invocation

---
 .../shader/shader_jit_x64_compiler.cpp        | 27 ++++++++++++++++---
 1 file changed, 23 insertions(+), 4 deletions(-)

diff --git a/src/video_core/shader/shader_jit_x64_compiler.cpp b/src/video_core/shader/shader_jit_x64_compiler.cpp
index 06c6f52e5..9744ce56d 100644
--- a/src/video_core/shader/shader_jit_x64_compiler.cpp
+++ b/src/video_core/shader/shader_jit_x64_compiler.cpp
@@ -580,6 +580,18 @@ void JitShader::Compile_RSQ(Instruction instr) {
 void JitShader::Compile_NOP(Instruction instr) {}
 
 void JitShader::Compile_END(Instruction instr) {
+    // Save conditional code
+    mov(byte[STATE + offsetof(UnitState, conditional_code[0])], COND0.cvt8());
+    mov(byte[STATE + offsetof(UnitState, conditional_code[1])], COND1.cvt8());
+
+    // Save address/loop registers
+    sar(ADDROFFS_REG_0, 4);
+    sar(ADDROFFS_REG_1, 4);
+    sar(LOOPCOUNT_REG, 4);
+    mov(dword[STATE + offsetof(UnitState, address_registers[0])], ADDROFFS_REG_0.cvt32());
+    mov(dword[STATE + offsetof(UnitState, address_registers[1])], ADDROFFS_REG_1.cvt32());
+    mov(dword[STATE + offsetof(UnitState, address_registers[2])], LOOPCOUNT_REG);
+
     ABI_PopRegistersAndAdjustStack(*this, ABI_ALL_CALLEE_SAVED, 8, 16);
     ret();
 }
@@ -885,10 +897,17 @@ void JitShader::Compile(const std::array<u32, MAX_PROGRAM_CODE_LENGTH>* program_
     mov(UNIFORMS, ABI_PARAM1);
     mov(STATE, ABI_PARAM2);
 
-    // Zero address/loop  registers
-    xor_(ADDROFFS_REG_0.cvt32(), ADDROFFS_REG_0.cvt32());
-    xor_(ADDROFFS_REG_1.cvt32(), ADDROFFS_REG_1.cvt32());
-    xor_(LOOPCOUNT_REG, LOOPCOUNT_REG);
+    // Load address/loop registers
+    movsxd(ADDROFFS_REG_0, dword[STATE + offsetof(UnitState, address_registers[0])]);
+    movsxd(ADDROFFS_REG_1, dword[STATE + offsetof(UnitState, address_registers[1])]);
+    mov(LOOPCOUNT_REG, dword[STATE + offsetof(UnitState, address_registers[2])]);
+    shl(ADDROFFS_REG_0, 4);
+    shl(ADDROFFS_REG_1, 4);
+    shl(LOOPCOUNT_REG, 4);
+
+    // Load conditional code
+    mov(COND0, byte[STATE + offsetof(UnitState, conditional_code[0])]);
+    mov(COND1, byte[STATE + offsetof(UnitState, conditional_code[1])]);
 
     // Used to set a register to one
     static const __m128 one = {1.f, 1.f, 1.f, 1.f};

From 9060e08e491bf1065656ba62abe94e2da9f51a5b Mon Sep 17 00:00:00 2001
From: wwylele <wwylele@gmail.com>
Date: Fri, 18 May 2018 23:28:58 +0300
Subject: [PATCH 02/19] shader/jit: implement breakc

---
 .../shader/shader_jit_x64_compiler.cpp        | 139 ++++++++++--------
 .../shader/shader_jit_x64_compiler.h          |   6 +
 2 files changed, 81 insertions(+), 64 deletions(-)

diff --git a/src/video_core/shader/shader_jit_x64_compiler.cpp b/src/video_core/shader/shader_jit_x64_compiler.cpp
index 06c6f52e5..9ca06e766 100644
--- a/src/video_core/shader/shader_jit_x64_compiler.cpp
+++ b/src/video_core/shader/shader_jit_x64_compiler.cpp
@@ -33,70 +33,70 @@ namespace Shader {
 typedef void (JitShader::*JitFunction)(Instruction instr);
 
 const JitFunction instr_table[64] = {
-    &JitShader::Compile_ADD,   // add
-    &JitShader::Compile_DP3,   // dp3
-    &JitShader::Compile_DP4,   // dp4
-    &JitShader::Compile_DPH,   // dph
-    nullptr,                   // unknown
-    &JitShader::Compile_EX2,   // ex2
-    &JitShader::Compile_LG2,   // lg2
-    nullptr,                   // unknown
-    &JitShader::Compile_MUL,   // mul
-    &JitShader::Compile_SGE,   // sge
-    &JitShader::Compile_SLT,   // slt
-    &JitShader::Compile_FLR,   // flr
-    &JitShader::Compile_MAX,   // max
-    &JitShader::Compile_MIN,   // min
-    &JitShader::Compile_RCP,   // rcp
-    &JitShader::Compile_RSQ,   // rsq
-    nullptr,                   // unknown
-    nullptr,                   // unknown
-    &JitShader::Compile_MOVA,  // mova
-    &JitShader::Compile_MOV,   // mov
-    nullptr,                   // unknown
-    nullptr,                   // unknown
-    nullptr,                   // unknown
-    nullptr,                   // unknown
-    &JitShader::Compile_DPH,   // dphi
-    nullptr,                   // unknown
-    &JitShader::Compile_SGE,   // sgei
-    &JitShader::Compile_SLT,   // slti
-    nullptr,                   // unknown
-    nullptr,                   // unknown
-    nullptr,                   // unknown
-    nullptr,                   // unknown
-    nullptr,                   // unknown
-    &JitShader::Compile_NOP,   // nop
-    &JitShader::Compile_END,   // end
-    nullptr,                   // break
-    &JitShader::Compile_CALL,  // call
-    &JitShader::Compile_CALLC, // callc
-    &JitShader::Compile_CALLU, // callu
-    &JitShader::Compile_IF,    // ifu
-    &JitShader::Compile_IF,    // ifc
-    &JitShader::Compile_LOOP,  // loop
-    &JitShader::Compile_EMIT,  // emit
-    &JitShader::Compile_SETE,  // sete
-    &JitShader::Compile_JMP,   // jmpc
-    &JitShader::Compile_JMP,   // jmpu
-    &JitShader::Compile_CMP,   // cmp
-    &JitShader::Compile_CMP,   // cmp
-    &JitShader::Compile_MAD,   // madi
-    &JitShader::Compile_MAD,   // madi
-    &JitShader::Compile_MAD,   // madi
-    &JitShader::Compile_MAD,   // madi
-    &JitShader::Compile_MAD,   // madi
-    &JitShader::Compile_MAD,   // madi
-    &JitShader::Compile_MAD,   // madi
-    &JitShader::Compile_MAD,   // madi
-    &JitShader::Compile_MAD,   // mad
-    &JitShader::Compile_MAD,   // mad
-    &JitShader::Compile_MAD,   // mad
-    &JitShader::Compile_MAD,   // mad
-    &JitShader::Compile_MAD,   // mad
-    &JitShader::Compile_MAD,   // mad
-    &JitShader::Compile_MAD,   // mad
-    &JitShader::Compile_MAD,   // mad
+    &JitShader::Compile_ADD,    // add
+    &JitShader::Compile_DP3,    // dp3
+    &JitShader::Compile_DP4,    // dp4
+    &JitShader::Compile_DPH,    // dph
+    nullptr,                    // unknown
+    &JitShader::Compile_EX2,    // ex2
+    &JitShader::Compile_LG2,    // lg2
+    nullptr,                    // unknown
+    &JitShader::Compile_MUL,    // mul
+    &JitShader::Compile_SGE,    // sge
+    &JitShader::Compile_SLT,    // slt
+    &JitShader::Compile_FLR,    // flr
+    &JitShader::Compile_MAX,    // max
+    &JitShader::Compile_MIN,    // min
+    &JitShader::Compile_RCP,    // rcp
+    &JitShader::Compile_RSQ,    // rsq
+    nullptr,                    // unknown
+    nullptr,                    // unknown
+    &JitShader::Compile_MOVA,   // mova
+    &JitShader::Compile_MOV,    // mov
+    nullptr,                    // unknown
+    nullptr,                    // unknown
+    nullptr,                    // unknown
+    nullptr,                    // unknown
+    &JitShader::Compile_DPH,    // dphi
+    nullptr,                    // unknown
+    &JitShader::Compile_SGE,    // sgei
+    &JitShader::Compile_SLT,    // slti
+    nullptr,                    // unknown
+    nullptr,                    // unknown
+    nullptr,                    // unknown
+    nullptr,                    // unknown
+    nullptr,                    // unknown
+    &JitShader::Compile_NOP,    // nop
+    &JitShader::Compile_END,    // end
+    &JitShader::Compile_BREAKC, // breakc
+    &JitShader::Compile_CALL,   // call
+    &JitShader::Compile_CALLC,  // callc
+    &JitShader::Compile_CALLU,  // callu
+    &JitShader::Compile_IF,     // ifu
+    &JitShader::Compile_IF,     // ifc
+    &JitShader::Compile_LOOP,   // loop
+    &JitShader::Compile_EMIT,   // emit
+    &JitShader::Compile_SETE,   // sete
+    &JitShader::Compile_JMP,    // jmpc
+    &JitShader::Compile_JMP,    // jmpu
+    &JitShader::Compile_CMP,    // cmp
+    &JitShader::Compile_CMP,    // cmp
+    &JitShader::Compile_MAD,    // madi
+    &JitShader::Compile_MAD,    // madi
+    &JitShader::Compile_MAD,    // madi
+    &JitShader::Compile_MAD,    // madi
+    &JitShader::Compile_MAD,    // madi
+    &JitShader::Compile_MAD,    // madi
+    &JitShader::Compile_MAD,    // madi
+    &JitShader::Compile_MAD,    // madi
+    &JitShader::Compile_MAD,    // mad
+    &JitShader::Compile_MAD,    // mad
+    &JitShader::Compile_MAD,    // mad
+    &JitShader::Compile_MAD,    // mad
+    &JitShader::Compile_MAD,    // mad
+    &JitShader::Compile_MAD,    // mad
+    &JitShader::Compile_MAD,    // mad
+    &JitShader::Compile_MAD,    // mad
 };
 
 // The following is used to alias some commonly used registers. Generally, RAX-RDX and XMM0-XMM3 can
@@ -584,6 +584,14 @@ void JitShader::Compile_END(Instruction instr) {
     ret();
 }
 
+void JitShader::Compile_BREAKC(Instruction instr) {
+    Compile_Assert(looping, "BREAKC must be inside a LOOP");
+    if (looping) {
+        Compile_EvaluateCondition(instr);
+        jnz(*loop_break_label);
+    }
+}
+
 void JitShader::Compile_CALL(Instruction instr) {
     // Push offset of the return
     push(qword, (instr.flow_control.dest_offset + instr.flow_control.num_instructions));
@@ -727,11 +735,14 @@ void JitShader::Compile_LOOP(Instruction instr) {
     Label l_loop_start;
     L(l_loop_start);
 
+    loop_break_label = Xbyak::Label();
     Compile_Block(instr.flow_control.dest_offset + 1);
 
     add(LOOPCOUNT_REG, LOOPINC); // Increment LOOPCOUNT_REG by Z-component
     sub(LOOPCOUNT, 1);           // Increment loop count by 1
     jnz(l_loop_start);           // Loop if not equal
+    L(*loop_break_label);
+    loop_break_label = boost::none;
 
     looping = false;
 }
diff --git a/src/video_core/shader/shader_jit_x64_compiler.h b/src/video_core/shader/shader_jit_x64_compiler.h
index 923c34f0d..8e1c87346 100644
--- a/src/video_core/shader/shader_jit_x64_compiler.h
+++ b/src/video_core/shader/shader_jit_x64_compiler.h
@@ -8,6 +8,7 @@
 #include <cstddef>
 #include <utility>
 #include <vector>
+#include <boost/optional.hpp>
 #include <nihstro/shader_bytecode.h>
 #include <xbyak.h>
 #include "common/bit_set.h"
@@ -58,6 +59,7 @@ public:
     void Compile_MOV(Instruction instr);
     void Compile_NOP(Instruction instr);
     void Compile_END(Instruction instr);
+    void Compile_BREAKC(Instruction instr);
     void Compile_CALL(Instruction instr);
     void Compile_CALLC(Instruction instr);
     void Compile_CALLU(Instruction instr);
@@ -119,6 +121,10 @@ private:
     /// Mapping of Pica VS instructions to pointers in the emitted code
     std::array<Xbyak::Label, MAX_PROGRAM_CODE_LENGTH> instruction_labels;
 
+    /// Label pointing to the end of the current LOOP block. Used by the BREAKC instruction to break
+    /// out of the loop.
+    boost::optional<Xbyak::Label> loop_break_label;
+
     /// Offsets in code where a return needs to be inserted
     std::vector<unsigned> return_offsets;
 

From a9b7720d98bf051dc79a7c3d34d6690d0adf418c Mon Sep 17 00:00:00 2001
From: Jan Beich <jbeich@FreeBSD.org>
Date: Sat, 2 Jun 2018 08:30:23 +0000
Subject: [PATCH 03/19] externals: don't try install cubeb files

Install the project...
/usr/local/bin/cmake -P cmake_install.cmake
-- Install configuration: "Release"
-- Installing: /prefix/share/man/man6/citra.6
CMake Error at externals/cubeb/cmake_install.cmake:44 (file):
  file INSTALL cannot find "/path/to/citra/include".
Call Stack (most recent call first):
  externals/cmake_install.cmake:46 (include)
  cmake_install.cmake:49 (include)

gmake: *** [Makefile:74: install] Error 1
---
 externals/CMakeLists.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
index cb7530f2d..016c445dd 100644
--- a/externals/CMakeLists.txt
+++ b/externals/CMakeLists.txt
@@ -81,5 +81,5 @@ endif()
 # Cubeb
 if(ENABLE_CUBEB)
     set(BUILD_TESTS OFF CACHE BOOL "")
-    add_subdirectory(cubeb)
+    add_subdirectory(cubeb EXCLUDE_FROM_ALL)
 endif()

From a4bed294fb870a4f7d89a4d90c030f09767ad0e7 Mon Sep 17 00:00:00 2001
From: MerryMage <MerryMage@users.noreply.github.com>
Date: Sun, 3 Jun 2018 20:54:32 +0100
Subject: [PATCH 04/19] dynarmic: Update to
 4b350a354a21339052c7fff88832c3f81f5624be

---
 externals/dynarmic | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/externals/dynarmic b/externals/dynarmic
index d1d470536..4b350a354 160000
--- a/externals/dynarmic
+++ b/externals/dynarmic
@@ -1 +1 @@
-Subproject commit d1d4705364031512cb89333aebc00b8d75a2f732
+Subproject commit 4b350a354a21339052c7fff88832c3f81f5624be

From b8c50071537d72e267bb3e7a8573971c6e946b88 Mon Sep 17 00:00:00 2001
From: MerryMage <MerryMage@users.noreply.github.com>
Date: Sun, 3 Jun 2018 21:06:57 +0100
Subject: [PATCH 05/19] arm_dyncom_interpreter: Clear exclusive memory state
 after SVC call

---
 src/core/arm/dyncom/arm_dyncom_interpreter.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
index b8c0cb34e..9548d0e16 100644
--- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
@@ -3866,6 +3866,8 @@ SWI_INST : {
             num_instrs >= cpu->NumInstrsToExecute ? 0 : cpu->NumInstrsToExecute - num_instrs;
         num_instrs = 0;
         Kernel::CallSVC(inst_cream->num & 0xFFFF);
+        // The kernel would call ERET to get here, which clears exclusive memory state.
+        cpu->UnsetExclusiveMemoryAddress();
     }
 
     cpu->Reg[15] += cpu->GetInstructionSize();

From 5ebd4668690c9e51ae80342d5e43bccac2339c1d Mon Sep 17 00:00:00 2001
From: zhupengfei <zhupengfei321@sina.cn>
Date: Sun, 20 May 2018 09:07:37 +0800
Subject: [PATCH 06/19] camera: Add camera flip config

---
 src/citra/config.cpp                          |   6 +
 src/citra/default_ini.h                       |   6 +
 src/citra_qt/camera/qt_camera_factory.cpp     |   6 +-
 src/citra_qt/camera/qt_camera_factory.h       |   4 +-
 src/citra_qt/camera/qt_multimedia_camera.cpp  |  14 +-
 src/citra_qt/camera/qt_multimedia_camera.h    |   6 +-
 src/citra_qt/camera/still_image_camera.cpp    |  16 +-
 src/citra_qt/camera/still_image_camera.h      |   6 +-
 src/citra_qt/configuration/config.cpp         |   8 +
 .../configuration/configure_camera.cpp        |  23 +-
 src/citra_qt/configuration/configure_camera.h |   1 +
 .../configuration/configure_camera.ui         | 572 ++++++++++--------
 src/core/frontend/camera/factory.cpp          |   9 +-
 src/core/frontend/camera/factory.h            |  15 +-
 src/core/hle/service/cam/cam.cpp              |   5 +-
 src/core/settings.h                           |   1 +
 16 files changed, 416 insertions(+), 282 deletions(-)

diff --git a/src/citra/config.cpp b/src/citra/config.cpp
index b4e3a2ce9..ce51b687b 100644
--- a/src/citra/config.cpp
+++ b/src/citra/config.cpp
@@ -155,14 +155,20 @@ void Config::ReadValues() {
         sdl2_config->Get("Camera", "camera_outer_right_name", "blank");
     Settings::values.camera_config[OuterRightCamera] =
         sdl2_config->Get("Camera", "camera_outer_right_config", "");
+    Settings::values.camera_flip[OuterRightCamera] =
+        sdl2_config->GetInteger("Camera", "camera_outer_right_flip", 0);
     Settings::values.camera_name[InnerCamera] =
         sdl2_config->Get("Camera", "camera_inner_name", "blank");
     Settings::values.camera_config[InnerCamera] =
         sdl2_config->Get("Camera", "camera_inner_config", "");
+    Settings::values.camera_flip[InnerCamera] =
+        sdl2_config->GetInteger("Camera", "camera_inner_flip", 0);
     Settings::values.camera_name[OuterLeftCamera] =
         sdl2_config->Get("Camera", "camera_outer_left_name", "blank");
     Settings::values.camera_config[OuterLeftCamera] =
         sdl2_config->Get("Camera", "camera_outer_left_config", "");
+    Settings::values.camera_flip[OuterLeftCamera] =
+        sdl2_config->GetInteger("Camera", "camera_outer_left_flip", 0);
 
     // Miscellaneous
     Settings::values.log_filter = sdl2_config->Get("Miscellaneous", "log_filter", "*:Info");
diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h
index 7179d6f94..4a17eb6ca 100644
--- a/src/citra/default_ini.h
+++ b/src/citra/default_ini.h
@@ -178,13 +178,19 @@ camera_outer_right_name =
 # A config string for the right outer camera. Its meaning is defined by the camera engine
 camera_outer_right_config =
 
+# The image flip to apply
+# 0: None (default), 1: Horizontal, 2: Vertical, 3: Reverse
+camera_outer_right_flip =
+
 # ... for the left outer camera
 camera_outer_left_name =
 camera_outer_left_config =
+camera_outer_left_flip =
 
 # ... for the inner camera
 camera_inner_name =
 camera_inner_config =
+camera_inner_flip =
 
 [Miscellaneous]
 # A filter which removes logs below a certain logging level.
diff --git a/src/citra_qt/camera/qt_camera_factory.cpp b/src/citra_qt/camera/qt_camera_factory.cpp
index fa78591ba..063a600df 100644
--- a/src/citra_qt/camera/qt_camera_factory.cpp
+++ b/src/citra_qt/camera/qt_camera_factory.cpp
@@ -7,9 +7,9 @@
 
 namespace Camera {
 
-std::unique_ptr<CameraInterface> QtCameraFactory::CreatePreview(const std::string& config,
-                                                                int width, int height) const {
-    std::unique_ptr<CameraInterface> camera = Create(config);
+std::unique_ptr<CameraInterface> QtCameraFactory::CreatePreview(
+    const std::string& config, int width, int height, const Service::CAM::Flip& flip) const {
+    std::unique_ptr<CameraInterface> camera = Create(config, flip);
 
     if (camera->IsPreviewAvailable()) {
         return camera;
diff --git a/src/citra_qt/camera/qt_camera_factory.h b/src/citra_qt/camera/qt_camera_factory.h
index 7efc21b58..9e590ca66 100644
--- a/src/citra_qt/camera/qt_camera_factory.h
+++ b/src/citra_qt/camera/qt_camera_factory.h
@@ -11,8 +11,8 @@ namespace Camera {
 
 // Base class for camera factories of citra_qt
 class QtCameraFactory : public CameraFactory {
-    std::unique_ptr<CameraInterface> CreatePreview(const std::string& config, int width,
-                                                   int height) const override;
+    std::unique_ptr<CameraInterface> CreatePreview(const std::string& config, int width, int height,
+                                                   const Service::CAM::Flip& flip) const override;
 };
 
 } // namespace Camera
diff --git a/src/citra_qt/camera/qt_multimedia_camera.cpp b/src/citra_qt/camera/qt_multimedia_camera.cpp
index 6c2668df6..5f2137835 100644
--- a/src/citra_qt/camera/qt_multimedia_camera.cpp
+++ b/src/citra_qt/camera/qt_multimedia_camera.cpp
@@ -46,7 +46,8 @@ bool QtCameraSurface::present(const QVideoFrame& frame) {
     return true;
 }
 
-QtMultimediaCamera::QtMultimediaCamera(const std::string& camera_name)
+QtMultimediaCamera::QtMultimediaCamera(const std::string& camera_name,
+                                       const Service::CAM::Flip& flip)
     : handler(QtMultimediaCameraHandler::GetHandler()) {
     if (handler->thread() == QThread::currentThread()) {
         handler->CreateCamera(camera_name);
@@ -54,6 +55,9 @@ QtMultimediaCamera::QtMultimediaCamera(const std::string& camera_name)
         QMetaObject::invokeMethod(handler.get(), "CreateCamera", Qt::BlockingQueuedConnection,
                                   Q_ARG(const std::string&, camera_name));
     }
+    using namespace Service::CAM;
+    flip_horizontal = basic_flip_horizontal = (flip == Flip::Horizontal) || (flip == Flip::Reverse);
+    flip_vertical = basic_flip_vertical = (flip == Flip::Vertical) || (flip == Flip::Reverse);
 }
 
 QtMultimediaCamera::~QtMultimediaCamera() {
@@ -107,8 +111,8 @@ void QtMultimediaCamera::SetResolution(const Service::CAM::Resolution& resolutio
 
 void QtMultimediaCamera::SetFlip(Service::CAM::Flip flip) {
     using namespace Service::CAM;
-    flip_horizontal = (flip == Flip::Horizontal) || (flip == Flip::Reverse);
-    flip_vertical = (flip == Flip::Vertical) || (flip == Flip::Reverse);
+    flip_horizontal = basic_flip_horizontal ^ (flip == Flip::Horizontal || flip == Flip::Reverse);
+    flip_vertical = basic_flip_vertical ^ (flip == Flip::Vertical || flip == Flip::Reverse);
 }
 
 void QtMultimediaCamera::SetEffect(Service::CAM::Effect effect) {
@@ -128,8 +132,8 @@ bool QtMultimediaCamera::IsPreviewAvailable() {
 }
 
 std::unique_ptr<CameraInterface> QtMultimediaCameraFactory::Create(
-    const std::string& config) const {
-    return std::make_unique<QtMultimediaCamera>(config);
+    const std::string& config, const Service::CAM::Flip& flip) const {
+    return std::make_unique<QtMultimediaCamera>(config, flip);
 }
 
 std::array<std::shared_ptr<QtMultimediaCameraHandler>, 3> QtMultimediaCameraHandler::handlers;
diff --git a/src/citra_qt/camera/qt_multimedia_camera.h b/src/citra_qt/camera/qt_multimedia_camera.h
index 103aff8a0..580834275 100644
--- a/src/citra_qt/camera/qt_multimedia_camera.h
+++ b/src/citra_qt/camera/qt_multimedia_camera.h
@@ -38,7 +38,7 @@ class QtMultimediaCameraHandler;
 /// This class is only an interface. It just calls QtMultimediaCameraHandler.
 class QtMultimediaCamera final : public CameraInterface {
 public:
-    QtMultimediaCamera(const std::string& camera_name);
+    QtMultimediaCamera(const std::string& camera_name, const Service::CAM::Flip& flip);
     ~QtMultimediaCamera();
     void StartCapture() override;
     void StopCapture() override;
@@ -55,11 +55,13 @@ private:
     int width, height;
     bool output_rgb;
     bool flip_horizontal, flip_vertical;
+    bool basic_flip_horizontal, basic_flip_vertical;
 };
 
 class QtMultimediaCameraFactory final : public QtCameraFactory {
 public:
-    std::unique_ptr<CameraInterface> Create(const std::string& config) const override;
+    std::unique_ptr<CameraInterface> Create(const std::string& config,
+                                            const Service::CAM::Flip& flip) const override;
 };
 
 class QtMultimediaCameraHandler final : public QObject {
diff --git a/src/citra_qt/camera/still_image_camera.cpp b/src/citra_qt/camera/still_image_camera.cpp
index ab0d18308..7e54fad3e 100644
--- a/src/citra_qt/camera/still_image_camera.cpp
+++ b/src/citra_qt/camera/still_image_camera.cpp
@@ -9,7 +9,12 @@
 
 namespace Camera {
 
-StillImageCamera::StillImageCamera(QImage image_) : image(std::move(image_)) {}
+StillImageCamera::StillImageCamera(QImage image_, const Service::CAM::Flip& flip)
+    : image(std::move(image_)) {
+    using namespace Service::CAM;
+    flip_horizontal = basic_flip_horizontal = (flip == Flip::Horizontal) || (flip == Flip::Reverse);
+    flip_vertical = basic_flip_vertical = (flip == Flip::Vertical) || (flip == Flip::Reverse);
+}
 
 void StillImageCamera::StartCapture() {}
 
@@ -26,8 +31,8 @@ void StillImageCamera::SetResolution(const Service::CAM::Resolution& resolution)
 
 void StillImageCamera::SetFlip(Service::CAM::Flip flip) {
     using namespace Service::CAM;
-    flip_horizontal = (flip == Flip::Horizontal) || (flip == Flip::Reverse);
-    flip_vertical = (flip == Flip::Vertical) || (flip == Flip::Reverse);
+    flip_horizontal = basic_flip_horizontal ^ (flip == Flip::Horizontal || flip == Flip::Reverse);
+    flip_vertical = basic_flip_vertical ^ (flip == Flip::Vertical || flip == Flip::Reverse);
 }
 
 void StillImageCamera::SetEffect(Service::CAM::Effect effect) {
@@ -58,7 +63,8 @@ const std::string StillImageCameraFactory::getFilePath() {
         .toStdString();
 }
 
-std::unique_ptr<CameraInterface> StillImageCameraFactory::Create(const std::string& config) const {
+std::unique_ptr<CameraInterface> StillImageCameraFactory::Create(
+    const std::string& config, const Service::CAM::Flip& flip) const {
     std::string real_config = config;
     if (config.empty()) {
         real_config = getFilePath();
@@ -67,7 +73,7 @@ std::unique_ptr<CameraInterface> StillImageCameraFactory::Create(const std::stri
     if (image.isNull()) {
         NGLOG_ERROR(Service_CAM, "Couldn't load image \"{}\"", real_config.c_str());
     }
-    return std::make_unique<StillImageCamera>(image);
+    return std::make_unique<StillImageCamera>(image, flip);
 }
 
 } // namespace Camera
diff --git a/src/citra_qt/camera/still_image_camera.h b/src/citra_qt/camera/still_image_camera.h
index c54d367e8..e9016981b 100644
--- a/src/citra_qt/camera/still_image_camera.h
+++ b/src/citra_qt/camera/still_image_camera.h
@@ -14,7 +14,7 @@ namespace Camera {
 
 class StillImageCamera final : public CameraInterface {
 public:
-    StillImageCamera(QImage image);
+    StillImageCamera(QImage image, const Service::CAM::Flip& flip);
     void StartCapture() override;
     void StopCapture() override;
     void SetResolution(const Service::CAM::Resolution&) override;
@@ -30,11 +30,13 @@ private:
     int width, height;
     bool output_rgb;
     bool flip_horizontal, flip_vertical;
+    bool basic_flip_horizontal, basic_flip_vertical;
 };
 
 class StillImageCameraFactory final : public QtCameraFactory {
 public:
-    std::unique_ptr<CameraInterface> Create(const std::string& config) const override;
+    std::unique_ptr<CameraInterface> Create(const std::string& config,
+                                            const Service::CAM::Flip& flip) const override;
 
 private:
     static const std::string getFilePath();
diff --git a/src/citra_qt/configuration/config.cpp b/src/citra_qt/configuration/config.cpp
index bdb296659..e5d252c81 100644
--- a/src/citra_qt/configuration/config.cpp
+++ b/src/citra_qt/configuration/config.cpp
@@ -128,14 +128,19 @@ void Config::ReadValues() {
         qt_config->value("camera_outer_right_name", "blank").toString().toStdString();
     Settings::values.camera_config[OuterRightCamera] =
         qt_config->value("camera_outer_right_config", "").toString().toStdString();
+    Settings::values.camera_flip[OuterRightCamera] =
+        qt_config->value("camera_outer_right_flip", "0").toInt();
     Settings::values.camera_name[InnerCamera] =
         qt_config->value("camera_inner_name", "blank").toString().toStdString();
     Settings::values.camera_config[InnerCamera] =
         qt_config->value("camera_inner_config", "").toString().toStdString();
+    Settings::values.camera_flip[InnerCamera] = qt_config->value("camera_inner_flip", "").toInt();
     Settings::values.camera_name[OuterLeftCamera] =
         qt_config->value("camera_outer_left_name", "blank").toString().toStdString();
     Settings::values.camera_config[OuterLeftCamera] =
         qt_config->value("camera_outer_left_config", "").toString().toStdString();
+    Settings::values.camera_flip[OuterLeftCamera] =
+        qt_config->value("camera_outer_left_flip", "").toInt();
     qt_config->endGroup();
 
     qt_config->beginGroup("Data Storage");
@@ -317,14 +322,17 @@ void Config::SaveValues() {
                         QString::fromStdString(Settings::values.camera_name[OuterRightCamera]));
     qt_config->setValue("camera_outer_right_config",
                         QString::fromStdString(Settings::values.camera_config[OuterRightCamera]));
+    qt_config->setValue("camera_outer_right_flip", Settings::values.camera_flip[OuterRightCamera]);
     qt_config->setValue("camera_inner_name",
                         QString::fromStdString(Settings::values.camera_name[InnerCamera]));
     qt_config->setValue("camera_inner_config",
                         QString::fromStdString(Settings::values.camera_config[InnerCamera]));
+    qt_config->setValue("camera_inner_flip", Settings::values.camera_flip[InnerCamera]);
     qt_config->setValue("camera_outer_left_name",
                         QString::fromStdString(Settings::values.camera_name[OuterLeftCamera]));
     qt_config->setValue("camera_outer_left_config",
                         QString::fromStdString(Settings::values.camera_config[OuterLeftCamera]));
+    qt_config->setValue("camera_outer_left_flip", Settings::values.camera_flip[OuterLeftCamera]);
     qt_config->endGroup();
 
     qt_config->beginGroup("Data Storage");
diff --git a/src/citra_qt/configuration/configure_camera.cpp b/src/citra_qt/configuration/configure_camera.cpp
index ca6db4623..e9d964b3a 100644
--- a/src/citra_qt/configuration/configure_camera.cpp
+++ b/src/citra_qt/configuration/configure_camera.cpp
@@ -27,14 +27,7 @@ ConfigureCamera::ConfigureCamera(QWidget* parent)
     // Load settings
     camera_name = Settings::values.camera_name;
     camera_config = Settings::values.camera_config;
-    for (auto&& item : camera_name) {
-        if (item == "opencv") {
-            QMessageBox::critical(this, tr("Error"),
-                                  tr("Sorry, Citra has removed support for OpenCV cameras.\n\nYour "
-                                     "existing OpenCV cameras have been replaced with Blank."));
-            item = "blank";
-        }
-    }
+    camera_flip = Settings::values.camera_flip;
     QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
     for (const QCameraInfo& cameraInfo : cameras) {
         ui->system_camera->addItem(cameraInfo.deviceName());
@@ -98,6 +91,8 @@ void ConfigureCamera::connectEvents() {
     connect(ui->system_camera,
             static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
             [=] { stopPreviewing(); });
+    connect(ui->camera_flip, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
+            this, [=] { stopPreviewing(); });
 }
 
 void ConfigureCamera::updateCameraMode() {
@@ -148,6 +143,8 @@ void ConfigureCamera::updateImageSourceUI() {
     }
     ui->system_camera_label->setHidden(image_source != 2);
     ui->system_camera->setHidden(image_source != 2);
+    ui->camera_flip_label->setHidden(image_source == 0);
+    ui->camera_flip->setHidden(image_source == 0);
 }
 
 void ConfigureCamera::recordConfig() {
@@ -166,10 +163,12 @@ void ConfigureCamera::recordConfig() {
     if (current_selected == CameraPosition::RearBoth) {
         camera_name[0] = camera_name[2] = implementation;
         camera_config[0] = camera_config[2] = config;
+        camera_flip[0] = camera_flip[2] = ui->camera_flip->currentIndex();
     } else if (current_selected != CameraPosition::Null) {
         int index = static_cast<int>(current_selected);
         camera_name[index] = implementation;
         camera_config[index] = config;
+        camera_flip[index] = ui->camera_flip->currentIndex();
     }
     current_selected = getCameraSelection();
 }
@@ -187,9 +186,9 @@ void ConfigureCamera::startPreviewing() {
     ui->preview_box->setToolTip(tr("Resolution: ") + QString::number(preview_width) + "*" +
                                 QString::number(preview_height));
     // Load previewing camera
-    previewing_camera =
-        Camera::CreateCameraPreview(camera_name[camera_selection], camera_config[camera_selection],
-                                    preview_width, preview_height);
+    previewing_camera = Camera::CreateCameraPreview(
+        camera_name[camera_selection], camera_config[camera_selection], preview_width,
+        preview_height, static_cast<Service::CAM::Flip>(camera_flip[camera_selection]));
     if (!previewing_camera) {
         stopPreviewing();
         return;
@@ -262,6 +261,7 @@ void ConfigureCamera::setConfiguration() {
     } else {
         ui->camera_file->setText(QString::fromStdString(camera_config[index]));
     }
+    ui->camera_flip->setCurrentIndex(camera_flip[index]);
     updateImageSourceUI();
 }
 
@@ -288,6 +288,7 @@ void ConfigureCamera::applyConfiguration() {
     stopPreviewing();
     Settings::values.camera_name = camera_name;
     Settings::values.camera_config = camera_config;
+    Settings::values.camera_flip = camera_flip;
     Settings::Apply();
 }
 
diff --git a/src/citra_qt/configuration/configure_camera.h b/src/citra_qt/configuration/configure_camera.h
index 5621de7ef..0aa55996e 100644
--- a/src/citra_qt/configuration/configure_camera.h
+++ b/src/citra_qt/configuration/configure_camera.h
@@ -47,6 +47,7 @@ private:
     std::unique_ptr<Ui::ConfigureCamera> ui;
     std::array<std::string, 3> camera_name;
     std::array<std::string, 3> camera_config;
+    std::array<int, 3> camera_flip;
     int timer_id = 0;
     int preview_width = 0;
     int preview_height = 0;
diff --git a/src/citra_qt/configuration/configure_camera.ui b/src/citra_qt/configuration/configure_camera.ui
index cd4d2e108..46c56b266 100644
--- a/src/citra_qt/configuration/configure_camera.ui
+++ b/src/citra_qt/configuration/configure_camera.ui
@@ -1,257 +1,347 @@
 <?xml version="1.0" encoding="UTF-8"?>
-
 <ui version="4.0">
-  <class>ConfigureCamera</class>
-  <widget class="QWidget" name="ConfigureCamera">
-    <layout class="QVBoxLayout" name="verticalLayout">
+ <class>ConfigureCamera</class>
+ <widget class="QWidget" name="ConfigureCamera">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QGroupBox" name="groupBox">
+     <property name="title">
+      <string>Camera</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_2">
       <item>
-        <widget class="QGroupBox" name="groupBox">
-          <property name="title">
-            <string>Camera</string>
+       <layout class="QHBoxLayout" name="horizontalLayout">
+        <item>
+         <widget class="QLabel" name="camera_selection_label">
+          <property name="toolTip">
+           <string>Select the camera to configure</string>
           </property>
-          <layout class="QVBoxLayout" name="verticalLayout_2">
-            <item>
-              <layout class="QHBoxLayout" name="horizontalLayout">
-                <item>
-                  <widget class="QLabel" name="camera_selection_label">
-                    <property name="toolTip">
-                      <string>Select the camera to configure</string>
-                    </property>
-                    <property name="text">
-                      <string>Camera to configure:</string>
-                    </property>
-                  </widget>
-                </item>
-                <item>
-                  <widget class="QComboBox" name="camera_selection">
-                    <property name="toolTip">
-                      <string>Select the camera to configure</string>
-                    </property>
-                    <item>
-                      <property name="text">
-                        <string>Front</string>
-                      </property>
-                    </item>
-                    <item>
-                      <property name="text">
-                        <string>Rear</string>
-                      </property>
-                    </item>
-                  </widget>
-                </item>
-              </layout>
-            </item>
-            <item>
-              <layout class="QHBoxLayout" name="horizontalLayout_2">
-                <item>
-                  <widget class="QLabel" name="camera_mode_label">
-                    <property name="toolTip">
-                      <string>Select the camera mode (single or double)</string>
-                    </property>
-                    <property name="text">
-                      <string>Camera mode:</string>
-                    </property>
-                  </widget>
-                </item>
-                <item>
-                  <widget class="QComboBox" name="camera_mode">
-                    <property name="toolTip">
-                      <string>Select the camera mode (single or double)</string>
-                    </property>
-                    <item>
-                      <property name="text">
-                        <string>Single (2D)</string>
-                      </property>
-                    </item>
-                    <item>
-                      <property name="text">
-                        <string>Double (3D)</string>
-                      </property>
-                    </item>
-                  </widget>
-                </item>
-              </layout>
-            </item>
-            <item>
-              <layout class="QHBoxLayout" name="horizontalLayout_3">
-                <item>
-                  <widget class="QLabel" name="camera_position_label">
-                    <property name="toolTip">
-                      <string>Select the position of camera to configure</string>
-                    </property>
-                    <property name="text">
-                      <string>Camera position:</string>
-                    </property>
-                  </widget>
-                </item>
-                <item>
-                  <widget class="QComboBox" name="camera_position">
-                    <property name="toolTip">
-                      <string>Select the position of camera to configure</string>
-                    </property>
-                    <item>
-                      <property name="text">
-                        <string>Left</string>
-                      </property>
-                    </item>
-                    <item>
-                      <property name="text">
-                        <string>Right</string>
-                      </property>
-                    </item>
-                  </widget>
-                </item>
-              </layout>
-            </item>
-          </layout>
-        </widget>
+          <property name="text">
+           <string>Camera to configure:</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QComboBox" name="camera_selection">
+          <property name="toolTip">
+           <string>Select the camera to configure</string>
+          </property>
+          <item>
+           <property name="text">
+            <string>Front</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>Rear</string>
+           </property>
+          </item>
+         </widget>
+        </item>
+       </layout>
       </item>
       <item>
-        <widget class="QGroupBox" name="configurationBox">
-          <property name="title">
-            <string>Configuration</string>
+       <layout class="QHBoxLayout" name="horizontalLayout_2">
+        <item>
+         <widget class="QLabel" name="camera_mode_label">
+          <property name="toolTip">
+           <string>Select the camera mode (single or double)</string>
           </property>
-          <layout class="QVBoxLayout" name="verticalLayout_configuration">
-            <item>
-              <layout class="QHBoxLayout" name="horizontalLayout_4">
-                <item>
-                  <widget class="QLabel" name="image_source_label">
-                    <property name="toolTip">
-                      <string>Select where the image of the emulated camera comes from. It may be an image or a real camera.</string>
-                    </property>
-                    <property name="text">
-                      <string>Camera Image Source:</string>
-                    </property>
-                  </widget>
-                </item>
-                <item>
-                  <widget class="QComboBox" name="image_source">
-                    <property name="toolTip">
-                      <string>Select where the image of the emulated camera come from. It may be an image or a real camera.</string>
-                    </property>
-                    <item>
-                      <property name="text">
-                        <string>Blank (blank)</string>
-                      </property>
-                    </item>
-                    <item>
-                      <property name="text">
-                        <string>Still Image (image)</string>
-                      </property>
-                    </item>
-                    <item>
-                      <property name="text">
-                        <string>System Camera (qt)</string>
-                      </property>
-                    </item>
-                  </widget>
-                </item>
-              </layout>
-            </item>
-            <item>
-              <layout class="QHBoxLayout" name="horizontalLayout_6">
-                <item>
-                  <widget class="QLabel" name="camera_file_label">
-                    <property name="frameShape">
-                      <enum>QFrame::NoFrame</enum>
-                    </property>
-                    <property name="text">
-                      <string>File:</string>
-                    </property>
-                  </widget>
-                </item>
-                <item>
-                  <widget class="QLineEdit" name="camera_file"/>
-                </item>
-                <item>
-                  <widget class="QToolButton" name="toolButton">
-                    <property name="text">
-                      <string>...</string>
-                    </property>
-                  </widget>
-                </item>
-              </layout>
-            </item>
-            <item>
-              <layout class="QHBoxLayout" name="horizontalLayout_7">
-                <item>
-                  <widget class="QLabel" name="system_camera_label">
-                    <property name="frameShape">
-                      <enum>QFrame::NoFrame</enum>
-                    </property>
-                    <property name="text">
-                      <string>Camera:</string>
-                    </property>
-                  </widget>
-                </item>
-                <item>
-                  <widget class="QComboBox" name="system_camera">
-                    <item>
-                      <property name="text">
-                        <string>&lt;Default&gt;</string>
-                      </property>
-                    </item>
-                  </widget>
-                </item>
-              </layout>
-            </item>
-            <item>
-              <widget class="QCheckBox" name="prompt_before_load">
-                <property name="text">
-                  <string>Prompt before load</string>
-                </property>
-              </widget>
-            </item>
-          </layout>
-        </widget>
+          <property name="text">
+           <string>Camera mode:</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QComboBox" name="camera_mode">
+          <property name="toolTip">
+           <string>Select the camera mode (single or double)</string>
+          </property>
+          <item>
+           <property name="text">
+            <string>Single (2D)</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>Double (3D)</string>
+           </property>
+          </item>
+         </widget>
+        </item>
+       </layout>
       </item>
       <item>
-        <widget class="QGroupBox" name="previewBox">
-          <property name="title">
-            <string>Preview</string>
+       <layout class="QHBoxLayout" name="horizontalLayout_3">
+        <item>
+         <widget class="QLabel" name="camera_position_label">
+          <property name="toolTip">
+           <string>Select the position of camera to configure</string>
           </property>
-          <layout class="QVBoxLayout" name="verticalLayout_3">
-            <item>
-              <widget class="QLabel" name="preview_box">
-                <property name="baseSize">
-                  <size>
-                    <width>512</width>
-                    <height>384</height>
-                  </size>
-                </property>
-                <property name="toolTip">
-                  <string>Resolution: 512*384</string>
-                </property>
-                <property name="text">
-                  <string/>
-                </property>
-              </widget>
-            </item>
-            <item>
-              <widget class="QPushButton" name="preview_button">
-                <property name="text">
-                  <string>Click to preview</string>
-                </property>
-              </widget>
-            </item>
-          </layout>
-        </widget>
+          <property name="text">
+           <string>Camera position:</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QComboBox" name="camera_position">
+          <property name="toolTip">
+           <string>Select the position of camera to configure</string>
+          </property>
+          <item>
+           <property name="text">
+            <string>Left</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>Right</string>
+           </property>
+          </item>
+         </widget>
+        </item>
+       </layout>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="configurationBox">
+     <property name="title">
+      <string>Configuration</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_configuration">
+      <item>
+       <layout class="QHBoxLayout" name="horizontalLayout_4">
+        <item>
+         <widget class="QLabel" name="image_source_label">
+          <property name="toolTip">
+           <string>Select where the image of the emulated camera comes from. It may be an image or a real camera.</string>
+          </property>
+          <property name="text">
+           <string>Camera Image Source:</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QComboBox" name="image_source">
+          <property name="toolTip">
+           <string>Select where the image of the emulated camera comes from. It may be an image or a real camera.</string>
+          </property>
+          <item>
+           <property name="text">
+            <string>Blank (blank)</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>Still Image (image)</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>System Camera (qt)</string>
+           </property>
+          </item>
+         </widget>
+        </item>
+       </layout>
       </item>
       <item>
-        <spacer>
-          <property name="orientation">
-            <enum>Qt::Vertical</enum>
+       <layout class="QHBoxLayout" name="horizontalLayout_6">
+        <item>
+         <widget class="QLabel" name="camera_file_label">
+          <property name="frameShape">
+           <enum>QFrame::NoFrame</enum>
           </property>
-          <property name="sizeHint" stdset="0">
-            <size>
-              <width>20</width>
-              <height>40</height>
-            </size>
+          <property name="text">
+           <string>File:</string>
           </property>
-        </spacer>
+         </widget>
+        </item>
+        <item>
+         <widget class="QLineEdit" name="camera_file"/>
+        </item>
+        <item>
+         <widget class="QToolButton" name="toolButton">
+          <property name="text">
+           <string>...</string>
+          </property>
+         </widget>
+        </item>
+       </layout>
       </item>
-    </layout>
-  </widget>
-  <resources/>
-  <connections/>
+      <item>
+       <layout class="QHBoxLayout" name="horizontalLayout_7">
+        <item>
+         <widget class="QLabel" name="system_camera_label">
+          <property name="frameShape">
+           <enum>QFrame::NoFrame</enum>
+          </property>
+          <property name="toolTip">
+           <string>Select the system camera to use</string>
+          </property>
+          <property name="text">
+           <string>Camera:</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QComboBox" name="system_camera">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="maximumSize">
+           <size>
+            <width>250</width>
+            <height>16777215</height>
+           </size>
+          </property>
+          <property name="toolTip">
+           <string>Select the system camera to use</string>
+          </property>
+          <item>
+           <property name="text">
+            <string>&lt;Default&gt;</string>
+           </property>
+          </item>
+         </widget>
+        </item>
+       </layout>
+      </item>
+      <item>
+       <layout class="QHBoxLayout" name="horizontalLayout_8">
+        <item>
+         <widget class="QLabel" name="camera_flip_label">
+          <property name="frameShape">
+           <enum>QFrame::NoFrame</enum>
+          </property>
+          <property name="toolTip">
+           <string>Select the image flip to apply</string>
+          </property>
+          <property name="text">
+           <string>Flip:</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QComboBox" name="camera_flip">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="maximumSize">
+           <size>
+            <width>800</width>
+            <height>16777215</height>
+           </size>
+          </property>
+          <property name="toolTip">
+           <string>Select the image flip to apply</string>
+          </property>
+          <item>
+           <property name="text">
+            <string>None</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>Horizontal</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>Vertical</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>Reverse</string>
+           </property>
+          </item>
+         </widget>
+        </item>
+       </layout>
+      </item>
+      <item>
+       <widget class="QCheckBox" name="prompt_before_load">
+        <property name="toolTip">
+         <string>Select an image file every time before the camera is loaded</string>
+        </property>
+        <property name="text">
+         <string>Prompt before load</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="previewBox">
+     <property name="title">
+      <string>Preview</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_3">
+      <item>
+       <widget class="QLabel" name="preview_box">
+        <property name="baseSize">
+         <size>
+          <width>512</width>
+          <height>384</height>
+         </size>
+        </property>
+        <property name="toolTip">
+         <string>Resolution: 512*384</string>
+        </property>
+        <property name="text">
+         <string/>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QPushButton" name="preview_button">
+        <property name="text">
+         <string>Click to preview</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <spacer>
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
 </ui>
diff --git a/src/core/frontend/camera/factory.cpp b/src/core/frontend/camera/factory.cpp
index f0434cdad..2a871196c 100644
--- a/src/core/frontend/camera/factory.cpp
+++ b/src/core/frontend/camera/factory.cpp
@@ -17,10 +17,11 @@ void RegisterFactory(const std::string& name, std::unique_ptr<CameraFactory> fac
     factories[name] = std::move(factory);
 }
 
-std::unique_ptr<CameraInterface> CreateCamera(const std::string& name, const std::string& config) {
+std::unique_ptr<CameraInterface> CreateCamera(const std::string& name, const std::string& config,
+                                              const Service::CAM::Flip& flip) {
     auto pair = factories.find(name);
     if (pair != factories.end()) {
-        return pair->second->Create(config);
+        return pair->second->Create(config, flip);
     }
 
     if (name != "blank") {
@@ -31,10 +32,10 @@ std::unique_ptr<CameraInterface> CreateCamera(const std::string& name, const std
 
 std::unique_ptr<CameraInterface> CreateCameraPreview(const std::string& name,
                                                      const std::string& config, int width,
-                                                     int height) {
+                                                     int height, const Service::CAM::Flip& flip) {
     auto pair = factories.find(name);
     if (pair != factories.end()) {
-        return pair->second->CreatePreview(config, width, height);
+        return pair->second->CreatePreview(config, width, height, flip);
     }
 
     if (name != "blank") {
diff --git a/src/core/frontend/camera/factory.h b/src/core/frontend/camera/factory.h
index 840be7022..2c4ab1479 100644
--- a/src/core/frontend/camera/factory.h
+++ b/src/core/frontend/camera/factory.h
@@ -18,22 +18,26 @@ public:
      * Creates a camera object based on the configuration string.
      * @param config Configuration string to create the camera. The implementation can decide the
      *               meaning of this string.
+     * @param flip The image flip to apply
      * @returns a unique_ptr to the created camera object.
      */
-    virtual std::unique_ptr<CameraInterface> Create(const std::string& config) const = 0;
+    virtual std::unique_ptr<CameraInterface> Create(const std::string& config,
+                                                    const Service::CAM::Flip& flip) const = 0;
 
     /**
      * Creates a camera object for preview based on the configuration string.
      * @param config Configuration string to create the camera. The implementation can decide the
      *               meaning of this string.
+     * @param flip The image flip to apply
      * @returns a unique_ptr to the created camera object.
      * Note: The default implementation for this is to call Create(). Derived classes may have other
      *       Implementations. For example, A dialog may be used instead of LOG_ERROR when error
      * occurs.
      */
     virtual std::unique_ptr<CameraInterface> CreatePreview(const std::string& config, int width,
-                                                           int height) const {
-        return Create(config);
+                                                           int height,
+                                                           const Service::CAM::Flip& flip) const {
+        return Create(config, flip);
     }
 };
 
@@ -50,7 +54,8 @@ void RegisterFactory(const std::string& name, std::unique_ptr<CameraFactory> fac
  * @param config Configuration string to create the camera. The meaning of this string is
  *     defined by the factory.
  */
-std::unique_ptr<CameraInterface> CreateCamera(const std::string& name, const std::string& config);
+std::unique_ptr<CameraInterface> CreateCamera(const std::string& name, const std::string& config,
+                                              const Service::CAM::Flip& flip);
 
 /**
  * Creates a camera from the factory for previewing.
@@ -60,6 +65,6 @@ std::unique_ptr<CameraInterface> CreateCamera(const std::string& name, const std
  */
 std::unique_ptr<CameraInterface> CreateCameraPreview(const std::string& name,
                                                      const std::string& config, int width,
-                                                     int height);
+                                                     int height, const Service::CAM::Flip& flip);
 
 } // namespace Camera
diff --git a/src/core/hle/service/cam/cam.cpp b/src/core/hle/service/cam/cam.cpp
index 3328dcf8e..78cdb23e8 100644
--- a/src/core/hle/service/cam/cam.cpp
+++ b/src/core/hle/service/cam/cam.cpp
@@ -1041,8 +1041,9 @@ void Module::ReloadCameraDevices() {
 }
 
 void Module::LoadCameraImplementation(CameraConfig& camera, int camera_id) {
-    camera.impl = Camera::CreateCamera(Settings::values.camera_name[camera_id],
-                                       Settings::values.camera_config[camera_id]);
+    camera.impl = Camera::CreateCamera(
+        Settings::values.camera_name[camera_id], Settings::values.camera_config[camera_id],
+        static_cast<Service::CAM::Flip>(Settings::values.camera_flip[camera_id]));
     camera.impl->SetFlip(camera.contexts[0].flip);
     camera.impl->SetEffect(camera.contexts[0].effect);
     camera.impl->SetFormat(camera.contexts[0].format);
diff --git a/src/core/settings.h b/src/core/settings.h
index b57a1cbed..5ce4811af 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -140,6 +140,7 @@ struct Values {
     // Camera
     std::array<std::string, Service::CAM::NumCameras> camera_name;
     std::array<std::string, Service::CAM::NumCameras> camera_config;
+    std::array<int, Service::CAM::NumCameras> camera_flip;
 
     // Debugging
     bool use_gdbstub;

From 6e410dcef55d55a40305baa574ace61d5f7fe86b Mon Sep 17 00:00:00 2001
From: zhupengfei <zhupengfei321@sina.cn>
Date: Sat, 26 May 2018 11:26:58 +0800
Subject: [PATCH 07/19] camera: refactor (add qt_camera_base)

---
 src/citra_qt/CMakeLists.txt                  |  4 +-
 src/citra_qt/camera/qt_camera_base.cpp       | 57 ++++++++++++++++++++
 src/citra_qt/camera/qt_camera_base.h         | 36 +++++++++++++
 src/citra_qt/camera/qt_camera_factory.cpp    | 24 ---------
 src/citra_qt/camera/qt_camera_factory.h      | 18 -------
 src/citra_qt/camera/qt_multimedia_camera.cpp | 31 ++---------
 src/citra_qt/camera/qt_multimedia_camera.h   | 14 ++---
 src/citra_qt/camera/still_image_camera.cpp   | 32 ++---------
 src/citra_qt/camera/still_image_camera.h     | 14 ++---
 9 files changed, 107 insertions(+), 123 deletions(-)
 create mode 100644 src/citra_qt/camera/qt_camera_base.cpp
 create mode 100644 src/citra_qt/camera/qt_camera_base.h
 delete mode 100644 src/citra_qt/camera/qt_camera_factory.cpp
 delete mode 100644 src/citra_qt/camera/qt_camera_factory.h

diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt
index 4e0fcdbeb..7b0d0eaac 100644
--- a/src/citra_qt/CMakeLists.txt
+++ b/src/citra_qt/CMakeLists.txt
@@ -13,8 +13,8 @@ add_executable(citra-qt
     camera/camera_util.h
     camera/still_image_camera.cpp
     camera/still_image_camera.h
-    camera/qt_camera_factory.cpp
-    camera/qt_camera_factory.h
+    camera/qt_camera_base.cpp
+    camera/qt_camera_base.h
     camera/qt_multimedia_camera.cpp
     camera/qt_multimedia_camera.h
     citra-qt.rc
diff --git a/src/citra_qt/camera/qt_camera_base.cpp b/src/citra_qt/camera/qt_camera_base.cpp
new file mode 100644
index 000000000..65bf2361c
--- /dev/null
+++ b/src/citra_qt/camera/qt_camera_base.cpp
@@ -0,0 +1,57 @@
+// Copyright 2018 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <QMessageBox>
+#include "citra_qt/camera/camera_util.h"
+#include "citra_qt/camera/qt_camera_base.h"
+
+namespace Camera {
+
+QtCameraInterface::QtCameraInterface(const Service::CAM::Flip& flip) {
+    using namespace Service::CAM;
+    flip_horizontal = basic_flip_horizontal = (flip == Flip::Horizontal) || (flip == Flip::Reverse);
+    flip_vertical = basic_flip_vertical = (flip == Flip::Vertical) || (flip == Flip::Reverse);
+}
+
+void QtCameraInterface::SetFormat(Service::CAM::OutputFormat output_format) {
+    output_rgb = output_format == Service::CAM::OutputFormat::RGB565;
+}
+
+void QtCameraInterface::SetResolution(const Service::CAM::Resolution& resolution) {
+    width = resolution.width;
+    height = resolution.height;
+}
+
+void QtCameraInterface::SetFlip(Service::CAM::Flip flip) {
+    using namespace Service::CAM;
+    flip_horizontal = basic_flip_horizontal ^ (flip == Flip::Horizontal || flip == Flip::Reverse);
+    flip_vertical = basic_flip_vertical ^ (flip == Flip::Vertical || flip == Flip::Reverse);
+}
+
+void QtCameraInterface::SetEffect(Service::CAM::Effect effect) {
+    if (effect != Service::CAM::Effect::None) {
+        NGLOG_ERROR(Service_CAM, "Unimplemented effect {}", static_cast<int>(effect));
+    }
+}
+
+std::vector<u16> QtCameraInterface::ReceiveFrame() {
+    return CameraUtil::ProcessImage(QtReceiveFrame(), width, height, output_rgb, flip_horizontal,
+                                    flip_vertical);
+}
+
+std::unique_ptr<CameraInterface> QtCameraFactory::CreatePreview(
+    const std::string& config, int width, int height, const Service::CAM::Flip& flip) const {
+    std::unique_ptr<CameraInterface> camera = Create(config, flip);
+
+    if (camera->IsPreviewAvailable()) {
+        return camera;
+    }
+    QMessageBox::critical(
+        nullptr, QObject::tr("Error"),
+        (config.empty() ? QObject::tr("Couldn't load the camera")
+                        : QObject::tr("Couldn't load %1").arg(QString::fromStdString(config))));
+    return nullptr;
+}
+
+} // namespace Camera
diff --git a/src/citra_qt/camera/qt_camera_base.h b/src/citra_qt/camera/qt_camera_base.h
new file mode 100644
index 000000000..e66c3bb46
--- /dev/null
+++ b/src/citra_qt/camera/qt_camera_base.h
@@ -0,0 +1,36 @@
+// Copyright 2018 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <string>
+#include "core/frontend/camera/factory.h"
+
+namespace Camera {
+
+// Base class for camera interfaces of citra_qt
+class QtCameraInterface : public CameraInterface {
+public:
+    QtCameraInterface(const Service::CAM::Flip& flip);
+    void SetResolution(const Service::CAM::Resolution&) override;
+    void SetFlip(Service::CAM::Flip) override;
+    void SetEffect(Service::CAM::Effect) override;
+    void SetFormat(Service::CAM::OutputFormat) override;
+    std::vector<u16> ReceiveFrame() override;
+    virtual QImage QtReceiveFrame() = 0;
+
+private:
+    int width, height;
+    bool output_rgb;
+    bool flip_horizontal, flip_vertical;
+    bool basic_flip_horizontal, basic_flip_vertical;
+};
+
+// Base class for camera factories of citra_qt
+class QtCameraFactory : public CameraFactory {
+    std::unique_ptr<CameraInterface> CreatePreview(const std::string& config, int width, int height,
+                                                   const Service::CAM::Flip& flip) const override;
+};
+
+} // namespace Camera
diff --git a/src/citra_qt/camera/qt_camera_factory.cpp b/src/citra_qt/camera/qt_camera_factory.cpp
deleted file mode 100644
index 063a600df..000000000
--- a/src/citra_qt/camera/qt_camera_factory.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2018 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include <QMessageBox>
-#include "citra_qt/camera/qt_camera_factory.h"
-
-namespace Camera {
-
-std::unique_ptr<CameraInterface> QtCameraFactory::CreatePreview(
-    const std::string& config, int width, int height, const Service::CAM::Flip& flip) const {
-    std::unique_ptr<CameraInterface> camera = Create(config, flip);
-
-    if (camera->IsPreviewAvailable()) {
-        return camera;
-    }
-    QMessageBox::critical(
-        nullptr, QObject::tr("Error"),
-        (config.empty() ? QObject::tr("Couldn't load the camera")
-                        : QObject::tr("Couldn't load %1").arg(QString::fromStdString(config))));
-    return nullptr;
-}
-
-} // namespace Camera
diff --git a/src/citra_qt/camera/qt_camera_factory.h b/src/citra_qt/camera/qt_camera_factory.h
deleted file mode 100644
index 9e590ca66..000000000
--- a/src/citra_qt/camera/qt_camera_factory.h
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2018 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include <string>
-#include "core/frontend/camera/factory.h"
-
-namespace Camera {
-
-// Base class for camera factories of citra_qt
-class QtCameraFactory : public CameraFactory {
-    std::unique_ptr<CameraInterface> CreatePreview(const std::string& config, int width, int height,
-                                                   const Service::CAM::Flip& flip) const override;
-};
-
-} // namespace Camera
diff --git a/src/citra_qt/camera/qt_multimedia_camera.cpp b/src/citra_qt/camera/qt_multimedia_camera.cpp
index 5f2137835..abf2ff25e 100644
--- a/src/citra_qt/camera/qt_multimedia_camera.cpp
+++ b/src/citra_qt/camera/qt_multimedia_camera.cpp
@@ -48,16 +48,13 @@ bool QtCameraSurface::present(const QVideoFrame& frame) {
 
 QtMultimediaCamera::QtMultimediaCamera(const std::string& camera_name,
                                        const Service::CAM::Flip& flip)
-    : handler(QtMultimediaCameraHandler::GetHandler()) {
+    : QtCameraInterface(flip), handler(QtMultimediaCameraHandler::GetHandler()) {
     if (handler->thread() == QThread::currentThread()) {
         handler->CreateCamera(camera_name);
     } else {
         QMetaObject::invokeMethod(handler.get(), "CreateCamera", Qt::BlockingQueuedConnection,
                                   Q_ARG(const std::string&, camera_name));
     }
-    using namespace Service::CAM;
-    flip_horizontal = basic_flip_horizontal = (flip == Flip::Horizontal) || (flip == Flip::Reverse);
-    flip_vertical = basic_flip_vertical = (flip == Flip::Vertical) || (flip == Flip::Reverse);
 }
 
 QtMultimediaCamera::~QtMultimediaCamera() {
@@ -77,10 +74,6 @@ void QtMultimediaCamera::StopCapture() {
     handler->StopCamera();
 }
 
-void QtMultimediaCamera::SetFormat(Service::CAM::OutputFormat output_format) {
-    output_rgb = output_format == Service::CAM::OutputFormat::RGB565;
-}
-
 void QtMultimediaCamera::SetFrameRate(Service::CAM::FrameRate frame_rate) {
     const std::array<QCamera::FrameRateRange, 13> FrameRateList = {
         /* Rate_15 */ QCamera::FrameRateRange(15, 15),
@@ -104,27 +97,9 @@ void QtMultimediaCamera::SetFrameRate(Service::CAM::FrameRate frame_rate) {
     handler->settings.setMinimumFrameRate(framerate.maximumFrameRate);
 }
 
-void QtMultimediaCamera::SetResolution(const Service::CAM::Resolution& resolution) {
-    width = resolution.width;
-    height = resolution.height;
-}
-
-void QtMultimediaCamera::SetFlip(Service::CAM::Flip flip) {
-    using namespace Service::CAM;
-    flip_horizontal = basic_flip_horizontal ^ (flip == Flip::Horizontal || flip == Flip::Reverse);
-    flip_vertical = basic_flip_vertical ^ (flip == Flip::Vertical || flip == Flip::Reverse);
-}
-
-void QtMultimediaCamera::SetEffect(Service::CAM::Effect effect) {
-    if (effect != Service::CAM::Effect::None) {
-        NGLOG_ERROR(Service_CAM, "Unimplemented effect {}", static_cast<int>(effect));
-    }
-}
-
-std::vector<u16> QtMultimediaCamera::ReceiveFrame() {
+QImage QtMultimediaCamera::QtReceiveFrame() {
     QMutexLocker locker(&handler->camera_surface.mutex);
-    return CameraUtil::ProcessImage(handler->camera_surface.current_frame, width, height,
-                                    output_rgb, flip_horizontal, flip_vertical);
+    return handler->camera_surface.current_frame;
 }
 
 bool QtMultimediaCamera::IsPreviewAvailable() {
diff --git a/src/citra_qt/camera/qt_multimedia_camera.h b/src/citra_qt/camera/qt_multimedia_camera.h
index 580834275..41024214c 100644
--- a/src/citra_qt/camera/qt_multimedia_camera.h
+++ b/src/citra_qt/camera/qt_multimedia_camera.h
@@ -13,7 +13,7 @@
 #include <QImage>
 #include <QMutex>
 #include "citra_qt/camera/camera_util.h"
-#include "citra_qt/camera/qt_camera_factory.h"
+#include "citra_qt/camera/qt_camera_base.h"
 #include "core/frontend/camera/interface.h"
 
 class GMainWindow;
@@ -36,26 +36,18 @@ private:
 class QtMultimediaCameraHandler;
 
 /// This class is only an interface. It just calls QtMultimediaCameraHandler.
-class QtMultimediaCamera final : public CameraInterface {
+class QtMultimediaCamera final : public QtCameraInterface {
 public:
     QtMultimediaCamera(const std::string& camera_name, const Service::CAM::Flip& flip);
     ~QtMultimediaCamera();
     void StartCapture() override;
     void StopCapture() override;
-    void SetResolution(const Service::CAM::Resolution&) override;
-    void SetFlip(Service::CAM::Flip) override;
-    void SetEffect(Service::CAM::Effect) override;
-    void SetFormat(Service::CAM::OutputFormat) override;
     void SetFrameRate(Service::CAM::FrameRate frame_rate) override;
-    std::vector<u16> ReceiveFrame() override;
+    QImage QtReceiveFrame() override;
     bool IsPreviewAvailable() override;
 
 private:
     std::shared_ptr<QtMultimediaCameraHandler> handler;
-    int width, height;
-    bool output_rgb;
-    bool flip_horizontal, flip_vertical;
-    bool basic_flip_horizontal, basic_flip_vertical;
 };
 
 class QtMultimediaCameraFactory final : public QtCameraFactory {
diff --git a/src/citra_qt/camera/still_image_camera.cpp b/src/citra_qt/camera/still_image_camera.cpp
index 7e54fad3e..2b9f4e54b 100644
--- a/src/citra_qt/camera/still_image_camera.cpp
+++ b/src/citra_qt/camera/still_image_camera.cpp
@@ -10,40 +10,14 @@
 namespace Camera {
 
 StillImageCamera::StillImageCamera(QImage image_, const Service::CAM::Flip& flip)
-    : image(std::move(image_)) {
-    using namespace Service::CAM;
-    flip_horizontal = basic_flip_horizontal = (flip == Flip::Horizontal) || (flip == Flip::Reverse);
-    flip_vertical = basic_flip_vertical = (flip == Flip::Vertical) || (flip == Flip::Reverse);
-}
+    : QtCameraInterface(flip), image(std::move(image_)) {}
 
 void StillImageCamera::StartCapture() {}
 
 void StillImageCamera::StopCapture() {}
 
-void StillImageCamera::SetFormat(Service::CAM::OutputFormat output_format) {
-    output_rgb = output_format == Service::CAM::OutputFormat::RGB565;
-}
-
-void StillImageCamera::SetResolution(const Service::CAM::Resolution& resolution) {
-    width = resolution.width;
-    height = resolution.height;
-}
-
-void StillImageCamera::SetFlip(Service::CAM::Flip flip) {
-    using namespace Service::CAM;
-    flip_horizontal = basic_flip_horizontal ^ (flip == Flip::Horizontal || flip == Flip::Reverse);
-    flip_vertical = basic_flip_vertical ^ (flip == Flip::Vertical || flip == Flip::Reverse);
-}
-
-void StillImageCamera::SetEffect(Service::CAM::Effect effect) {
-    if (effect != Service::CAM::Effect::None) {
-        NGLOG_ERROR(Service_CAM, "Unimplemented effect {}", static_cast<int>(effect));
-    }
-}
-
-std::vector<u16> StillImageCamera::ReceiveFrame() {
-    return CameraUtil::ProcessImage(image, width, height, output_rgb, flip_horizontal,
-                                    flip_vertical);
+QImage StillImageCamera::QtReceiveFrame() {
+    return image;
 }
 
 bool StillImageCamera::IsPreviewAvailable() {
diff --git a/src/citra_qt/camera/still_image_camera.h b/src/citra_qt/camera/still_image_camera.h
index e9016981b..11011622f 100644
--- a/src/citra_qt/camera/still_image_camera.h
+++ b/src/citra_qt/camera/still_image_camera.h
@@ -7,30 +7,22 @@
 #include <vector>
 #include <QImage>
 #include "citra_qt/camera/camera_util.h"
-#include "citra_qt/camera/qt_camera_factory.h"
+#include "citra_qt/camera/qt_camera_base.h"
 #include "core/frontend/camera/interface.h"
 
 namespace Camera {
 
-class StillImageCamera final : public CameraInterface {
+class StillImageCamera final : public QtCameraInterface {
 public:
     StillImageCamera(QImage image, const Service::CAM::Flip& flip);
     void StartCapture() override;
     void StopCapture() override;
-    void SetResolution(const Service::CAM::Resolution&) override;
-    void SetFlip(Service::CAM::Flip) override;
-    void SetEffect(Service::CAM::Effect) override;
-    void SetFormat(Service::CAM::OutputFormat) override;
     void SetFrameRate(Service::CAM::FrameRate frame_rate) override {}
-    std::vector<u16> ReceiveFrame() override;
+    QImage QtReceiveFrame() override;
     bool IsPreviewAvailable() override;
 
 private:
     QImage image;
-    int width, height;
-    bool output_rgb;
-    bool flip_horizontal, flip_vertical;
-    bool basic_flip_horizontal, basic_flip_vertical;
 };
 
 class StillImageCameraFactory final : public QtCameraFactory {

From 3cb91338e966730cbda7940577246b50b35f8259 Mon Sep 17 00:00:00 2001
From: zhupengfei <zhupengfei321@sina.cn>
Date: Sat, 26 May 2018 11:32:18 +0800
Subject: [PATCH 08/19] camera: migrate logging macros

---
 src/core/frontend/camera/factory.cpp | 4 ++--
 src/core/frontend/camera/factory.h   | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/core/frontend/camera/factory.cpp b/src/core/frontend/camera/factory.cpp
index 2a871196c..619fa3974 100644
--- a/src/core/frontend/camera/factory.cpp
+++ b/src/core/frontend/camera/factory.cpp
@@ -25,7 +25,7 @@ std::unique_ptr<CameraInterface> CreateCamera(const std::string& name, const std
     }
 
     if (name != "blank") {
-        LOG_ERROR(Service_CAM, "Unknown camera \"%s\"", name.c_str());
+        NGLOG_ERROR(Service_CAM, "Unknown camera {}", name);
     }
     return std::make_unique<BlankCamera>();
 }
@@ -39,7 +39,7 @@ std::unique_ptr<CameraInterface> CreateCameraPreview(const std::string& name,
     }
 
     if (name != "blank") {
-        LOG_ERROR(Service_CAM, "Unknown camera \"%s\"", name.c_str());
+        NGLOG_ERROR(Service_CAM, "Unknown camera {}", name);
     }
     return std::make_unique<BlankCamera>();
 }
diff --git a/src/core/frontend/camera/factory.h b/src/core/frontend/camera/factory.h
index 2c4ab1479..dc795f0ce 100644
--- a/src/core/frontend/camera/factory.h
+++ b/src/core/frontend/camera/factory.h
@@ -31,7 +31,7 @@ public:
      * @param flip The image flip to apply
      * @returns a unique_ptr to the created camera object.
      * Note: The default implementation for this is to call Create(). Derived classes may have other
-     *       Implementations. For example, A dialog may be used instead of LOG_ERROR when error
+     *       Implementations. For example, A dialog may be used instead of NGLOG_ERROR when error
      * occurs.
      */
     virtual std::unique_ptr<CameraInterface> CreatePreview(const std::string& config, int width,

From 341c07156ac02f213e14c18ca2e28d119df7719f Mon Sep 17 00:00:00 2001
From: zhupengfei <zhupengfei321@sina.cn>
Date: Sat, 2 Jun 2018 22:13:54 +0800
Subject: [PATCH 09/19] camera: Single/Double (QtMultimediaCamera)

---
 src/citra_qt/camera/qt_multimedia_camera.cpp | 20 +++++++++++++++++---
 src/citra_qt/camera/qt_multimedia_camera.h   |  4 +++-
 src/citra_qt/camera/still_image_camera.cpp   |  5 ++---
 src/citra_qt/camera/still_image_camera.h     |  2 +-
 4 files changed, 23 insertions(+), 8 deletions(-)

diff --git a/src/citra_qt/camera/qt_multimedia_camera.cpp b/src/citra_qt/camera/qt_multimedia_camera.cpp
index abf2ff25e..05bcbd4f8 100644
--- a/src/citra_qt/camera/qt_multimedia_camera.cpp
+++ b/src/citra_qt/camera/qt_multimedia_camera.cpp
@@ -48,7 +48,7 @@ bool QtCameraSurface::present(const QVideoFrame& frame) {
 
 QtMultimediaCamera::QtMultimediaCamera(const std::string& camera_name,
                                        const Service::CAM::Flip& flip)
-    : QtCameraInterface(flip), handler(QtMultimediaCameraHandler::GetHandler()) {
+    : QtCameraInterface(flip), handler(QtMultimediaCameraHandler::GetHandler(camera_name)) {
     if (handler->thread() == QThread::currentThread()) {
         handler->CreateCamera(camera_name);
     } else {
@@ -94,7 +94,7 @@ void QtMultimediaCamera::SetFrameRate(Service::CAM::FrameRate frame_rate) {
     auto framerate = FrameRateList[static_cast<int>(frame_rate)];
 
     handler->settings.setMinimumFrameRate(framerate.minimumFrameRate);
-    handler->settings.setMinimumFrameRate(framerate.maximumFrameRate);
+    handler->settings.setMaximumFrameRate(framerate.maximumFrameRate);
 }
 
 QImage QtMultimediaCamera::QtReceiveFrame() {
@@ -115,17 +115,25 @@ std::array<std::shared_ptr<QtMultimediaCameraHandler>, 3> QtMultimediaCameraHand
 
 std::array<bool, 3> QtMultimediaCameraHandler::status;
 
+std::unordered_map<std::string, std::shared_ptr<QtMultimediaCameraHandler>>
+    QtMultimediaCameraHandler::loaded;
+
 void QtMultimediaCameraHandler::Init() {
     for (auto& handler : handlers) {
         handler = std::make_shared<QtMultimediaCameraHandler>();
     }
 }
 
-std::shared_ptr<QtMultimediaCameraHandler> QtMultimediaCameraHandler::GetHandler() {
+std::shared_ptr<QtMultimediaCameraHandler> QtMultimediaCameraHandler::GetHandler(
+    const std::string& camera_name) {
+    if (loaded.count(camera_name)) {
+        return loaded.at(camera_name);
+    }
     for (int i = 0; i < handlers.size(); i++) {
         if (!status[i]) {
             NGLOG_INFO(Service_CAM, "Successfully got handler {}", i);
             status[i] = true;
+            loaded.emplace(camera_name, handlers[i]);
             return handlers[i];
         }
     }
@@ -140,6 +148,12 @@ void QtMultimediaCameraHandler::ReleaseHandler(
             NGLOG_INFO(Service_CAM, "Successfully released handler {}", i);
             status[i] = false;
             handlers[i]->started = false;
+            for (auto it = loaded.begin(); it != loaded.end(); it++) {
+                if (it->second == handlers[i]) {
+                    loaded.erase(it);
+                    break;
+                }
+            }
             break;
         }
     }
diff --git a/src/citra_qt/camera/qt_multimedia_camera.h b/src/citra_qt/camera/qt_multimedia_camera.h
index 41024214c..e6d7b6b6d 100644
--- a/src/citra_qt/camera/qt_multimedia_camera.h
+++ b/src/citra_qt/camera/qt_multimedia_camera.h
@@ -6,6 +6,7 @@
 
 #include <array>
 #include <string>
+#include <unordered_map>
 #include <vector>
 #include <QAbstractVideoSurface>
 #include <QCamera>
@@ -62,7 +63,7 @@ class QtMultimediaCameraHandler final : public QObject {
 public:
     /// Creates the global handler. Must be called in UI thread.
     static void Init();
-    static std::shared_ptr<QtMultimediaCameraHandler> GetHandler();
+    static std::shared_ptr<QtMultimediaCameraHandler> GetHandler(const std::string& camera_name);
     static void ReleaseHandler(const std::shared_ptr<QtMultimediaCameraHandler>& handler);
 
     /**
@@ -92,6 +93,7 @@ private:
 
     static std::array<std::shared_ptr<QtMultimediaCameraHandler>, 3> handlers;
     static std::array<bool, 3> status;
+    static std::unordered_map<std::string, std::shared_ptr<QtMultimediaCameraHandler>> loaded;
 
     friend class QtMultimediaCamera; // For access to camera_surface (and camera)
 };
diff --git a/src/citra_qt/camera/still_image_camera.cpp b/src/citra_qt/camera/still_image_camera.cpp
index 2b9f4e54b..a166e3336 100644
--- a/src/citra_qt/camera/still_image_camera.cpp
+++ b/src/citra_qt/camera/still_image_camera.cpp
@@ -24,7 +24,7 @@ bool StillImageCamera::IsPreviewAvailable() {
     return !image.isNull();
 }
 
-const std::string StillImageCameraFactory::getFilePath() {
+const std::string StillImageCameraFactory::GetFilePath() {
     QList<QByteArray> types = QImageReader::supportedImageFormats();
     QList<QString> temp_filters;
     for (QByteArray type : types) {
@@ -32,7 +32,6 @@ const std::string StillImageCameraFactory::getFilePath() {
     }
 
     QString filter = QObject::tr("Supported image files (%1)").arg(temp_filters.join(" "));
-
     return QFileDialog::getOpenFileName(nullptr, QObject::tr("Open File"), ".", filter)
         .toStdString();
 }
@@ -41,7 +40,7 @@ std::unique_ptr<CameraInterface> StillImageCameraFactory::Create(
     const std::string& config, const Service::CAM::Flip& flip) const {
     std::string real_config = config;
     if (config.empty()) {
-        real_config = getFilePath();
+        real_config = GetFilePath();
     }
     QImage image(QString::fromStdString(real_config));
     if (image.isNull()) {
diff --git a/src/citra_qt/camera/still_image_camera.h b/src/citra_qt/camera/still_image_camera.h
index 11011622f..80e43ba17 100644
--- a/src/citra_qt/camera/still_image_camera.h
+++ b/src/citra_qt/camera/still_image_camera.h
@@ -31,7 +31,7 @@ public:
                                             const Service::CAM::Flip& flip) const override;
 
 private:
-    static const std::string getFilePath();
+    static const std::string GetFilePath();
 };
 
 } // namespace Camera

From 7c48160beb8a4b0937dbe39ac2e84bcd422be08e Mon Sep 17 00:00:00 2001
From: zhupengfei <zhupengfei321@sina.cn>
Date: Sun, 3 Jun 2018 11:29:46 +0800
Subject: [PATCH 10/19] StillImageCamera: move GetFilePath to UI thread

---
 src/citra_qt/camera/qt_camera_base.cpp       |  5 +++--
 src/citra_qt/camera/qt_camera_base.h         |  2 +-
 src/citra_qt/camera/qt_multimedia_camera.cpp |  4 ++--
 src/citra_qt/camera/qt_multimedia_camera.h   |  2 +-
 src/citra_qt/camera/still_image_camera.cpp   | 16 ++++++++++++----
 src/citra_qt/camera/still_image_camera.h     |  9 +++++----
 src/core/frontend/camera/factory.h           |  4 ++--
 7 files changed, 26 insertions(+), 16 deletions(-)

diff --git a/src/citra_qt/camera/qt_camera_base.cpp b/src/citra_qt/camera/qt_camera_base.cpp
index 65bf2361c..69593ab51 100644
--- a/src/citra_qt/camera/qt_camera_base.cpp
+++ b/src/citra_qt/camera/qt_camera_base.cpp
@@ -40,8 +40,9 @@ std::vector<u16> QtCameraInterface::ReceiveFrame() {
                                     flip_vertical);
 }
 
-std::unique_ptr<CameraInterface> QtCameraFactory::CreatePreview(
-    const std::string& config, int width, int height, const Service::CAM::Flip& flip) const {
+std::unique_ptr<CameraInterface> QtCameraFactory::CreatePreview(const std::string& config,
+                                                                int width, int height,
+                                                                const Service::CAM::Flip& flip) {
     std::unique_ptr<CameraInterface> camera = Create(config, flip);
 
     if (camera->IsPreviewAvailable()) {
diff --git a/src/citra_qt/camera/qt_camera_base.h b/src/citra_qt/camera/qt_camera_base.h
index e66c3bb46..6c6095a28 100644
--- a/src/citra_qt/camera/qt_camera_base.h
+++ b/src/citra_qt/camera/qt_camera_base.h
@@ -30,7 +30,7 @@ private:
 // Base class for camera factories of citra_qt
 class QtCameraFactory : public CameraFactory {
     std::unique_ptr<CameraInterface> CreatePreview(const std::string& config, int width, int height,
-                                                   const Service::CAM::Flip& flip) const override;
+                                                   const Service::CAM::Flip& flip) override;
 };
 
 } // namespace Camera
diff --git a/src/citra_qt/camera/qt_multimedia_camera.cpp b/src/citra_qt/camera/qt_multimedia_camera.cpp
index 05bcbd4f8..ad6bad876 100644
--- a/src/citra_qt/camera/qt_multimedia_camera.cpp
+++ b/src/citra_qt/camera/qt_multimedia_camera.cpp
@@ -106,8 +106,8 @@ bool QtMultimediaCamera::IsPreviewAvailable() {
     return handler->CameraAvailable();
 }
 
-std::unique_ptr<CameraInterface> QtMultimediaCameraFactory::Create(
-    const std::string& config, const Service::CAM::Flip& flip) const {
+std::unique_ptr<CameraInterface> QtMultimediaCameraFactory::Create(const std::string& config,
+                                                                   const Service::CAM::Flip& flip) {
     return std::make_unique<QtMultimediaCamera>(config, flip);
 }
 
diff --git a/src/citra_qt/camera/qt_multimedia_camera.h b/src/citra_qt/camera/qt_multimedia_camera.h
index e6d7b6b6d..14242c554 100644
--- a/src/citra_qt/camera/qt_multimedia_camera.h
+++ b/src/citra_qt/camera/qt_multimedia_camera.h
@@ -54,7 +54,7 @@ private:
 class QtMultimediaCameraFactory final : public QtCameraFactory {
 public:
     std::unique_ptr<CameraInterface> Create(const std::string& config,
-                                            const Service::CAM::Flip& flip) const override;
+                                            const Service::CAM::Flip& flip) override;
 };
 
 class QtMultimediaCameraHandler final : public QObject {
diff --git a/src/citra_qt/camera/still_image_camera.cpp b/src/citra_qt/camera/still_image_camera.cpp
index a166e3336..b466d17df 100644
--- a/src/citra_qt/camera/still_image_camera.cpp
+++ b/src/citra_qt/camera/still_image_camera.cpp
@@ -5,6 +5,7 @@
 #include <QFileDialog>
 #include <QImageReader>
 #include <QMessageBox>
+#include <QThread>
 #include "citra_qt/camera/still_image_camera.h"
 
 namespace Camera {
@@ -24,7 +25,7 @@ bool StillImageCamera::IsPreviewAvailable() {
     return !image.isNull();
 }
 
-const std::string StillImageCameraFactory::GetFilePath() {
+const std::string StillImageCameraFactory::GetFilePath() const {
     QList<QByteArray> types = QImageReader::supportedImageFormats();
     QList<QString> temp_filters;
     for (QByteArray type : types) {
@@ -36,11 +37,18 @@ const std::string StillImageCameraFactory::GetFilePath() {
         .toStdString();
 }
 
-std::unique_ptr<CameraInterface> StillImageCameraFactory::Create(
-    const std::string& config, const Service::CAM::Flip& flip) const {
+std::unique_ptr<CameraInterface> StillImageCameraFactory::Create(const std::string& config,
+                                                                 const Service::CAM::Flip& flip) {
     std::string real_config = config;
     if (config.empty()) {
-        real_config = GetFilePath();
+        // call GetFilePath() in UI thread (note: StillImageCameraFactory itself is initialized in
+        // UI thread, so we can just pass in "this" here)
+        if (thread() == QThread::currentThread()) {
+            real_config = GetFilePath();
+        } else {
+            QMetaObject::invokeMethod(this, "GetFilePath", Qt::BlockingQueuedConnection,
+                                      Q_RETURN_ARG(std::string, real_config));
+        }
     }
     QImage image(QString::fromStdString(real_config));
     if (image.isNull()) {
diff --git a/src/citra_qt/camera/still_image_camera.h b/src/citra_qt/camera/still_image_camera.h
index 80e43ba17..ccfc13211 100644
--- a/src/citra_qt/camera/still_image_camera.h
+++ b/src/citra_qt/camera/still_image_camera.h
@@ -25,13 +25,14 @@ private:
     QImage image;
 };
 
-class StillImageCameraFactory final : public QtCameraFactory {
+class StillImageCameraFactory final : public QObject, public QtCameraFactory {
+    Q_OBJECT
+
 public:
     std::unique_ptr<CameraInterface> Create(const std::string& config,
-                                            const Service::CAM::Flip& flip) const override;
+                                            const Service::CAM::Flip& flip) override;
 
-private:
-    static const std::string GetFilePath();
+    Q_INVOKABLE const std::string GetFilePath() const;
 };
 
 } // namespace Camera
diff --git a/src/core/frontend/camera/factory.h b/src/core/frontend/camera/factory.h
index dc795f0ce..0fe9f314f 100644
--- a/src/core/frontend/camera/factory.h
+++ b/src/core/frontend/camera/factory.h
@@ -22,7 +22,7 @@ public:
      * @returns a unique_ptr to the created camera object.
      */
     virtual std::unique_ptr<CameraInterface> Create(const std::string& config,
-                                                    const Service::CAM::Flip& flip) const = 0;
+                                                    const Service::CAM::Flip& flip) = 0;
 
     /**
      * Creates a camera object for preview based on the configuration string.
@@ -36,7 +36,7 @@ public:
      */
     virtual std::unique_ptr<CameraInterface> CreatePreview(const std::string& config, int width,
                                                            int height,
-                                                           const Service::CAM::Flip& flip) const {
+                                                           const Service::CAM::Flip& flip) {
         return Create(config, flip);
     }
 };

From a15e4e80c695e8a5976418c333a99b610f3b6d9d Mon Sep 17 00:00:00 2001
From: zhupengfei <zhupengfei321@sina.cn>
Date: Thu, 7 Jun 2018 12:59:18 +0800
Subject: [PATCH 11/19] QtMultimediaCamera: fix invalid settings

---
 src/citra_qt/camera/qt_multimedia_camera.cpp | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/src/citra_qt/camera/qt_multimedia_camera.cpp b/src/citra_qt/camera/qt_multimedia_camera.cpp
index ad6bad876..76a21453d 100644
--- a/src/citra_qt/camera/qt_multimedia_camera.cpp
+++ b/src/citra_qt/camera/qt_multimedia_camera.cpp
@@ -93,8 +93,10 @@ void QtMultimediaCamera::SetFrameRate(Service::CAM::FrameRate frame_rate) {
 
     auto framerate = FrameRateList[static_cast<int>(frame_rate)];
 
-    handler->settings.setMinimumFrameRate(framerate.minimumFrameRate);
-    handler->settings.setMaximumFrameRate(framerate.maximumFrameRate);
+    if (handler->camera->supportedViewfinderFrameRateRanges().contains(framerate)) {
+        handler->settings.setMinimumFrameRate(framerate.minimumFrameRate);
+        handler->settings.setMaximumFrameRate(framerate.maximumFrameRate);
+    }
 }
 
 QImage QtMultimediaCamera::QtReceiveFrame() {
@@ -171,6 +173,7 @@ void QtMultimediaCameraHandler::CreateCamera(const std::string& camera_name) {
     settings.setMinimumFrameRate(30);
     settings.setMaximumFrameRate(30);
     camera->setViewfinder(&camera_surface);
+    camera->load();
 }
 
 void QtMultimediaCameraHandler::StopCamera() {

From 3c554153c78ece768e05b126ff2bc51338f0c08d Mon Sep 17 00:00:00 2001
From: zhupengfei <zhupengfei321@sina.cn>
Date: Thu, 7 Jun 2018 14:48:52 +0800
Subject: [PATCH 12/19] StillImageCamera: fix multiple prompt

---
 src/citra_qt/camera/still_image_camera.cpp | 14 ++++++++++++--
 src/citra_qt/camera/still_image_camera.h   |  7 +++++++
 2 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/src/citra_qt/camera/still_image_camera.cpp b/src/citra_qt/camera/still_image_camera.cpp
index b466d17df..e02d0d0d3 100644
--- a/src/citra_qt/camera/still_image_camera.cpp
+++ b/src/citra_qt/camera/still_image_camera.cpp
@@ -13,6 +13,10 @@ namespace Camera {
 StillImageCamera::StillImageCamera(QImage image_, const Service::CAM::Flip& flip)
     : QtCameraInterface(flip), image(std::move(image_)) {}
 
+StillImageCamera::~StillImageCamera() {
+    StillImageCameraFactory::last_path.clear();
+}
+
 void StillImageCamera::StartCapture() {}
 
 void StillImageCamera::StopCapture() {}
@@ -25,7 +29,12 @@ bool StillImageCamera::IsPreviewAvailable() {
     return !image.isNull();
 }
 
+std::string StillImageCameraFactory::last_path;
+
 const std::string StillImageCameraFactory::GetFilePath() const {
+    if (!last_path.empty()) {
+        return last_path;
+    }
     QList<QByteArray> types = QImageReader::supportedImageFormats();
     QList<QString> temp_filters;
     for (QByteArray type : types) {
@@ -33,8 +42,9 @@ const std::string StillImageCameraFactory::GetFilePath() const {
     }
 
     QString filter = QObject::tr("Supported image files (%1)").arg(temp_filters.join(" "));
-    return QFileDialog::getOpenFileName(nullptr, QObject::tr("Open File"), ".", filter)
-        .toStdString();
+    last_path =
+        QFileDialog::getOpenFileName(nullptr, QObject::tr("Open File"), ".", filter).toStdString();
+    return last_path;
 }
 
 std::unique_ptr<CameraInterface> StillImageCameraFactory::Create(const std::string& config,
diff --git a/src/citra_qt/camera/still_image_camera.h b/src/citra_qt/camera/still_image_camera.h
index ccfc13211..19ca044f0 100644
--- a/src/citra_qt/camera/still_image_camera.h
+++ b/src/citra_qt/camera/still_image_camera.h
@@ -15,6 +15,7 @@ namespace Camera {
 class StillImageCamera final : public QtCameraInterface {
 public:
     StillImageCamera(QImage image, const Service::CAM::Flip& flip);
+    ~StillImageCamera();
     void StartCapture() override;
     void StopCapture() override;
     void SetFrameRate(Service::CAM::FrameRate frame_rate) override {}
@@ -33,6 +34,12 @@ public:
                                             const Service::CAM::Flip& flip) override;
 
     Q_INVOKABLE const std::string GetFilePath() const;
+
+private:
+    /// Record the path chosen to avoid multiple prompt problem
+    static std::string last_path;
+
+    friend class StillImageCamera;
 };
 
 } // namespace Camera

From cb52033133e6ec39ca61ad06c11dd822c6641759 Mon Sep 17 00:00:00 2001
From: zhupengfei <zhupengfei321@sina.cn>
Date: Thu, 7 Jun 2018 17:49:18 +0800
Subject: [PATCH 13/19] game_list: fix system title display

---
 src/citra_qt/game_list_p.h | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/src/citra_qt/game_list_p.h b/src/citra_qt/game_list_p.h
index 1546709aa..a9341de00 100644
--- a/src/citra_qt/game_list_p.h
+++ b/src/citra_qt/game_list_p.h
@@ -173,14 +173,20 @@ public:
                               &extension);
             QString title = data(TitleRole).toString();
             QString second_name = QString::fromStdString(filename + extension);
-            static QRegExp installed_system_pattern(
+            static QRegExp installed_pattern(
                 QString::fromStdString(
                     FileUtil::GetUserPath(D_SDMC_IDX) +
                     "Nintendo "
                     "3DS/00000000000000000000000000000000/00000000000000000000000000000000/"
-                    "title/000400(0|1)0/[0-9a-f]{8}/content/")
+                    "title/0004000(0|e)/[0-9a-f]{8}/content/")
                     .replace("\\", "\\\\"));
-            if (installed_system_pattern.exactMatch(QString::fromStdString(path))) {
+            static QRegExp system_pattern(
+                QString::fromStdString(FileUtil::GetUserPath(D_NAND_IDX) +
+                                       "00000000000000000000000000000000/"
+                                       "title/00040010/[0-9a-f]{8}/content/")
+                    .replace("\\", "\\\\"));
+            if (installed_pattern.exactMatch(QString::fromStdString(path)) ||
+                system_pattern.exactMatch(QString::fromStdString(path))) {
                 // Use a different mechanism for system / installed titles showing program ID
                 second_name = QString("%1-%2")
                                   .arg(data(ProgramIdRole).toULongLong(), 16, 16, QChar('0'))

From 613593167079ef874faa06095bfa06f39c7013a3 Mon Sep 17 00:00:00 2001
From: liushuyu <liushuyu011@gmail.com>
Date: Fri, 8 Jun 2018 02:01:36 -0600
Subject: [PATCH 14/19] travis: share env variables with Docker

---
 .travis/common/travis-ci.env  | 15 +++++++++++++++
 .travis/linux-frozen/build.sh |  2 +-
 .travis/linux/build.sh        |  2 +-
 3 files changed, 17 insertions(+), 2 deletions(-)
 create mode 100644 .travis/common/travis-ci.env

diff --git a/.travis/common/travis-ci.env b/.travis/common/travis-ci.env
new file mode 100644
index 000000000..7d63674b4
--- /dev/null
+++ b/.travis/common/travis-ci.env
@@ -0,0 +1,15 @@
+# List of environment variables to be shared with Docker containers
+CI
+TRAVIS
+CONTINUOUS_INTEGRATION
+TRAVIS_BRANCH
+TRAVIS_BUILD_ID
+TRAVIS_BUILD_NUMBER
+TRAVIS_COMMIT
+TRAVIS_JOB_ID
+TRAVIS_JOB_NUMBER
+TRAVIS_REPO_SLUG
+TRAVIS_TAG
+
+# citra specific flags
+ENABLE_COMPATIBILITY_REPORTING
diff --git a/.travis/linux-frozen/build.sh b/.travis/linux-frozen/build.sh
index a6372bd33..d849ceaf2 100755
--- a/.travis/linux-frozen/build.sh
+++ b/.travis/linux-frozen/build.sh
@@ -1,4 +1,4 @@
 #!/bin/bash -ex
 mkdir -p "$HOME/.ccache"
 docker pull ubuntu:18.04
-docker run -e ENABLE_COMPATIBILITY_REPORTING -v $(pwd):/citra -v "$HOME/.ccache":/root/.ccache ubuntu:18.04 /bin/bash -ex /citra/.travis/linux-frozen/docker.sh
+docker run --env-file .travis/common/travis-ci.env -v $(pwd):/citra -v "$HOME/.ccache":/root/.ccache ubuntu:18.04 /bin/bash -ex /citra/.travis/linux-frozen/docker.sh
diff --git a/.travis/linux/build.sh b/.travis/linux/build.sh
index 53e8fa610..499d15b1b 100755
--- a/.travis/linux/build.sh
+++ b/.travis/linux/build.sh
@@ -1,3 +1,3 @@
 #!/bin/bash -ex
 mkdir -p "$HOME/.ccache"
-docker run -e ENABLE_COMPATIBILITY_REPORTING -v $(pwd):/citra -v "$HOME/.ccache":/root/.ccache ubuntu:18.04 /bin/bash -ex /citra/.travis/linux/docker.sh
+docker run --env-file .travis/common/travis-ci.env -v $(pwd):/citra -v "$HOME/.ccache":/root/.ccache ubuntu:18.04 /bin/bash -ex /citra/.travis/linux/docker.sh

From 9f18ec6247909cc2b67cb2b91516f2ccd3e28e07 Mon Sep 17 00:00:00 2001
From: Jan Beich <jbeich@FreeBSD.org>
Date: Fri, 8 Jun 2018 08:34:57 +0000
Subject: [PATCH 15/19] externals: update soundtouch to pick up x86 fix

---
 externals/soundtouch | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/externals/soundtouch b/externals/soundtouch
index 019d2089b..060181eaf 160000
--- a/externals/soundtouch
+++ b/externals/soundtouch
@@ -1 +1 @@
-Subproject commit 019d2089bbadf70d73ba85aa8ea51490b071262c
+Subproject commit 060181eaf273180d3a7e87349895bd0cb6ccbf4a

From 23ef36a1cf9a82a4383bdba957768f2e7b5d1955 Mon Sep 17 00:00:00 2001
From: Jan Beich <jbeich@FreeBSD.org>
Date: Fri, 8 Jun 2018 11:03:04 +0000
Subject: [PATCH 16/19] externals: update cryptopp to
 CRYPTOPP_7_0_0-23-gf320e7d9

---
 externals/cryptopp/cryptopp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/externals/cryptopp/cryptopp b/externals/cryptopp/cryptopp
index 5be140bce..f320e7d92 160000
--- a/externals/cryptopp/cryptopp
+++ b/externals/cryptopp/cryptopp
@@ -1 +1 @@
-Subproject commit 5be140bcea453a00f7f2fec09fb9e37849d65d98
+Subproject commit f320e7d92a33ee80ae42deef79da78cfc30868af

From e24fb768e33cef5f41fe075f782dd57892ca6e73 Mon Sep 17 00:00:00 2001
From: Steveice10 <Steveice10@gmail.com>
Date: Fri, 8 Jun 2018 18:12:35 -0700
Subject: [PATCH 17/19] boss: Return buff_size in parameter 2 of
 ReceiveProperty.

---
 src/core/hle/service/boss/boss.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/core/hle/service/boss/boss.cpp b/src/core/hle/service/boss/boss.cpp
index 7eae94972..974b5ed29 100644
--- a/src/core/hle/service/boss/boss.cpp
+++ b/src/core/hle/service/boss/boss.cpp
@@ -404,7 +404,7 @@ void ReceiveProperty(Service::Interface* self) {
 
     cmd_buff[0] = IPC::MakeHeader(0x16, 0x2, 0x2);
     cmd_buff[1] = RESULT_SUCCESS.raw;
-    cmd_buff[2] = 0; // stub 0 (32 bit value)
+    cmd_buff[2] = buff_size; // Should be actual number of read bytes.
     cmd_buff[3] = (buff_size << 4 | 0xC);
     cmd_buff[4] = buff_addr;
 

From 2cecb3bd6e04a3ff753efc625ed0d4324d51864c Mon Sep 17 00:00:00 2001
From: liushuyu <liushuyu011@gmail.com>
Date: Fri, 8 Jun 2018 19:11:59 -0600
Subject: [PATCH 18/19] appveyor: fix mingw issue (again)

---
 appveyor.yml | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/appveyor.yml b/appveyor.yml
index a6e66881d..772635267 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -27,13 +27,14 @@ install:
   - ps: |
         if ($env:BUILD_TYPE -eq 'mingw') {
           $dependencies = "mingw64/mingw-w64-x86_64-qt5"
+          C:\msys64\usr\bin\bash -lc "pacman -Syy"
           # redirect err to null to prevent warnings from becoming errors
           # workaround to prevent pacman from failing due to cyclical dependencies
           C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw64/mingw-w64-x86_64-freetype mingw64/mingw-w64-x86_64-fontconfig" 2> $null
           C:\msys64\usr\bin\bash -lc "pacman --noconfirm -U http://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-SDL2-2.0.5-2-any.pkg.tar.xz" 2> $null
           C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S $dependencies" 2> $null
-          # stick to cmake 3.9.6 since on lower versions it could happen that cmake generates a Makefile that links against gcc_eh
-          C:\msys64\usr\bin\bash -lc "pacman --noconfirm -U http://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-cmake-3.9.6-1-any.pkg.tar.xz" 2> $null
+          # freeze the cmake to a stable version, on version < 3.9.6 cmake may generate a Makefile links against gcc_eh instead of gcc_s_eh
+          C:\msys64\usr\bin\bash -lc "pacman --noconfirm -U http://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-cmake-3.11.1-2-any.pkg.tar.xz" 2> $null
         }
 
 before_build:

From e206f6c202c90ff7ea7687bbb518a288737168cd Mon Sep 17 00:00:00 2001
From: liushuyu <liushuyu011@gmail.com>
Date: Sat, 9 Jun 2018 14:19:15 -0600
Subject: [PATCH 19/19] travis: fix tx push (again)

---
 .travis/transifex/docker.sh | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/.travis/transifex/docker.sh b/.travis/transifex/docker.sh
index 9ca97e222..88913ba9e 100644
--- a/.travis/transifex/docker.sh
+++ b/.travis/transifex/docker.sh
@@ -9,7 +9,21 @@ echo -e "\e[1m\e[33mInstalling dependencies...\e[0m"
 apk update
 apk add build-base cmake python3-dev qt5-qttools-dev qt5-qtmultimedia-dev
 
-pip3 install transifex-client
+pip3 install --upgrade pip transifex-client
+
+cat << 'EOF' > /usr/bin/tx
+#!/usr/bin/python3
+
+# -*- coding: utf-8 -*-
+import re
+import sys
+
+from txclib.cmdline import main
+
+if __name__ == '__main__':
+    sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
+    sys.exit(main())
+EOF
 
 echo -e "\e[1m\e[33mBuild tools information:\e[0m"
 cmake --version