From 185556025eacd0462404f950848090139664ddb4 Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 13 Apr 2018 21:26:03 -0400 Subject: [PATCH] (jroweboy) textures: Add support for other formats. --- .../renderer_opengl/gl_rasterizer_cache.cpp | 104 +++++++++++------- .../renderer_opengl/gl_rasterizer_cache.h | 33 ++++-- src/video_core/textures/decoders.cpp | 37 +++++-- src/video_core/textures/decoders.h | 3 +- src/video_core/textures/texture.h | 19 +++- .../debugger/graphics/graphics_surface.cpp | 4 +- 6 files changed, 142 insertions(+), 58 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 213b20a21a..c3361d3a81 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -51,9 +51,14 @@ static constexpr std::array fb_format_tuples = {{ {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, false, 1}, // RGBA8 }}; -static constexpr std::array 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 std::array tex_format_tuples = {{ + {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, false, 1}, // RGBA8 + {GL_RGB5_A1, GL_RGB, GL_UNSIGNED_SHORT_5_5_5_1, false, 1}, // RGB5A1 + {GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, false, 1}, // RGB565 + {GL_R11F_G11F_B10F, GL_RGB, GL_FLOAT, false, 1}, // R11FG11FB10F + {GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, true, 16}, // BC1 + {GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, true, 16}, // BC2 + {GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, true, 16}, // BC3 }}; static const FormatTuple& GetFormatTuple(PixelFormat pixel_format) { @@ -85,24 +90,8 @@ static u16 GetResolutionScaleFactor() { } template -static void MortonCopyTile(u32 stride, u8* tile_buffer, u8* gl_buffer) { - constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / 8; - constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format); - for (u32 y = 0; y < 8; ++y) { - for (u32 x = 0; x < 8; ++x) { - 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; - if (morton_to_gl) { - std::memcpy(gl_ptr, tile_ptr, bytes_per_pixel); - } else { - std::memcpy(tile_ptr, gl_ptr, bytes_per_pixel); - } - } - } -} - -template -void MortonCopy(u32 stride, u32 height, u8* gl_buffer, VAddr base, VAddr start, VAddr end) { +void MortonCopy(u32 stride, u32 height, u32 block_height, u8* gl_buffer, VAddr base, VAddr start, + VAddr end) { constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / 8; constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format); @@ -114,27 +103,67 @@ void MortonCopy(u32 stride, u32 height, u8* gl_buffer, VAddr base, VAddr start, } template <> -void MortonCopy(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); +void MortonCopy(u32 stride, u32 height, u32 block_height, u8* gl_buffer, + VAddr base, VAddr start, VAddr end) { + constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(PixelFormat::BC1) / 8; + constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(PixelFormat::BC1); // 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); + auto data = Tegra::Texture::UnswizzleTexture(base, Tegra::Texture::TextureFormat::BC1, stride, + height, block_height); std::memcpy(gl_buffer, data.data(), data.size()); } -static constexpr std::array morton_to_gl_fns = { - MortonCopy, - MortonCopy, +template <> +void MortonCopy(u32 stride, u32 height, u32 block_height, u8* gl_buffer, + VAddr base, VAddr start, VAddr end) { + constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(PixelFormat::BC2) / 8; + constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(PixelFormat::BC2); + + // 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::BC2, stride, + height, block_height); + std::memcpy(gl_buffer, data.data(), data.size()); +} + +template <> +void MortonCopy(u32 stride, u32 height, u32 block_height, u8* gl_buffer, + VAddr base, VAddr start, VAddr end) { + constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(PixelFormat::BC3) / 8; + constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(PixelFormat::BC3); + + // 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 + // NGLOG_CRITICAL(Render_OpenGL, "need to use correct swizzle/GOB parameters!"); + auto data = Tegra::Texture::UnswizzleTexture(base, Tegra::Texture::TextureFormat::BC3, stride, + height, block_height); + std::memcpy(gl_buffer, data.data(), data.size()); +} + +static constexpr std::array morton_to_gl_fns = + { + MortonCopy, // RGBA8 + MortonCopy, // RGB5A1 + MortonCopy, // RGB565 + MortonCopy, // RG11FB10F + MortonCopy, // BC1 + MortonCopy, // BC2 + MortonCopy, // BC3 }; -static constexpr std::array gl_to_morton_fns = { - MortonCopy, - MortonCopy, +static constexpr std::array gl_to_morton_fns = + { + MortonCopy, // RGBA8 + MortonCopy, // RGB5A1 + MortonCopy, // RGB565 + MortonCopy, // RG11FB10F + MortonCopy, // BC1 + MortonCopy, // BC2 + MortonCopy, // BC3 }; // Allocate an uninitialized texture of appropriate size and format for the surface @@ -491,8 +520,8 @@ void CachedSurface::LoadGLBuffer(VAddr load_start, VAddr load_end) { texture_src_data + start_offset, &gl_buffer[start_offset], true); } else { - morton_to_gl_fns[static_cast(pixel_format)](stride, height, &gl_buffer[0], addr, - load_start, load_end); + morton_to_gl_fns[static_cast(pixel_format)]( + stride, height, block_height, &gl_buffer[0], addr, load_start, load_end); } } @@ -536,8 +565,8 @@ void CachedSurface::FlushGLBuffer(VAddr flush_start, VAddr flush_end) { ASSERT(type == SurfaceType::Color); std::memcpy(dst_buffer + start_offset, &gl_buffer[start_offset], flush_end - flush_start); } else { - gl_to_morton_fns[static_cast(pixel_format)](stride, height, &gl_buffer[0], addr, - flush_start, flush_end); + gl_to_morton_fns[static_cast(pixel_format)]( + stride, height, block_height, &gl_buffer[0], addr, flush_start, flush_end); } } @@ -1040,6 +1069,7 @@ Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextu params.width = config.tic.Width(); params.height = config.tic.Height(); params.is_tiled = config.tic.IsTiled(); + params.block_height = config.tic.BlockHeight(); params.pixel_format = SurfaceParams::PixelFormatFromTextureFormat(config.tic.format); params.UpdateParams(); diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 3293905d6e..6971af6fa6 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -52,8 +52,17 @@ enum class ScaleMatch { struct SurfaceParams { enum class PixelFormat { + // Texture and color buffer formats RGBA8 = 0, - DXT1 = 1, + RGB5A1 = 1, + RGB565 = 2, + RG11FB10F = 3, + + // Compressed Texture formats + BC1 = 4, + BC2 = 5, + BC3 = 6, + Invalid = 255, }; @@ -70,9 +79,14 @@ struct SurfaceParams { if (format == PixelFormat::Invalid) return 0; - constexpr std::array bpp_table = { - 32, // RGBA8 - 64, // DXT1 + constexpr std::array bpp_table = { + 32, // RGBA8 + 16, // RGB5A1 + 16, // RGB565 + 32, // RG11FB10F + 64, // BC1 + 128, // BC2 + 128, // BC3 }; ASSERT(static_cast(format) < bpp_table.size()); @@ -107,8 +121,12 @@ struct SurfaceParams { switch (format) { case Tegra::Texture::TextureFormat::A8R8G8B8: return PixelFormat::RGBA8; - case Tegra::Texture::TextureFormat::DXT1: - return PixelFormat::DXT1; + case Tegra::Texture::TextureFormat::BC1: + return PixelFormat::BC1; + case Tegra::Texture::TextureFormat::BC2: + return PixelFormat::BC2; + case Tegra::Texture::TextureFormat::BC3: + return PixelFormat::BC3; default: NGLOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast(format)); UNREACHABLE(); @@ -140,7 +158,7 @@ struct SurfaceParams { return SurfaceType::Color; } - if ((unsigned int)pixel_format <= static_cast(PixelFormat::DXT1)) { + if ((unsigned int)pixel_format <= static_cast(PixelFormat::BC3)) { return SurfaceType::Texture; } @@ -213,6 +231,7 @@ struct SurfaceParams { u32 width = 0; u32 height = 0; u32 stride = 0; + u32 block_height = 0; u16 res_scale = 1; bool is_tiled = false; diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp index 2e87281ebc..927ac14bbe 100644 --- a/src/video_core/textures/decoders.cpp +++ b/src/video_core/textures/decoders.cpp @@ -45,18 +45,26 @@ static void CopySwizzledData(u32 width, u32 height, u32 bytes_per_pixel, u32 out u32 BytesPerPixel(TextureFormat format) { switch (format) { - case TextureFormat::DXT1: - // In this case a 'pixel' actually refers to a 4x4 tile. - return 8; case TextureFormat::A8R8G8B8: + case TextureFormat::BF10GF11RF11: return 4; + case TextureFormat::A1B5G5R5: + case TextureFormat::B5G6R5: + return 2; + // In this case a 'pixel' actually refers to a 4x4 tile. + case TextureFormat::BC1: + return 8; + case TextureFormat::BC2: + case TextureFormat::BC3: + return 16; default: UNIMPLEMENTED_MSG("Format not implemented"); break; } } -std::vector UnswizzleTexture(VAddr address, TextureFormat format, u32 width, u32 height) { +std::vector UnswizzleTexture(VAddr address, TextureFormat format, u32 width, u32 height, + u32 block_height) { u8* data = Memory::GetPointer(address); u32 bytes_per_pixel = BytesPerPixel(format); @@ -65,11 +73,21 @@ std::vector UnswizzleTexture(VAddr address, TextureFormat format, u32 width, std::vector unswizzled_data(width * height * bytes_per_pixel); switch (format) { - case TextureFormat::DXT1: - // In the DXT1 format, each 4x4 tile is swizzled instead of just individual pixel values. + case TextureFormat::BC1: + // In the BC1 format, each 4x4 tile is swizzled instead of just individual pixel values. CopySwizzledData(width / 4, height / 4, bytes_per_pixel, bytes_per_pixel, data, unswizzled_data.data(), true, DefaultBlockHeight); break; + case TextureFormat::BC2: + // TODO + CopySwizzledData(width / 4, height / 4, bytes_per_pixel, bytes_per_pixel, data, + unswizzled_data.data(), true, DefaultBlockHeight); + break; + case TextureFormat::BC3: + // TODO + CopySwizzledData(width / 4, height / 4, bytes_per_pixel, bytes_per_pixel, data, + unswizzled_data.data(), true, block_height); + break; case TextureFormat::A8R8G8B8: CopySwizzledData(width, height, bytes_per_pixel, bytes_per_pixel, data, unswizzled_data.data(), true, DefaultBlockHeight); @@ -88,8 +106,13 @@ std::vector DecodeTexture(const std::vector& texture_data, TextureFormat // TODO(Subv): Implement. switch (format) { - case TextureFormat::DXT1: + case TextureFormat::BC1: + case TextureFormat::BC2: + case TextureFormat::BC3: case TextureFormat::A8R8G8B8: + case TextureFormat::A1B5G5R5: + case TextureFormat::B5G6R5: + case TextureFormat::BF10GF11RF11: // TODO(Subv): For the time being just forward the same data without any decoding. rgba_data = texture_data; break; diff --git a/src/video_core/textures/decoders.h b/src/video_core/textures/decoders.h index 0c21694ff2..104641e29d 100644 --- a/src/video_core/textures/decoders.h +++ b/src/video_core/textures/decoders.h @@ -14,7 +14,8 @@ namespace Texture { /** * Unswizzles a swizzled texture without changing its format. */ -std::vector UnswizzleTexture(VAddr address, TextureFormat format, u32 width, u32 height); +std::vector UnswizzleTexture(VAddr address, TextureFormat format, u32 width, u32 height, + u32 block_height); /** * Decodes an unswizzled texture into a A8R8G8B8 texture. diff --git a/src/video_core/textures/texture.h b/src/video_core/textures/texture.h index 9d443ea90c..768eac3ed3 100644 --- a/src/video_core/textures/texture.h +++ b/src/video_core/textures/texture.h @@ -14,9 +14,13 @@ namespace Texture { enum class TextureFormat : u32 { A8R8G8B8 = 0x8, - DXT1 = 0x24, - DXT23 = 0x25, - DXT45 = 0x26, + A1B5G5R5 = 0x14, + B5G6R5 = 0x15, + BF10GF11RF11 = 0x21, + // Compressed Textures + BC1 = 0x24, + BC2 = 0x25, + BC3 = 0x26, }; enum class TextureType : u32 { @@ -70,7 +74,10 @@ struct TICEntry { BitField<0, 16, u32> address_high; BitField<21, 3, TICHeaderVersion> header_version; }; - INSERT_PADDING_BYTES(4); + union { + BitField<3, 3, u8> gobs_per_block; + }; + INSERT_PADDING_BYTES(3); union { BitField<0, 16, u32> width_minus_1; BitField<23, 4, TextureType> texture_type; @@ -94,6 +101,10 @@ struct TICEntry { return header_version == TICHeaderVersion::BlockLinear || header_version == TICHeaderVersion::BlockLinearColorKey; } + + u32 BlockHeight() const { + return 1 << gobs_per_block; + } }; static_assert(sizeof(TICEntry) == 0x20, "TICEntry has wrong size"); diff --git a/src/yuzu/debugger/graphics/graphics_surface.cpp b/src/yuzu/debugger/graphics/graphics_surface.cpp index 1e4844b578..78cbe96585 100644 --- a/src/yuzu/debugger/graphics/graphics_surface.cpp +++ b/src/yuzu/debugger/graphics/graphics_surface.cpp @@ -378,8 +378,8 @@ void GraphicsSurfaceWidget::OnUpdate() { QImage decoded_image(surface_width, surface_height, QImage::Format_ARGB32); VAddr address = gpu.memory_manager->PhysicalToVirtualAddress(surface_address); - auto unswizzled_data = - Tegra::Texture::UnswizzleTexture(address, surface_format, surface_width, surface_height); + auto unswizzled_data = Tegra::Texture::UnswizzleTexture(address, surface_format, surface_width, + surface_height, 16); auto texture_data = Tegra::Texture::DecodeTexture(unswizzled_data, surface_format, surface_width, surface_height);