summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Yuri Kunde Schlesner2017-01-06 01:59:34 -0200
committerGravatar Yuri Kunde Schlesner2017-02-04 12:33:28 -0800
commitc74787a11c44bd1fa444425d36ac3049dffe1496 (patch)
treef3f4b9ed7d54a3f1d2a7e8add80646299adc4cb1 /src
parentPica/Texture: Simplify/cleanup texture tile addressing (diff)
downloadyuzu-c74787a11c44bd1fa444425d36ac3049dffe1496.tar.gz
yuzu-c74787a11c44bd1fa444425d36ac3049dffe1496.tar.xz
yuzu-c74787a11c44bd1fa444425d36ac3049dffe1496.zip
Pica/Texture: Move part of ETC1 decoding to new file and cleanups
Diffstat (limited to 'src')
-rw-r--r--src/video_core/CMakeLists.txt2
-rw-r--r--src/video_core/texture/etc1.cpp124
-rw-r--r--src/video_core/texture/etc1.h16
-rw-r--r--src/video_core/texture/texture_decode.cpp127
4 files changed, 159 insertions, 110 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index ecb424cfd..ad984cd94 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -15,6 +15,7 @@ set(SRCS
15 shader/shader.cpp 15 shader/shader.cpp
16 shader/shader_interpreter.cpp 16 shader/shader_interpreter.cpp
17 swrasterizer.cpp 17 swrasterizer.cpp
18 texture/etc1.cpp
18 texture/texture_decode.cpp 19 texture/texture_decode.cpp
19 vertex_loader.cpp 20 vertex_loader.cpp
20 video_core.cpp 21 video_core.cpp
@@ -44,6 +45,7 @@ set(HEADERS
44 shader/shader.h 45 shader/shader.h
45 shader/shader_interpreter.h 46 shader/shader_interpreter.h
46 swrasterizer.h 47 swrasterizer.h
48 texture/etc1.h
47 texture/texture_decode.h 49 texture/texture_decode.h
48 utils.h 50 utils.h
49 vertex_loader.h 51 vertex_loader.h
diff --git a/src/video_core/texture/etc1.cpp b/src/video_core/texture/etc1.cpp
new file mode 100644
index 000000000..af60cde1e
--- /dev/null
+++ b/src/video_core/texture/etc1.cpp
@@ -0,0 +1,124 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include "common/bit_field.h"
9#include "common/color.h"
10#include "common/common_types.h"
11#include "common/math_util.h"
12#include "common/vector_math.h"
13#include "video_core/texture/etc1.h"
14
15namespace Pica {
16namespace Texture {
17
18namespace {
19
20constexpr std::array<u8[2], 8> etc1_modifier_table = {{
21 {2, 8}, {5, 17}, {9, 29}, {13, 42}, {18, 60}, {24, 80}, {33, 106}, {47, 183},
22}};
23
24union ETC1Tile {
25 u64 raw;
26
27 // Each of these two is a collection of 16 bits (one per lookup value)
28 BitField<0, 16, u64> table_subindexes;
29 BitField<16, 16, u64> negation_flags;
30
31 unsigned GetTableSubIndex(unsigned index) const {
32 return (table_subindexes >> index) & 1;
33 }
34
35 bool GetNegationFlag(unsigned index) const {
36 return ((negation_flags >> index) & 1) == 1;
37 }
38
39 BitField<32, 1, u64> flip;
40 BitField<33, 1, u64> differential_mode;
41
42 BitField<34, 3, u64> table_index_2;
43 BitField<37, 3, u64> table_index_1;
44
45 union {
46 // delta value + base value
47 BitField<40, 3, s64> db;
48 BitField<43, 5, u64> b;
49
50 BitField<48, 3, s64> dg;
51 BitField<51, 5, u64> g;
52
53 BitField<56, 3, s64> dr;
54 BitField<59, 5, u64> r;
55 } differential;
56
57 union {
58 BitField<40, 4, u64> b2;
59 BitField<44, 4, u64> b1;
60
61 BitField<48, 4, u64> g2;
62 BitField<52, 4, u64> g1;
63
64 BitField<56, 4, u64> r2;
65 BitField<60, 4, u64> r1;
66 } separate;
67
68 const Math::Vec3<u8> GetRGB(unsigned int x, unsigned int y) const {
69 int texel = 4 * x + y;
70
71 if (flip)
72 std::swap(x, y);
73
74 // Lookup base value
75 Math::Vec3<int> ret;
76 if (differential_mode) {
77 ret.r() = static_cast<int>(differential.r);
78 ret.g() = static_cast<int>(differential.g);
79 ret.b() = static_cast<int>(differential.b);
80 if (x >= 2) {
81 ret.r() += static_cast<int>(differential.dr);
82 ret.g() += static_cast<int>(differential.dg);
83 ret.b() += static_cast<int>(differential.db);
84 }
85 ret.r() = Color::Convert5To8(ret.r());
86 ret.g() = Color::Convert5To8(ret.g());
87 ret.b() = Color::Convert5To8(ret.b());
88 } else {
89 if (x < 2) {
90 ret.r() = Color::Convert4To8(static_cast<u8>(separate.r1));
91 ret.g() = Color::Convert4To8(static_cast<u8>(separate.g1));
92 ret.b() = Color::Convert4To8(static_cast<u8>(separate.b1));
93 } else {
94 ret.r() = Color::Convert4To8(static_cast<u8>(separate.r2));
95 ret.g() = Color::Convert4To8(static_cast<u8>(separate.g2));
96 ret.b() = Color::Convert4To8(static_cast<u8>(separate.b2));
97 }
98 }
99
100 // Add modifier
101 unsigned table_index =
102 static_cast<int>((x < 2) ? table_index_1.Value() : table_index_2.Value());
103
104 int modifier = etc1_modifier_table[table_index][GetTableSubIndex(texel)];
105 if (GetNegationFlag(texel))
106 modifier *= -1;
107
108 ret.r() = MathUtil::Clamp(ret.r() + modifier, 0, 255);
109 ret.g() = MathUtil::Clamp(ret.g() + modifier, 0, 255);
110 ret.b() = MathUtil::Clamp(ret.b() + modifier, 0, 255);
111
112 return ret.Cast<u8>();
113 }
114};
115
116} // anonymous namespace
117
118Math::Vec3<u8> SampleETC1Subtile(u64 value, unsigned int x, unsigned int y) {
119 ETC1Tile tile{value};
120 return tile.GetRGB(x, y);
121}
122
123} // namespace Texture
124} // namespace Pica
diff --git a/src/video_core/texture/etc1.h b/src/video_core/texture/etc1.h
new file mode 100644
index 000000000..e188b19df
--- /dev/null
+++ b/src/video_core/texture/etc1.h
@@ -0,0 +1,16 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8#include "common/vector_math.h"
9
10namespace Pica {
11namespace Texture {
12
13Math::Vec3<u8> SampleETC1Subtile(u64 value, unsigned int x, unsigned int y);
14
15} // namespace Texture
16} // namespace Pica
diff --git a/src/video_core/texture/texture_decode.cpp b/src/video_core/texture/texture_decode.cpp
index f13d6e577..f611a1aa9 100644
--- a/src/video_core/texture/texture_decode.cpp
+++ b/src/video_core/texture/texture_decode.cpp
@@ -8,8 +8,10 @@
8#include "common/color.h" 8#include "common/color.h"
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "common/math_util.h" 10#include "common/math_util.h"
11#include "common/swap.h"
11#include "common/vector_math.h" 12#include "common/vector_math.h"
12#include "video_core/pica.h" 13#include "video_core/pica.h"
14#include "video_core/texture/etc1.h"
13#include "video_core/texture/texture_decode.h" 15#include "video_core/texture/texture_decode.h"
14#include "video_core/utils.h" 16#include "video_core/utils.h"
15 17
@@ -177,127 +179,32 @@ Math::Vec4<u8> LookupTexelInTile(const u8* source, unsigned int x, unsigned int
177 case Regs::TextureFormat::ETC1: 179 case Regs::TextureFormat::ETC1:
178 case Regs::TextureFormat::ETC1A4: { 180 case Regs::TextureFormat::ETC1A4: {
179 bool has_alpha = (info.format == Regs::TextureFormat::ETC1A4); 181 bool has_alpha = (info.format == Regs::TextureFormat::ETC1A4);
182 size_t subtile_size = has_alpha ? 16 : 8;
180 183
181 // ETC1 further subdivides each 8x8 tile into four 4x4 subtiles 184 // ETC1 further subdivides each 8x8 tile into four 4x4 subtiles
182 constexpr unsigned int subtile_width = 4; 185 constexpr unsigned int subtile_width = 4;
183 constexpr unsigned int subtile_height = 4; 186 constexpr unsigned int subtile_height = 4;
184 187
185 unsigned int subtile_index = (x / subtile_width) + 2 * (y / subtile_height); 188 unsigned int subtile_index = (x / subtile_width) + 2 * (y / subtile_height);
186 size_t subtile_size = has_alpha ? 16 : 8; 189 x %= subtile_width;
190 y %= subtile_height;
187 191
188 // TODO(yuriks): Use memcpy instead of reinterpret_cast 192 const u8* subtile_ptr = source + subtile_index * subtile_size;
189 const u64* source_ptr = reinterpret_cast<const u64*>(source + subtile_index * subtile_size);
190 193
191 u64 alpha = 0xFFFFFFFFFFFFFFFF; 194 u8 alpha = 255;
192 if (has_alpha) { 195 if (has_alpha) {
193 alpha = *source_ptr; 196 u64_le packed_alpha;
194 source_ptr++; 197 memcpy(&packed_alpha, subtile_ptr, sizeof(u64));
198 subtile_ptr += sizeof(u64);
199
200 alpha = Color::Convert4To8((packed_alpha >> (4 * (x * subtile_width + y))) & 0xF);
195 } 201 }
196 202
197 union ETC1Tile { 203 u64_le subtile_data;
198 // Each of these two is a collection of 16 bits (one per lookup value) 204 memcpy(&subtile_data, subtile_ptr, sizeof(u64));
199 BitField<0, 16, u64> table_subindexes; 205
200 BitField<16, 16, u64> negation_flags; 206 return Math::MakeVec(SampleETC1Subtile(subtile_data, x, y),
201 207 disable_alpha ? (u8)255 : alpha);
202 unsigned GetTableSubIndex(unsigned index) const {
203 return (table_subindexes >> index) & 1;
204 }
205
206 bool GetNegationFlag(unsigned index) const {
207 return ((negation_flags >> index) & 1) == 1;
208 }
209
210 BitField<32, 1, u64> flip;
211 BitField<33, 1, u64> differential_mode;
212
213 BitField<34, 3, u64> table_index_2;
214 BitField<37, 3, u64> table_index_1;
215
216 union {
217 // delta value + base value
218 BitField<40, 3, s64> db;
219 BitField<43, 5, u64> b;
220
221 BitField<48, 3, s64> dg;
222 BitField<51, 5, u64> g;
223
224 BitField<56, 3, s64> dr;
225 BitField<59, 5, u64> r;
226 } differential;
227
228 union {
229 BitField<40, 4, u64> b2;
230 BitField<44, 4, u64> b1;
231
232 BitField<48, 4, u64> g2;
233 BitField<52, 4, u64> g1;
234
235 BitField<56, 4, u64> r2;
236 BitField<60, 4, u64> r1;
237 } separate;
238
239 const Math::Vec3<u8> GetRGB(int x, int y) const {
240 int texel = 4 * x + y;
241
242 if (flip)
243 std::swap(x, y);
244
245 // Lookup base value
246 Math::Vec3<int> ret;
247 if (differential_mode) {
248 ret.r() = static_cast<int>(differential.r);
249 ret.g() = static_cast<int>(differential.g);
250 ret.b() = static_cast<int>(differential.b);
251 if (x >= 2) {
252 ret.r() += static_cast<int>(differential.dr);
253 ret.g() += static_cast<int>(differential.dg);
254 ret.b() += static_cast<int>(differential.db);
255 }
256 ret.r() = Color::Convert5To8(ret.r());
257 ret.g() = Color::Convert5To8(ret.g());
258 ret.b() = Color::Convert5To8(ret.b());
259 } else {
260 if (x < 2) {
261 ret.r() = Color::Convert4To8(static_cast<u8>(separate.r1));
262 ret.g() = Color::Convert4To8(static_cast<u8>(separate.g1));
263 ret.b() = Color::Convert4To8(static_cast<u8>(separate.b1));
264 } else {
265 ret.r() = Color::Convert4To8(static_cast<u8>(separate.r2));
266 ret.g() = Color::Convert4To8(static_cast<u8>(separate.g2));
267 ret.b() = Color::Convert4To8(static_cast<u8>(separate.b2));
268 }
269 }
270
271 // Add modifier
272 unsigned table_index =
273 static_cast<int>((x < 2) ? table_index_1.Value() : table_index_2.Value());
274
275 static const std::array<std::array<u8, 2>, 8> etc1_modifier_table = {{
276 {{2, 8}},
277 {{5, 17}},
278 {{9, 29}},
279 {{13, 42}},
280 {{18, 60}},
281 {{24, 80}},
282 {{33, 106}},
283 {{47, 183}},
284 }};
285
286 int modifier = etc1_modifier_table.at(table_index).at(GetTableSubIndex(texel));
287 if (GetNegationFlag(texel))
288 modifier *= -1;
289
290 ret.r() = MathUtil::Clamp(ret.r() + modifier, 0, 255);
291 ret.g() = MathUtil::Clamp(ret.g() + modifier, 0, 255);
292 ret.b() = MathUtil::Clamp(ret.b() + modifier, 0, 255);
293
294 return ret.Cast<u8>();
295 }
296 } const* etc1_tile = reinterpret_cast<const ETC1Tile*>(source_ptr);
297
298 alpha >>= 4 * ((x & 3) * 4 + (y & 3));
299 return Math::MakeVec(etc1_tile->GetRGB(x & 3, y & 3),
300 disable_alpha ? (u8)255 : Color::Convert4To8(alpha & 0xF));
301 } 208 }
302 209
303 default: 210 default: