diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index b23b8fb29..2e90ebcf4 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -681,6 +681,14 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, GLuint program,
         Surface surface = res_cache.GetTextureSurface(texture);
         if (surface != nullptr) {
             state.texture_units[current_bindpoint].texture_2d = surface->texture.handle;
+            state.texture_units[current_bindpoint].swizzle.r =
+                MaxwellToGL::SwizzleSource(texture.tic.x_source);
+            state.texture_units[current_bindpoint].swizzle.g =
+                MaxwellToGL::SwizzleSource(texture.tic.y_source);
+            state.texture_units[current_bindpoint].swizzle.b =
+                MaxwellToGL::SwizzleSource(texture.tic.z_source);
+            state.texture_units[current_bindpoint].swizzle.a =
+                MaxwellToGL::SwizzleSource(texture.tic.w_source);
         } else {
             // Can occur when texture addr is null or its memory is unmapped/invalid
             state.texture_units[current_bindpoint].texture_2d = 0;
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index f91dfe36a..44f0c8a01 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -50,6 +50,10 @@ OpenGLState::OpenGLState() {
     for (auto& texture_unit : texture_units) {
         texture_unit.texture_2d = 0;
         texture_unit.sampler = 0;
+        texture_unit.swizzle.r = GL_RED;
+        texture_unit.swizzle.g = GL_GREEN;
+        texture_unit.swizzle.b = GL_BLUE;
+        texture_unit.swizzle.a = GL_ALPHA;
     }
 
     lighting_lut.texture_buffer = 0;
@@ -200,6 +204,15 @@ void OpenGLState::Apply() const {
         if (texture_units[i].sampler != cur_state.texture_units[i].sampler) {
             glBindSampler(i, texture_units[i].sampler);
         }
+        // Update the texture swizzle
+        if (texture_units[i].swizzle.r != cur_state.texture_units[i].swizzle.r ||
+            texture_units[i].swizzle.g != cur_state.texture_units[i].swizzle.g ||
+            texture_units[i].swizzle.b != cur_state.texture_units[i].swizzle.b ||
+            texture_units[i].swizzle.a != cur_state.texture_units[i].swizzle.a) {
+            std::array<GLint, 4> mask = {texture_units[i].swizzle.r, texture_units[i].swizzle.g,
+                                         texture_units[i].swizzle.b, texture_units[i].swizzle.a};
+            glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, mask.data());
+        }
     }
 
     // Constbuffers
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index 75c08e645..839e50e93 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -85,6 +85,12 @@ public:
     struct {
         GLuint texture_2d; // GL_TEXTURE_BINDING_2D
         GLuint sampler;    // GL_SAMPLER_BINDING
+        struct {
+            GLint r; // GL_TEXTURE_SWIZZLE_R
+            GLint g; // GL_TEXTURE_SWIZZLE_G
+            GLint b; // GL_TEXTURE_SWIZZLE_B
+            GLint a; // GL_TEXTURE_SWIZZLE_A
+        } swizzle;
     } texture_units[32];
 
     struct {
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h
index cf11983cf..2155fb019 100644
--- a/src/video_core/renderer_opengl/maxwell_to_gl.h
+++ b/src/video_core/renderer_opengl/maxwell_to_gl.h
@@ -180,4 +180,25 @@ inline GLenum BlendFunc(Maxwell::Blend::Factor factor) {
     return {};
 }
 
+inline GLenum SwizzleSource(Tegra::Texture::SwizzleSource source) {
+    switch (source) {
+    case Tegra::Texture::SwizzleSource::Zero:
+        return GL_ZERO;
+    case Tegra::Texture::SwizzleSource::R:
+        return GL_RED;
+    case Tegra::Texture::SwizzleSource::G:
+        return GL_GREEN;
+    case Tegra::Texture::SwizzleSource::B:
+        return GL_BLUE;
+    case Tegra::Texture::SwizzleSource::A:
+        return GL_ALPHA;
+    case Tegra::Texture::SwizzleSource::OneInt:
+    case Tegra::Texture::SwizzleSource::OneFloat:
+        return GL_ONE;
+    }
+    NGLOG_CRITICAL(Render_OpenGL, "Unimplemented swizzle source={}", static_cast<u32>(source));
+    UNREACHABLE();
+    return {};
+}
+
 } // namespace MaxwellToGL
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 3440d2190..f33766bfd 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -316,6 +316,7 @@ void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x,
     }};
 
     state.texture_units[0].texture_2d = screen_info.display_texture;
+    state.texture_units[0].swizzle = {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA};
     state.Apply();
 
     glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices.data());
diff --git a/src/video_core/textures/texture.h b/src/video_core/textures/texture.h
index f48ca30b8..a17eaf19d 100644
--- a/src/video_core/textures/texture.h
+++ b/src/video_core/textures/texture.h
@@ -122,6 +122,17 @@ enum class ComponentType : u32 {
     FLOAT = 7
 };
 
+enum class SwizzleSource : u32 {
+    Zero = 0,
+
+    R = 2,
+    G = 3,
+    B = 4,
+    A = 5,
+    OneInt = 6,
+    OneFloat = 7,
+};
+
 union TextureHandle {
     u32 raw;
     BitField<0, 20, u32> tic_id;
@@ -139,6 +150,11 @@ struct TICEntry {
         BitField<10, 3, ComponentType> g_type;
         BitField<13, 3, ComponentType> b_type;
         BitField<16, 3, ComponentType> a_type;
+
+        BitField<19, 3, SwizzleSource> x_source;
+        BitField<22, 3, SwizzleSource> y_source;
+        BitField<25, 3, SwizzleSource> z_source;
+        BitField<28, 3, SwizzleSource> w_source;
     };
     u32 address_low;
     union {