summaryrefslogtreecommitdiff
path: root/src/video_core/debug_utils
diff options
context:
space:
mode:
authorGravatar Emmanuel Gil Peyrot2016-09-18 09:38:01 +0900
committerGravatar Emmanuel Gil Peyrot2016-09-18 09:38:01 +0900
commitdc8479928c5aee4c6ad6fe4f59006fb604cee701 (patch)
tree569a7f13128450bbab973236615587ff00bced5f /src/video_core/debug_utils
parentTravis: Import Dolphin’s clang-format hook. (diff)
downloadyuzu-dc8479928c5aee4c6ad6fe4f59006fb604cee701.tar.gz
yuzu-dc8479928c5aee4c6ad6fe4f59006fb604cee701.tar.xz
yuzu-dc8479928c5aee4c6ad6fe4f59006fb604cee701.zip
Sources: Run clang-format on everything.
Diffstat (limited to 'src/video_core/debug_utils')
-rw-r--r--src/video_core/debug_utils/debug_utils.cpp430
-rw-r--r--src/video_core/debug_utils/debug_utils.h31
2 files changed, 237 insertions, 224 deletions
diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp
index bfa686380..1cb868ead 100644
--- a/src/video_core/debug_utils/debug_utils.cpp
+++ b/src/video_core/debug_utils/debug_utils.cpp
@@ -50,7 +50,8 @@ void DebugContext::DoOnEvent(Event event, void* data) {
50 { 50 {
51 std::unique_lock<std::mutex> lock(breakpoint_mutex); 51 std::unique_lock<std::mutex> lock(breakpoint_mutex);
52 52
53 // Commit the rasterizer's caches so framebuffers, render targets, etc. will show on debug widgets 53 // Commit the rasterizer's caches so framebuffers, render targets, etc. will show on debug
54 // widgets
54 VideoCore::g_renderer->Rasterizer()->FlushAll(); 55 VideoCore::g_renderer->Rasterizer()->FlushAll();
55 56
56 // TODO: Should stop the CPU thread here once we multithread emulation. 57 // TODO: Should stop the CPU thread here once we multithread emulation.
@@ -64,7 +65,7 @@ void DebugContext::DoOnEvent(Event event, void* data) {
64 } 65 }
65 66
66 // Wait until another thread tells us to Resume() 67 // Wait until another thread tells us to Resume()
67 resume_from_breakpoint.wait(lock, [&]{ return !at_breakpoint; }); 68 resume_from_breakpoint.wait(lock, [&] { return !at_breakpoint; });
68 } 69 }
69} 70}
70 71
@@ -88,8 +89,9 @@ std::shared_ptr<DebugContext> g_debug_context; // TODO: Get rid of this global
88 89
89namespace DebugUtils { 90namespace DebugUtils {
90 91
91void DumpShader(const std::string& filename, const Regs::ShaderConfig& config, const Shader::ShaderSetup& setup, const Regs::VSOutputAttributes* output_attributes) 92void DumpShader(const std::string& filename, const Regs::ShaderConfig& config,
92{ 93 const Shader::ShaderSetup& setup,
94 const Regs::VSOutputAttributes* output_attributes) {
93 struct StuffToWrite { 95 struct StuffToWrite {
94 const u8* pointer; 96 const u8* pointer;
95 u32 size; 97 u32 size;
@@ -97,7 +99,7 @@ void DumpShader(const std::string& filename, const Regs::ShaderConfig& config, c
97 std::vector<StuffToWrite> writing_queue; 99 std::vector<StuffToWrite> writing_queue;
98 u32 write_offset = 0; 100 u32 write_offset = 0;
99 101
100 auto QueueForWriting = [&writing_queue,&write_offset](const u8* pointer, u32 size) { 102 auto QueueForWriting = [&writing_queue, &write_offset](const u8* pointer, u32 size) {
101 writing_queue.push_back({pointer, size}); 103 writing_queue.push_back({pointer, size});
102 u32 old_write_offset = write_offset; 104 u32 old_write_offset = write_offset;
103 write_offset += size; 105 write_offset += size;
@@ -108,99 +110,94 @@ void DumpShader(const std::string& filename, const Regs::ShaderConfig& config, c
108 // into shbin format (separate type and component mask). 110 // into shbin format (separate type and component mask).
109 union OutputRegisterInfo { 111 union OutputRegisterInfo {
110 enum Type : u64 { 112 enum Type : u64 {
111 POSITION = 0, 113 POSITION = 0,
112 QUATERNION = 1, 114 QUATERNION = 1,
113 COLOR = 2, 115 COLOR = 2,
114 TEXCOORD0 = 3, 116 TEXCOORD0 = 3,
115 TEXCOORD1 = 5, 117 TEXCOORD1 = 5,
116 TEXCOORD2 = 6, 118 TEXCOORD2 = 6,
117 119
118 VIEW = 8, 120 VIEW = 8,
119 }; 121 };
120 122
121 BitField< 0, 64, u64> hex; 123 BitField<0, 64, u64> hex;
122 124
123 BitField< 0, 16, Type> type; 125 BitField<0, 16, Type> type;
124 BitField<16, 16, u64> id; 126 BitField<16, 16, u64> id;
125 BitField<32, 4, u64> component_mask; 127 BitField<32, 4, u64> component_mask;
126 }; 128 };
127 129
128 // This is put into a try-catch block to make sure we notice unknown configurations. 130 // This is put into a try-catch block to make sure we notice unknown configurations.
129 std::vector<OutputRegisterInfo> output_info_table; 131 std::vector<OutputRegisterInfo> output_info_table;
130 for (unsigned i = 0; i < 7; ++i) { 132 for (unsigned i = 0; i < 7; ++i) {
131 using OutputAttributes = Pica::Regs::VSOutputAttributes; 133 using OutputAttributes = Pica::Regs::VSOutputAttributes;
132 134
133 // TODO: It's still unclear how the attribute components map to the register! 135 // TODO: It's still unclear how the attribute components map to the register!
134 // Once we know that, this code probably will not make much sense anymore. 136 // Once we know that, this code probably will not make much sense anymore.
135 std::map<OutputAttributes::Semantic, std::pair<OutputRegisterInfo::Type, u32> > map = { 137 std::map<OutputAttributes::Semantic, std::pair<OutputRegisterInfo::Type, u32>> map = {
136 { OutputAttributes::POSITION_X, { OutputRegisterInfo::POSITION, 1} }, 138 {OutputAttributes::POSITION_X, {OutputRegisterInfo::POSITION, 1}},
137 { OutputAttributes::POSITION_Y, { OutputRegisterInfo::POSITION, 2} }, 139 {OutputAttributes::POSITION_Y, {OutputRegisterInfo::POSITION, 2}},
138 { OutputAttributes::POSITION_Z, { OutputRegisterInfo::POSITION, 4} }, 140 {OutputAttributes::POSITION_Z, {OutputRegisterInfo::POSITION, 4}},
139 { OutputAttributes::POSITION_W, { OutputRegisterInfo::POSITION, 8} }, 141 {OutputAttributes::POSITION_W, {OutputRegisterInfo::POSITION, 8}},
140 { OutputAttributes::QUATERNION_X, { OutputRegisterInfo::QUATERNION, 1} }, 142 {OutputAttributes::QUATERNION_X, {OutputRegisterInfo::QUATERNION, 1}},
141 { OutputAttributes::QUATERNION_Y, { OutputRegisterInfo::QUATERNION, 2} }, 143 {OutputAttributes::QUATERNION_Y, {OutputRegisterInfo::QUATERNION, 2}},
142 { OutputAttributes::QUATERNION_Z, { OutputRegisterInfo::QUATERNION, 4} }, 144 {OutputAttributes::QUATERNION_Z, {OutputRegisterInfo::QUATERNION, 4}},
143 { OutputAttributes::QUATERNION_W, { OutputRegisterInfo::QUATERNION, 8} }, 145 {OutputAttributes::QUATERNION_W, {OutputRegisterInfo::QUATERNION, 8}},
144 { OutputAttributes::COLOR_R, { OutputRegisterInfo::COLOR, 1} }, 146 {OutputAttributes::COLOR_R, {OutputRegisterInfo::COLOR, 1}},
145 { OutputAttributes::COLOR_G, { OutputRegisterInfo::COLOR, 2} }, 147 {OutputAttributes::COLOR_G, {OutputRegisterInfo::COLOR, 2}},
146 { OutputAttributes::COLOR_B, { OutputRegisterInfo::COLOR, 4} }, 148 {OutputAttributes::COLOR_B, {OutputRegisterInfo::COLOR, 4}},
147 { OutputAttributes::COLOR_A, { OutputRegisterInfo::COLOR, 8} }, 149 {OutputAttributes::COLOR_A, {OutputRegisterInfo::COLOR, 8}},
148 { OutputAttributes::TEXCOORD0_U, { OutputRegisterInfo::TEXCOORD0, 1} }, 150 {OutputAttributes::TEXCOORD0_U, {OutputRegisterInfo::TEXCOORD0, 1}},
149 { OutputAttributes::TEXCOORD0_V, { OutputRegisterInfo::TEXCOORD0, 2} }, 151 {OutputAttributes::TEXCOORD0_V, {OutputRegisterInfo::TEXCOORD0, 2}},
150 { OutputAttributes::TEXCOORD1_U, { OutputRegisterInfo::TEXCOORD1, 1} }, 152 {OutputAttributes::TEXCOORD1_U, {OutputRegisterInfo::TEXCOORD1, 1}},
151 { OutputAttributes::TEXCOORD1_V, { OutputRegisterInfo::TEXCOORD1, 2} }, 153 {OutputAttributes::TEXCOORD1_V, {OutputRegisterInfo::TEXCOORD1, 2}},
152 { OutputAttributes::TEXCOORD2_U, { OutputRegisterInfo::TEXCOORD2, 1} }, 154 {OutputAttributes::TEXCOORD2_U, {OutputRegisterInfo::TEXCOORD2, 1}},
153 { OutputAttributes::TEXCOORD2_V, { OutputRegisterInfo::TEXCOORD2, 2} }, 155 {OutputAttributes::TEXCOORD2_V, {OutputRegisterInfo::TEXCOORD2, 2}},
154 { OutputAttributes::VIEW_X, { OutputRegisterInfo::VIEW, 1} }, 156 {OutputAttributes::VIEW_X, {OutputRegisterInfo::VIEW, 1}},
155 { OutputAttributes::VIEW_Y, { OutputRegisterInfo::VIEW, 2} }, 157 {OutputAttributes::VIEW_Y, {OutputRegisterInfo::VIEW, 2}},
156 { OutputAttributes::VIEW_Z, { OutputRegisterInfo::VIEW, 4} } 158 {OutputAttributes::VIEW_Z, {OutputRegisterInfo::VIEW, 4}}};
157 }; 159
158 160 for (const auto& semantic : std::vector<OutputAttributes::Semantic>{
159 for (const auto& semantic : std::vector<OutputAttributes::Semantic>{ 161 output_attributes[i].map_x, output_attributes[i].map_y, output_attributes[i].map_z,
160 output_attributes[i].map_x, 162 output_attributes[i].map_w}) {
161 output_attributes[i].map_y, 163 if (semantic == OutputAttributes::INVALID)
162 output_attributes[i].map_z, 164 continue;
163 output_attributes[i].map_w }) { 165
164 if (semantic == OutputAttributes::INVALID) 166 try {
165 continue; 167 OutputRegisterInfo::Type type = map.at(semantic).first;
166 168 u32 component_mask = map.at(semantic).second;
167 try { 169
168 OutputRegisterInfo::Type type = map.at(semantic).first; 170 auto it = std::find_if(output_info_table.begin(), output_info_table.end(),
169 u32 component_mask = map.at(semantic).second; 171 [&i, &type](const OutputRegisterInfo& info) {
170 172 return info.id == i && info.type == type;
171 auto it = std::find_if(output_info_table.begin(), output_info_table.end(), 173 });
172 [&i, &type](const OutputRegisterInfo& info) { 174
173 return info.id == i && info.type == type; 175 if (it == output_info_table.end()) {
174 } 176 output_info_table.emplace_back();
175 ); 177 output_info_table.back().type.Assign(type);
176 178 output_info_table.back().component_mask.Assign(component_mask);
177 if (it == output_info_table.end()) { 179 output_info_table.back().id.Assign(i);
178 output_info_table.emplace_back(); 180 } else {
179 output_info_table.back().type.Assign(type); 181 it->component_mask.Assign(it->component_mask | component_mask);
180 output_info_table.back().component_mask.Assign(component_mask);
181 output_info_table.back().id.Assign(i);
182 } else {
183 it->component_mask.Assign(it->component_mask | component_mask);
184 }
185 } catch (const std::out_of_range& ) {
186 DEBUG_ASSERT_MSG(false, "Unknown output attribute mapping");
187 LOG_ERROR(HW_GPU, "Unknown output attribute mapping: %03x, %03x, %03x, %03x",
188 (int)output_attributes[i].map_x.Value(),
189 (int)output_attributes[i].map_y.Value(),
190 (int)output_attributes[i].map_z.Value(),
191 (int)output_attributes[i].map_w.Value());
192 } 182 }
183 } catch (const std::out_of_range&) {
184 DEBUG_ASSERT_MSG(false, "Unknown output attribute mapping");
185 LOG_ERROR(HW_GPU, "Unknown output attribute mapping: %03x, %03x, %03x, %03x",
186 (int)output_attributes[i].map_x.Value(),
187 (int)output_attributes[i].map_y.Value(),
188 (int)output_attributes[i].map_z.Value(),
189 (int)output_attributes[i].map_w.Value());
193 } 190 }
194 } 191 }
195 192 }
196 193
197 struct { 194 struct {
198 DVLBHeader header; 195 DVLBHeader header;
199 u32 dvle_offset; 196 u32 dvle_offset;
200 } dvlb{ {DVLBHeader::MAGIC_WORD, 1 } }; // 1 DVLE 197 } dvlb{{DVLBHeader::MAGIC_WORD, 1}}; // 1 DVLE
201 198
202 DVLPHeader dvlp{ DVLPHeader::MAGIC_WORD }; 199 DVLPHeader dvlp{DVLPHeader::MAGIC_WORD};
203 DVLEHeader dvle{ DVLEHeader::MAGIC_WORD }; 200 DVLEHeader dvle{DVLEHeader::MAGIC_WORD};
204 201
205 QueueForWriting(reinterpret_cast<const u8*>(&dvlb), sizeof(dvlb)); 202 QueueForWriting(reinterpret_cast<const u8*>(&dvlb), sizeof(dvlb));
206 u32 dvlp_offset = QueueForWriting(reinterpret_cast<const u8*>(&dvlp), sizeof(dvlp)); 203 u32 dvlp_offset = QueueForWriting(reinterpret_cast<const u8*>(&dvlp), sizeof(dvlp));
@@ -216,14 +213,16 @@ void DumpShader(const std::string& filename, const Regs::ShaderConfig& config, c
216 dvlp.swizzle_info_num_entries = static_cast<uint32_t>(setup.swizzle_data.size()); 213 dvlp.swizzle_info_num_entries = static_cast<uint32_t>(setup.swizzle_data.size());
217 u32 dummy = 0; 214 u32 dummy = 0;
218 for (unsigned int i = 0; i < setup.swizzle_data.size(); ++i) { 215 for (unsigned int i = 0; i < setup.swizzle_data.size(); ++i) {
219 QueueForWriting(reinterpret_cast<const u8*>(&setup.swizzle_data[i]), sizeof(setup.swizzle_data[i])); 216 QueueForWriting(reinterpret_cast<const u8*>(&setup.swizzle_data[i]),
217 sizeof(setup.swizzle_data[i]));
220 QueueForWriting(reinterpret_cast<const u8*>(&dummy), sizeof(dummy)); 218 QueueForWriting(reinterpret_cast<const u8*>(&dummy), sizeof(dummy));
221 } 219 }
222 220
223 dvle.main_offset_words = config.main_offset; 221 dvle.main_offset_words = config.main_offset;
224 dvle.output_register_table_offset = write_offset - dvlb.dvle_offset; 222 dvle.output_register_table_offset = write_offset - dvlb.dvle_offset;
225 dvle.output_register_table_size = static_cast<u32>(output_info_table.size()); 223 dvle.output_register_table_size = static_cast<u32>(output_info_table.size());
226 QueueForWriting(reinterpret_cast<const u8*>(output_info_table.data()), static_cast<u32>(output_info_table.size() * sizeof(OutputRegisterInfo))); 224 QueueForWriting(reinterpret_cast<const u8*>(output_info_table.data()),
225 static_cast<u32>(output_info_table.size() * sizeof(OutputRegisterInfo)));
227 226
228 // TODO: Create a label table for "main" 227 // TODO: Create a label table for "main"
229 228
@@ -258,10 +257,8 @@ void DumpShader(const std::string& filename, const Regs::ShaderConfig& config, c
258 constant.f.w = nihstro::to_float24(setup.uniforms.f[i].w.ToFloat32()); 257 constant.f.w = nihstro::to_float24(setup.uniforms.f[i].w.ToFloat32());
259 258
260 // Store constant if it's different from zero.. 259 // Store constant if it's different from zero..
261 if (setup.uniforms.f[i].x.ToFloat32() != 0.0 || 260 if (setup.uniforms.f[i].x.ToFloat32() != 0.0 || setup.uniforms.f[i].y.ToFloat32() != 0.0 ||
262 setup.uniforms.f[i].y.ToFloat32() != 0.0 || 261 setup.uniforms.f[i].z.ToFloat32() != 0.0 || setup.uniforms.f[i].w.ToFloat32() != 0.0)
263 setup.uniforms.f[i].z.ToFloat32() != 0.0 ||
264 setup.uniforms.f[i].w.ToFloat32() != 0.0)
265 constant_table.emplace_back(constant); 262 constant_table.emplace_back(constant);
266 } 263 }
267 dvle.constant_table_offset = write_offset - dvlb.dvle_offset; 264 dvle.constant_table_offset = write_offset - dvlb.dvle_offset;
@@ -282,8 +279,7 @@ static std::unique_ptr<PicaTrace> pica_trace;
282static std::mutex pica_trace_mutex; 279static std::mutex pica_trace_mutex;
283static int is_pica_tracing = false; 280static int is_pica_tracing = false;
284 281
285void StartPicaTracing() 282void StartPicaTracing() {
286{
287 if (is_pica_tracing) { 283 if (is_pica_tracing) {
288 LOG_WARNING(HW_GPU, "StartPicaTracing called even though tracing already running!"); 284 LOG_WARNING(HW_GPU, "StartPicaTracing called even though tracing already running!");
289 return; 285 return;
@@ -295,13 +291,11 @@ void StartPicaTracing()
295 is_pica_tracing = true; 291 is_pica_tracing = true;
296} 292}
297 293
298bool IsPicaTracing() 294bool IsPicaTracing() {
299{
300 return is_pica_tracing != 0; 295 return is_pica_tracing != 0;
301} 296}
302 297
303void OnPicaRegWrite(PicaTrace::Write write) 298void OnPicaRegWrite(PicaTrace::Write write) {
304{
305 // Double check for is_pica_tracing to avoid pointless locking overhead 299 // Double check for is_pica_tracing to avoid pointless locking overhead
306 if (!is_pica_tracing) 300 if (!is_pica_tracing)
307 return; 301 return;
@@ -314,8 +308,7 @@ void OnPicaRegWrite(PicaTrace::Write write)
314 pica_trace->writes.push_back(write); 308 pica_trace->writes.push_back(write);
315} 309}
316 310
317std::unique_ptr<PicaTrace> FinishPicaTracing() 311std::unique_ptr<PicaTrace> FinishPicaTracing() {
318{
319 if (!is_pica_tracing) { 312 if (!is_pica_tracing) {
320 LOG_WARNING(HW_GPU, "FinishPicaTracing called even though tracing isn't running!"); 313 LOG_WARNING(HW_GPU, "FinishPicaTracing called even though tracing isn't running!");
321 return {}; 314 return {};
@@ -331,12 +324,12 @@ std::unique_ptr<PicaTrace> FinishPicaTracing()
331 return ret; 324 return ret;
332} 325}
333 326
334const Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const TextureInfo& info, bool disable_alpha) { 327const Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const TextureInfo& info,
328 bool disable_alpha) {
335 const unsigned int coarse_x = x & ~7; 329 const unsigned int coarse_x = x & ~7;
336 const unsigned int coarse_y = y & ~7; 330 const unsigned int coarse_y = y & ~7;
337 331
338 if (info.format != Regs::TextureFormat::ETC1 && 332 if (info.format != Regs::TextureFormat::ETC1 && info.format != Regs::TextureFormat::ETC1A4) {
339 info.format != Regs::TextureFormat::ETC1A4) {
340 // TODO(neobrain): Fix code design to unify vertical block offsets! 333 // TODO(neobrain): Fix code design to unify vertical block offsets!
341 source += coarse_y * info.stride; 334 source += coarse_y * info.stride;
342 } 335 }
@@ -344,73 +337,63 @@ const Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const Texture
344 // TODO: Assert that width/height are multiples of block dimensions 337 // TODO: Assert that width/height are multiples of block dimensions
345 338
346 switch (info.format) { 339 switch (info.format) {
347 case Regs::TextureFormat::RGBA8: 340 case Regs::TextureFormat::RGBA8: {
348 {
349 auto res = Color::DecodeRGBA8(source + VideoCore::GetMortonOffset(x, y, 4)); 341 auto res = Color::DecodeRGBA8(source + VideoCore::GetMortonOffset(x, y, 4));
350 return { res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a()) }; 342 return {res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a())};
351 } 343 }
352 344
353 case Regs::TextureFormat::RGB8: 345 case Regs::TextureFormat::RGB8: {
354 {
355 auto res = Color::DecodeRGB8(source + VideoCore::GetMortonOffset(x, y, 3)); 346 auto res = Color::DecodeRGB8(source + VideoCore::GetMortonOffset(x, y, 3));
356 return { res.r(), res.g(), res.b(), 255 }; 347 return {res.r(), res.g(), res.b(), 255};
357 } 348 }
358 349
359 case Regs::TextureFormat::RGB5A1: 350 case Regs::TextureFormat::RGB5A1: {
360 {
361 auto res = Color::DecodeRGB5A1(source + VideoCore::GetMortonOffset(x, y, 2)); 351 auto res = Color::DecodeRGB5A1(source + VideoCore::GetMortonOffset(x, y, 2));
362 return { res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a()) }; 352 return {res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a())};
363 } 353 }
364 354
365 case Regs::TextureFormat::RGB565: 355 case Regs::TextureFormat::RGB565: {
366 {
367 auto res = Color::DecodeRGB565(source + VideoCore::GetMortonOffset(x, y, 2)); 356 auto res = Color::DecodeRGB565(source + VideoCore::GetMortonOffset(x, y, 2));
368 return { res.r(), res.g(), res.b(), 255 }; 357 return {res.r(), res.g(), res.b(), 255};
369 } 358 }
370 359
371 case Regs::TextureFormat::RGBA4: 360 case Regs::TextureFormat::RGBA4: {
372 {
373 auto res = Color::DecodeRGBA4(source + VideoCore::GetMortonOffset(x, y, 2)); 361 auto res = Color::DecodeRGBA4(source + VideoCore::GetMortonOffset(x, y, 2));
374 return { res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a()) }; 362 return {res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a())};
375 } 363 }
376 364
377 case Regs::TextureFormat::IA8: 365 case Regs::TextureFormat::IA8: {
378 {
379 const u8* source_ptr = source + VideoCore::GetMortonOffset(x, y, 2); 366 const u8* source_ptr = source + VideoCore::GetMortonOffset(x, y, 2);
380 367
381 if (disable_alpha) { 368 if (disable_alpha) {
382 // Show intensity as red, alpha as green 369 // Show intensity as red, alpha as green
383 return { source_ptr[1], source_ptr[0], 0, 255 }; 370 return {source_ptr[1], source_ptr[0], 0, 255};
384 } else { 371 } else {
385 return { source_ptr[1], source_ptr[1], source_ptr[1], source_ptr[0] }; 372 return {source_ptr[1], source_ptr[1], source_ptr[1], source_ptr[0]};
386 } 373 }
387 } 374 }
388 375
389 case Regs::TextureFormat::RG8: 376 case Regs::TextureFormat::RG8: {
390 {
391 auto res = Color::DecodeRG8(source + VideoCore::GetMortonOffset(x, y, 2)); 377 auto res = Color::DecodeRG8(source + VideoCore::GetMortonOffset(x, y, 2));
392 return { res.r(), res.g(), 0, 255 }; 378 return {res.r(), res.g(), 0, 255};
393 } 379 }
394 380
395 case Regs::TextureFormat::I8: 381 case Regs::TextureFormat::I8: {
396 {
397 const u8* source_ptr = source + VideoCore::GetMortonOffset(x, y, 1); 382 const u8* source_ptr = source + VideoCore::GetMortonOffset(x, y, 1);
398 return { *source_ptr, *source_ptr, *source_ptr, 255 }; 383 return {*source_ptr, *source_ptr, *source_ptr, 255};
399 } 384 }
400 385
401 case Regs::TextureFormat::A8: 386 case Regs::TextureFormat::A8: {
402 {
403 const u8* source_ptr = source + VideoCore::GetMortonOffset(x, y, 1); 387 const u8* source_ptr = source + VideoCore::GetMortonOffset(x, y, 1);
404 388
405 if (disable_alpha) { 389 if (disable_alpha) {
406 return { *source_ptr, *source_ptr, *source_ptr, 255 }; 390 return {*source_ptr, *source_ptr, *source_ptr, 255};
407 } else { 391 } else {
408 return { 0, 0, 0, *source_ptr }; 392 return {0, 0, 0, *source_ptr};
409 } 393 }
410 } 394 }
411 395
412 case Regs::TextureFormat::IA4: 396 case Regs::TextureFormat::IA4: {
413 {
414 const u8* source_ptr = source + VideoCore::GetMortonOffset(x, y, 1); 397 const u8* source_ptr = source + VideoCore::GetMortonOffset(x, y, 1);
415 398
416 u8 i = Color::Convert4To8(((*source_ptr) & 0xF0) >> 4); 399 u8 i = Color::Convert4To8(((*source_ptr) & 0xF0) >> 4);
@@ -418,25 +401,23 @@ const Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const Texture
418 401
419 if (disable_alpha) { 402 if (disable_alpha) {
420 // Show intensity as red, alpha as green 403 // Show intensity as red, alpha as green
421 return { i, a, 0, 255 }; 404 return {i, a, 0, 255};
422 } else { 405 } else {
423 return { i, i, i, a }; 406 return {i, i, i, a};
424 } 407 }
425 } 408 }
426 409
427 case Regs::TextureFormat::I4: 410 case Regs::TextureFormat::I4: {
428 {
429 u32 morton_offset = VideoCore::GetMortonOffset(x, y, 1); 411 u32 morton_offset = VideoCore::GetMortonOffset(x, y, 1);
430 const u8* source_ptr = source + morton_offset / 2; 412 const u8* source_ptr = source + morton_offset / 2;
431 413
432 u8 i = (morton_offset % 2) ? ((*source_ptr & 0xF0) >> 4) : (*source_ptr & 0xF); 414 u8 i = (morton_offset % 2) ? ((*source_ptr & 0xF0) >> 4) : (*source_ptr & 0xF);
433 i = Color::Convert4To8(i); 415 i = Color::Convert4To8(i);
434 416
435 return { i, i, i, 255 }; 417 return {i, i, i, 255};
436 } 418 }
437 419
438 case Regs::TextureFormat::A4: 420 case Regs::TextureFormat::A4: {
439 {
440 u32 morton_offset = VideoCore::GetMortonOffset(x, y, 1); 421 u32 morton_offset = VideoCore::GetMortonOffset(x, y, 1);
441 const u8* source_ptr = source + morton_offset / 2; 422 const u8* source_ptr = source + morton_offset / 2;
442 423
@@ -444,15 +425,14 @@ const Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const Texture
444 a = Color::Convert4To8(a); 425 a = Color::Convert4To8(a);
445 426
446 if (disable_alpha) { 427 if (disable_alpha) {
447 return { a, a, a, 255 }; 428 return {a, a, a, 255};
448 } else { 429 } else {
449 return { 0, 0, 0, a }; 430 return {0, 0, 0, a};
450 } 431 }
451 } 432 }
452 433
453 case Regs::TextureFormat::ETC1: 434 case Regs::TextureFormat::ETC1:
454 case Regs::TextureFormat::ETC1A4: 435 case Regs::TextureFormat::ETC1A4: {
455 {
456 bool has_alpha = (info.format == Regs::TextureFormat::ETC1A4); 436 bool has_alpha = (info.format == Regs::TextureFormat::ETC1A4);
457 437
458 // ETC1 further subdivides each 8x8 tile into four 4x4 subtiles 438 // ETC1 further subdivides each 8x8 tile into four 4x4 subtiles
@@ -462,10 +442,9 @@ const Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const Texture
462 int subtile_index = ((x / subtile_width) & 1) + 2 * ((y / subtile_height) & 1); 442 int subtile_index = ((x / subtile_width) & 1) + 2 * ((y / subtile_height) & 1);
463 unsigned subtile_bytes = has_alpha ? 2 : 1; // TODO: Name... 443 unsigned subtile_bytes = has_alpha ? 2 : 1; // TODO: Name...
464 444
465 const u64* source_ptr = (const u64*)(source 445 const u64* source_ptr = (const u64*)(source + coarse_x * subtile_bytes * 4 +
466 + coarse_x * subtile_bytes * 4 446 coarse_y * subtile_bytes * 4 * (info.width / 8) +
467 + coarse_y * subtile_bytes * 4 * (info.width / 8) 447 subtile_index * subtile_bytes * 8);
468 + subtile_index * subtile_bytes * 8);
469 u64 alpha = 0xFFFFFFFFFFFFFFFF; 448 u64 alpha = 0xFFFFFFFFFFFFFFFF;
470 if (has_alpha) { 449 if (has_alpha) {
471 alpha = *source_ptr; 450 alpha = *source_ptr;
@@ -474,7 +453,7 @@ const Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const Texture
474 453
475 union ETC1Tile { 454 union ETC1Tile {
476 // Each of these two is a collection of 16 bits (one per lookup value) 455 // Each of these two is a collection of 16 bits (one per lookup value)
477 BitField< 0, 16, u64> table_subindexes; 456 BitField<0, 16, u64> table_subindexes;
478 BitField<16, 16, u64> negation_flags; 457 BitField<16, 16, u64> negation_flags;
479 458
480 unsigned GetTableSubIndex(unsigned index) const { 459 unsigned GetTableSubIndex(unsigned index) const {
@@ -547,12 +526,17 @@ const Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const Texture
547 } 526 }
548 527
549 // Add modifier 528 // Add modifier
550 unsigned table_index = static_cast<int>((x < 2) ? table_index_1.Value() : table_index_2.Value()); 529 unsigned table_index =
551 530 static_cast<int>((x < 2) ? table_index_1.Value() : table_index_2.Value());
552 static const std::array<std::array<u8, 2>, 8> etc1_modifier_table = {{ 531
553 {{ 2, 8 }}, {{ 5, 17 }}, {{ 9, 29 }}, {{ 13, 42 }}, 532 static const std::array<std::array<u8, 2>, 8> etc1_modifier_table = {{{{2, 8}},
554 {{ 18, 60 }}, {{ 24, 80 }}, {{ 33, 106 }}, {{ 47, 183 }} 533 {{5, 17}},
555 }}; 534 {{9, 29}},
535 {{13, 42}},
536 {{18, 60}},
537 {{24, 80}},
538 {{33, 106}},
539 {{47, 183}}}};
556 540
557 int modifier = etc1_modifier_table.at(table_index).at(GetTableSubIndex(texel)); 541 int modifier = etc1_modifier_table.at(table_index).at(GetTableSubIndex(texel));
558 if (GetNegationFlag(texel)) 542 if (GetNegationFlag(texel))
@@ -564,7 +548,7 @@ const Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const Texture
564 548
565 return ret.Cast<u8>(); 549 return ret.Cast<u8>();
566 } 550 }
567 } const *etc1_tile = reinterpret_cast<const ETC1Tile*>(source_ptr); 551 } const* etc1_tile = reinterpret_cast<const ETC1Tile*>(source_ptr);
568 552
569 alpha >>= 4 * ((x & 3) * 4 + (y & 3)); 553 alpha >>= 4 * ((x & 3) * 4 + (y & 3));
570 return Math::MakeVec(etc1_tile->GetRGB(x & 3, y & 3), 554 return Math::MakeVec(etc1_tile->GetRGB(x & 3, y & 3),
@@ -579,8 +563,7 @@ const Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const Texture
579} 563}
580 564
581TextureInfo TextureInfo::FromPicaRegister(const Regs::TextureConfig& config, 565TextureInfo TextureInfo::FromPicaRegister(const Regs::TextureConfig& config,
582 const Regs::TextureFormat& format) 566 const Regs::TextureFormat& format) {
583{
584 TextureInfo info; 567 TextureInfo info;
585 info.physical_address = config.GetPhysicalAddress(); 568 info.physical_address = config.GetPhysicalAddress();
586 info.width = config.width; 569 info.width = config.width;
@@ -595,13 +578,13 @@ TextureInfo TextureInfo::FromPicaRegister(const Regs::TextureConfig& config,
595static void WriteIOFile(png_structp png_ptr, png_bytep data, png_size_t length) { 578static void WriteIOFile(png_structp png_ptr, png_bytep data, png_size_t length) {
596 auto* fp = static_cast<FileUtil::IOFile*>(png_get_io_ptr(png_ptr)); 579 auto* fp = static_cast<FileUtil::IOFile*>(png_get_io_ptr(png_ptr));
597 if (!fp->WriteBytes(data, length)) 580 if (!fp->WriteBytes(data, length))
598 png_error(png_ptr, "Failed to write to output PNG file."); 581 png_error(png_ptr, "Failed to write to output PNG file.");
599} 582}
600 583
601static void FlushIOFile(png_structp png_ptr) { 584static void FlushIOFile(png_structp png_ptr) {
602 auto* fp = static_cast<FileUtil::IOFile*>(png_get_io_ptr(png_ptr)); 585 auto* fp = static_cast<FileUtil::IOFile*>(png_get_io_ptr(png_ptr));
603 if (!fp->Flush()) 586 if (!fp->Flush())
604 png_error(png_ptr, "Failed to flush to output PNG file."); 587 png_error(png_ptr, "Failed to flush to output PNG file.");
605} 588}
606#endif 589#endif
607 590
@@ -614,7 +597,8 @@ void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) {
614 597
615 // Write data to file 598 // Write data to file
616 static int dump_index = 0; 599 static int dump_index = 0;
617 std::string filename = std::string("texture_dump") + std::to_string(++dump_index) + std::string(".png"); 600 std::string filename =
601 std::string("texture_dump") + std::to_string(++dump_index) + std::string(".png");
618 u32 row_stride = texture_config.width * 3; 602 u32 row_stride = texture_config.width * 3;
619 603
620 u8* buf; 604 u8* buf;
@@ -632,7 +616,6 @@ void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) {
632 if (png_ptr == nullptr) { 616 if (png_ptr == nullptr) {
633 LOG_ERROR(Debug_GPU, "Could not allocate write struct"); 617 LOG_ERROR(Debug_GPU, "Could not allocate write struct");
634 goto finalise; 618 goto finalise;
635
636 } 619 }
637 620
638 // Initialize info structure 621 // Initialize info structure
@@ -651,9 +634,9 @@ void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) {
651 png_set_write_fn(png_ptr, static_cast<void*>(&fp), WriteIOFile, FlushIOFile); 634 png_set_write_fn(png_ptr, static_cast<void*>(&fp), WriteIOFile, FlushIOFile);
652 635
653 // Write header (8 bit color depth) 636 // Write header (8 bit color depth)
654 png_set_IHDR(png_ptr, info_ptr, texture_config.width, texture_config.height, 637 png_set_IHDR(png_ptr, info_ptr, texture_config.width, texture_config.height, 8,
655 8, PNG_COLOR_TYPE_RGB /*_ALPHA*/, PNG_INTERLACE_NONE, 638 PNG_COLOR_TYPE_RGB /*_ALPHA*/, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
656 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); 639 PNG_FILTER_TYPE_BASE);
657 640
658 png_text title_text; 641 png_text title_text;
659 title_text.compression = PNG_TEXT_COMPRESSION_NONE; 642 title_text.compression = PNG_TEXT_COMPRESSION_NONE;
@@ -672,15 +655,14 @@ void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) {
672 info.stride = row_stride; 655 info.stride = row_stride;
673 info.format = g_state.regs.texture0_format; 656 info.format = g_state.regs.texture0_format;
674 Math::Vec4<u8> texture_color = LookupTexture(data, x, y, info); 657 Math::Vec4<u8> texture_color = LookupTexture(data, x, y, info);
675 buf[3 * x + y * row_stride ] = texture_color.r(); 658 buf[3 * x + y * row_stride] = texture_color.r();
676 buf[3 * x + y * row_stride + 1] = texture_color.g(); 659 buf[3 * x + y * row_stride + 1] = texture_color.g();
677 buf[3 * x + y * row_stride + 2] = texture_color.b(); 660 buf[3 * x + y * row_stride + 2] = texture_color.b();
678 } 661 }
679 } 662 }
680 663
681 // Write image data 664 // Write image data
682 for (unsigned y = 0; y < texture_config.height; ++y) 665 for (unsigned y = 0; y < texture_config.height; ++y) {
683 {
684 u8* row_ptr = (u8*)buf + y * row_stride; 666 u8* row_ptr = (u8*)buf + y * row_stride;
685 png_write_row(png_ptr, row_ptr); 667 png_write_row(png_ptr, row_ptr);
686 } 668 }
@@ -691,12 +673,15 @@ void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) {
691 png_write_end(png_ptr, nullptr); 673 png_write_end(png_ptr, nullptr);
692 674
693finalise: 675finalise:
694 if (info_ptr != nullptr) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); 676 if (info_ptr != nullptr)
695 if (png_ptr != nullptr) png_destroy_write_struct(&png_ptr, (png_infopp)nullptr); 677 png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
678 if (png_ptr != nullptr)
679 png_destroy_write_struct(&png_ptr, (png_infopp) nullptr);
696#endif 680#endif
697} 681}
698 682
699static std::string ReplacePattern(const std::string& input, const std::string& pattern, const std::string& replacement) { 683static std::string ReplacePattern(const std::string& input, const std::string& pattern,
684 const std::string& replacement) {
700 size_t start = input.find(pattern); 685 size_t start = input.find(pattern);
701 if (start == std::string::npos) 686 if (start == std::string::npos)
702 return input; 687 return input;
@@ -709,16 +694,16 @@ static std::string ReplacePattern(const std::string& input, const std::string& p
709static std::string GetTevStageConfigSourceString(const Pica::Regs::TevStageConfig::Source& source) { 694static std::string GetTevStageConfigSourceString(const Pica::Regs::TevStageConfig::Source& source) {
710 using Source = Pica::Regs::TevStageConfig::Source; 695 using Source = Pica::Regs::TevStageConfig::Source;
711 static const std::map<Source, std::string> source_map = { 696 static const std::map<Source, std::string> source_map = {
712 { Source::PrimaryColor, "PrimaryColor" }, 697 {Source::PrimaryColor, "PrimaryColor"},
713 { Source::PrimaryFragmentColor, "PrimaryFragmentColor" }, 698 {Source::PrimaryFragmentColor, "PrimaryFragmentColor"},
714 { Source::SecondaryFragmentColor, "SecondaryFragmentColor" }, 699 {Source::SecondaryFragmentColor, "SecondaryFragmentColor"},
715 { Source::Texture0, "Texture0" }, 700 {Source::Texture0, "Texture0"},
716 { Source::Texture1, "Texture1" }, 701 {Source::Texture1, "Texture1"},
717 { Source::Texture2, "Texture2" }, 702 {Source::Texture2, "Texture2"},
718 { Source::Texture3, "Texture3" }, 703 {Source::Texture3, "Texture3"},
719 { Source::PreviousBuffer, "PreviousBuffer" }, 704 {Source::PreviousBuffer, "PreviousBuffer"},
720 { Source::Constant, "Constant" }, 705 {Source::Constant, "Constant"},
721 { Source::Previous, "Previous" }, 706 {Source::Previous, "Previous"},
722 }; 707 };
723 708
724 const auto src_it = source_map.find(source); 709 const auto src_it = source_map.find(source);
@@ -728,19 +713,21 @@ static std::string GetTevStageConfigSourceString(const Pica::Regs::TevStageConfi
728 return src_it->second; 713 return src_it->second;
729} 714}
730 715
731static std::string GetTevStageConfigColorSourceString(const Pica::Regs::TevStageConfig::Source& source, const Pica::Regs::TevStageConfig::ColorModifier modifier) { 716static std::string
717GetTevStageConfigColorSourceString(const Pica::Regs::TevStageConfig::Source& source,
718 const Pica::Regs::TevStageConfig::ColorModifier modifier) {
732 using ColorModifier = Pica::Regs::TevStageConfig::ColorModifier; 719 using ColorModifier = Pica::Regs::TevStageConfig::ColorModifier;
733 static const std::map<ColorModifier, std::string> color_modifier_map = { 720 static const std::map<ColorModifier, std::string> color_modifier_map = {
734 { ColorModifier::SourceColor, "%source.rgb" }, 721 {ColorModifier::SourceColor, "%source.rgb"},
735 { ColorModifier::OneMinusSourceColor, "(1.0 - %source.rgb)" }, 722 {ColorModifier::OneMinusSourceColor, "(1.0 - %source.rgb)"},
736 { ColorModifier::SourceAlpha, "%source.aaa" }, 723 {ColorModifier::SourceAlpha, "%source.aaa"},
737 { ColorModifier::OneMinusSourceAlpha, "(1.0 - %source.aaa)" }, 724 {ColorModifier::OneMinusSourceAlpha, "(1.0 - %source.aaa)"},
738 { ColorModifier::SourceRed, "%source.rrr" }, 725 {ColorModifier::SourceRed, "%source.rrr"},
739 { ColorModifier::OneMinusSourceRed, "(1.0 - %source.rrr)" }, 726 {ColorModifier::OneMinusSourceRed, "(1.0 - %source.rrr)"},
740 { ColorModifier::SourceGreen, "%source.ggg" }, 727 {ColorModifier::SourceGreen, "%source.ggg"},
741 { ColorModifier::OneMinusSourceGreen, "(1.0 - %source.ggg)" }, 728 {ColorModifier::OneMinusSourceGreen, "(1.0 - %source.ggg)"},
742 { ColorModifier::SourceBlue, "%source.bbb" }, 729 {ColorModifier::SourceBlue, "%source.bbb"},
743 { ColorModifier::OneMinusSourceBlue, "(1.0 - %source.bbb)" }, 730 {ColorModifier::OneMinusSourceBlue, "(1.0 - %source.bbb)"},
744 }; 731 };
745 732
746 auto src_str = GetTevStageConfigSourceString(source); 733 auto src_str = GetTevStageConfigSourceString(source);
@@ -752,17 +739,19 @@ static std::string GetTevStageConfigColorSourceString(const Pica::Regs::TevStage
752 return ReplacePattern(modifier_str, "%source", src_str); 739 return ReplacePattern(modifier_str, "%source", src_str);
753} 740}
754 741
755static std::string GetTevStageConfigAlphaSourceString(const Pica::Regs::TevStageConfig::Source& source, const Pica::Regs::TevStageConfig::AlphaModifier modifier) { 742static std::string
743GetTevStageConfigAlphaSourceString(const Pica::Regs::TevStageConfig::Source& source,
744 const Pica::Regs::TevStageConfig::AlphaModifier modifier) {
756 using AlphaModifier = Pica::Regs::TevStageConfig::AlphaModifier; 745 using AlphaModifier = Pica::Regs::TevStageConfig::AlphaModifier;
757 static const std::map<AlphaModifier, std::string> alpha_modifier_map = { 746 static const std::map<AlphaModifier, std::string> alpha_modifier_map = {
758 { AlphaModifier::SourceAlpha, "%source.a" }, 747 {AlphaModifier::SourceAlpha, "%source.a"},
759 { AlphaModifier::OneMinusSourceAlpha, "(1.0 - %source.a)" }, 748 {AlphaModifier::OneMinusSourceAlpha, "(1.0 - %source.a)"},
760 { AlphaModifier::SourceRed, "%source.r" }, 749 {AlphaModifier::SourceRed, "%source.r"},
761 { AlphaModifier::OneMinusSourceRed, "(1.0 - %source.r)" }, 750 {AlphaModifier::OneMinusSourceRed, "(1.0 - %source.r)"},
762 { AlphaModifier::SourceGreen, "%source.g" }, 751 {AlphaModifier::SourceGreen, "%source.g"},
763 { AlphaModifier::OneMinusSourceGreen, "(1.0 - %source.g)" }, 752 {AlphaModifier::OneMinusSourceGreen, "(1.0 - %source.g)"},
764 { AlphaModifier::SourceBlue, "%source.b" }, 753 {AlphaModifier::SourceBlue, "%source.b"},
765 { AlphaModifier::OneMinusSourceBlue, "(1.0 - %source.b)" }, 754 {AlphaModifier::OneMinusSourceBlue, "(1.0 - %source.b)"},
766 }; 755 };
767 756
768 auto src_str = GetTevStageConfigSourceString(source); 757 auto src_str = GetTevStageConfigSourceString(source);
@@ -774,18 +763,19 @@ static std::string GetTevStageConfigAlphaSourceString(const Pica::Regs::TevStage
774 return ReplacePattern(modifier_str, "%source", src_str); 763 return ReplacePattern(modifier_str, "%source", src_str);
775} 764}
776 765
777static std::string GetTevStageConfigOperationString(const Pica::Regs::TevStageConfig::Operation& operation) { 766static std::string
767GetTevStageConfigOperationString(const Pica::Regs::TevStageConfig::Operation& operation) {
778 using Operation = Pica::Regs::TevStageConfig::Operation; 768 using Operation = Pica::Regs::TevStageConfig::Operation;
779 static const std::map<Operation, std::string> combiner_map = { 769 static const std::map<Operation, std::string> combiner_map = {
780 { Operation::Replace, "%source1" }, 770 {Operation::Replace, "%source1"},
781 { Operation::Modulate, "(%source1 * %source2)" }, 771 {Operation::Modulate, "(%source1 * %source2)"},
782 { Operation::Add, "(%source1 + %source2)" }, 772 {Operation::Add, "(%source1 + %source2)"},
783 { Operation::AddSigned, "(%source1 + %source2) - 0.5" }, 773 {Operation::AddSigned, "(%source1 + %source2) - 0.5"},
784 { Operation::Lerp, "lerp(%source1, %source2, %source3)" }, 774 {Operation::Lerp, "lerp(%source1, %source2, %source3)"},
785 { Operation::Subtract, "(%source1 - %source2)" }, 775 {Operation::Subtract, "(%source1 - %source2)"},
786 { Operation::Dot3_RGB, "dot(%source1, %source2)" }, 776 {Operation::Dot3_RGB, "dot(%source1, %source2)"},
787 { Operation::MultiplyThenAdd, "((%source1 * %source2) + %source3)" }, 777 {Operation::MultiplyThenAdd, "((%source1 * %source2) + %source3)"},
788 { Operation::AddThenMultiply, "((%source1 + %source2) * %source3)" }, 778 {Operation::AddThenMultiply, "((%source1 + %source2) * %source3)"},
789 }; 779 };
790 780
791 const auto op_it = combiner_map.find(operation); 781 const auto op_it = combiner_map.find(operation);
@@ -797,23 +787,37 @@ static std::string GetTevStageConfigOperationString(const Pica::Regs::TevStageCo
797 787
798std::string GetTevStageConfigColorCombinerString(const Pica::Regs::TevStageConfig& tev_stage) { 788std::string GetTevStageConfigColorCombinerString(const Pica::Regs::TevStageConfig& tev_stage) {
799 auto op_str = GetTevStageConfigOperationString(tev_stage.color_op); 789 auto op_str = GetTevStageConfigOperationString(tev_stage.color_op);
800 op_str = ReplacePattern(op_str, "%source1", GetTevStageConfigColorSourceString(tev_stage.color_source1, tev_stage.color_modifier1)); 790 op_str = ReplacePattern(
801 op_str = ReplacePattern(op_str, "%source2", GetTevStageConfigColorSourceString(tev_stage.color_source2, tev_stage.color_modifier2)); 791 op_str, "%source1",
802 return ReplacePattern(op_str, "%source3", GetTevStageConfigColorSourceString(tev_stage.color_source3, tev_stage.color_modifier3)); 792 GetTevStageConfigColorSourceString(tev_stage.color_source1, tev_stage.color_modifier1));
793 op_str = ReplacePattern(
794 op_str, "%source2",
795 GetTevStageConfigColorSourceString(tev_stage.color_source2, tev_stage.color_modifier2));
796 return ReplacePattern(
797 op_str, "%source3",
798 GetTevStageConfigColorSourceString(tev_stage.color_source3, tev_stage.color_modifier3));
803} 799}
804 800
805std::string GetTevStageConfigAlphaCombinerString(const Pica::Regs::TevStageConfig& tev_stage) { 801std::string GetTevStageConfigAlphaCombinerString(const Pica::Regs::TevStageConfig& tev_stage) {
806 auto op_str = GetTevStageConfigOperationString(tev_stage.alpha_op); 802 auto op_str = GetTevStageConfigOperationString(tev_stage.alpha_op);
807 op_str = ReplacePattern(op_str, "%source1", GetTevStageConfigAlphaSourceString(tev_stage.alpha_source1, tev_stage.alpha_modifier1)); 803 op_str = ReplacePattern(
808 op_str = ReplacePattern(op_str, "%source2", GetTevStageConfigAlphaSourceString(tev_stage.alpha_source2, tev_stage.alpha_modifier2)); 804 op_str, "%source1",
809 return ReplacePattern(op_str, "%source3", GetTevStageConfigAlphaSourceString(tev_stage.alpha_source3, tev_stage.alpha_modifier3)); 805 GetTevStageConfigAlphaSourceString(tev_stage.alpha_source1, tev_stage.alpha_modifier1));
806 op_str = ReplacePattern(
807 op_str, "%source2",
808 GetTevStageConfigAlphaSourceString(tev_stage.alpha_source2, tev_stage.alpha_modifier2));
809 return ReplacePattern(
810 op_str, "%source3",
811 GetTevStageConfigAlphaSourceString(tev_stage.alpha_source3, tev_stage.alpha_modifier3));
810} 812}
811 813
812void DumpTevStageConfig(const std::array<Pica::Regs::TevStageConfig, 6>& stages) { 814void DumpTevStageConfig(const std::array<Pica::Regs::TevStageConfig, 6>& stages) {
813 std::string stage_info = "Tev setup:\n"; 815 std::string stage_info = "Tev setup:\n";
814 for (size_t index = 0; index < stages.size(); ++index) { 816 for (size_t index = 0; index < stages.size(); ++index) {
815 const auto& tev_stage = stages[index]; 817 const auto& tev_stage = stages[index];
816 stage_info += "Stage " + std::to_string(index) + ": " + GetTevStageConfigColorCombinerString(tev_stage) + " " + GetTevStageConfigAlphaCombinerString(tev_stage) + "\n"; 818 stage_info += "Stage " + std::to_string(index) + ": " +
819 GetTevStageConfigColorCombinerString(tev_stage) + " " +
820 GetTevStageConfigAlphaCombinerString(tev_stage) + "\n";
817 } 821 }
818 LOG_TRACE(HW_GPU, "%s", stage_info.c_str()); 822 LOG_TRACE(HW_GPU, "%s", stage_info.c_str());
819} 823}
diff --git a/src/video_core/debug_utils/debug_utils.h b/src/video_core/debug_utils/debug_utils.h
index 92e9734ae..1a58f40ff 100644
--- a/src/video_core/debug_utils/debug_utils.h
+++ b/src/video_core/debug_utils/debug_utils.h
@@ -53,13 +53,16 @@ public:
53 * Most importantly this is used for our debugger GUI. 53 * Most importantly this is used for our debugger GUI.
54 * 54 *
55 * To implement event handling, override the OnPicaBreakPointHit and OnPicaResume methods. 55 * To implement event handling, override the OnPicaBreakPointHit and OnPicaResume methods.
56 * @warning All BreakPointObservers need to be on the same thread to guarantee thread-safe state access 56 * @warning All BreakPointObservers need to be on the same thread to guarantee thread-safe state
57 * @todo Evaluate an alternative interface, in which there is only one managing observer and multiple child observers running (by design) on the same thread. 57 * access
58 * @todo Evaluate an alternative interface, in which there is only one managing observer and
59 * multiple child observers running (by design) on the same thread.
58 */ 60 */
59 class BreakPointObserver { 61 class BreakPointObserver {
60 public: 62 public:
61 /// Constructs the object such that it observes events of the given DebugContext. 63 /// Constructs the object such that it observes events of the given DebugContext.
62 BreakPointObserver(std::shared_ptr<DebugContext> debug_context) : context_weak(debug_context) { 64 BreakPointObserver(std::shared_ptr<DebugContext> debug_context)
65 : context_weak(debug_context) {
63 std::unique_lock<std::mutex> lock(debug_context->breakpoint_mutex); 66 std::unique_lock<std::mutex> lock(debug_context->breakpoint_mutex);
64 debug_context->breakpoint_observers.push_back(this); 67 debug_context->breakpoint_observers.push_back(this);
65 } 68 }
@@ -122,7 +125,8 @@ public:
122 * The current thread then is halted until Resume() is called from another thread (or until 125 * The current thread then is halted until Resume() is called from another thread (or until
123 * emulation is stopped). 126 * emulation is stopped).
124 * @param event Event which has happened 127 * @param event Event which has happened
125 * @param data Optional data pointer (pass nullptr if unused). Needs to remain valid until Resume() is called. 128 * @param data Optional data pointer (pass nullptr if unused). Needs to remain valid until
129 * Resume() is called.
126 */ 130 */
127 void OnEvent(Event event, void* data) { 131 void OnEvent(Event event, void* data) {
128 // This check is left in the header to allow the compiler to inline it. 132 // This check is left in the header to allow the compiler to inline it.
@@ -132,11 +136,12 @@ public:
132 DoOnEvent(event, data); 136 DoOnEvent(event, data);
133 } 137 }
134 138
135 void DoOnEvent(Event event, void *data); 139 void DoOnEvent(Event event, void* data);
136 140
137 /** 141 /**
138 * Resume from the current breakpoint. 142 * Resume from the current breakpoint.
139 * @warning Calling this from the same thread that OnEvent was called in will cause a deadlock. Calling from any other thread is safe. 143 * @warning Calling this from the same thread that OnEvent was called in will cause a deadlock.
144 * Calling from any other thread is safe.
140 */ 145 */
141 void Resume(); 146 void Resume();
142 147
@@ -144,7 +149,7 @@ public:
144 * Delete all set breakpoints and resume emulation. 149 * Delete all set breakpoints and resume emulation.
145 */ 150 */
146 void ClearBreakpoints() { 151 void ClearBreakpoints() {
147 for (auto &bp : breakpoints) { 152 for (auto& bp : breakpoints) {
148 bp.enabled = false; 153 bp.enabled = false;
149 } 154 }
150 Resume(); 155 Resume();
@@ -182,8 +187,8 @@ namespace DebugUtils {
182#define PICA_LOG_TEV 0 187#define PICA_LOG_TEV 0
183 188
184void DumpShader(const std::string& filename, const Regs::ShaderConfig& config, 189void DumpShader(const std::string& filename, const Regs::ShaderConfig& config,
185 const Shader::ShaderSetup& setup, const Regs::VSOutputAttributes* output_attributes); 190 const Shader::ShaderSetup& setup,
186 191 const Regs::VSOutputAttributes* output_attributes);
187 192
188// Utility class to log Pica commands. 193// Utility class to log Pica commands.
189struct PicaTrace { 194struct PicaTrace {
@@ -216,7 +221,10 @@ struct TextureInfo {
216 * @param source Source pointer to read data from 221 * @param source Source pointer to read data from
217 * @param s,t Texture coordinates to read from 222 * @param s,t Texture coordinates to read from
218 * @param info TextureInfo object describing the texture setup 223 * @param info TextureInfo object describing the texture setup
219 * @param disable_alpha This is used for debug widgets which use this method to display textures without providing a good way to visualize alpha by themselves. If true, this will return 255 for the alpha component, and either drop the information entirely or store it in an "unused" color channel. 224 * @param disable_alpha This is used for debug widgets which use this method to display textures
225 * without providing a good way to visualize alpha by themselves. If true, this will return 255 for
226 * the alpha component, and either drop the information entirely or store it in an "unused" color
227 * channel.
220 * @todo Eventually we should get rid of the disable_alpha parameter. 228 * @todo Eventually we should get rid of the disable_alpha parameter.
221 */ 229 */
222const Math::Vec4<u8> LookupTexture(const u8* source, int s, int t, const TextureInfo& info, 230const Math::Vec4<u8> LookupTexture(const u8* source, int s, int t, const TextureInfo& info,
@@ -237,7 +245,8 @@ class MemoryAccessTracker {
237 /// Combine overlapping and close ranges 245 /// Combine overlapping and close ranges
238 void SimplifyRanges() { 246 void SimplifyRanges() {
239 for (auto it = ranges.begin(); it != ranges.end(); ++it) { 247 for (auto it = ranges.begin(); it != ranges.end(); ++it) {
240 // NOTE: We add 32 to the range end address to make sure "close" ranges are combined, too 248 // NOTE: We add 32 to the range end address to make sure "close" ranges are combined,
249 // too
241 auto it2 = std::next(it); 250 auto it2 = std::next(it);
242 while (it2 != ranges.end() && it->first + it->second + 32 >= it2->first) { 251 while (it2 != ranges.end() && it->first + it->second + 32 >= it2->first) {
243 it->second = std::max(it->second, it2->first + it2->second - it->first); 252 it->second = std::max(it->second, it2->first + it2->second - it->first);