From 17b5c749bf21558fddc6f13cbfc864d17e9c4aae Mon Sep 17 00:00:00 2001
From: Connor McLaughlin <stenzek@gmail.com>
Date: Sun, 23 Aug 2020 14:42:53 +1000
Subject: [PATCH] libretro: Re-enable hw context switch, add auto option

---
 src/common/CMakeLists.txt                     |  1 +
 src/common/common.vcxproj                     |  1 +
 src/common/common.vcxproj.filters             |  3 +-
 src/common/make_array.h                       | 12 +++++++
 src/core/settings.cpp                         | 23 ++++++------
 .../libretro_host_interface.cpp               | 35 +++++++------------
 6 files changed, 42 insertions(+), 33 deletions(-)
 create mode 100644 src/common/make_array.h

diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 88310ed1f..51439d95c 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -49,6 +49,7 @@ add_library(common
   jit_code_buffer.h
   log.cpp
   log.h
+  make_array.h
   md5_digest.cpp
   md5_digest.h
   minizip_helpers.cpp
diff --git a/src/common/common.vcxproj b/src/common/common.vcxproj
index 2d14bb975..4032da1d0 100644
--- a/src/common/common.vcxproj
+++ b/src/common/common.vcxproj
@@ -66,6 +66,7 @@
     <ClInclude Include="iso_reader.h" />
     <ClInclude Include="jit_code_buffer.h" />
     <ClInclude Include="log.h" />
+    <ClInclude Include="make_array.h" />
     <ClInclude Include="md5_digest.h" />
     <ClInclude Include="null_audio_stream.h" />
     <ClInclude Include="progress_callback.h" />
diff --git a/src/common/common.vcxproj.filters b/src/common/common.vcxproj.filters
index 5c40671c8..72c03a7ce 100644
--- a/src/common/common.vcxproj.filters
+++ b/src/common/common.vcxproj.filters
@@ -101,6 +101,7 @@
     <ClInclude Include="image.h" />
     <ClInclude Include="minizip_helpers.h" />
     <ClInclude Include="win32_progress_callback.h" />
+    <ClInclude Include="make_array.h" />
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="jit_code_buffer.cpp" />
@@ -210,4 +211,4 @@
       <UniqueIdentifier>{642ff5eb-af39-4aab-a42f-6eb8188a11d7}</UniqueIdentifier>
     </Filter>
   </ItemGroup>
-</Project>
+</Project>
\ No newline at end of file
diff --git a/src/common/make_array.h b/src/common/make_array.h
new file mode 100644
index 000000000..989c5ebb0
--- /dev/null
+++ b/src/common/make_array.h
@@ -0,0 +1,12 @@
+#pragma once
+#include <array>
+#include <type_traits>
+
+// Source: https://gist.github.com/klmr/2775736#file-make_array-hpp
+
+template<typename... T>
+constexpr auto make_array(T&&... values)
+  -> std::array<typename std::decay<typename std::common_type<T...>::type>::type, sizeof...(T)>
+{
+  return {std::forward<T>(values)...};
+}
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index d63d0fbf2..e0254e3c8 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -1,4 +1,5 @@
 #include "settings.h"
+#include "common/make_array.h"
 #include "common/string_util.h"
 #include "host_interface.h"
 #include <algorithm>
@@ -380,7 +381,8 @@ const char* Settings::GetDiscRegionDisplayName(DiscRegion region)
 
 static std::array<const char*, 3> s_cpu_execution_mode_names = {{"Interpreter", "CachedInterpreter", "Recompiler"}};
 static std::array<const char*, 3> s_cpu_execution_mode_display_names = {
-  {TRANSLATABLE("CPUExecutionMode", "Intepreter (Slowest)"), TRANSLATABLE("CPUExecutionMode", "Cached Interpreter (Faster)"),
+  {TRANSLATABLE("CPUExecutionMode", "Intepreter (Slowest)"),
+   TRANSLATABLE("CPUExecutionMode", "Cached Interpreter (Faster)"),
    TRANSLATABLE("CPUExecutionMode", "Recompiler (Fastest)")}};
 
 std::optional<CPUExecutionMode> Settings::ParseCPUExecutionMode(const char* str)
@@ -407,17 +409,17 @@ const char* Settings::GetCPUExecutionModeDisplayName(CPUExecutionMode mode)
   return s_cpu_execution_mode_display_names[static_cast<u8>(mode)];
 }
 
-static std::array<const char*, 4> s_gpu_renderer_names = {{
+static constexpr auto s_gpu_renderer_names = make_array(
 #ifdef WIN32
   "D3D11",
 #endif
-  "Vulkan", "OpenGL", "Software"}};
-static std::array<const char*, 4> s_gpu_renderer_display_names = {{
+  "Vulkan", "OpenGL", "Software");
+static constexpr auto s_gpu_renderer_display_names = make_array(
 #ifdef WIN32
   TRANSLATABLE("GPURenderer", "Hardware (D3D11)"),
 #endif
   TRANSLATABLE("GPURenderer", "Hardware (Vulkan)"), TRANSLATABLE("GPURenderer", "Hardware (OpenGL)"),
-  TRANSLATABLE("GPURenderer", "Software")}};
+  TRANSLATABLE("GPURenderer", "Software"));
 
 std::optional<GPURenderer> Settings::ParseRendererName(const char* str)
 {
@@ -444,9 +446,9 @@ const char* Settings::GetRendererDisplayName(GPURenderer renderer)
 }
 
 static std::array<const char*, 3> s_display_crop_mode_names = {{"None", "Overscan", "Borders"}};
-static std::array<const char*, 3> s_display_crop_mode_display_names = {{TRANSLATABLE("DisplayCropMode", "None"),
-                                                                        TRANSLATABLE("DisplayCropMode", "Only Overscan Area"),
-                                                                        TRANSLATABLE("DisplayCropMode", "All Borders")}};
+static std::array<const char*, 3> s_display_crop_mode_display_names = {
+  {TRANSLATABLE("DisplayCropMode", "None"), TRANSLATABLE("DisplayCropMode", "Only Overscan Area"),
+   TRANSLATABLE("DisplayCropMode", "All Borders")}};
 
 std::optional<DisplayCropMode> Settings::ParseDisplayCropMode(const char* str)
 {
@@ -502,8 +504,9 @@ float Settings::GetDisplayAspectRatioValue(DisplayAspectRatio ar)
 }
 
 static std::array<const char*, 3> s_audio_backend_names = {{"Null", "Cubeb", "SDL"}};
-static std::array<const char*, 3> s_audio_backend_display_names = {
-  {TRANSLATABLE("AudioBackend", "Null (No Output)"), TRANSLATABLE("AudioBackend", "Cubeb"), TRANSLATABLE("AudioBackend", "SDL")}};
+static std::array<const char*, 3> s_audio_backend_display_names = {{TRANSLATABLE("AudioBackend", "Null (No Output)"),
+                                                                    TRANSLATABLE("AudioBackend", "Cubeb"),
+                                                                    TRANSLATABLE("AudioBackend", "SDL")}};
 
 std::optional<AudioBackend> Settings::ParseAudioBackend(const char* str)
 {
diff --git a/src/duckstation-libretro/libretro_host_interface.cpp b/src/duckstation-libretro/libretro_host_interface.cpp
index c5b4ad2eb..a8fc3660b 100644
--- a/src/duckstation-libretro/libretro_host_interface.cpp
+++ b/src/duckstation-libretro/libretro_host_interface.cpp
@@ -409,13 +409,13 @@ static std::array<retro_core_option_definition, 31> s_option_definitions = {{
   {"duckstation_GPU.Renderer",
    "GPU Renderer",
    "Which renderer to use to emulate the GPU",
-   {
+   {{"Auto", "Hardware (Auto)"},
 #ifdef WIN32
-     {"D3D11", "Hardware (D3D11)"},
+    {"D3D11", "Hardware (D3D11)"},
 #endif
-     {"OpenGL", "Hardware (OpenGL)"},
-     {"Vulkan", "Hardware (Vulkan)"},
-     {"Software", "Software"}},
+    {"OpenGL", "Hardware (OpenGL)"},
+    {"Vulkan", "Hardware (Vulkan)"},
+    {"Software", "Software"}},
 #ifdef WIN32
    "D3D11"
 #else
@@ -849,32 +849,23 @@ static std::optional<GPURenderer> RenderAPIToRenderer(HostDisplay::RenderAPI api
 
 bool LibretroHostInterface::RequestHardwareRendererContext()
 {
-  GPURenderer renderer = Settings::DEFAULT_GPU_RENDERER;
   retro_variable renderer_variable{"duckstation_GPU.Renderer",
                                    Settings::GetRendererName(Settings::DEFAULT_GPU_RENDERER)};
-  if (g_retro_environment_callback(RETRO_ENVIRONMENT_GET_VARIABLE, &renderer_variable) && renderer_variable.value)
-    renderer = Settings::ParseRendererName(renderer_variable.value).value_or(Settings::DEFAULT_GPU_RENDERER);
-
-  Log_InfoPrintf("Renderer = %s", Settings::GetRendererName(renderer));
+  if (!g_retro_environment_callback(RETRO_ENVIRONMENT_GET_VARIABLE, &renderer_variable) || !renderer_variable.value)
+    renderer_variable.value = Settings::GetRendererName(Settings::DEFAULT_GPU_RENDERER);
 
+  GPURenderer renderer = Settings::ParseRendererName(renderer_variable.value).value_or(Settings::DEFAULT_GPU_RENDERER);
   unsigned preferred_renderer = 0;
-  if (g_retro_environment_callback(RETRO_ENVIRONMENT_GET_PREFERRED_HW_RENDER, &preferred_renderer))
+  g_retro_environment_callback(RETRO_ENVIRONMENT_GET_PREFERRED_HW_RENDER, &preferred_renderer);
+  if (std::strcmp(renderer_variable.value, "Auto") == 0)
   {
     std::optional<GPURenderer> preferred_gpu_renderer =
       RetroHwContextToRenderer(static_cast<retro_hw_context_type>(preferred_renderer));
-    if (!preferred_gpu_renderer.has_value() || preferred_gpu_renderer.value() != renderer)
-    {
-      const char* preferred_name =
-        preferred_gpu_renderer.has_value() ? Settings::GetRendererName(preferred_gpu_renderer.value()) : "Unknown";
-      const char* config_name = Settings::GetRendererName(renderer);
-      renderer = preferred_gpu_renderer.value_or(GPURenderer::Software);
-      ReportFormattedError(
-        "Mismatch between frontend's preferred GPU renderer '%s' and configured renderer '%s'. Please "
-        "change your video driver to '%s'. Using '%s' renderer for now.",
-        preferred_name, config_name, config_name, Settings::GetRendererName(renderer));
-    }
+    if (preferred_gpu_renderer.has_value())
+      renderer = preferred_gpu_renderer.value();
   }
 
+  Log_InfoPrintf("Renderer = %s", Settings::GetRendererName(renderer));
   if (renderer == GPURenderer::Software)
   {
     m_hw_render_callback_valid = false;