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 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(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 {