From bc0f1896fc1092bdc66fb66f977163de08672f01 Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 23 Apr 2018 23:45:47 -0400 Subject: [PATCH] gl_rasterizer_cache: Handle compressed texture sizes. --- .../renderer_opengl/gl_rasterizer_cache.cpp | 37 ++++++------- .../renderer_opengl/gl_rasterizer_cache.h | 52 +++++++++++++++++-- 2 files changed, 65 insertions(+), 24 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index d139d51e92..e1ad00feb8 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -41,18 +41,15 @@ struct FormatTuple { GLenum format; 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 tex_format_tuples = {{ - {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, false, 1}, // ABGR8 - {GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, false, 1}, // B5G6R5 - {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, false, 1}, // A2B10G10R10 - {GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, true, 16}, // DXT1 - {GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, true, 16}, // DXT23 - {GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, true, 16}, // DXT45 + {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, false}, // ABGR8 + {GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, false}, // B5G6R5 + {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, false}, // A2B10G10R10 + {GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, true}, // DXT1 + {GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, true}, // DXT23 + {GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, true}, // DXT45 }}; static const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType component_type) { @@ -476,7 +473,7 @@ void CachedSurface::LoadGLBuffer(Tegra::GPUVAddr load_start, Tegra::GPUVAddr loa return; if (gl_buffer == nullptr) { - gl_buffer_size = width * height * GetGLBytesPerPixel(pixel_format); + gl_buffer_size = GetActualWidth() * GetActualHeight() * GetGLBytesPerPixel(pixel_format); gl_buffer.reset(new u8[gl_buffer_size]); } @@ -491,8 +488,9 @@ void CachedSurface::LoadGLBuffer(Tegra::GPUVAddr load_start, Tegra::GPUVAddr loa std::memcpy(&gl_buffer[start_offset], texture_src_data + start_offset, bytes_per_pixel * width * height); } else { - morton_to_gl_fns[static_cast(pixel_format)]( - stride, block_height, height, &gl_buffer[0], addr, load_start, load_end); + morton_to_gl_fns[static_cast(pixel_format)](GetActualWidth(), block_height, + GetActualHeight(), &gl_buffer[0], addr, + load_start, load_end); } } @@ -548,7 +546,8 @@ void CachedSurface::UploadGLTexture(const MathUtil::Rectangle& rect, GLuint MICROPROFILE_SCOPE(OpenGL_TextureUL); - ASSERT(gl_buffer_size == width * height * GetGLBytesPerPixel(pixel_format)); + ASSERT(gl_buffer_size == + GetActualWidth() * GetActualHeight() * GetGLBytesPerPixel(pixel_format)); // Load data from memory to the surface GLint x0 = static_cast(rect.left); @@ -583,11 +582,9 @@ void CachedSurface::UploadGLTexture(const MathUtil::Rectangle& rect, GLuint glActiveTexture(GL_TEXTURE0); if (tuple.compressed) { glCompressedTexImage2D(GL_TEXTURE_2D, 0, tuple.internal_format, - static_cast(rect.GetWidth()), - static_cast(rect.GetHeight()), 0, - rect.GetWidth() * rect.GetHeight() * - GetGLBytesPerPixel(pixel_format) / tuple.compression_factor, - &gl_buffer[buffer_offset]); + static_cast(rect.GetWidth() * GetCompresssionFactor()), + static_cast(rect.GetHeight() * GetCompresssionFactor()), 0, + size, &gl_buffer[buffer_offset]); } else { glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, static_cast(rect.GetWidth()), static_cast(rect.GetHeight()), tuple.format, tuple.type, @@ -1041,10 +1038,10 @@ Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextu SurfaceParams params; params.addr = 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.width = config.tic.Width() / params.GetCompresssionFactor(); + params.height = config.tic.Height() / params.GetCompresssionFactor(); // TODO(Subv): Different types per component are not supported. ASSERT(config.tic.r_type.Value() == config.tic.g_type.Value() && diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 5f77f4e610..08858bab43 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -84,23 +84,49 @@ struct SurfaceParams { Invalid = 4, }; - static constexpr unsigned int GetFormatBpp(PixelFormat format) { + /** + * Gets the compression factor for the specified PixelFormat. This applies to just the + * "compressed width" and "compressed height", not the overall compression factor of a + * compressed image. This is used for maintaining proper surface sizes for compressed texture + * formats. + */ + static constexpr u32 GetCompresssionFactor(PixelFormat format) { if (format == PixelFormat::Invalid) return 0; - constexpr std::array bpp_table = { + constexpr std::array compression_factor_table = {{ + 1, // ABGR8 + 1, // B5G6R5 + 1, // A2B10G10R10 + 4, // DXT1 + 4, // DXT23 + 4, // DXT45 + }}; + + ASSERT(static_cast(format) < compression_factor_table.size()); + return compression_factor_table[static_cast(format)]; + } + u32 GetCompresssionFactor() const { + return GetCompresssionFactor(pixel_format); + } + + static constexpr u32 GetFormatBpp(PixelFormat format) { + if (format == PixelFormat::Invalid) + return 0; + + constexpr std::array bpp_table = {{ 32, // ABGR8 16, // B5G6R5 32, // A2B10G10R10 64, // DXT1 128, // DXT23 128, // DXT45 - }; + }}; ASSERT(static_cast(format) < bpp_table.size()); return bpp_table[static_cast(format)]; } - unsigned int GetFormatBpp() const { + u32 GetFormatBpp() const { return GetFormatBpp(pixel_format); } @@ -255,6 +281,24 @@ struct SurfaceParams { // Returns the region of the biggest valid rectange within interval SurfaceInterval GetCopyableInterval(const Surface& src_surface) const; + /** + * Gets the actual width (in pixels) of the surface. This is provided because `width` is used + * for tracking the surface region in memory, which may be compressed for certain formats. In + * this scenario, `width` is actually the compressed width. + */ + u32 GetActualWidth() const { + return width * GetCompresssionFactor(); + } + + /** + * Gets the actual height (in pixels) of the surface. This is provided because `height` is used + * for tracking the surface region in memory, which may be compressed for certain formats. In + * this scenario, `height` is actually the compressed height. + */ + u32 GetActualHeight() const { + return height * GetCompresssionFactor(); + } + u32 GetScaledWidth() const { return width * res_scale; }