diff options
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 10 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 1 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | 234 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.h | 85 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/maxwell_to_gl.h | 27 | ||||
| -rw-r--r-- | src/video_core/textures/decoders.h | 6 | 
6 files changed, 254 insertions, 109 deletions
| diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index cb180b93c..7bb5544fc 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -731,11 +731,15 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr      if (mag_filter != config.mag_filter) {          mag_filter = config.mag_filter; -        glSamplerParameteri(s, GL_TEXTURE_MAG_FILTER, MaxwellToGL::TextureFilterMode(mag_filter)); +        glSamplerParameteri( +            s, GL_TEXTURE_MAG_FILTER, +            MaxwellToGL::TextureFilterMode(mag_filter, Tegra::Texture::TextureMipmapFilter::None));      } -    if (min_filter != config.min_filter) { +    if (min_filter != config.min_filter || mip_filter != config.mip_filter) {          min_filter = config.min_filter; -        glSamplerParameteri(s, GL_TEXTURE_MIN_FILTER, MaxwellToGL::TextureFilterMode(min_filter)); +        mip_filter = config.mip_filter; +        glSamplerParameteri(s, GL_TEXTURE_MIN_FILTER, +                            MaxwellToGL::TextureFilterMode(min_filter, mip_filter));      }      if (wrap_u != config.wrap_u) { diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 5020a5392..7b0615125 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -93,6 +93,7 @@ private:      private:          Tegra::Texture::TextureFilter mag_filter;          Tegra::Texture::TextureFilter min_filter; +        Tegra::Texture::TextureMipmapFilter mip_filter;          Tegra::Texture::WrapMode wrap_u;          Tegra::Texture::WrapMode wrap_v;          Tegra::Texture::WrapMode wrap_p; diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 30c2803f5..1d43a419d 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -91,27 +91,36 @@ void SurfaceParams::InitCacheParameters(Tegra::GPUVAddr gpu_addr_) {      }  } -std::size_t SurfaceParams::InnerMemorySize(bool layer_only) const { +std::size_t SurfaceParams::InnerMipmapMemorySize(u32 mip_level, bool force_gl, bool layer_only, +                                                 bool uncompressed) const {      const u32 compression_factor{GetCompressionFactor(pixel_format)};      const u32 bytes_per_pixel{GetBytesPerPixel(pixel_format)};      u32 m_depth = (layer_only ? 1U : depth); -    u32 m_width = std::max(1U, width / compression_factor); -    u32 m_height = std::max(1U, height / compression_factor); -    std::size_t size = Tegra::Texture::CalculateSize(is_tiled, bytes_per_pixel, m_width, m_height, -                                                     m_depth, block_height, block_depth); -    u32 m_block_height = block_height; -    u32 m_block_depth = block_depth; -    std::size_t block_size_bytes = 512 * block_height * block_depth; // 512 is GOB size -    for (u32 i = 1; i < max_mip_level; i++) { -        m_width = std::max(1U, m_width / 2); -        m_height = std::max(1U, m_height / 2); -        m_depth = std::max(1U, m_depth / 2); -        m_block_height = std::max(1U, m_block_height / 2); -        m_block_depth = std::max(1U, m_block_depth / 2); -        size += Tegra::Texture::CalculateSize(is_tiled, bytes_per_pixel, m_width, m_height, m_depth, -                                              m_block_height, m_block_depth); +    u32 m_width = MipWidth(mip_level); +    u32 m_height = MipHeight(mip_level); +    m_width = uncompressed ? m_width +                           : std::max(1U, (m_width + compression_factor - 1) / compression_factor); +    m_height = uncompressed +                   ? m_height +                   : std::max(1U, (m_height + compression_factor - 1) / compression_factor); +    m_depth = std::max(1U, m_depth >> mip_level); +    u32 m_block_height = MipBlockHeight(mip_level); +    u32 m_block_depth = MipBlockDepth(mip_level); +    return Tegra::Texture::CalculateSize(force_gl ? false : is_tiled, bytes_per_pixel, m_width, +                                         m_height, m_depth, m_block_height, m_block_depth); +} + +std::size_t SurfaceParams::InnerMemorySize(bool force_gl, bool layer_only, +                                           bool uncompressed) const { +    std::size_t block_size_bytes = Tegra::Texture::GetGOBSize() * block_height * block_depth; +    std::size_t size = 0; +    for (u32 i = 0; i < max_mip_level; i++) { +        size += InnerMipmapMemorySize(i, force_gl, layer_only, uncompressed); +    } +    if (!force_gl && is_tiled) { +        size = Common::AlignUp(size, block_size_bytes);      } -    return is_tiled ? Common::AlignUp(size, block_size_bytes) : size; +    return size;  }  /*static*/ SurfaceParams SurfaceParams::CreateForTexture( @@ -189,7 +198,7 @@ std::size_t SurfaceParams::InnerMemorySize(bool layer_only) const {      params.unaligned_height = config.height;      params.target = SurfaceTarget::Texture2D;      params.depth = 1; -    params.max_mip_level = 0; +    params.max_mip_level = 1;      params.is_layered = false;      // Render target specific parameters, not used for caching @@ -223,7 +232,7 @@ std::size_t SurfaceParams::InnerMemorySize(bool layer_only) const {      params.unaligned_height = zeta_height;      params.target = SurfaceTarget::Texture2D;      params.depth = 1; -    params.max_mip_level = 0; +    params.max_mip_level = 1;      params.is_layered = false;      params.rt = {}; @@ -250,7 +259,7 @@ std::size_t SurfaceParams::InnerMemorySize(bool layer_only) const {      params.unaligned_height = config.height;      params.target = SurfaceTarget::Texture2D;      params.depth = 1; -    params.max_mip_level = 0; +    params.max_mip_level = 1;      params.rt = {};      params.InitCacheParameters(config.Address()); @@ -374,13 +383,13 @@ static const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType      return format;  } -MathUtil::Rectangle<u32> SurfaceParams::GetRect() const { -    u32 actual_height{unaligned_height}; +MathUtil::Rectangle<u32> SurfaceParams::GetRect(u32 mip_level) const { +    u32 actual_height{std::max(1U, unaligned_height >> mip_level)};      if (IsPixelFormatASTC(pixel_format)) {          // ASTC formats must stop at the ATSC block size boundary          actual_height = Common::AlignDown(actual_height, GetASTCBlockSize(pixel_format).second);      } -    return {0, actual_height, width, 0}; +    return {0, actual_height, MipWidth(mip_level), 0};  }  /// Returns true if the specified PixelFormat is a BCn format, e.g. DXT or DXN @@ -564,28 +573,31 @@ static constexpr GLConversionArray gl_to_morton_fns = {  };  void SwizzleFunc(const GLConversionArray& functions, const SurfaceParams& params, -                 std::vector<u8>& gl_buffer) { -    u32 depth = params.depth; +                 std::vector<u8>& gl_buffer, u32 mip_level) { +    u32 depth = params.MipDepth(mip_level);      if (params.target == SurfaceParams::SurfaceTarget::Texture2D) {          // TODO(Blinkhawk): Eliminate this condition once all texture types are implemented.          depth = 1U;      }      if (params.is_layered) { -        u64 offset = 0; +        u64 offset = params.GetMipmapLevelOffset(mip_level);          u64 offset_gl = 0;          u64 layer_size = params.LayerMemorySize(); -        u64 gl_size = params.LayerSizeGL(); -        for (u32 i = 0; i < depth; i++) { +        u64 gl_size = params.LayerSizeGL(mip_level); +        for (u32 i = 0; i < params.depth; i++) {              functions[static_cast<std::size_t>(params.pixel_format)]( -                params.width, params.block_height, params.height, params.block_depth, 1, +                params.MipWidth(mip_level), params.MipBlockHeight(mip_level), +                params.MipHeight(mip_level), params.MipBlockDepth(mip_level), 1,                  gl_buffer.data() + offset_gl, gl_size, params.addr + offset);              offset += layer_size;              offset_gl += gl_size;          }      } else { +        u64 offset = params.GetMipmapLevelOffset(mip_level);          functions[static_cast<std::size_t>(params.pixel_format)]( -            params.width, params.block_height, params.height, params.block_depth, depth, -            gl_buffer.data(), gl_buffer.size(), params.addr); +            params.MipWidth(mip_level), params.MipBlockHeight(mip_level), +            params.MipHeight(mip_level), params.MipBlockDepth(mip_level), depth, gl_buffer.data(), +            gl_buffer.size(), params.addr + offset);      }  } @@ -840,31 +852,38 @@ CachedSurface::CachedSurface(const SurfaceParams& params)          // Only pre-create the texture for non-compressed textures.          switch (params.target) {          case SurfaceParams::SurfaceTarget::Texture1D: -            glTexStorage1D(SurfaceTargetToGL(params.target), 1, format_tuple.internal_format, -                           rect.GetWidth()); +            glTexStorage1D(SurfaceTargetToGL(params.target), params.max_mip_level, +                           format_tuple.internal_format, rect.GetWidth());              break;          case SurfaceParams::SurfaceTarget::Texture2D:          case SurfaceParams::SurfaceTarget::TextureCubemap: -            glTexStorage2D(SurfaceTargetToGL(params.target), 1, format_tuple.internal_format, -                           rect.GetWidth(), rect.GetHeight()); +            glTexStorage2D(SurfaceTargetToGL(params.target), params.max_mip_level, +                           format_tuple.internal_format, rect.GetWidth(), rect.GetHeight());              break;          case SurfaceParams::SurfaceTarget::Texture3D:          case SurfaceParams::SurfaceTarget::Texture2DArray: -            glTexStorage3D(SurfaceTargetToGL(params.target), 1, format_tuple.internal_format, -                           rect.GetWidth(), rect.GetHeight(), params.depth); +            glTexStorage3D(SurfaceTargetToGL(params.target), params.max_mip_level, +                           format_tuple.internal_format, rect.GetWidth(), rect.GetHeight(), +                           params.depth);              break;          default:              LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",                           static_cast<u32>(params.target));              UNREACHABLE(); -            glTexStorage2D(GL_TEXTURE_2D, 1, format_tuple.internal_format, rect.GetWidth(), -                           rect.GetHeight()); +            glTexStorage2D(GL_TEXTURE_2D, params.max_mip_level, format_tuple.internal_format, +                           rect.GetWidth(), rect.GetHeight());          }      }      glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MIN_FILTER, GL_LINEAR); +    glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MAG_FILTER, GL_LINEAR);      glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);      glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +    glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MAX_LEVEL, +                    params.max_mip_level - 1); +    if (params.max_mip_level == 1) { +        glTexParameterf(SurfaceTargetToGL(params.target), GL_TEXTURE_LOD_BIAS, 1000.0); +    }      LabelGLObject(GL_TEXTURE, texture.handle, params.addr,                    SurfaceParams::SurfaceTargetName(params.target)); @@ -993,20 +1012,22 @@ static void ConvertFormatAsNeeded_FlushGLBuffer(std::vector<u8>& data, PixelForm  MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192));  void CachedSurface::LoadGLBuffer() {      MICROPROFILE_SCOPE(OpenGL_SurfaceLoad); - -    gl_buffer.resize(params.size_in_bytes_gl); +    gl_buffer.resize(params.max_mip_level); +    for (u32 i = 0; i < params.max_mip_level; i++) +        gl_buffer[i].resize(params.GetMipmapSizeGL(i));      if (params.is_tiled) {          ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}",                     params.block_width, static_cast<u32>(params.target)); - -        SwizzleFunc(morton_to_gl_fns, params, gl_buffer); +        for (u32 i = 0; i < params.max_mip_level; i++) +            SwizzleFunc(morton_to_gl_fns, params, gl_buffer[i], i);      } else {          const auto texture_src_data{Memory::GetPointer(params.addr)};          const auto texture_src_data_end{texture_src_data + params.size_in_bytes_gl}; -        gl_buffer.assign(texture_src_data, texture_src_data_end); +        gl_buffer[0].assign(texture_src_data, texture_src_data_end);      } - -    ConvertFormatAsNeeded_LoadGLBuffer(gl_buffer, params.pixel_format, params.width, params.height); +    for (u32 i = 0; i < params.max_mip_level; i++) +        ConvertFormatAsNeeded_LoadGLBuffer(gl_buffer[i], params.pixel_format, params.MipWidth(i), +                                           params.MipHeight(i));  }  MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64)); @@ -1016,7 +1037,8 @@ void CachedSurface::FlushGLBuffer() {      ASSERT_MSG(!IsPixelFormatASTC(params.pixel_format), "Unimplemented");      // OpenGL temporary buffer needs to be big enough to store raw texture size -    gl_buffer.resize(GetSizeInBytes()); +    gl_buffer.resize(1); +    gl_buffer[0].resize(GetSizeInBytes());      const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type);      // Ensure no bad interactions with GL_UNPACK_ALIGNMENT @@ -1025,9 +1047,9 @@ void CachedSurface::FlushGLBuffer() {      ASSERT(!tuple.compressed);      glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);      glGetTextureImage(texture.handle, 0, tuple.format, tuple.type, -                      static_cast<GLsizei>(gl_buffer.size()), gl_buffer.data()); +                      static_cast<GLsizei>(gl_buffer[0].size()), gl_buffer[0].data());      glPixelStorei(GL_PACK_ROW_LENGTH, 0); -    ConvertFormatAsNeeded_FlushGLBuffer(gl_buffer, params.pixel_format, params.width, +    ConvertFormatAsNeeded_FlushGLBuffer(gl_buffer[0], params.pixel_format, params.width,                                          params.height);      ASSERT(params.type != SurfaceType::Fill);      const u8* const texture_src_data = Memory::GetPointer(params.addr); @@ -1036,26 +1058,21 @@ void CachedSurface::FlushGLBuffer() {          ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}",                     params.block_width, static_cast<u32>(params.target)); -        SwizzleFunc(gl_to_morton_fns, params, gl_buffer); +        SwizzleFunc(gl_to_morton_fns, params, gl_buffer[0], 0);      } else { -        std::memcpy(Memory::GetPointer(GetAddr()), gl_buffer.data(), GetSizeInBytes()); +        std::memcpy(Memory::GetPointer(GetAddr()), gl_buffer[0].data(), GetSizeInBytes());      }  } -MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192)); -void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle) { -    if (params.type == SurfaceType::Fill) -        return; - -    MICROPROFILE_SCOPE(OpenGL_TextureUL); - -    const auto& rect{params.GetRect()}; +void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle, +                                          GLuint draw_fb_handle) { +    const auto& rect{params.GetRect(mip_map)};      // Load data from memory to the surface      const GLint x0 = static_cast<GLint>(rect.left);      const GLint y0 = static_cast<GLint>(rect.bottom);      std::size_t buffer_offset = -        static_cast<std::size_t>(static_cast<std::size_t>(y0) * params.width + +        static_cast<std::size_t>(static_cast<std::size_t>(y0) * params.MipWidth(mip_map) +                                   static_cast<std::size_t>(x0)) *          SurfaceParams::GetBytesPerPixel(params.pixel_format); @@ -1073,88 +1090,117 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle      cur_state.Apply();      // Ensure no bad interactions with GL_UNPACK_ALIGNMENT -    ASSERT(params.width * SurfaceParams::GetBytesPerPixel(params.pixel_format) % 4 == 0); -    glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(params.width)); +    ASSERT(params.MipWidth(mip_map) * SurfaceParams::GetBytesPerPixel(params.pixel_format) % 4 == +           0); +    glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(params.MipWidth(mip_map))); +    GLsizei image_size = static_cast<GLsizei>(params.GetMipmapSizeGL(mip_map, false));      glActiveTexture(GL_TEXTURE0);      if (tuple.compressed) {          switch (params.target) {          case SurfaceParams::SurfaceTarget::Texture2D: -            glCompressedTexImage2D( -                SurfaceTargetToGL(params.target), 0, tuple.internal_format, -                static_cast<GLsizei>(params.width), static_cast<GLsizei>(params.height), 0, -                static_cast<GLsizei>(params.size_in_bytes_gl), &gl_buffer[buffer_offset]); +            glCompressedTexImage2D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format, +                                   static_cast<GLsizei>(params.MipWidth(mip_map)), +                                   static_cast<GLsizei>(params.MipHeight(mip_map)), 0, image_size, +                                   &gl_buffer[mip_map][buffer_offset]);              break;          case SurfaceParams::SurfaceTarget::Texture3D: +            glCompressedTexImage3D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format, +                                   static_cast<GLsizei>(params.MipWidth(mip_map)), +                                   static_cast<GLsizei>(params.MipHeight(mip_map)), +                                   static_cast<GLsizei>(params.MipDepth(mip_map)), 0, image_size, +                                   &gl_buffer[mip_map][buffer_offset]); +            break;          case SurfaceParams::SurfaceTarget::Texture2DArray: -            glCompressedTexImage3D( -                SurfaceTargetToGL(params.target), 0, tuple.internal_format, -                static_cast<GLsizei>(params.width), static_cast<GLsizei>(params.height), -                static_cast<GLsizei>(params.depth), 0, -                static_cast<GLsizei>(params.size_in_bytes_gl), &gl_buffer[buffer_offset]); +            glCompressedTexImage3D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format, +                                   static_cast<GLsizei>(params.MipWidth(mip_map)), +                                   static_cast<GLsizei>(params.MipHeight(mip_map)), +                                   static_cast<GLsizei>(params.depth), 0, image_size, +                                   &gl_buffer[mip_map][buffer_offset]);              break; -        case SurfaceParams::SurfaceTarget::TextureCubemap: +        case SurfaceParams::SurfaceTarget::TextureCubemap: { +            GLsizei layer_size = static_cast<GLsizei>(params.LayerSizeGL(mip_map));              for (std::size_t face = 0; face < params.depth; ++face) {                  glCompressedTexImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), -                                       0, tuple.internal_format, static_cast<GLsizei>(params.width), -                                       static_cast<GLsizei>(params.height), 0, -                                       static_cast<GLsizei>(params.SizeInBytesCubeFaceGL()), -                                       &gl_buffer[buffer_offset]); -                buffer_offset += params.SizeInBytesCubeFace(); +                                       mip_map, tuple.internal_format, +                                       static_cast<GLsizei>(params.MipWidth(mip_map)), +                                       static_cast<GLsizei>(params.MipHeight(mip_map)), 0, +                                       layer_size, &gl_buffer[mip_map][buffer_offset]); +                buffer_offset += layer_size;              }              break; +        }          default:              LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",                           static_cast<u32>(params.target));              UNREACHABLE(); -            glCompressedTexImage2D( -                GL_TEXTURE_2D, 0, tuple.internal_format, static_cast<GLsizei>(params.width), -                static_cast<GLsizei>(params.height), 0, -                static_cast<GLsizei>(params.size_in_bytes_gl), &gl_buffer[buffer_offset]); +            glCompressedTexImage2D(GL_TEXTURE_2D, mip_map, tuple.internal_format, +                                   static_cast<GLsizei>(params.MipWidth(mip_map)), +                                   static_cast<GLsizei>(params.MipHeight(mip_map)), 0, +                                   static_cast<GLsizei>(params.size_in_bytes_gl), +                                   &gl_buffer[mip_map][buffer_offset]);          }      } else {          switch (params.target) {          case SurfaceParams::SurfaceTarget::Texture1D: -            glTexSubImage1D(SurfaceTargetToGL(params.target), 0, x0, +            glTexSubImage1D(SurfaceTargetToGL(params.target), mip_map, x0,                              static_cast<GLsizei>(rect.GetWidth()), tuple.format, tuple.type, -                            &gl_buffer[buffer_offset]); +                            &gl_buffer[mip_map][buffer_offset]);              break;          case SurfaceParams::SurfaceTarget::Texture2D: -            glTexSubImage2D(SurfaceTargetToGL(params.target), 0, x0, y0, +            glTexSubImage2D(SurfaceTargetToGL(params.target), mip_map, x0, y0,                              static_cast<GLsizei>(rect.GetWidth()),                              static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, -                            &gl_buffer[buffer_offset]); +                            &gl_buffer[mip_map][buffer_offset]);              break;          case SurfaceParams::SurfaceTarget::Texture3D: +            glTexSubImage3D(SurfaceTargetToGL(params.target), mip_map, x0, y0, 0, +                            static_cast<GLsizei>(rect.GetWidth()), +                            static_cast<GLsizei>(rect.GetHeight()), params.MipDepth(mip_map), +                            tuple.format, tuple.type, &gl_buffer[mip_map][buffer_offset]); +            break;          case SurfaceParams::SurfaceTarget::Texture2DArray: -            glTexSubImage3D(SurfaceTargetToGL(params.target), 0, x0, y0, 0, +            glTexSubImage3D(SurfaceTargetToGL(params.target), mip_map, x0, y0, 0,                              static_cast<GLsizei>(rect.GetWidth()),                              static_cast<GLsizei>(rect.GetHeight()), params.depth, tuple.format, -                            tuple.type, &gl_buffer[buffer_offset]); +                            tuple.type, &gl_buffer[mip_map][buffer_offset]);              break; -        case SurfaceParams::SurfaceTarget::TextureCubemap: +        case SurfaceParams::SurfaceTarget::TextureCubemap: { +            std::size_t start = buffer_offset;              for (std::size_t face = 0; face < params.depth; ++face) { -                glTexSubImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), 0, x0, -                                y0, static_cast<GLsizei>(rect.GetWidth()), +                glTexSubImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), mip_map, +                                x0, y0, static_cast<GLsizei>(rect.GetWidth()),                                  static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, -                                &gl_buffer[buffer_offset]); -                buffer_offset += params.SizeInBytesCubeFace(); +                                &gl_buffer[mip_map][buffer_offset]); +                buffer_offset += params.LayerSizeGL(mip_map);              }              break; +        }          default:              LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",                           static_cast<u32>(params.target));              UNREACHABLE(); -            glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, static_cast<GLsizei>(rect.GetWidth()), +            glTexSubImage2D(GL_TEXTURE_2D, mip_map, x0, y0, static_cast<GLsizei>(rect.GetWidth()),                              static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, -                            &gl_buffer[buffer_offset]); +                            &gl_buffer[mip_map][buffer_offset]);          }      }      glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);  } +MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192)); +void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle) { +    if (params.type == SurfaceType::Fill) +        return; + +    MICROPROFILE_SCOPE(OpenGL_TextureUL); + +    for (u32 i = 0; i < params.max_mip_level; i++) +        UploadGLMipmapTexture(i, read_fb_handle, draw_fb_handle); +} +  RasterizerCacheOpenGL::RasterizerCacheOpenGL() {      read_framebuffer.Create();      draw_framebuffer.Create(); diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 6a49880c2..e72f4f2d2 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -834,7 +834,7 @@ struct SurfaceParams {      }      /// Returns the rectangle corresponding to this surface -    MathUtil::Rectangle<u32> GetRect() const; +    MathUtil::Rectangle<u32> GetRect(u32 mip_level = 0) const;      /// Returns the total size of this surface in bytes, adjusted for compression      std::size_t SizeInBytesRaw(bool ignore_tiled = false) const { @@ -865,7 +865,7 @@ struct SurfaceParams {      /// Returns the exact size of memory occupied by the texture in VRAM, including mipmaps.      std::size_t MemorySize() const { -        std::size_t size = InnerMemorySize(is_layered); +        std::size_t size = InnerMemorySize(false, is_layered);          if (is_layered)              return size * depth;          return size; @@ -874,12 +874,78 @@ struct SurfaceParams {      /// Returns the exact size of the memory occupied by a layer in a texture in VRAM, including      /// mipmaps.      std::size_t LayerMemorySize() const { -        return InnerMemorySize(true); +        return InnerMemorySize(false, true);      }      /// Returns the size of a layer of this surface in OpenGL. -    std::size_t LayerSizeGL() const { -        return SizeInBytesRaw(true) / depth; +    std::size_t LayerSizeGL(u32 mip_level) const { +        return InnerMipmapMemorySize(mip_level, true, is_layered, false); +    } + +    std::size_t GetMipmapSizeGL(u32 mip_level, bool ignore_compressed = true) const { +        std::size_t size = InnerMipmapMemorySize(mip_level, true, is_layered, ignore_compressed); +        if (is_layered) +            return size * depth; +        return size; +    } + +    std::size_t GetMipmapLevelOffset(u32 mip_level) const { +        std::size_t offset = 0; +        for (u32 i = 0; i < mip_level; i++) +            offset += InnerMipmapMemorySize(i, false, is_layered); +        return offset; +    } + +    std::size_t GetMipmapLevelOffsetGL(u32 mip_level) const { +        std::size_t offset = 0; +        for (u32 i = 0; i < mip_level; i++) +            offset += InnerMipmapMemorySize(i, true, is_layered); +        return offset; +    } + +    u32 MipWidth(u32 mip_level) const { +        return std::max(1U, width >> mip_level); +    } + +    u32 MipHeight(u32 mip_level) const { +        return std::max(1U, height >> mip_level); +    } + +    u32 MipDepth(u32 mip_level) const { +        return std::max(1U, depth >> mip_level); +    } + +    // Auto block resizing algorithm from: +    // https://cgit.freedesktop.org/mesa/mesa/tree/src/gallium/drivers/nouveau/nv50/nv50_miptree.c +    u32 MipBlockHeight(u32 mip_level) const { +        if (mip_level == 0) +            return block_height; +        u32 alt_height = MipHeight(mip_level); +        u32 h = GetDefaultBlockHeight(pixel_format); +        u32 blocks_in_y = (alt_height + h - 1) / h; +        u32 bh = 16; +        while (bh > 1 && blocks_in_y <= bh * 4) { +            bh >>= 1; +        } +        return bh; +    } + +    u32 MipBlockDepth(u32 mip_level) const { +        if (mip_level == 0) +            return block_depth; +        if (is_layered) +            return 1; +        u32 depth = MipDepth(mip_level); +        u32 bd = 32; +        while (bd > 1 && depth * 2 <= bd) { +            bd >>= 1; +        } +        if (bd == 32) { +            u32 bh = MipBlockHeight(mip_level); +            if (bh >= 4) +                return 16; +        } +        return bd;      }      /// Creates SurfaceParams from a texture configuration @@ -940,7 +1006,10 @@ struct SurfaceParams {      } rt;  private: -    std::size_t InnerMemorySize(bool layer_only = false) const; +    std::size_t InnerMipmapMemorySize(u32 mip_level, bool force_gl = false, bool layer_only = false, +                                      bool uncompressed = false) const; +    std::size_t InnerMemorySize(bool force_gl = false, bool layer_only = false, +                                bool uncompressed = false) const;  };  }; // namespace OpenGL @@ -1002,8 +1071,10 @@ public:      void UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle);  private: +    void UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle, GLuint draw_fb_handle); +      OGLTexture texture; -    std::vector<u8> gl_buffer; +    std::vector<std::vector<u8>> gl_buffer;      SurfaceParams params;      GLenum gl_target;      std::size_t cached_size_in_bytes; diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h index 0f6dcab2b..87d511c38 100644 --- a/src/video_core/renderer_opengl/maxwell_to_gl.h +++ b/src/video_core/renderer_opengl/maxwell_to_gl.h @@ -135,12 +135,29 @@ inline GLenum PrimitiveTopology(Maxwell::PrimitiveTopology topology) {      return {};  } -inline GLenum TextureFilterMode(Tegra::Texture::TextureFilter filter_mode) { +inline GLenum TextureFilterMode(Tegra::Texture::TextureFilter filter_mode, +                                Tegra::Texture::TextureMipmapFilter mip_filter_mode) {      switch (filter_mode) { -    case Tegra::Texture::TextureFilter::Linear: -        return GL_LINEAR; -    case Tegra::Texture::TextureFilter::Nearest: -        return GL_NEAREST; +    case Tegra::Texture::TextureFilter::Linear: { +        switch (mip_filter_mode) { +        case Tegra::Texture::TextureMipmapFilter::None: +            return GL_LINEAR; +        case Tegra::Texture::TextureMipmapFilter::Nearest: +            return GL_NEAREST_MIPMAP_LINEAR; +        case Tegra::Texture::TextureMipmapFilter::Linear: +            return GL_LINEAR_MIPMAP_LINEAR; +        } +    } +    case Tegra::Texture::TextureFilter::Nearest: { +        switch (mip_filter_mode) { +        case Tegra::Texture::TextureMipmapFilter::None: +            return GL_NEAREST; +        case Tegra::Texture::TextureMipmapFilter::Nearest: +            return GL_NEAREST_MIPMAP_NEAREST; +        case Tegra::Texture::TextureMipmapFilter::Linear: +            return GL_LINEAR_MIPMAP_NEAREST; +        } +    }      }      LOG_CRITICAL(Render_OpenGL, "Unimplemented texture filter mode={}",                   static_cast<u32>(filter_mode)); diff --git a/src/video_core/textures/decoders.h b/src/video_core/textures/decoders.h index 4726f54a5..b390219e4 100644 --- a/src/video_core/textures/decoders.h +++ b/src/video_core/textures/decoders.h @@ -10,6 +10,12 @@  namespace Tegra::Texture { +// GOBSize constant. Calculated by 64 bytes in x multiplied by 8 y coords, represents +// an small rect of (64/bytes_per_pixel)X8. +inline std::size_t GetGOBSize() { +    return 512; +} +  /**   * Unswizzles a swizzled texture without changing its format.   */ | 
