1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
|
// Copyright 2008 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <array>
#include <span>
#include <tuple>
#include "Common/CommonTypes.h"
#include "Common/EnumFormatter.h"
#include "Common/SpanUtils.h"
enum
{
TMEM_SIZE = 1024 * 1024,
TMEM_LINE_SIZE = 32,
};
alignas(16) extern std::array<u8, TMEM_SIZE> s_tex_mem;
enum class TextureFormat
{
// These values represent texture format in GX registers.
I4 = 0x0,
I8 = 0x1,
IA4 = 0x2,
IA8 = 0x3,
RGB565 = 0x4,
RGB5A3 = 0x5,
RGBA8 = 0x6,
C4 = 0x8,
C8 = 0x9,
C14X2 = 0xA,
CMPR = 0xE,
// Special texture format used to represent YUVY xfb copies.
// They aren't really textures, but they share so much hardware and usecases that it makes sense
// to emulate them as part of texture cache.
// This isn't a real value that can be used on console; it only exists for ease of implementation.
XFB = 0xF,
};
template <>
struct fmt::formatter<TextureFormat> : EnumFormatter<TextureFormat::CMPR>
{
static constexpr array_type names = {"I4", "I8", "IA4", "IA8", "RGB565",
"RGB5A3", "RGBA8", nullptr, "C4", "C8",
"C14X2", nullptr, nullptr, nullptr, "CMPR"};
constexpr formatter() : EnumFormatter(names) {}
};
static inline bool IsColorIndexed(TextureFormat format)
{
return format == TextureFormat::C4 || format == TextureFormat::C8 ||
format == TextureFormat::C14X2;
}
static inline bool IsValidTextureFormat(TextureFormat format)
{
return format <= TextureFormat::RGBA8 || IsColorIndexed(format) || format == TextureFormat::CMPR;
}
// The EFB Copy pipeline looks like:
//
// 1. Read EFB -> 2. Select color/depth -> 3. Downscale (optional)
// -> 4. YUV conversion (optional) -> 5. Encode Tiles -> 6. Write RAM
//
// The "Encode Tiles" stage receives RGBA8 texels from previous stages and encodes them to various
// formats. EFBCopyFormat is the tile encoder mode. Note that the tile encoder does not care about
// color vs. depth or intensity formats - it only sees RGBA8 texels.
enum class EFBCopyFormat
{
// These values represent EFB copy format in GX registers.
// Most (but not all) of these values correspond to values of TextureFormat.
R4 = 0x0, // R4, I4, Z4
// FIXME: Does 0x1 (Z8) have identical results to 0x8 (Z8H)?
// Is either or both of 0x1 and 0x8 used in games?
R8_0x1 = 0x1, // R8, I8, Z8H (?)
RA4 = 0x2, // RA4, IA4
// FIXME: Earlier versions of this file named the value 0x3 "GX_TF_Z16", which does not reflect
// the results one would expect when copying from the depth buffer with this format.
// For reference: When copying from the depth buffer, R should receive the top 8 bits of
// the Z value, and A should be either 0xFF or 0 (please investigate).
// Please test original hardware and make sure dolphin-emu implements this format
// correctly.
RA8 = 0x3, // RA8, IA8, (FIXME: Z16 too?)
RGB565 = 0x4,
RGB5A3 = 0x5,
RGBA8 = 0x6, // RGBA8, Z24
A8 = 0x7,
R8 = 0x8, // R8, I8, Z8H
G8 = 0x9, // G8, Z8M
B8 = 0xA, // B8, Z8L
RG8 = 0xB, // RG8, Z16R (Note: G and R are reversed)
GB8 = 0xC, // GB8, Z16L
// Special texture format used to represent YUVY xfb copies.
// They aren't really textures, but they share so much hardware and usecases that it makes sense
// to emulate them as part of texture cache.
// This isn't a real value that can be used on console; it only exists for ease of implementation.
XFB = 0xF,
};
template <>
struct fmt::formatter<EFBCopyFormat> : EnumFormatter<EFBCopyFormat::GB8>
{
static constexpr array_type names = {
"R4/I4/Z4", "R8/I8/Z8H (?)", "RA4/IA4", "RA8/IA8 (Z16 too?)",
"RGB565", "RGB5A3", "RGBA8", "A8",
"R8/I8/Z8H", "G8/Z8M", "B8/Z8L", "RG8/Z16R (Note: G and R are reversed)",
"GB8/Z16L",
};
constexpr formatter() : EnumFormatter(names) {}
};
enum class TLUTFormat
{
// These values represent TLUT format in GX registers.
IA8 = 0x0,
RGB565 = 0x1,
RGB5A3 = 0x2,
};
template <>
struct fmt::formatter<TLUTFormat> : EnumFormatter<TLUTFormat::RGB5A3>
{
constexpr formatter() : EnumFormatter({"IA8", "RGB565", "RGB5A3"}) {}
};
static inline bool IsValidTLUTFormat(TLUTFormat tlutfmt)
{
return tlutfmt == TLUTFormat::IA8 || tlutfmt == TLUTFormat::RGB565 ||
tlutfmt == TLUTFormat::RGB5A3;
}
static inline bool IsCompatibleTextureFormat(TextureFormat from_format, TextureFormat to_format)
{
if (from_format == to_format)
return true;
// Indexed and paletted formats are "compatible", that is do not require conversion.
switch (from_format)
{
case TextureFormat::I4:
case TextureFormat::C4:
return to_format == TextureFormat::I4 || to_format == TextureFormat::C4;
case TextureFormat::I8:
case TextureFormat::C8:
return to_format == TextureFormat::I8 || to_format == TextureFormat::C8;
default:
return false;
}
}
static inline bool CanReinterpretTextureOnGPU(TextureFormat from_format, TextureFormat to_format)
{
// Currently, we can only reinterpret textures of the same width.
switch (from_format)
{
case TextureFormat::I8:
case TextureFormat::IA4:
return to_format == TextureFormat::I8 || to_format == TextureFormat::IA4;
case TextureFormat::IA8:
case TextureFormat::RGB565:
case TextureFormat::RGB5A3:
return to_format == TextureFormat::IA8 || to_format == TextureFormat::RGB565 ||
to_format == TextureFormat::RGB5A3;
default:
return false;
}
}
inline std::span<u8> TexDecoder_GetTmemSpan(size_t offset = 0)
{
return Common::SafeSubspan(std::span<u8>(s_tex_mem), offset);
}
int TexDecoder_GetTexelSizeInNibbles(TextureFormat format);
int TexDecoder_GetTextureSizeInBytes(int width, int height, TextureFormat format);
int TexDecoder_GetBlockWidthInTexels(TextureFormat format);
int TexDecoder_GetBlockHeightInTexels(TextureFormat format);
int TexDecoder_GetEFBCopyBlockWidthInTexels(EFBCopyFormat format);
int TexDecoder_GetEFBCopyBlockHeightInTexels(EFBCopyFormat format);
int TexDecoder_GetPaletteSize(TextureFormat fmt);
TextureFormat TexDecoder_GetEFBCopyBaseFormat(EFBCopyFormat format);
void TexDecoder_Decode(u8* dst, const u8* src, int width, int height, TextureFormat texformat,
const u8* tlut, TLUTFormat tlutfmt);
void TexDecoder_DecodeRGBA8FromTmem(u8* dst, const u8* src_ar, const u8* src_gb, int width,
int height);
void TexDecoder_DecodeTexel(u8* dst, std::span<const u8> src, int s, int t, int imageWidth,
TextureFormat texformat, std::span<const u8> tlut, TLUTFormat tlutfmt);
void TexDecoder_DecodeTexelRGBA8FromTmem(u8* dst, std::span<const u8> src_ar,
std::span<const u8> src_gb, int s, int t, int imageWidth);
void TexDecoder_DecodeTexelRGBA8FromTmem(u8* dst, const u8* src_ar, const u8* src_gb, int s, int t,
int imageWidth);
void TexDecoder_DecodeXFB(u8* dst, const u8* src, u32 width, u32 height, u32 stride);
void TexDecoder_SetTexFmtOverlayOptions(bool enable, bool center);
/* Internal method, implemented by TextureDecoder_Generic and TextureDecoder_x64. */
void _TexDecoder_DecodeImpl(u32* dst, const u8* src, int width, int height, TextureFormat texformat,
const u8* tlut, TLUTFormat tlutfmt);
|