(jroweboy) textures: Add support for other formats.
This commit is contained in:
@@ -51,9 +51,14 @@ 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, 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 std::array<FormatTuple, 7> 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 <bool morton_to_gl, PixelFormat format>
|
||||
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 <bool morton_to_gl, PixelFormat format>
|
||||
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<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);
|
||||
void MortonCopy<true, PixelFormat::BC1>(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<void (*)(u32, u32, u8*, VAddr, VAddr, VAddr), 2> morton_to_gl_fns = {
|
||||
MortonCopy<true, PixelFormat::RGBA8>,
|
||||
MortonCopy<true, PixelFormat::DXT1>,
|
||||
template <>
|
||||
void MortonCopy<true, PixelFormat::BC2>(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<true, PixelFormat::BC3>(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<void (*)(u32, u32, u32, u8*, VAddr, VAddr, VAddr), 7> morton_to_gl_fns =
|
||||
{
|
||||
MortonCopy<true, PixelFormat::RGBA8>, // RGBA8
|
||||
MortonCopy<true, PixelFormat::RGB5A1>, // RGB5A1
|
||||
MortonCopy<true, PixelFormat::RGB565>, // RGB565
|
||||
MortonCopy<true, PixelFormat::RG11FB10F>, // RG11FB10F
|
||||
MortonCopy<true, PixelFormat::BC1>, // BC1
|
||||
MortonCopy<true, PixelFormat::BC2>, // BC2
|
||||
MortonCopy<true, PixelFormat::BC3>, // BC3
|
||||
};
|
||||
|
||||
static constexpr std::array<void (*)(u32, u32, u8*, VAddr, VAddr, VAddr), 2> gl_to_morton_fns = {
|
||||
MortonCopy<false, PixelFormat::RGBA8>,
|
||||
MortonCopy<false, PixelFormat::DXT1>,
|
||||
static constexpr std::array<void (*)(u32, u32, u32, u8*, VAddr, VAddr, VAddr), 7> gl_to_morton_fns =
|
||||
{
|
||||
MortonCopy<false, PixelFormat::RGBA8>, // RGBA8
|
||||
MortonCopy<false, PixelFormat::RGB5A1>, // RGB5A1
|
||||
MortonCopy<false, PixelFormat::RGB565>, // RGB565
|
||||
MortonCopy<false, PixelFormat::RG11FB10F>, // RG11FB10F
|
||||
MortonCopy<false, PixelFormat::BC1>, // BC1
|
||||
MortonCopy<false, PixelFormat::BC2>, // BC2
|
||||
MortonCopy<false, PixelFormat::BC3>, // 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<size_t>(pixel_format)](stride, height, &gl_buffer[0], addr,
|
||||
load_start, load_end);
|
||||
morton_to_gl_fns[static_cast<size_t>(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<size_t>(pixel_format)](stride, height, &gl_buffer[0], addr,
|
||||
flush_start, flush_end);
|
||||
gl_to_morton_fns[static_cast<size_t>(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();
|
||||
|
||||
|
||||
@@ -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<unsigned int, 2> bpp_table = {
|
||||
32, // RGBA8
|
||||
64, // DXT1
|
||||
constexpr std::array<unsigned int, 7> bpp_table = {
|
||||
32, // RGBA8
|
||||
16, // RGB5A1
|
||||
16, // RGB565
|
||||
32, // RG11FB10F
|
||||
64, // BC1
|
||||
128, // BC2
|
||||
128, // BC3
|
||||
};
|
||||
|
||||
ASSERT(static_cast<size_t>(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<u32>(format));
|
||||
UNREACHABLE();
|
||||
@@ -140,7 +158,7 @@ struct SurfaceParams {
|
||||
return SurfaceType::Color;
|
||||
}
|
||||
|
||||
if ((unsigned int)pixel_format <= static_cast<unsigned int>(PixelFormat::DXT1)) {
|
||||
if ((unsigned int)pixel_format <= static_cast<unsigned int>(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;
|
||||
|
||||
@@ -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<u8> UnswizzleTexture(VAddr address, TextureFormat format, u32 width, u32 height) {
|
||||
std::vector<u8> 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<u8> UnswizzleTexture(VAddr address, TextureFormat format, u32 width,
|
||||
std::vector<u8> 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<u8> DecodeTexture(const std::vector<u8>& 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;
|
||||
|
||||
@@ -14,7 +14,8 @@ namespace Texture {
|
||||
/**
|
||||
* Unswizzles a swizzled texture without changing its format.
|
||||
*/
|
||||
std::vector<u8> UnswizzleTexture(VAddr address, TextureFormat format, u32 width, u32 height);
|
||||
std::vector<u8> UnswizzleTexture(VAddr address, TextureFormat format, u32 width, u32 height,
|
||||
u32 block_height);
|
||||
|
||||
/**
|
||||
* Decodes an unswizzled texture into a A8R8G8B8 texture.
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user