diff options
Diffstat (limited to 'src/video_core/textures')
-rw-r--r-- | src/video_core/textures/decoders.cpp | 105 | ||||
-rw-r--r-- | src/video_core/textures/decoders.h | 26 | ||||
-rw-r--r-- | src/video_core/textures/texture.h | 137 |
3 files changed, 268 insertions, 0 deletions
diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp new file mode 100644 index 000000000..2e87281eb --- /dev/null +++ b/src/video_core/textures/decoders.cpp @@ -0,0 +1,105 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <cstring> +#include "common/assert.h" +#include "video_core/textures/decoders.h" +#include "video_core/textures/texture.h" + +namespace Tegra { +namespace Texture { + +/** + * Calculates the offset of an (x, y) position within a swizzled texture. + * Taken from the Tegra X1 TRM. + */ +static u32 GetSwizzleOffset(u32 x, u32 y, u32 image_width, u32 bytes_per_pixel, u32 block_height) { + u32 image_width_in_gobs = image_width * bytes_per_pixel / 64; + u32 GOB_address = 0 + (y / (8 * block_height)) * 512 * block_height * image_width_in_gobs + + (x * bytes_per_pixel / 64) * 512 * block_height + + (y % (8 * block_height) / 8) * 512; + x *= bytes_per_pixel; + u32 address = GOB_address + ((x % 64) / 32) * 256 + ((y % 8) / 2) * 64 + ((x % 32) / 16) * 32 + + (y % 2) * 16 + (x % 16); + + return address; +} + +static void CopySwizzledData(u32 width, u32 height, u32 bytes_per_pixel, u32 out_bytes_per_pixel, + u8* swizzled_data, u8* unswizzled_data, bool unswizzle, + u32 block_height) { + u8* data_ptrs[2]; + for (unsigned y = 0; y < height; ++y) { + for (unsigned x = 0; x < width; ++x) { + u32 swizzle_offset = GetSwizzleOffset(x, y, width, bytes_per_pixel, block_height); + u32 pixel_index = (x + y * width) * out_bytes_per_pixel; + + data_ptrs[unswizzle] = swizzled_data + swizzle_offset; + data_ptrs[!unswizzle] = &unswizzled_data[pixel_index]; + + std::memcpy(data_ptrs[0], data_ptrs[1], bytes_per_pixel); + } + } +} + +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: + return 4; + default: + UNIMPLEMENTED_MSG("Format not implemented"); + break; + } +} + +std::vector<u8> UnswizzleTexture(VAddr address, TextureFormat format, u32 width, u32 height) { + u8* data = Memory::GetPointer(address); + u32 bytes_per_pixel = BytesPerPixel(format); + + static constexpr u32 DefaultBlockHeight = 16; + + 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. + CopySwizzledData(width / 4, height / 4, bytes_per_pixel, bytes_per_pixel, data, + unswizzled_data.data(), true, DefaultBlockHeight); + break; + case TextureFormat::A8R8G8B8: + CopySwizzledData(width, height, bytes_per_pixel, bytes_per_pixel, data, + unswizzled_data.data(), true, DefaultBlockHeight); + break; + default: + UNIMPLEMENTED_MSG("Format not implemented"); + break; + } + + return unswizzled_data; +} + +std::vector<u8> DecodeTexture(const std::vector<u8>& texture_data, TextureFormat format, u32 width, + u32 height) { + std::vector<u8> rgba_data; + + // TODO(Subv): Implement. + switch (format) { + case TextureFormat::DXT1: + case TextureFormat::A8R8G8B8: + // TODO(Subv): For the time being just forward the same data without any decoding. + rgba_data = texture_data; + break; + default: + UNIMPLEMENTED_MSG("Format not implemented"); + break; + } + + return rgba_data; +} + +} // namespace Texture +} // namespace Tegra diff --git a/src/video_core/textures/decoders.h b/src/video_core/textures/decoders.h new file mode 100644 index 000000000..0c21694ff --- /dev/null +++ b/src/video_core/textures/decoders.h @@ -0,0 +1,26 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <vector> +#include "common/common_types.h" +#include "video_core/textures/texture.h" + +namespace Tegra { +namespace Texture { + +/** + * Unswizzles a swizzled texture without changing its format. + */ +std::vector<u8> UnswizzleTexture(VAddr address, TextureFormat format, u32 width, u32 height); + +/** + * Decodes an unswizzled texture into a A8R8G8B8 texture. + */ +std::vector<u8> DecodeTexture(const std::vector<u8>& texture_data, TextureFormat format, u32 width, + u32 height); + +} // namespace Texture +} // namespace Tegra diff --git a/src/video_core/textures/texture.h b/src/video_core/textures/texture.h new file mode 100644 index 000000000..07936f8a3 --- /dev/null +++ b/src/video_core/textures/texture.h @@ -0,0 +1,137 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "common/bit_field.h" +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "video_core/memory_manager.h" + +namespace Tegra { +namespace Texture { + +enum class TextureFormat : u32 { + A8R8G8B8 = 8, + DXT1 = 0x24, +}; + +enum class TextureType : u32 { + Texture1D = 0, + Texture2D = 1, + Texture3D = 2, + TextureCubemap = 3, + Texture1DArray = 4, + Texture2DArray = 5, + Texture1DBuffer = 6, + Texture2DNoMipmap = 7, + TextureCubeArray = 8, +}; + +enum class TICHeaderVersion : u32 { + OneDBuffer = 0, + PitchColorKey = 1, + Pitch = 2, + BlockLinear = 3, + BlockLinearColorKey = 4, +}; + +union TextureHandle { + u32 raw; + BitField<0, 20, u32> tic_id; + BitField<20, 12, u32> tsc_id; +}; +static_assert(sizeof(TextureHandle) == 4, "TextureHandle has wrong size"); + +struct TICEntry { + union { + u32 raw; + 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; + }; + u32 address_low; + union { + BitField<0, 16, u32> address_high; + BitField<21, 3, TICHeaderVersion> header_version; + }; + INSERT_PADDING_BYTES(4); + union { + BitField<0, 16, u32> width_minus_1; + BitField<23, 4, TextureType> texture_type; + }; + u16 height_minus_1; + INSERT_PADDING_BYTES(10); + + GPUVAddr Address() const { + return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | address_low); + } + + u32 Width() const { + return width_minus_1 + 1; + } + + u32 Height() const { + return height_minus_1 + 1; + } +}; +static_assert(sizeof(TICEntry) == 0x20, "TICEntry has wrong size"); + +enum class WrapMode : u32 { + Wrap = 0, + Mirror = 1, + ClampToEdge = 2, + Border = 3, + ClampOGL = 4, + MirrorOnceClampToEdge = 5, + MirrorOnceBorder = 6, + MirrorOnceClampOGL = 7, +}; + +enum class TextureFilter : u32 { + Nearest = 1, + Linear = 2, +}; + +enum class TextureMipmapFilter : u32 { + None = 1, + Nearest = 2, + Linear = 3, +}; + +struct TSCEntry { + union { + BitField<0, 3, WrapMode> wrap_u; + BitField<3, 3, WrapMode> wrap_v; + BitField<6, 3, WrapMode> wrap_p; + BitField<9, 1, u32> depth_compare_enabled; + BitField<10, 3, u32> depth_compare_func; + }; + union { + BitField<0, 2, TextureFilter> mag_filter; + BitField<4, 2, TextureFilter> min_filter; + BitField<6, 2, TextureMipmapFilter> mip_filter; + }; + INSERT_PADDING_BYTES(8); + u32 border_color_r; + u32 border_color_g; + u32 border_color_b; + u32 border_color_a; +}; +static_assert(sizeof(TSCEntry) == 0x20, "TSCEntry has wrong size"); + +struct FullTextureInfo { + u32 index; + TICEntry tic; + TSCEntry tsc; + bool enabled; +}; + +/// Returns the number of bytes per pixel of the input texture format. +u32 BytesPerPixel(TextureFormat format); + +} // namespace Texture +} // namespace Tegra |