diff --git a/src/core/hw/gpu.h b/src/core/hw/gpu.h
index 7c3a17ee5..9fd694f65 100644
--- a/src/core/hw/gpu.h
+++ b/src/core/hw/gpu.h
@@ -53,6 +53,7 @@ struct Regs {
                   "Structure size and register block length don't match")
 #endif
 
+    // All of those formats are described in reverse byte order, since the 3DS is little-endian.
     enum class PixelFormat : u32 {
         RGBA8  = 0,
         RGB8   = 1,
@@ -61,6 +62,24 @@ struct Regs {
         RGBA4  = 4,
     };
 
+    /**
+     * Returns the number of bytes per pixel.
+     */
+    static int BytesPerPixel(PixelFormat format) {
+        switch (format) {
+        case PixelFormat::RGBA8:
+            return 4;
+        case PixelFormat::RGB8:
+            return 3;
+        case PixelFormat::RGB565:
+        case PixelFormat::RGB5A1:
+        case PixelFormat::RGBA4:
+            return 2;
+        default:
+            UNIMPLEMENTED();
+        }
+    }
+
     INSERT_PADDING_WORDS(0x4);
 
     struct {
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 735c0cf45..272695174 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -61,15 +61,13 @@ void RendererOpenGL::SwapBuffers() {
     for(int i : {0, 1}) {
         const auto& framebuffer = GPU::g_regs.framebuffer_config[i];
 
-        if (textures[i].width != (GLsizei)framebuffer.width || textures[i].height != (GLsizei)framebuffer.height) {
+        if (textures[i].width != (GLsizei)framebuffer.width ||
+            textures[i].height != (GLsizei)framebuffer.height ||
+            textures[i].format != framebuffer.color_format) {
             // Reallocate texture if the framebuffer size has changed.
             // This is expected to not happen very often and hence should not be a
             // performance problem.
-            glBindTexture(GL_TEXTURE_2D, textures[i].handle);
-            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, framebuffer.width, framebuffer.height, 0,
-                GL_BGR, GL_UNSIGNED_BYTE, nullptr);
-            textures[i].width = framebuffer.width;
-            textures[i].height = framebuffer.height;
+            ConfigureFramebufferTexture(textures[i], framebuffer);
         }
 
         LoadFBToActiveGLTexture(GPU::g_regs.framebuffer_config[i], textures[i]);
@@ -98,13 +96,12 @@ void RendererOpenGL::LoadFBToActiveGLTexture(const GPU::Regs::FramebufferConfig&
 
     const u8* framebuffer_data = Memory::GetPointer(framebuffer_vaddr);
 
-    // TODO: Handle other pixel formats
-    ASSERT_MSG(framebuffer.color_format == GPU::Regs::PixelFormat::RGB8,
-                     "Unsupported 3DS pixel format.");
+    int bpp = GPU::Regs::BytesPerPixel(framebuffer.color_format);
+    size_t pixel_stride = framebuffer.stride / bpp;
 
-    size_t pixel_stride = framebuffer.stride / 3;
     // OpenGL only supports specifying a stride in units of pixels, not bytes, unfortunately
-    ASSERT(pixel_stride * 3 == framebuffer.stride);
+    ASSERT(pixel_stride * bpp == framebuffer.stride);
+
     // Ensure no bad interactions with GL_UNPACK_ALIGNMENT, which by default
     // only allows rows to have a memory alignement of 4.
     ASSERT(pixel_stride % 4 == 0);
@@ -118,7 +115,7 @@ void RendererOpenGL::LoadFBToActiveGLTexture(const GPU::Regs::FramebufferConfig&
     // TODO: Applications could theoretically crash Citra here by specifying too large
     //       framebuffer sizes. We should make sure that this cannot happen.
     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, framebuffer.width, framebuffer.height,
-        GL_BGR, GL_UNSIGNED_BYTE, framebuffer_data);
+        texture.gl_format, texture.gl_type, framebuffer_data);
 
     glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
 
@@ -171,6 +168,59 @@ void RendererOpenGL::InitOpenGLObjects() {
     glBindTexture(GL_TEXTURE_2D, 0);
 }
 
+void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
+                                                 const GPU::Regs::FramebufferConfig& framebuffer) {
+    GPU::Regs::PixelFormat format = framebuffer.color_format;
+    GLint internal_format;
+
+    texture.format = format;
+    texture.width = framebuffer.width;
+    texture.height = framebuffer.height;
+
+    switch (format) {
+    case GPU::Regs::PixelFormat::RGBA8:
+        internal_format = GL_RGBA;
+        texture.gl_format = GL_RGBA;
+        texture.gl_type = GL_UNSIGNED_INT_8_8_8_8;
+        break;
+
+    case GPU::Regs::PixelFormat::RGB8:
+        // This pixel format uses BGR since GL_UNSIGNED_BYTE specifies byte-order, unlike every
+        // specific OpenGL type used in this function using native-endian (that is, little-endian
+        // mostly everywhere) for words or half-words.
+        // TODO: check how those behave on big-endian processors.
+        internal_format = GL_RGB;
+        texture.gl_format = GL_BGR;
+        texture.gl_type = GL_UNSIGNED_BYTE;
+        break;
+
+    case GPU::Regs::PixelFormat::RGB565:
+        internal_format = GL_RGB;
+        texture.gl_format = GL_RGB;
+        texture.gl_type = GL_UNSIGNED_SHORT_5_6_5;
+        break;
+
+    case GPU::Regs::PixelFormat::RGB5A1:
+        internal_format = GL_RGBA;
+        texture.gl_format = GL_RGBA;
+        texture.gl_type = GL_UNSIGNED_SHORT_5_5_5_1;
+        break;
+
+    case GPU::Regs::PixelFormat::RGBA4:
+        internal_format = GL_RGBA;
+        texture.gl_format = GL_RGBA;
+        texture.gl_type = GL_UNSIGNED_SHORT_4_4_4_4;
+        break;
+
+    default:
+        UNIMPLEMENTED();
+    }
+
+    glBindTexture(GL_TEXTURE_2D, texture.handle);
+    glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.width, texture.height, 0,
+            texture.gl_format, texture.gl_type, nullptr);
+}
+
 /**
  * Draws a single texture to the emulator window, rotating the texture to correct for the 3DS's LCD rotation.
  */
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h
index cf78c1e77..bcabab557 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.h
+++ b/src/video_core/renderer_opengl/renderer_opengl.h
@@ -43,9 +43,14 @@ private:
         GLuint handle;
         GLsizei width;
         GLsizei height;
+        GPU::Regs::PixelFormat format;
+        GLenum gl_format;
+        GLenum gl_type;
     };
 
     void InitOpenGLObjects();
+    static void ConfigureFramebufferTexture(TextureInfo& texture,
+                                            const GPU::Regs::FramebufferConfig& framebuffer);
     void DrawScreens();
     void DrawSingleScreenRotated(const TextureInfo& texture, float x, float y, float w, float h);
     void UpdateFramerate();