summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Tony Wasserka2014-12-06 19:10:08 +0100
committerGravatar Tony Wasserka2014-12-20 18:05:53 +0100
commitfd2539121cddd6177a964770a6985f8880ca1646 (patch)
tree67d2e0e33ee435569e3a82eaa891c2154ed83d53
parentBitField: Add an explicit Assign method. (diff)
downloadyuzu-fd2539121cddd6177a964770a6985f8880ca1646.tar.gz
yuzu-fd2539121cddd6177a964770a6985f8880ca1646.tar.xz
yuzu-fd2539121cddd6177a964770a6985f8880ca1646.zip
Pica: Initial support for multitexturing.
-rw-r--r--src/citra_qt/debugger/graphics_cmdlists.cpp39
-rw-r--r--src/video_core/pica.h40
-rw-r--r--src/video_core/rasterizer.cpp58
-rw-r--r--src/video_core/vertex_shader.h9
4 files changed, 115 insertions, 31 deletions
diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp
index 7f97cf143..bdd676470 100644
--- a/src/citra_qt/debugger/graphics_cmdlists.cpp
+++ b/src/citra_qt/debugger/graphics_cmdlists.cpp
@@ -223,9 +223,21 @@ void GPUCommandListModel::OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace&
223 223
224void GPUCommandListWidget::OnCommandDoubleClicked(const QModelIndex& index) { 224void GPUCommandListWidget::OnCommandDoubleClicked(const QModelIndex& index) {
225 const int command_id = list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toInt(); 225 const int command_id = list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toInt();
226 if (COMMAND_IN_RANGE(command_id, texture0)) { 226 if (COMMAND_IN_RANGE(command_id, texture0) ||
227 auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(Pica::registers.texture0, 227 COMMAND_IN_RANGE(command_id, texture1) ||
228 Pica::registers.texture0_format); 228 COMMAND_IN_RANGE(command_id, texture2)) {
229
230 unsigned index;
231 if (COMMAND_IN_RANGE(command_id, texture0)) {
232 index = 0;
233 } else if (COMMAND_IN_RANGE(command_id, texture1)) {
234 index = 1;
235 } else {
236 index = 2;
237 }
238 auto config = Pica::registers.GetTextures()[index].config;
239 auto format = Pica::registers.GetTextures()[index].format;
240 auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config, format);
229 241
230 // TODO: Instead, emit a signal here to be caught by the main window widget. 242 // TODO: Instead, emit a signal here to be caught by the main window widget.
231 auto main_window = static_cast<QMainWindow*>(parent()); 243 auto main_window = static_cast<QMainWindow*>(parent());
@@ -237,10 +249,23 @@ void GPUCommandListWidget::SetCommandInfo(const QModelIndex& index) {
237 QWidget* new_info_widget; 249 QWidget* new_info_widget;
238 250
239 const int command_id = list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toInt(); 251 const int command_id = list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toInt();
240 if (COMMAND_IN_RANGE(command_id, texture0)) { 252 if (COMMAND_IN_RANGE(command_id, texture0) ||
241 u8* src = Memory::GetPointer(Pica::registers.texture0.GetPhysicalAddress()); 253 COMMAND_IN_RANGE(command_id, texture1) ||
242 auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(Pica::registers.texture0, 254 COMMAND_IN_RANGE(command_id, texture2)) {
243 Pica::registers.texture0_format); 255
256 unsigned index;
257 if (COMMAND_IN_RANGE(command_id, texture0)) {
258 index = 0;
259 } else if (COMMAND_IN_RANGE(command_id, texture1)) {
260 index = 1;
261 } else {
262 index = 2;
263 }
264 auto config = Pica::registers.GetTextures()[index].config;
265 auto format = Pica::registers.GetTextures()[index].format;
266
267 auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config, format);
268 u8* src = Memory::GetPointer(config.GetPhysicalAddress());
244 new_info_widget = new TextureInfoWidget(src, info); 269 new_info_widget = new TextureInfoWidget(src, info);
245 } else { 270 } else {
246 new_info_widget = new QWidget; 271 new_info_widget = new QWidget;
diff --git a/src/video_core/pica.h b/src/video_core/pica.h
index 4c3791ad9..92a87c086 100644
--- a/src/video_core/pica.h
+++ b/src/video_core/pica.h
@@ -155,12 +155,34 @@ struct Regs {
155 } 155 }
156 } 156 }
157 157
158 BitField< 0, 1, u32> texturing_enable; 158 union {
159 BitField< 0, 1, u32> texture0_enable;
160 BitField< 1, 1, u32> texture1_enable;
161 BitField< 2, 1, u32> texture2_enable;
162 };
159 TextureConfig texture0; 163 TextureConfig texture0;
160 INSERT_PADDING_WORDS(0x8); 164 INSERT_PADDING_WORDS(0x8);
161 BitField<0, 4, TextureFormat> texture0_format; 165 BitField<0, 4, TextureFormat> texture0_format;
162 166 INSERT_PADDING_WORDS(0x2);
163 INSERT_PADDING_WORDS(0x31); 167 TextureConfig texture1;
168 BitField<0, 4, TextureFormat> texture1_format;
169 INSERT_PADDING_WORDS(0x2);
170 TextureConfig texture2;
171 BitField<0, 4, TextureFormat> texture2_format;
172 INSERT_PADDING_WORDS(0x21);
173
174 struct FullTextureConfig {
175 const bool enabled;
176 const TextureConfig config;
177 const TextureFormat format;
178 };
179 const std::array<FullTextureConfig, 3> GetTextures() const {
180 return {{
181 { static_cast<bool>(texture0_enable), texture0, texture0_format },
182 { static_cast<bool>(texture1_enable), texture1, texture1_format },
183 { static_cast<bool>(texture2_enable), texture2, texture2_format }
184 }};
185 }
164 186
165 // 0xc0-0xff: Texture Combiner (akin to glTexEnv) 187 // 0xc0-0xff: Texture Combiner (akin to glTexEnv)
166 struct TevStageConfig { 188 struct TevStageConfig {
@@ -556,9 +578,13 @@ struct Regs {
556 ADD_FIELD(viewport_depth_range); 578 ADD_FIELD(viewport_depth_range);
557 ADD_FIELD(viewport_depth_far_plane); 579 ADD_FIELD(viewport_depth_far_plane);
558 ADD_FIELD(viewport_corner); 580 ADD_FIELD(viewport_corner);
559 ADD_FIELD(texturing_enable); 581 ADD_FIELD(texture0_enable);
560 ADD_FIELD(texture0); 582 ADD_FIELD(texture0);
561 ADD_FIELD(texture0_format); 583 ADD_FIELD(texture0_format);
584 ADD_FIELD(texture1);
585 ADD_FIELD(texture1_format);
586 ADD_FIELD(texture2);
587 ADD_FIELD(texture2_format);
562 ADD_FIELD(tev_stage0); 588 ADD_FIELD(tev_stage0);
563 ADD_FIELD(tev_stage1); 589 ADD_FIELD(tev_stage1);
564 ADD_FIELD(tev_stage2); 590 ADD_FIELD(tev_stage2);
@@ -622,9 +648,13 @@ ASSERT_REG_POSITION(viewport_depth_far_plane, 0x4e);
622ASSERT_REG_POSITION(vs_output_attributes[0], 0x50); 648ASSERT_REG_POSITION(vs_output_attributes[0], 0x50);
623ASSERT_REG_POSITION(vs_output_attributes[1], 0x51); 649ASSERT_REG_POSITION(vs_output_attributes[1], 0x51);
624ASSERT_REG_POSITION(viewport_corner, 0x68); 650ASSERT_REG_POSITION(viewport_corner, 0x68);
625ASSERT_REG_POSITION(texturing_enable, 0x80); 651ASSERT_REG_POSITION(texture0_enable, 0x80);
626ASSERT_REG_POSITION(texture0, 0x81); 652ASSERT_REG_POSITION(texture0, 0x81);
627ASSERT_REG_POSITION(texture0_format, 0x8e); 653ASSERT_REG_POSITION(texture0_format, 0x8e);
654ASSERT_REG_POSITION(texture1, 0x91);
655ASSERT_REG_POSITION(texture1_format, 0x96);
656ASSERT_REG_POSITION(texture2, 0x99);
657ASSERT_REG_POSITION(texture2_format, 0x9e);
628ASSERT_REG_POSITION(tev_stage0, 0xc0); 658ASSERT_REG_POSITION(tev_stage0, 0xc0);
629ASSERT_REG_POSITION(tev_stage1, 0xc8); 659ASSERT_REG_POSITION(tev_stage1, 0xc8);
630ASSERT_REG_POSITION(tev_stage2, 0xd0); 660ASSERT_REG_POSITION(tev_stage2, 0xd0);
diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp
index b7e04a560..2ff6d19a6 100644
--- a/src/video_core/rasterizer.cpp
+++ b/src/video_core/rasterizer.cpp
@@ -167,10 +167,22 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0,
167 (u8)(GetInterpolatedAttribute(v0.color.a(), v1.color.a(), v2.color.a()).ToFloat32() * 255) 167 (u8)(GetInterpolatedAttribute(v0.color.a(), v1.color.a(), v2.color.a()).ToFloat32() * 255)
168 }; 168 };
169 169
170 Math::Vec4<u8> texture_color{}; 170 Math::Vec2<float24> uv[3];
171 float24 u = GetInterpolatedAttribute(v0.tc0.u(), v1.tc0.u(), v2.tc0.u()); 171 uv[0].u() = GetInterpolatedAttribute(v0.tc0.u(), v1.tc0.u(), v2.tc0.u());
172 float24 v = GetInterpolatedAttribute(v0.tc0.v(), v1.tc0.v(), v2.tc0.v()); 172 uv[0].v() = GetInterpolatedAttribute(v0.tc0.v(), v1.tc0.v(), v2.tc0.v());
173 if (registers.texturing_enable) { 173 uv[1].u() = GetInterpolatedAttribute(v0.tc1.u(), v1.tc1.u(), v2.tc1.u());
174 uv[1].v() = GetInterpolatedAttribute(v0.tc1.v(), v1.tc1.v(), v2.tc1.v());
175 uv[2].u() = GetInterpolatedAttribute(v0.tc2.u(), v1.tc2.u(), v2.tc2.u());
176 uv[2].v() = GetInterpolatedAttribute(v0.tc2.v(), v1.tc2.v(), v2.tc2.v());
177
178 Math::Vec4<u8> texture_color[3]{};
179 for (int i = 0; i < 3; ++i) {
180 auto texture = registers.GetTextures()[i];
181 if (!texture.enabled)
182 continue;
183
184 _dbg_assert_(GPU, 0 != texture.config.address);
185
174 // Images are split into 8x8 tiles. Each tile is composed of four 4x4 subtiles each 186 // Images are split into 8x8 tiles. Each tile is composed of four 4x4 subtiles each
175 // of which is composed of four 2x2 subtiles each of which is composed of four texels. 187 // of which is composed of four 2x2 subtiles each of which is composed of four texels.
176 // Each structure is embedded into the next-bigger one in a diagonal pattern, e.g. 188 // Each structure is embedded into the next-bigger one in a diagonal pattern, e.g.
@@ -189,14 +201,11 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0,
189 // 02 03 06 07 18 19 22 23 201 // 02 03 06 07 18 19 22 23
190 // 00 01 04 05 16 17 20 21 202 // 00 01 04 05 16 17 20 21
191 203
192 // TODO: This is currently hardcoded for RGB8
193 u32* texture_data = (u32*)Memory::GetPointer(registers.texture0.GetPhysicalAddress());
194
195 // TODO(neobrain): Not sure if this swizzling pattern is used for all textures. 204 // TODO(neobrain): Not sure if this swizzling pattern is used for all textures.
196 // To be flexible in case different but similar patterns are used, we keep this 205 // To be flexible in case different but similar patterns are used, we keep this
197 // somewhat inefficient code around for now. 206 // somewhat inefficient code around for now.
198 int s = (int)(u * float24::FromFloat32(static_cast<float>(registers.texture0.width))).ToFloat32(); 207 int s = (int)(uv[i].u() * float24::FromFloat32(static_cast<float>(texture.config.width))).ToFloat32();
199 int t = (int)(v * float24::FromFloat32(static_cast<float>(registers.texture0.height))).ToFloat32(); 208 int t = (int)(uv[i].v() * float24::FromFloat32(static_cast<float>(texture.config.height))).ToFloat32();
200 int texel_index_within_tile = 0; 209 int texel_index_within_tile = 0;
201 for (int block_size_index = 0; block_size_index < 3; ++block_size_index) { 210 for (int block_size_index = 0; block_size_index < 3; ++block_size_index) {
202 int sub_tile_width = 1 << block_size_index; 211 int sub_tile_width = 1 << block_size_index;
@@ -213,14 +222,17 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0,
213 int coarse_s = (s / block_width) * block_width; 222 int coarse_s = (s / block_width) * block_width;
214 int coarse_t = (t / block_height) * block_height; 223 int coarse_t = (t / block_height) * block_height;
215 224
216 const int row_stride = registers.texture0.width * 3; 225 // TODO: This is currently hardcoded for RGB8
226 u32* texture_data = (u32*)Memory::GetPointer(texture.config.GetPhysicalAddress());
227
228 const int row_stride = texture.config.width * 3;
217 u8* source_ptr = (u8*)texture_data + coarse_s * block_height * 3 + coarse_t * row_stride + texel_index_within_tile * 3; 229 u8* source_ptr = (u8*)texture_data + coarse_s * block_height * 3 + coarse_t * row_stride + texel_index_within_tile * 3;
218 texture_color.r() = source_ptr[2]; 230 texture_color[i].r() = source_ptr[2];
219 texture_color.g() = source_ptr[1]; 231 texture_color[i].g() = source_ptr[1];
220 texture_color.b() = source_ptr[0]; 232 texture_color[i].b() = source_ptr[0];
221 texture_color.a() = 0xFF; 233 texture_color[i].a() = 0xFF;
222 234
223 DebugUtils::DumpTexture(registers.texture0, (u8*)texture_data); 235 DebugUtils::DumpTexture(texture.config, (u8*)texture_data);
224 } 236 }
225 237
226 // Texture environment - consists of 6 stages of color and alpha combining. 238 // Texture environment - consists of 6 stages of color and alpha combining.
@@ -243,7 +255,13 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0,
243 return primary_color.rgb(); 255 return primary_color.rgb();
244 256
245 case Source::Texture0: 257 case Source::Texture0:
246 return texture_color.rgb(); 258 return texture_color[0].rgb();
259
260 case Source::Texture1:
261 return texture_color[1].rgb();
262
263 case Source::Texture2:
264 return texture_color[2].rgb();
247 265
248 case Source::Constant: 266 case Source::Constant:
249 return {tev_stage.const_r, tev_stage.const_g, tev_stage.const_b}; 267 return {tev_stage.const_r, tev_stage.const_g, tev_stage.const_b};
@@ -263,7 +281,13 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0,
263 return primary_color.a(); 281 return primary_color.a();
264 282
265 case Source::Texture0: 283 case Source::Texture0:
266 return texture_color.a(); 284 return texture_color[0].a();
285
286 case Source::Texture1:
287 return texture_color[1].a();
288
289 case Source::Texture2:
290 return texture_color[2].a();
267 291
268 case Source::Constant: 292 case Source::Constant:
269 return tev_stage.const_a; 293 return tev_stage.const_a;
diff --git a/src/video_core/vertex_shader.h b/src/video_core/vertex_shader.h
index bfb6fb6e3..c1292fc2d 100644
--- a/src/video_core/vertex_shader.h
+++ b/src/video_core/vertex_shader.h
@@ -27,15 +27,18 @@ struct OutputVertex {
27 Math::Vec4<float24> dummy; // quaternions (not implemented, yet) 27 Math::Vec4<float24> dummy; // quaternions (not implemented, yet)
28 Math::Vec4<float24> color; 28 Math::Vec4<float24> color;
29 Math::Vec2<float24> tc0; 29 Math::Vec2<float24> tc0;
30 Math::Vec2<float24> tc1;
31 float24 pad[6];
32 Math::Vec2<float24> tc2;
30 33
31 // Padding for optimal alignment 34 // Padding for optimal alignment
32 float24 pad[14]; 35 float24 pad2[4];
33 36
34 // Attributes used to store intermediate results 37 // Attributes used to store intermediate results
35 38
36 // position after perspective divide 39 // position after perspective divide
37 Math::Vec3<float24> screenpos; 40 Math::Vec3<float24> screenpos;
38 float24 pad2; 41 float24 pad3;
39 42
40 // Linear interpolation 43 // Linear interpolation
41 // factor: 0=this, 1=vtx 44 // factor: 0=this, 1=vtx
@@ -44,6 +47,8 @@ struct OutputVertex {
44 47
45 // TODO: Should perform perspective correct interpolation here... 48 // TODO: Should perform perspective correct interpolation here...
46 tc0 = tc0 * factor + vtx.tc0 * (float24::FromFloat32(1) - factor); 49 tc0 = tc0 * factor + vtx.tc0 * (float24::FromFloat32(1) - factor);
50 tc1 = tc1 * factor + vtx.tc1 * (float24::FromFloat32(1) - factor);
51 tc2 = tc2 * factor + vtx.tc2 * (float24::FromFloat32(1) - factor);
47 52
48 screenpos = screenpos * factor + vtx.screenpos * (float24::FromFloat32(1) - factor); 53 screenpos = screenpos * factor + vtx.screenpos * (float24::FromFloat32(1) - factor);
49 54