summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/citra_qt/debugger/graphics/graphics_surface.cpp13
-rw-r--r--src/video_core/pica.h5
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp3
-rw-r--r--src/video_core/texture/texture_decode.cpp108
-rw-r--r--src/video_core/texture/texture_decode.h32
5 files changed, 117 insertions, 44 deletions
diff --git a/src/citra_qt/debugger/graphics/graphics_surface.cpp b/src/citra_qt/debugger/graphics/graphics_surface.cpp
index c0a72a6ef..bd82b00d4 100644
--- a/src/citra_qt/debugger/graphics/graphics_surface.cpp
+++ b/src/citra_qt/debugger/graphics/graphics_surface.cpp
@@ -568,19 +568,14 @@ void GraphicsSurfaceWidget::OnUpdate() {
568 568
569 surface_picture_label->show(); 569 surface_picture_label->show();
570 570
571 unsigned nibbles_per_pixel = GraphicsSurfaceWidget::NibblesPerPixel(surface_format);
572 unsigned stride = nibbles_per_pixel * surface_width / 2;
573
574 // We handle depth formats here because DebugUtils only supports TextureFormats
575 if (surface_format <= Format::MaxTextureFormat) { 571 if (surface_format <= Format::MaxTextureFormat) {
576
577 // Generate a virtual texture 572 // Generate a virtual texture
578 Pica::Texture::TextureInfo info; 573 Pica::Texture::TextureInfo info;
579 info.physical_address = surface_address; 574 info.physical_address = surface_address;
580 info.width = surface_width; 575 info.width = surface_width;
581 info.height = surface_height; 576 info.height = surface_height;
582 info.format = static_cast<Pica::Regs::TextureFormat>(surface_format); 577 info.format = static_cast<Pica::Regs::TextureFormat>(surface_format);
583 info.stride = stride; 578 info.SetDefaultStride();
584 579
585 for (unsigned int y = 0; y < surface_height; ++y) { 580 for (unsigned int y = 0; y < surface_height; ++y) {
586 for (unsigned int x = 0; x < surface_width; ++x) { 581 for (unsigned int x = 0; x < surface_width; ++x) {
@@ -588,8 +583,12 @@ void GraphicsSurfaceWidget::OnUpdate() {
588 decoded_image.setPixel(x, y, qRgba(color.r(), color.g(), color.b(), color.a())); 583 decoded_image.setPixel(x, y, qRgba(color.r(), color.g(), color.b(), color.a()));
589 } 584 }
590 } 585 }
591
592 } else { 586 } else {
587 // We handle depth formats here because DebugUtils only supports TextureFormats
588
589 // TODO(yuriks): Convert to newer tile-based addressing
590 unsigned nibbles_per_pixel = GraphicsSurfaceWidget::NibblesPerPixel(surface_format);
591 unsigned stride = nibbles_per_pixel * surface_width / 2;
593 592
594 ASSERT_MSG(nibbles_per_pixel >= 2, 593 ASSERT_MSG(nibbles_per_pixel >= 2,
595 "Depth decoder only supports formats with at least one byte per pixel"); 594 "Depth decoder only supports formats with at least one byte per pixel");
diff --git a/src/video_core/pica.h b/src/video_core/pica.h
index b2db609ec..4ab4f1f40 100644
--- a/src/video_core/pica.h
+++ b/src/video_core/pica.h
@@ -275,8 +275,11 @@ struct Regs {
275 case TextureFormat::I8: 275 case TextureFormat::I8:
276 case TextureFormat::A8: 276 case TextureFormat::A8:
277 case TextureFormat::IA4: 277 case TextureFormat::IA4:
278 default: // placeholder for yet unknown formats
279 return 2; 278 return 2;
279
280 default: // placeholder for yet unknown formats
281 UNIMPLEMENTED();
282 return 0;
280 } 283 }
281 } 284 }
282 285
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 4167d3161..60380257a 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -342,9 +342,8 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo
342 Pica::Texture::TextureInfo tex_info; 342 Pica::Texture::TextureInfo tex_info;
343 tex_info.width = params.width; 343 tex_info.width = params.width;
344 tex_info.height = params.height; 344 tex_info.height = params.height;
345 tex_info.stride =
346 params.width * CachedSurface::GetFormatBpp(params.pixel_format) / 8;
347 tex_info.format = (Pica::Regs::TextureFormat)params.pixel_format; 345 tex_info.format = (Pica::Regs::TextureFormat)params.pixel_format;
346 tex_info.SetDefaultStride();
348 tex_info.physical_address = params.addr; 347 tex_info.physical_address = params.addr;
349 348
350 for (unsigned y = 0; y < params.height; ++y) { 349 for (unsigned y = 0; y < params.height; ++y) {
diff --git a/src/video_core/texture/texture_decode.cpp b/src/video_core/texture/texture_decode.cpp
index a3b05fe81..f13d6e577 100644
--- a/src/video_core/texture/texture_decode.cpp
+++ b/src/video_core/texture/texture_decode.cpp
@@ -9,52 +9,104 @@
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/vector_math.h" 11#include "common/vector_math.h"
12#include "video_core/pica.h"
12#include "video_core/texture/texture_decode.h" 13#include "video_core/texture/texture_decode.h"
13#include "video_core/utils.h" 14#include "video_core/utils.h"
14 15
16using TextureFormat = Pica::Regs::TextureFormat;
17
15namespace Pica { 18namespace Pica {
16namespace Texture { 19namespace Texture {
17 20
18Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const TextureInfo& info, 21constexpr size_t TILE_SIZE = 8 * 8;
19 bool disable_alpha) { 22constexpr size_t ETC1_SUBTILES = 2 * 2;
20 const unsigned int coarse_x = x & ~7; 23
21 const unsigned int coarse_y = y & ~7; 24size_t CalculateTileSize(TextureFormat format) {
25 switch (format) {
26 case TextureFormat::RGBA8:
27 return 4 * TILE_SIZE;
28
29 case TextureFormat::RGB8:
30 return 3 * TILE_SIZE;
31
32 case TextureFormat::RGB5A1:
33 case TextureFormat::RGB565:
34 case TextureFormat::RGBA4:
35 case TextureFormat::IA8:
36 case TextureFormat::RG8:
37 return 2 * TILE_SIZE;
38
39 case TextureFormat::I8:
40 case TextureFormat::A8:
41 case TextureFormat::IA4:
42 return 1 * TILE_SIZE;
43
44 case TextureFormat::I4:
45 case TextureFormat::A4:
46 return TILE_SIZE / 2;
47
48 case TextureFormat::ETC1:
49 return ETC1_SUBTILES * 8;
50
51 case TextureFormat::ETC1A4:
52 return ETC1_SUBTILES * 16;
22 53
23 if (info.format != Regs::TextureFormat::ETC1 && info.format != Regs::TextureFormat::ETC1A4) { 54 default: // placeholder for yet unknown formats
24 // TODO(neobrain): Fix code design to unify vertical block offsets! 55 UNIMPLEMENTED();
25 source += coarse_y * info.stride; 56 return 0;
26 } 57 }
58}
59
60Math::Vec4<u8> LookupTexture(const u8* source, unsigned int x, unsigned int y,
61 const TextureInfo& info, bool disable_alpha) {
62 // Coordinate in tiles
63 const unsigned int coarse_x = x / 8;
64 const unsigned int coarse_y = y / 8;
27 65
28 // TODO: Assert that width/height are multiples of block dimensions 66 // Coordinate inside the tile
67 const unsigned int fine_x = x % 8;
68 const unsigned int fine_y = y % 8;
69
70 const u8* line = source + coarse_y * info.stride;
71 const u8* tile = line + coarse_x * CalculateTileSize(info.format);
72 return LookupTexelInTile(tile, fine_x, fine_y, info, disable_alpha);
73}
74
75Math::Vec4<u8> LookupTexelInTile(const u8* source, unsigned int x, unsigned int y,
76 const TextureInfo& info, bool disable_alpha) {
77 DEBUG_ASSERT(x < 8);
78 DEBUG_ASSERT(y < 8);
79
80 using VideoCore::MortonInterleave;
29 81
30 switch (info.format) { 82 switch (info.format) {
31 case Regs::TextureFormat::RGBA8: { 83 case Regs::TextureFormat::RGBA8: {
32 auto res = Color::DecodeRGBA8(source + VideoCore::GetMortonOffset(x, y, 4)); 84 auto res = Color::DecodeRGBA8(source + MortonInterleave(x, y) * 4);
33 return {res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a())}; 85 return {res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a())};
34 } 86 }
35 87
36 case Regs::TextureFormat::RGB8: { 88 case Regs::TextureFormat::RGB8: {
37 auto res = Color::DecodeRGB8(source + VideoCore::GetMortonOffset(x, y, 3)); 89 auto res = Color::DecodeRGB8(source + MortonInterleave(x, y) * 3);
38 return {res.r(), res.g(), res.b(), 255}; 90 return {res.r(), res.g(), res.b(), 255};
39 } 91 }
40 92
41 case Regs::TextureFormat::RGB5A1: { 93 case Regs::TextureFormat::RGB5A1: {
42 auto res = Color::DecodeRGB5A1(source + VideoCore::GetMortonOffset(x, y, 2)); 94 auto res = Color::DecodeRGB5A1(source + MortonInterleave(x, y) * 2);
43 return {res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a())}; 95 return {res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a())};
44 } 96 }
45 97
46 case Regs::TextureFormat::RGB565: { 98 case Regs::TextureFormat::RGB565: {
47 auto res = Color::DecodeRGB565(source + VideoCore::GetMortonOffset(x, y, 2)); 99 auto res = Color::DecodeRGB565(source + MortonInterleave(x, y) * 2);
48 return {res.r(), res.g(), res.b(), 255}; 100 return {res.r(), res.g(), res.b(), 255};
49 } 101 }
50 102
51 case Regs::TextureFormat::RGBA4: { 103 case Regs::TextureFormat::RGBA4: {
52 auto res = Color::DecodeRGBA4(source + VideoCore::GetMortonOffset(x, y, 2)); 104 auto res = Color::DecodeRGBA4(source + MortonInterleave(x, y) * 2);
53 return {res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a())}; 105 return {res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a())};
54 } 106 }
55 107
56 case Regs::TextureFormat::IA8: { 108 case Regs::TextureFormat::IA8: {
57 const u8* source_ptr = source + VideoCore::GetMortonOffset(x, y, 2); 109 const u8* source_ptr = source + MortonInterleave(x, y) * 2;
58 110
59 if (disable_alpha) { 111 if (disable_alpha) {
60 // Show intensity as red, alpha as green 112 // Show intensity as red, alpha as green
@@ -65,17 +117,17 @@ Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const TextureInfo&
65 } 117 }
66 118
67 case Regs::TextureFormat::RG8: { 119 case Regs::TextureFormat::RG8: {
68 auto res = Color::DecodeRG8(source + VideoCore::GetMortonOffset(x, y, 2)); 120 auto res = Color::DecodeRG8(source + MortonInterleave(x, y) * 2);
69 return {res.r(), res.g(), 0, 255}; 121 return {res.r(), res.g(), 0, 255};
70 } 122 }
71 123
72 case Regs::TextureFormat::I8: { 124 case Regs::TextureFormat::I8: {
73 const u8* source_ptr = source + VideoCore::GetMortonOffset(x, y, 1); 125 const u8* source_ptr = source + MortonInterleave(x, y);
74 return {*source_ptr, *source_ptr, *source_ptr, 255}; 126 return {*source_ptr, *source_ptr, *source_ptr, 255};
75 } 127 }
76 128
77 case Regs::TextureFormat::A8: { 129 case Regs::TextureFormat::A8: {
78 const u8* source_ptr = source + VideoCore::GetMortonOffset(x, y, 1); 130 const u8* source_ptr = source + MortonInterleave(x, y);
79 131
80 if (disable_alpha) { 132 if (disable_alpha) {
81 return {*source_ptr, *source_ptr, *source_ptr, 255}; 133 return {*source_ptr, *source_ptr, *source_ptr, 255};
@@ -85,7 +137,7 @@ Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const TextureInfo&
85 } 137 }
86 138
87 case Regs::TextureFormat::IA4: { 139 case Regs::TextureFormat::IA4: {
88 const u8* source_ptr = source + VideoCore::GetMortonOffset(x, y, 1); 140 const u8* source_ptr = source + MortonInterleave(x, y);
89 141
90 u8 i = Color::Convert4To8(((*source_ptr) & 0xF0) >> 4); 142 u8 i = Color::Convert4To8(((*source_ptr) & 0xF0) >> 4);
91 u8 a = Color::Convert4To8((*source_ptr) & 0xF); 143 u8 a = Color::Convert4To8((*source_ptr) & 0xF);
@@ -99,7 +151,7 @@ Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const TextureInfo&
99 } 151 }
100 152
101 case Regs::TextureFormat::I4: { 153 case Regs::TextureFormat::I4: {
102 u32 morton_offset = VideoCore::GetMortonOffset(x, y, 1); 154 u32 morton_offset = MortonInterleave(x, y);
103 const u8* source_ptr = source + morton_offset / 2; 155 const u8* source_ptr = source + morton_offset / 2;
104 156
105 u8 i = (morton_offset % 2) ? ((*source_ptr & 0xF0) >> 4) : (*source_ptr & 0xF); 157 u8 i = (morton_offset % 2) ? ((*source_ptr & 0xF0) >> 4) : (*source_ptr & 0xF);
@@ -109,7 +161,7 @@ Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const TextureInfo&
109 } 161 }
110 162
111 case Regs::TextureFormat::A4: { 163 case Regs::TextureFormat::A4: {
112 u32 morton_offset = VideoCore::GetMortonOffset(x, y, 1); 164 u32 morton_offset = MortonInterleave(x, y);
113 const u8* source_ptr = source + morton_offset / 2; 165 const u8* source_ptr = source + morton_offset / 2;
114 166
115 u8 a = (morton_offset % 2) ? ((*source_ptr & 0xF0) >> 4) : (*source_ptr & 0xF); 167 u8 a = (morton_offset % 2) ? ((*source_ptr & 0xF0) >> 4) : (*source_ptr & 0xF);
@@ -127,15 +179,15 @@ Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const TextureInfo&
127 bool has_alpha = (info.format == Regs::TextureFormat::ETC1A4); 179 bool has_alpha = (info.format == Regs::TextureFormat::ETC1A4);
128 180
129 // ETC1 further subdivides each 8x8 tile into four 4x4 subtiles 181 // ETC1 further subdivides each 8x8 tile into four 4x4 subtiles
130 const int subtile_width = 4; 182 constexpr unsigned int subtile_width = 4;
131 const int subtile_height = 4; 183 constexpr unsigned int subtile_height = 4;
184
185 unsigned int subtile_index = (x / subtile_width) + 2 * (y / subtile_height);
186 size_t subtile_size = has_alpha ? 16 : 8;
132 187
133 int subtile_index = ((x / subtile_width) & 1) + 2 * ((y / subtile_height) & 1); 188 // TODO(yuriks): Use memcpy instead of reinterpret_cast
134 unsigned subtile_bytes = has_alpha ? 2 : 1; // TODO: Name... 189 const u64* source_ptr = reinterpret_cast<const u64*>(source + subtile_index * subtile_size);
135 190
136 const u64* source_ptr = (const u64*)(source + coarse_x * subtile_bytes * 4 +
137 coarse_y * subtile_bytes * 4 * (info.width / 8) +
138 subtile_index * subtile_bytes * 8);
139 u64 alpha = 0xFFFFFFFFFFFFFFFF; 191 u64 alpha = 0xFFFFFFFFFFFFFFFF;
140 if (has_alpha) { 192 if (has_alpha) {
141 alpha = *source_ptr; 193 alpha = *source_ptr;
@@ -262,7 +314,7 @@ TextureInfo TextureInfo::FromPicaRegister(const Regs::TextureConfig& config,
262 info.width = config.width; 314 info.width = config.width;
263 info.height = config.height; 315 info.height = config.height;
264 info.format = format; 316 info.format = format;
265 info.stride = Pica::Regs::NibblesPerPixel(info.format) * info.width / 2; 317 info.SetDefaultStride();
266 return info; 318 return info;
267} 319}
268 320
diff --git a/src/video_core/texture/texture_decode.h b/src/video_core/texture/texture_decode.h
index 0c1438b0f..5c636939a 100644
--- a/src/video_core/texture/texture_decode.h
+++ b/src/video_core/texture/texture_decode.h
@@ -11,21 +11,29 @@
11namespace Pica { 11namespace Pica {
12namespace Texture { 12namespace Texture {
13 13
14/// Returns the byte size of a 8*8 tile of the specified texture format.
15size_t CalculateTileSize(Pica::Regs::TextureFormat format);
16
14struct TextureInfo { 17struct TextureInfo {
15 PAddr physical_address; 18 PAddr physical_address;
16 int width; 19 unsigned int width;
17 int height; 20 unsigned int height;
18 int stride; 21 ptrdiff_t stride;
19 Pica::Regs::TextureFormat format; 22 Pica::Regs::TextureFormat format;
20 23
21 static TextureInfo FromPicaRegister(const Pica::Regs::TextureConfig& config, 24 static TextureInfo FromPicaRegister(const Pica::Regs::TextureConfig& config,
22 const Pica::Regs::TextureFormat& format); 25 const Pica::Regs::TextureFormat& format);
26
27 /// Calculates stride from format and width, assuming that the entire texture is contiguous.
28 void SetDefaultStride() {
29 stride = Pica::Texture::CalculateTileSize(format) * (width / 8);
30 }
23}; 31};
24 32
25/** 33/**
26 * Lookup texel located at the given coordinates and return an RGBA vector of its color. 34 * Lookup texel located at the given coordinates and return an RGBA vector of its color.
27 * @param source Source pointer to read data from 35 * @param source Source pointer to read data from
28 * @param s,t Texture coordinates to read from 36 * @param x,y Texture coordinates to read from
29 * @param info TextureInfo object describing the texture setup 37 * @param info TextureInfo object describing the texture setup
30 * @param disable_alpha This is used for debug widgets which use this method to display textures 38 * @param disable_alpha This is used for debug widgets which use this method to display textures
31 * without providing a good way to visualize alpha by themselves. If true, this will return 255 for 39 * without providing a good way to visualize alpha by themselves. If true, this will return 255 for
@@ -33,8 +41,20 @@ struct TextureInfo {
33 * channel. 41 * channel.
34 * @todo Eventually we should get rid of the disable_alpha parameter. 42 * @todo Eventually we should get rid of the disable_alpha parameter.
35 */ 43 */
36Math::Vec4<u8> LookupTexture(const u8* source, int s, int t, const TextureInfo& info, 44Math::Vec4<u8> LookupTexture(const u8* source, unsigned int x, unsigned int y,
37 bool disable_alpha = false); 45 const TextureInfo& info, bool disable_alpha = false);
46
47/**
48 * Looks up a texel from a single 8x8 texture tile.
49 *
50 * @param source Pointer to the beginning of the tile.
51 * @param x, y In-tile coordinates to read from. Must be < 8.
52 * @param info TextureInfo describing the texture format.
53 * @param disable_alpha Used for debugging. Sets the result alpha to 255 and either discards the
54 * real alpha or inserts it in an otherwise unused channel.
55 */
56Math::Vec4<u8> LookupTexelInTile(const u8* source, unsigned int x, unsigned int y,
57 const TextureInfo& info, bool disable_alpha);
38 58
39} // namespace Texture 59} // namespace Texture
40} // namespace Pica 60} // namespace Pica