diff --git a/Source/Android/jni/MainAndroid.cpp b/Source/Android/jni/MainAndroid.cpp
index 7e3da54b25..5e12fffa57 100644
--- a/Source/Android/jni/MainAndroid.cpp
+++ b/Source/Android/jni/MainAndroid.cpp
@@ -747,35 +747,21 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceChang
   if (surf == nullptr)
     __android_log_print(ANDROID_LOG_ERROR, DOLPHIN_TAG, "Error: Surface is null.");
 
-  // If GLInterface isn't a thing yet then we don't need to let it know that the
-  // surface has changed
-  if (GLInterface)
-  {
-    GLInterface->UpdateHandle(surf);
-    Renderer::s_ChangedSurface.Reset();
-    Renderer::s_SurfaceNeedsChanged.Set();
-    Renderer::s_ChangedSurface.Wait();
-  }
+  if (g_renderer)
+    g_renderer->ChangeSurface(surf);
 }
 
 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceDestroyed(JNIEnv* env,
                                                                                      jobject obj)
 {
+  if (g_renderer)
+    g_renderer->ChangeSurface(nullptr);
+
   if (surf)
   {
     ANativeWindow_release(surf);
     surf = nullptr;
   }
-
-  // If GLInterface isn't a thing yet then we don't need to let it know that the
-  // surface has changed
-  if (GLInterface)
-  {
-    GLInterface->UpdateHandle(nullptr);
-    Renderer::s_ChangedSurface.Reset();
-    Renderer::s_SurfaceNeedsChanged.Set();
-    Renderer::s_ChangedSurface.Wait();
-  }
 }
 JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_RefreshWiimotes(JNIEnv* env,
                                                                                     jobject obj)
diff --git a/Source/Core/DolphinWX/FrameTools.cpp b/Source/Core/DolphinWX/FrameTools.cpp
index 55e31075d6..2b690c0e5a 100644
--- a/Source/Core/DolphinWX/FrameTools.cpp
+++ b/Source/Core/DolphinWX/FrameTools.cpp
@@ -77,6 +77,7 @@
 
 #include "InputCommon/ControllerInterface/ControllerInterface.h"
 
+#include "VideoCommon/RenderBase.h"
 #include "VideoCommon/VideoBackendBase.h"
 #include "VideoCommon/VideoConfig.h"
 
@@ -907,6 +908,12 @@ void CFrame::OnRenderParentResize(wxSizeEvent& event)
     }
     m_LogWindow->Refresh();
     m_LogWindow->Update();
+
+    // We call Renderer::ChangeSurface here to indicate the size has changed,
+    // but pass the same window handle. This is needed for the Vulkan backend,
+    // otherwise it cannot tell that the window has been resized on some drivers.
+    if (g_renderer)
+      g_renderer->ChangeSurface(GetRenderHandle());
   }
   event.Skip();
 }
diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp
index 3fb9ebb755..c1e8165b9b 100644
--- a/Source/Core/VideoBackends/OGL/Render.cpp
+++ b/Source/Core/VideoBackends/OGL/Render.cpp
@@ -1620,12 +1620,16 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight,
   OSD::DoCallbacks(OSD::CallbackType::OnFrame);
   OSD::DrawMessages();
 
-  if (s_SurfaceNeedsChanged.IsSet())
+#ifdef ANDROID
+  if (s_surface_needs_change.IsSet())
   {
+    GLInterface->UpdateHandle(s_new_surface_handle);
     GLInterface->UpdateSurface();
-    s_SurfaceNeedsChanged.Clear();
-    s_ChangedSurface.Set();
+    s_new_surface_handle = nullptr;
+    s_surface_needs_change.Clear();
+    s_surface_changed.Set();
   }
+#endif
 
   // Copy the rendered frame to the real window
   GLInterface->Swap();
@@ -1814,4 +1818,16 @@ int Renderer::GetMaxTextureSize()
     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &s_max_texture_size);
   return s_max_texture_size;
 }
+
+void Renderer::ChangeSurface(void* new_surface_handle)
+{
+// Win32 polls the window size when redrawing, X11 runs an event loop in another thread.
+// This is only necessary for Android at this point, although handling resizes here
+// would be more efficient than polling.
+#ifdef ANDROID
+  s_new_surface_handle = new_surface_handle;
+  s_surface_needs_change.Set();
+  s_surface_changed.Wait();
+#endif
+}
 }
diff --git a/Source/Core/VideoBackends/OGL/Render.h b/Source/Core/VideoBackends/OGL/Render.h
index c240a936d3..57611f6856 100644
--- a/Source/Core/VideoBackends/OGL/Render.h
+++ b/Source/Core/VideoBackends/OGL/Render.h
@@ -105,6 +105,8 @@ public:
 
   int GetMaxTextureSize() override;
 
+  void ChangeSurface(void* new_surface_handle) override;
+
 private:
   void UpdateEFBCache(EFBAccessType type, u32 cacheRectIdx, const EFBRectangle& efbPixelRc,
                       const TargetRectangle& targetPixelRc, const void* data);
diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp
index 3b50cd2313..8fb77a341f 100644
--- a/Source/Core/VideoCommon/RenderBase.cpp
+++ b/Source/Core/VideoCommon/RenderBase.cpp
@@ -60,10 +60,6 @@ Common::Event Renderer::s_screenshotCompleted;
 
 volatile bool Renderer::s_bScreenshot;
 
-// Final surface changing
-Common::Flag Renderer::s_SurfaceNeedsChanged;
-Common::Event Renderer::s_ChangedSurface;
-
 // The framebuffer size
 int Renderer::s_target_width;
 int Renderer::s_target_height;
@@ -74,6 +70,11 @@ int Renderer::s_backbuffer_height;
 
 std::unique_ptr<PostProcessingShaderImplementation> Renderer::m_post_processor;
 
+// Final surface changing
+Common::Flag Renderer::s_surface_needs_change;
+Common::Event Renderer::s_surface_changed;
+void* Renderer::s_new_surface_handle;
+
 TargetRectangle Renderer::target_rc;
 
 int Renderer::s_last_efb_scale;
diff --git a/Source/Core/VideoCommon/RenderBase.h b/Source/Core/VideoCommon/RenderBase.h
index 1ae3121637..44a0b982b7 100644
--- a/Source/Core/VideoCommon/RenderBase.h
+++ b/Source/Core/VideoCommon/RenderBase.h
@@ -138,9 +138,8 @@ public:
   static Common::Event s_screenshotCompleted;
 
   // Final surface changing
-  static Common::Flag s_SurfaceNeedsChanged;
-  static Common::Event s_ChangedSurface;
-
+  // This is called when the surface is resized (WX) or the window changes (Android).
+  virtual void ChangeSurface(void* new_surface_handle) {}
 protected:
   static void CalculateTargetScale(int x, int y, int* scaledX, int* scaledY);
   bool CalculateTargetSize(unsigned int framebuffer_width, unsigned int framebuffer_height);
@@ -178,6 +177,10 @@ protected:
 
   static const float GX_MAX_DEPTH;
 
+  static Common::Flag s_surface_needs_change;
+  static Common::Event s_surface_changed;
+  static void* s_new_surface_handle;
+
 private:
   static PEControl::PixelFormat prev_efb_format;
   static unsigned int efb_scale_numeratorX;