Просмотр исходного кода

Merge pull request #314 from jroweboy/tegra-progress-3b

GPU: Bind uploaded textures when drawing (Rebased)
bunnei 8 лет назад
Родитель
Сommit
227bc78cbe

+ 2 - 0
src/video_core/engines/maxwell_3d.cpp

@@ -231,6 +231,8 @@ Texture::TICEntry Maxwell3D::GetTICEntry(u32 tic_index) const {
 
 
     // TODO(Subv): Different data types for separate components are not supported
     // TODO(Subv): Different data types for separate components are not supported
     ASSERT(r_type == g_type && r_type == b_type && r_type == a_type);
     ASSERT(r_type == g_type && r_type == b_type && r_type == a_type);
+    // TODO(Subv): Only UNORM formats are supported for now.
+    ASSERT(r_type == Texture::ComponentType::UNORM);
 
 
     return tic_entry;
     return tic_entry;
 }
 }

+ 91 - 3
src/video_core/renderer_opengl/gl_rasterizer.cpp

@@ -66,6 +66,12 @@ RasterizerOpenGL::RasterizerOpenGL() {
     has_ARB_separate_shader_objects = false;
     has_ARB_separate_shader_objects = false;
     has_ARB_vertex_attrib_binding = false;
     has_ARB_vertex_attrib_binding = false;
 
 
+    // Create sampler objects
+    for (size_t i = 0; i < texture_samplers.size(); ++i) {
+        texture_samplers[i].Create();
+        state.texture_units[i].sampler = texture_samplers[i].sampler.handle;
+    }
+
     GLint ext_num;
     GLint ext_num;
     glGetIntegerv(GL_NUM_EXTENSIONS, &ext_num);
     glGetIntegerv(GL_NUM_EXTENSIONS, &ext_num);
     for (GLint i = 0; i < ext_num; i++) {
     for (GLint i = 0; i < ext_num; i++) {
@@ -270,7 +276,9 @@ void RasterizerOpenGL::DrawArrays() {
 
 
     // TODO(bunnei): Sync framebuffer_scale uniform here
     // TODO(bunnei): Sync framebuffer_scale uniform here
     // TODO(bunnei): Sync scissorbox uniform(s) here
     // TODO(bunnei): Sync scissorbox uniform(s) here
-    // TODO(bunnei): Sync and bind the texture surfaces
+
+    // Sync and bind the texture surfaces
+    BindTextures();
 
 
     // Sync and bind the shader
     // Sync and bind the shader
     if (shader_dirty) {
     if (shader_dirty) {
@@ -374,6 +382,39 @@ void RasterizerOpenGL::DrawArrays() {
     }
     }
 }
 }
 
 
+void RasterizerOpenGL::BindTextures() {
+    using Regs = Tegra::Engines::Maxwell3D::Regs;
+    auto maxwell3d = Core::System::GetInstance().GPU().Get3DEngine();
+
+    // Each Maxwell shader stage can have an arbitrary number of textures, but we're limited to a
+    // certain number in OpenGL. We try to only use the minimum amount of host textures by not
+    // keeping a 1:1 relation between guest texture ids and host texture ids, ie, guest texture id 8
+    // can be host texture id 0 if it's the only texture used in the guest shader program.
+    u32 host_texture_index = 0;
+    for (u32 stage = 0; stage < Regs::MaxShaderStage; ++stage) {
+        ASSERT(host_texture_index < texture_samplers.size());
+        const auto textures = maxwell3d.GetStageTextures(static_cast<Regs::ShaderStage>(stage));
+        for (unsigned texture_index = 0; texture_index < textures.size(); ++texture_index) {
+            const auto& texture = textures[texture_index];
+
+            if (texture.enabled) {
+                texture_samplers[host_texture_index].SyncWithConfig(texture.tsc);
+                Surface surface = res_cache.GetTextureSurface(texture);
+                if (surface != nullptr) {
+                    state.texture_units[host_texture_index].texture_2d = surface->texture.handle;
+                } else {
+                    // Can occur when texture addr is null or its memory is unmapped/invalid
+                    state.texture_units[texture_index].texture_2d = 0;
+                }
+
+                ++host_texture_index;
+            } else {
+                state.texture_units[texture_index].texture_2d = 0;
+            }
+        }
+    }
+}
+
 void RasterizerOpenGL::NotifyMaxwellRegisterChanged(u32 id) {}
 void RasterizerOpenGL::NotifyMaxwellRegisterChanged(u32 id) {}
 
 
 void RasterizerOpenGL::FlushAll() {
 void RasterizerOpenGL::FlushAll() {
@@ -452,6 +493,44 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& framebu
     return true;
     return true;
 }
 }
 
 
+void RasterizerOpenGL::SamplerInfo::Create() {
+    sampler.Create();
+    mag_filter = min_filter = Tegra::Texture::TextureFilter::Linear;
+    wrap_u = wrap_v = Tegra::Texture::WrapMode::Wrap;
+    border_color_r = border_color_g = border_color_b = border_color_a = 0;
+
+    // default is GL_LINEAR_MIPMAP_LINEAR
+    glSamplerParameteri(sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    // Other attributes have correct defaults
+}
+
+void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntry& config) {
+    GLuint s = sampler.handle;
+
+    if (mag_filter != config.mag_filter) {
+        mag_filter = config.mag_filter;
+        glSamplerParameteri(s, GL_TEXTURE_MAG_FILTER, MaxwellToGL::TextureFilterMode(mag_filter));
+    }
+    if (min_filter != config.min_filter) {
+        min_filter = config.min_filter;
+        glSamplerParameteri(s, GL_TEXTURE_MIN_FILTER, MaxwellToGL::TextureFilterMode(min_filter));
+    }
+
+    if (wrap_u != config.wrap_u) {
+        wrap_u = config.wrap_u;
+        glSamplerParameteri(s, GL_TEXTURE_WRAP_S, MaxwellToGL::WrapMode(wrap_u));
+    }
+    if (wrap_v != config.wrap_v) {
+        wrap_v = config.wrap_v;
+        glSamplerParameteri(s, GL_TEXTURE_WRAP_T, MaxwellToGL::WrapMode(wrap_v));
+    }
+
+    if (wrap_u == Tegra::Texture::WrapMode::Border || wrap_v == Tegra::Texture::WrapMode::Border) {
+        // TODO(Subv): Implement border color
+        ASSERT(false);
+    }
+}
+
 void RasterizerOpenGL::SetShader() {
 void RasterizerOpenGL::SetShader() {
     // TODO(bunnei): The below sets up a static test shader for passing untransformed vertices to
     // TODO(bunnei): The below sets up a static test shader for passing untransformed vertices to
     // OpenGL for rendering. This should be removed/replaced when we start emulating Maxwell
     // OpenGL for rendering. This should be removed/replaced when we start emulating Maxwell
@@ -479,10 +558,10 @@ void main() {
 in vec2 frag_tex_coord;
 in vec2 frag_tex_coord;
 out vec4 color;
 out vec4 color;
 
 
-uniform sampler2D color_texture;
+uniform sampler2D tex[32];
 
 
 void main() {
 void main() {
-    color = vec4(1.0, 0.0, 1.0, 0.0);
+    color = texture(tex[0], frag_tex_coord);
 }
 }
 )";
 )";
 
 
@@ -503,6 +582,15 @@ void main() {
     state.draw.shader_program = test_shader.shader.handle;
     state.draw.shader_program = test_shader.shader.handle;
     state.Apply();
     state.Apply();
 
 
+    for (u32 texture = 0; texture < texture_samplers.size(); ++texture) {
+        // Set the texture samplers to correspond to different texture units
+        std::string uniform_name = "tex[" + std::to_string(texture) + "]";
+        GLint uniform_tex = glGetUniformLocation(test_shader.shader.handle, uniform_name.c_str());
+        if (uniform_tex != -1) {
+            glUniform1i(uniform_tex, TextureUnits::MaxwellTexture(texture).id);
+        }
+    }
+
     if (has_ARB_separate_shader_objects) {
     if (has_ARB_separate_shader_objects) {
         state.draw.shader_program = 0;
         state.draw.shader_program = 0;
         state.Apply();
         state.Apply();

+ 23 - 1
src/video_core/renderer_opengl/gl_rasterizer.h

@@ -85,12 +85,34 @@ public:
                   "FSUniformData structure must be less than 16kb as per the OpenGL spec");
                   "FSUniformData structure must be less than 16kb as per the OpenGL spec");
 
 
 private:
 private:
-    struct SamplerInfo {};
+    class SamplerInfo {
+    public:
+        OGLSampler sampler;
+
+        /// Creates the sampler object, initializing its state so that it's in sync with the
+        /// SamplerInfo struct.
+        void Create();
+        /// Syncs the sampler object with the config, updating any necessary state.
+        void SyncWithConfig(const Tegra::Texture::TSCEntry& config);
+
+    private:
+        Tegra::Texture::TextureFilter mag_filter;
+        Tegra::Texture::TextureFilter min_filter;
+        Tegra::Texture::WrapMode wrap_u;
+        Tegra::Texture::WrapMode wrap_v;
+        u32 border_color_r;
+        u32 border_color_g;
+        u32 border_color_b;
+        u32 border_color_a;
+    };
 
 
     /// Binds the framebuffer color and depth surface
     /// Binds the framebuffer color and depth surface
     void BindFramebufferSurfaces(const Surface& color_surface, const Surface& depth_surface,
     void BindFramebufferSurfaces(const Surface& color_surface, const Surface& depth_surface,
                                  bool has_stencil);
                                  bool has_stencil);
 
 
+    /// Binds the required textures to OpenGL before drawing a batch.
+    void BindTextures();
+
     /// Syncs the viewport to match the guest state
     /// Syncs the viewport to match the guest state
     void SyncViewport(const MathUtil::Rectangle<u32>& surfaces_rect, u16 res_scale);
     void SyncViewport(const MathUtil::Rectangle<u32>& surfaces_rect, u16 res_scale);
 
 

+ 84 - 104
src/video_core/renderer_opengl/gl_rasterizer_cache.cpp

@@ -30,6 +30,7 @@
 #include "video_core/engines/maxwell_3d.h"
 #include "video_core/engines/maxwell_3d.h"
 #include "video_core/renderer_opengl/gl_rasterizer_cache.h"
 #include "video_core/renderer_opengl/gl_rasterizer_cache.h"
 #include "video_core/renderer_opengl/gl_state.h"
 #include "video_core/renderer_opengl/gl_state.h"
+#include "video_core/textures/decoders.h"
 #include "video_core/utils.h"
 #include "video_core/utils.h"
 #include "video_core/video_core.h"
 #include "video_core/video_core.h"
 
 
@@ -40,36 +41,36 @@ struct FormatTuple {
     GLint internal_format;
     GLint internal_format;
     GLenum format;
     GLenum format;
     GLenum type;
     GLenum type;
+    bool compressed;
+    // How many pixels in the original texture are equivalent to one pixel in the compressed
+    // texture.
+    u32 compression_factor;
 };
 };
 
 
-static constexpr std::array<FormatTuple, 5> fb_format_tuples = {{
-    {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8},     // RGBA8
-    {GL_RGB8, GL_BGR, GL_UNSIGNED_BYTE},              // RGB8
-    {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1}, // RGB5A1
-    {GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5},     // RGB565
-    {GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4},   // RGBA4
+static constexpr std::array<FormatTuple, 1> fb_format_tuples = {{
+    {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, false, 1}, // RGBA8
 }};
 }};
 
 
-static constexpr std::array<FormatTuple, 4> depth_format_tuples = {{
-    {GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}, // D16
-    {},
-    {GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT},   // D24
-    {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}, // D24S8
+static constexpr std::array<FormatTuple, 2> tex_format_tuples = {{
+    {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, false, 1},                       // RGBA8
+    {GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, true, 16}, // DXT1
 }};
 }};
 
 
-static constexpr FormatTuple tex_tuple = {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE};
-
 static const FormatTuple& GetFormatTuple(PixelFormat pixel_format) {
 static const FormatTuple& GetFormatTuple(PixelFormat pixel_format) {
     const SurfaceType type = SurfaceParams::GetFormatType(pixel_format);
     const SurfaceType type = SurfaceParams::GetFormatType(pixel_format);
     if (type == SurfaceType::Color) {
     if (type == SurfaceType::Color) {
         ASSERT(static_cast<size_t>(pixel_format) < fb_format_tuples.size());
         ASSERT(static_cast<size_t>(pixel_format) < fb_format_tuples.size());
         return fb_format_tuples[static_cast<unsigned int>(pixel_format)];
         return fb_format_tuples[static_cast<unsigned int>(pixel_format)];
     } else if (type == SurfaceType::Depth || type == SurfaceType::DepthStencil) {
     } else if (type == SurfaceType::Depth || type == SurfaceType::DepthStencil) {
-        size_t tuple_idx = static_cast<size_t>(pixel_format) - 14;
-        ASSERT(tuple_idx < depth_format_tuples.size());
-        return depth_format_tuples[tuple_idx];
+        // TODO(Subv): Implement depth formats
+        ASSERT_MSG(false, "Unimplemented");
+    } else if (type == SurfaceType::Texture) {
+        ASSERT(static_cast<size_t>(pixel_format) < tex_format_tuples.size());
+        return tex_format_tuples[static_cast<unsigned int>(pixel_format)];
     }
     }
-    return tex_tuple;
+
+    UNREACHABLE();
+    return {};
 }
 }
 
 
 template <typename Map, typename Interval>
 template <typename Map, typename Interval>
@@ -92,26 +93,16 @@ static void MortonCopyTile(u32 stride, u8* tile_buffer, u8* gl_buffer) {
             u8* tile_ptr = tile_buffer + VideoCore::MortonInterleave(x, y) * bytes_per_pixel;
             u8* tile_ptr = tile_buffer + VideoCore::MortonInterleave(x, y) * bytes_per_pixel;
             u8* gl_ptr = gl_buffer + ((7 - y) * stride + x) * gl_bytes_per_pixel;
             u8* gl_ptr = gl_buffer + ((7 - y) * stride + x) * gl_bytes_per_pixel;
             if (morton_to_gl) {
             if (morton_to_gl) {
-                if (format == PixelFormat::D24S8) {
-                    gl_ptr[0] = tile_ptr[3];
-                    std::memcpy(gl_ptr + 1, tile_ptr, 3);
-                } else {
-                    std::memcpy(gl_ptr, tile_ptr, bytes_per_pixel);
-                }
+                std::memcpy(gl_ptr, tile_ptr, bytes_per_pixel);
             } else {
             } else {
-                if (format == PixelFormat::D24S8) {
-                    std::memcpy(tile_ptr, gl_ptr + 1, 3);
-                    tile_ptr[3] = gl_ptr[0];
-                } else {
-                    std::memcpy(tile_ptr, gl_ptr, bytes_per_pixel);
-                }
+                std::memcpy(tile_ptr, gl_ptr, bytes_per_pixel);
             }
             }
         }
         }
     }
     }
 }
 }
 
 
 template <bool morton_to_gl, PixelFormat format>
 template <bool morton_to_gl, PixelFormat format>
-static void MortonCopy(u32 stride, u32 height, u8* gl_buffer, VAddr base, VAddr start, VAddr end) {
+void MortonCopy(u32 stride, u32 height, u8* gl_buffer, VAddr base, VAddr start, VAddr end) {
     constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / 8;
     constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / 8;
     constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format);
     constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format);
 
 
@@ -122,46 +113,28 @@ static void MortonCopy(u32 stride, u32 height, u8* gl_buffer, VAddr base, VAddr
                                    Memory::GetPointer(base), gl_buffer, morton_to_gl);
                                    Memory::GetPointer(base), gl_buffer, morton_to_gl);
 }
 }
 
 
-static constexpr std::array<void (*)(u32, u32, u8*, VAddr, VAddr, VAddr), 18> morton_to_gl_fns = {
+template <>
+void MortonCopy<true, PixelFormat::DXT1>(u32 stride, u32 height, u8* gl_buffer, VAddr base,
+                                         VAddr start, VAddr end) {
+    constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(PixelFormat::DXT1) / 8;
+    constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(PixelFormat::DXT1);
+
+    // TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should check the
+    // configuration for this and perform more generic un/swizzle
+    LOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!");
+    auto data =
+        Tegra::Texture::UnswizzleTexture(base, Tegra::Texture::TextureFormat::DXT1, stride, height);
+    std::memcpy(gl_buffer, data.data(), data.size());
+}
+
+static constexpr std::array<void (*)(u32, u32, u8*, VAddr, VAddr, VAddr), 2> morton_to_gl_fns = {
     MortonCopy<true, PixelFormat::RGBA8>,
     MortonCopy<true, PixelFormat::RGBA8>,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
+    MortonCopy<true, PixelFormat::DXT1>,
 };
 };
 
 
-static constexpr std::array<void (*)(u32, u32, u8*, VAddr, VAddr, VAddr), 18> gl_to_morton_fns = {
+static constexpr std::array<void (*)(u32, u32, u8*, VAddr, VAddr, VAddr), 2> gl_to_morton_fns = {
     MortonCopy<false, PixelFormat::RGBA8>,
     MortonCopy<false, PixelFormat::RGBA8>,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
+    MortonCopy<false, PixelFormat::DXT1>,
 };
 };
 
 
 // Allocate an uninitialized texture of appropriate size and format for the surface
 // Allocate an uninitialized texture of appropriate size and format for the surface
@@ -175,8 +148,11 @@ static void AllocateSurfaceTexture(GLuint texture, const FormatTuple& format_tup
     cur_state.Apply();
     cur_state.Apply();
     glActiveTexture(GL_TEXTURE0);
     glActiveTexture(GL_TEXTURE0);
 
 
-    glTexImage2D(GL_TEXTURE_2D, 0, format_tuple.internal_format, width, height, 0,
-                 format_tuple.format, format_tuple.type, nullptr);
+    if (!format_tuple.compressed) {
+        // Only pre-create the texture for non-compressed textures.
+        glTexImage2D(GL_TEXTURE_2D, 0, format_tuple.internal_format, width, height, 0,
+                     format_tuple.format, format_tuple.type, nullptr);
+    }
 
 
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@@ -606,9 +582,18 @@ void CachedSurface::UploadGLTexture(const MathUtil::Rectangle<u32>& rect, GLuint
     glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(stride));
     glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(stride));
 
 
     glActiveTexture(GL_TEXTURE0);
     glActiveTexture(GL_TEXTURE0);
-    glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, static_cast<GLsizei>(rect.GetWidth()),
-                    static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type,
-                    &gl_buffer[buffer_offset]);
+    if (tuple.compressed) {
+        glCompressedTexImage2D(GL_TEXTURE_2D, 0, tuple.internal_format,
+                               static_cast<GLsizei>(rect.GetWidth()),
+                               static_cast<GLsizei>(rect.GetHeight()), 0,
+                               rect.GetWidth() * rect.GetHeight() *
+                                   GetGLBytesPerPixel(pixel_format) / tuple.compression_factor,
+                               &gl_buffer[buffer_offset]);
+    } else {
+        glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, static_cast<GLsizei>(rect.GetWidth()),
+                        static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type,
+                        &gl_buffer[buffer_offset]);
+    }
 
 
     glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
     glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
 
 
@@ -954,15 +939,6 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, ScaleMatc
             if (expandable != nullptr && expandable->res_scale > target_res_scale) {
             if (expandable != nullptr && expandable->res_scale > target_res_scale) {
                 target_res_scale = expandable->res_scale;
                 target_res_scale = expandable->res_scale;
             }
             }
-            // Keep res_scale when reinterpreting d24s8 -> rgba8
-            if (params.pixel_format == PixelFormat::RGBA8) {
-                find_params.pixel_format = PixelFormat::D24S8;
-                expandable = FindMatch<MatchFlags::Expand | MatchFlags::Invalid>(
-                    surface_cache, find_params, match_res_scale);
-                if (expandable != nullptr && expandable->res_scale > target_res_scale) {
-                    target_res_scale = expandable->res_scale;
-                }
-            }
         }
         }
         SurfaceParams new_params = params;
         SurfaceParams new_params = params;
         new_params.res_scale = target_res_scale;
         new_params.res_scale = target_res_scale;
@@ -1056,9 +1032,34 @@ SurfaceRect_Tuple RasterizerCacheOpenGL::GetSurfaceSubRect(const SurfaceParams&
     return std::make_tuple(surface, surface->GetScaledSubRect(params));
     return std::make_tuple(surface, surface->GetScaledSubRect(params));
 }
 }
 
 
-Surface RasterizerCacheOpenGL::GetTextureSurface(const void* config) {
-    UNREACHABLE();
-    return {};
+Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextureInfo& config) {
+    auto& gpu = Core::System::GetInstance().GPU();
+
+    SurfaceParams params;
+    params.addr = gpu.memory_manager->PhysicalToVirtualAddress(config.tic.Address());
+    params.width = config.tic.Width();
+    params.height = config.tic.Height();
+    params.is_tiled = config.tic.IsTiled();
+    params.pixel_format = SurfaceParams::PixelFormatFromTextureFormat(config.tic.format);
+    params.UpdateParams();
+
+    if (config.tic.Width() % 8 != 0 || config.tic.Height() % 8 != 0) {
+        Surface src_surface;
+        MathUtil::Rectangle<u32> rect;
+        std::tie(src_surface, rect) = GetSurfaceSubRect(params, ScaleMatch::Ignore, true);
+
+        params.res_scale = src_surface->res_scale;
+        Surface tmp_surface = CreateSurface(params);
+        BlitTextures(src_surface->texture.handle, rect, tmp_surface->texture.handle,
+                     tmp_surface->GetScaledRect(),
+                     SurfaceParams::GetFormatType(params.pixel_format), read_framebuffer.handle,
+                     draw_framebuffer.handle);
+
+        remove_surfaces.emplace(tmp_surface);
+        return tmp_surface;
+    }
+
+    return GetSurface(params, ScaleMatch::Ignore, true);
 }
 }
 
 
 SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(
 SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(
@@ -1240,27 +1241,6 @@ void RasterizerCacheOpenGL::ValidateSurface(const Surface& surface, VAddr addr,
             continue;
             continue;
         }
         }
 
 
-        // D24S8 to RGBA8
-        if (surface->pixel_format == PixelFormat::RGBA8) {
-            params.pixel_format = PixelFormat::D24S8;
-            Surface reinterpret_surface =
-                FindMatch<MatchFlags::Copy>(surface_cache, params, ScaleMatch::Ignore, interval);
-            if (reinterpret_surface != nullptr) {
-                ASSERT(reinterpret_surface->pixel_format == PixelFormat::D24S8);
-
-                SurfaceInterval convert_interval = params.GetCopyableInterval(reinterpret_surface);
-                SurfaceParams convert_params = surface->FromInterval(convert_interval);
-                auto src_rect = reinterpret_surface->GetScaledSubRect(convert_params);
-                auto dest_rect = surface->GetScaledSubRect(convert_params);
-
-                ConvertD24S8toABGR(reinterpret_surface->texture.handle, src_rect,
-                                   surface->texture.handle, dest_rect);
-
-                surface->invalid_regions.erase(convert_interval);
-                continue;
-            }
-        }
-
         // Load data from Switch memory
         // Load data from Switch memory
         FlushRegion(params.addr, params.size);
         FlushRegion(params.addr, params.size);
         surface->LoadGLBuffer(params.addr, params.end);
         surface->LoadGLBuffer(params.addr, params.end);

+ 30 - 59
src/video_core/renderer_opengl/gl_rasterizer_cache.h

@@ -24,6 +24,7 @@
 #include "common/math_util.h"
 #include "common/math_util.h"
 #include "video_core/gpu.h"
 #include "video_core/gpu.h"
 #include "video_core/renderer_opengl/gl_resource_manager.h"
 #include "video_core/renderer_opengl/gl_resource_manager.h"
+#include "video_core/textures/texture.h"
 
 
 struct CachedSurface;
 struct CachedSurface;
 using Surface = std::shared_ptr<CachedSurface>;
 using Surface = std::shared_ptr<CachedSurface>;
@@ -51,30 +52,8 @@ enum class ScaleMatch {
 
 
 struct SurfaceParams {
 struct SurfaceParams {
     enum class PixelFormat {
     enum class PixelFormat {
-        // First 5 formats are shared between textures and color buffers
         RGBA8 = 0,
         RGBA8 = 0,
-        RGB8 = 1,
-        RGB5A1 = 2,
-        RGB565 = 3,
-        RGBA4 = 4,
-
-        // Texture-only formats
-        IA8 = 5,
-        RG8 = 6,
-        I8 = 7,
-        A8 = 8,
-        IA4 = 9,
-        I4 = 10,
-        A4 = 11,
-        ETC1 = 12,
-        ETC1A4 = 13,
-
-        // Depth buffer-only formats
-        D16 = 14,
-        // gap
-        D24 = 16,
-        D24S8 = 17,
-
+        DXT1 = 1,
         Invalid = 255,
         Invalid = 255,
     };
     };
 
 
@@ -88,28 +67,15 @@ struct SurfaceParams {
     };
     };
 
 
     static constexpr unsigned int GetFormatBpp(PixelFormat format) {
     static constexpr unsigned int GetFormatBpp(PixelFormat format) {
-        constexpr std::array<unsigned int, 18> bpp_table = {
+        if (format == PixelFormat::Invalid)
+            return 0;
+
+        constexpr std::array<unsigned int, 2> bpp_table = {
             32, // RGBA8
             32, // RGBA8
-            24, // RGB8
-            16, // RGB5A1
-            16, // RGB565
-            16, // RGBA4
-            16, // IA8
-            16, // RG8
-            8,  // I8
-            8,  // A8
-            8,  // IA4
-            4,  // I4
-            4,  // A4
-            4,  // ETC1
-            8,  // ETC1A4
-            16, // D16
-            0,
-            24, // D24
-            32, // D24S8
+            64, // DXT1
         };
         };
 
 
-        assert(static_cast<size_t>(format) < bpp_table.size());
+        ASSERT(static_cast<size_t>(format) < bpp_table.size());
         return bpp_table[static_cast<size_t>(format)];
         return bpp_table[static_cast<size_t>(format)];
     }
     }
     unsigned int GetFormatBpp() const {
     unsigned int GetFormatBpp() const {
@@ -134,6 +100,18 @@ struct SurfaceParams {
         }
         }
     }
     }
 
 
+    static PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format) {
+        // TODO(Subv): Properly implement this
+        switch (format) {
+        case Tegra::Texture::TextureFormat::A8R8G8B8:
+            return PixelFormat::RGBA8;
+        case Tegra::Texture::TextureFormat::DXT1:
+            return PixelFormat::DXT1;
+        default:
+            UNREACHABLE();
+        }
+    }
+
     static bool CheckFormatsBlittable(PixelFormat pixel_format_a, PixelFormat pixel_format_b) {
     static bool CheckFormatsBlittable(PixelFormat pixel_format_a, PixelFormat pixel_format_b) {
         SurfaceType a_type = GetFormatType(pixel_format_a);
         SurfaceType a_type = GetFormatType(pixel_format_a);
         SurfaceType b_type = GetFormatType(pixel_format_b);
         SurfaceType b_type = GetFormatType(pixel_format_b);
@@ -154,22 +132,17 @@ struct SurfaceParams {
         return false;
         return false;
     }
     }
 
 
-    static constexpr SurfaceType GetFormatType(PixelFormat pixel_format) {
-        if ((unsigned int)pixel_format < 5) {
+    static SurfaceType GetFormatType(PixelFormat pixel_format) {
+        if ((unsigned int)pixel_format <= static_cast<unsigned int>(PixelFormat::RGBA8)) {
             return SurfaceType::Color;
             return SurfaceType::Color;
         }
         }
 
 
-        if ((unsigned int)pixel_format < 14) {
+        if ((unsigned int)pixel_format <= static_cast<unsigned int>(PixelFormat::DXT1)) {
             return SurfaceType::Texture;
             return SurfaceType::Texture;
         }
         }
 
 
-        if (pixel_format == PixelFormat::D16 || pixel_format == PixelFormat::D24) {
-            return SurfaceType::Depth;
-        }
-
-        if (pixel_format == PixelFormat::D24S8) {
-            return SurfaceType::DepthStencil;
-        }
+        // TODO(Subv): Implement the other formats
+        ASSERT(false);
 
 
         return SurfaceType::Invalid;
         return SurfaceType::Invalid;
     }
     }
@@ -265,12 +238,10 @@ struct CachedSurface : SurfaceParams {
     OGLTexture texture;
     OGLTexture texture;
 
 
     static constexpr unsigned int GetGLBytesPerPixel(PixelFormat format) {
     static constexpr unsigned int GetGLBytesPerPixel(PixelFormat format) {
-        // OpenGL needs 4 bpp alignment for D24 since using GL_UNSIGNED_INT as type
-        return format == PixelFormat::Invalid
-                   ? 0
-                   : (format == PixelFormat::D24 || GetFormatType(format) == SurfaceType::Texture)
-                         ? 4
-                         : SurfaceParams::GetFormatBpp(format) / 8;
+        if (format == PixelFormat::Invalid)
+            return 0;
+
+        return SurfaceParams::GetFormatBpp(format) / 8;
     }
     }
 
 
     std::unique_ptr<u8[]> gl_buffer;
     std::unique_ptr<u8[]> gl_buffer;
@@ -313,7 +284,7 @@ public:
                                         bool load_if_create);
                                         bool load_if_create);
 
 
     /// Get a surface based on the texture configuration
     /// Get a surface based on the texture configuration
-    Surface GetTextureSurface(const void* config);
+    Surface GetTextureSurface(const Tegra::Texture::FullTextureInfo& config);
 
 
     /// Get the color and depth surfaces based on the framebuffer configuration
     /// Get the color and depth surfaces based on the framebuffer configuration
     SurfaceSurfaceRect_Tuple GetFramebufferSurfaces(bool using_color_fb, bool using_depth_fb,
     SurfaceSurfaceRect_Tuple GetFramebufferSurfaces(bool using_color_fb, bool using_depth_fb,

+ 1 - 1
src/video_core/renderer_opengl/gl_state.cpp

@@ -194,7 +194,7 @@ void OpenGLState::Apply() const {
     // Textures
     // Textures
     for (unsigned i = 0; i < ARRAY_SIZE(texture_units); ++i) {
     for (unsigned i = 0; i < ARRAY_SIZE(texture_units); ++i) {
         if (texture_units[i].texture_2d != cur_state.texture_units[i].texture_2d) {
         if (texture_units[i].texture_2d != cur_state.texture_units[i].texture_2d) {
-            glActiveTexture(TextureUnits::PicaTexture(i).Enum());
+            glActiveTexture(TextureUnits::MaxwellTexture(i).Enum());
             glBindTexture(GL_TEXTURE_2D, texture_units[i].texture_2d);
             glBindTexture(GL_TEXTURE_2D, texture_units[i].texture_2d);
         }
         }
         if (texture_units[i].sampler != cur_state.texture_units[i].sampler) {
         if (texture_units[i].sampler != cur_state.texture_units[i].sampler) {

+ 1 - 1
src/video_core/renderer_opengl/gl_state.h

@@ -16,7 +16,7 @@ struct TextureUnit {
     }
     }
 };
 };
 
 
-constexpr TextureUnit PicaTexture(int unit) {
+constexpr TextureUnit MaxwellTexture(int unit) {
     return TextureUnit{unit};
     return TextureUnit{unit};
 }
 }
 
 

+ 23 - 0
src/video_core/renderer_opengl/maxwell_to_gl.h

@@ -47,4 +47,27 @@ inline GLenum PrimitiveTopology(Maxwell::PrimitiveTopology topology) {
     return {};
     return {};
 }
 }
 
 
+inline GLenum TextureFilterMode(Tegra::Texture::TextureFilter filter_mode) {
+    switch (filter_mode) {
+    case Tegra::Texture::TextureFilter::Linear:
+        return GL_LINEAR;
+    case Tegra::Texture::TextureFilter::Nearest:
+        return GL_NEAREST;
+    }
+    LOG_CRITICAL(Render_OpenGL, "Unimplemented texture filter mode=%u",
+                 static_cast<u32>(filter_mode));
+    UNREACHABLE();
+    return {};
+}
+
+inline GLenum WrapMode(Tegra::Texture::WrapMode wrap_mode) {
+    switch (wrap_mode) {
+    case Tegra::Texture::WrapMode::ClampToEdge:
+        return GL_CLAMP_TO_EDGE;
+    }
+    LOG_CRITICAL(Render_OpenGL, "Unimplemented texture wrap mode=%u", static_cast<u32>(wrap_mode));
+    UNREACHABLE();
+    return {};
+}
+
 } // namespace MaxwellToGL
 } // namespace MaxwellToGL

+ 19 - 4
src/video_core/textures/texture.h

@@ -37,6 +37,16 @@ enum class TICHeaderVersion : u32 {
     BlockLinearColorKey = 4,
     BlockLinearColorKey = 4,
 };
 };
 
 
+enum class ComponentType : u32 {
+    SNORM = 1,
+    UNORM = 2,
+    SINT = 3,
+    UINT = 4,
+    SNORM_FORCE_FP16 = 5,
+    UNORM_FORCE_FP16 = 6,
+    FLOAT = 7
+};
+
 union TextureHandle {
 union TextureHandle {
     u32 raw;
     u32 raw;
     BitField<0, 20, u32> tic_id;
     BitField<0, 20, u32> tic_id;
@@ -48,10 +58,10 @@ struct TICEntry {
     union {
     union {
         u32 raw;
         u32 raw;
         BitField<0, 7, TextureFormat> format;
         BitField<0, 7, TextureFormat> format;
-        BitField<7, 3, u32> r_type;
-        BitField<10, 3, u32> g_type;
-        BitField<13, 3, u32> b_type;
-        BitField<16, 3, u32> a_type;
+        BitField<7, 3, ComponentType> r_type;
+        BitField<10, 3, ComponentType> g_type;
+        BitField<13, 3, ComponentType> b_type;
+        BitField<16, 3, ComponentType> a_type;
     };
     };
     u32 address_low;
     u32 address_low;
     union {
     union {
@@ -77,6 +87,11 @@ struct TICEntry {
     u32 Height() const {
     u32 Height() const {
         return height_minus_1 + 1;
         return height_minus_1 + 1;
     }
     }
+
+    bool IsTiled() const {
+        return header_version == TICHeaderVersion::BlockLinear ||
+               header_version == TICHeaderVersion::BlockLinearColorKey;
+    }
 };
 };
 static_assert(sizeof(TICEntry) == 0x20, "TICEntry has wrong size");
 static_assert(sizeof(TICEntry) == 0x20, "TICEntry has wrong size");