aboutsummaryrefslogtreecommitdiff
path: root/src/video_core/debug_utils
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core/debug_utils')
-rw-r--r--src/video_core/debug_utils/debug_utils.cpp71
-rw-r--r--src/video_core/debug_utils/debug_utils.h85
2 files changed, 87 insertions, 69 deletions
diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp
index bac6d69c7..fb20f81dd 100644
--- a/src/video_core/debug_utils/debug_utils.cpp
+++ b/src/video_core/debug_utils/debug_utils.cpp
@@ -4,35 +4,41 @@
#include <algorithm>
#include <condition_variable>
+#include <cstdint>
#include <cstring>
#include <fstream>
-#include <list>
#include <map>
#include <mutex>
+#include <stdexcept>
#include <string>
#ifdef HAVE_PNG
#include <png.h>
+#include <setjmp.h>
#endif
+#include <nihstro/bit_field.h>
#include <nihstro/float24.h>
#include <nihstro/shader_binary.h>
#include "common/assert.h"
+#include "common/bit_field.h"
#include "common/color.h"
#include "common/common_types.h"
#include "common/file_util.h"
+#include "common/logging/log.h"
#include "common/math_util.h"
#include "common/vector_math.h"
-#include "core/settings.h"
-
+#include "video_core/debug_utils/debug_utils.h"
#include "video_core/pica.h"
#include "video_core/pica_state.h"
+#include "video_core/pica_types.h"
+#include "video_core/rasterizer_interface.h"
#include "video_core/renderer_base.h"
+#include "video_core/shader/shader.h"
#include "video_core/utils.h"
#include "video_core/video_core.h"
-#include "video_core/debug_utils/debug_utils.h"
using nihstro::DVLBHeader;
using nihstro::DVLEHeader;
@@ -40,15 +46,12 @@ using nihstro::DVLPHeader;
namespace Pica {
-void DebugContext::OnEvent(Event event, void* data) {
- if (!breakpoints[event].enabled)
- return;
-
+void DebugContext::DoOnEvent(Event event, void* data) {
{
std::unique_lock<std::mutex> lock(breakpoint_mutex);
- // Commit the hardware renderer's framebuffer so it will show on debug widgets
- VideoCore::g_renderer->Rasterizer()->FlushFramebuffer();
+ // Commit the rasterizer's caches so framebuffers, render targets, etc. will show on debug widgets
+ VideoCore::g_renderer->Rasterizer()->FlushAll();
// TODO: Should stop the CPU thread here once we multithread emulation.
@@ -85,35 +88,6 @@ std::shared_ptr<DebugContext> g_debug_context; // TODO: Get rid of this global
namespace DebugUtils {
-void GeometryDumper::AddTriangle(Vertex& v0, Vertex& v1, Vertex& v2) {
- vertices.push_back(v0);
- vertices.push_back(v1);
- vertices.push_back(v2);
-
- int num_vertices = (int)vertices.size();
- faces.push_back({{ num_vertices-3, num_vertices-2, num_vertices-1 }});
-}
-
-void GeometryDumper::Dump() {
- static int index = 0;
- std::string filename = std::string("geometry_dump") + std::to_string(++index) + ".obj";
-
- std::ofstream file(filename);
-
- for (const auto& vertex : vertices) {
- file << "v " << vertex.pos[0]
- << " " << vertex.pos[1]
- << " " << vertex.pos[2] << std::endl;
- }
-
- for (const Face& face : faces) {
- file << "f " << 1+face.index[0]
- << " " << 1+face.index[1]
- << " " << 1+face.index[2] << std::endl;
- }
-}
-
-
void DumpShader(const std::string& filename, const Regs::ShaderConfig& config, const Shader::ShaderSetup& setup, const Regs::VSOutputAttributes* output_attributes)
{
struct StuffToWrite {
@@ -315,7 +289,7 @@ void StartPicaTracing()
}
std::lock_guard<std::mutex> lock(pica_trace_mutex);
- pica_trace = std::unique_ptr<PicaTrace>(new PicaTrace);
+ pica_trace = std::make_unique<PicaTrace>();
is_pica_tracing = true;
}
@@ -615,6 +589,21 @@ TextureInfo TextureInfo::FromPicaRegister(const Regs::TextureConfig& config,
return info;
}
+#ifdef HAVE_PNG
+// Adapter functions to libpng to write/flush to File::IOFile instances.
+static void WriteIOFile(png_structp png_ptr, png_bytep data, png_size_t length) {
+ auto* fp = static_cast<FileUtil::IOFile*>(png_get_io_ptr(png_ptr));
+ if (!fp->WriteBytes(data, length))
+ png_error(png_ptr, "Failed to write to output PNG file.");
+}
+
+static void FlushIOFile(png_structp png_ptr) {
+ auto* fp = static_cast<FileUtil::IOFile*>(png_get_io_ptr(png_ptr));
+ if (!fp->Flush())
+ png_error(png_ptr, "Failed to flush to output PNG file.");
+}
+#endif
+
void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) {
#ifndef HAVE_PNG
return;
@@ -658,7 +647,7 @@ void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) {
goto finalise;
}
- png_init_io(png_ptr, fp.GetHandle());
+ png_set_write_fn(png_ptr, static_cast<void*>(&fp), WriteIOFile, FlushIOFile);
// Write header (8 bit color depth)
png_set_IHDR(png_ptr, info_ptr, texture_config.width, texture_config.height,
diff --git a/src/video_core/debug_utils/debug_utils.h b/src/video_core/debug_utils/debug_utils.h
index 795160a32..f628292a4 100644
--- a/src/video_core/debug_utils/debug_utils.h
+++ b/src/video_core/debug_utils/debug_utils.h
@@ -4,23 +4,33 @@
#pragma once
+#include <algorithm>
#include <array>
#include <condition_variable>
+#include <iterator>
#include <list>
#include <map>
#include <memory>
#include <mutex>
+#include <string>
+#include <utility>
#include <vector>
+#include "common/common_types.h"
#include "common/vector_math.h"
-#include "core/tracer/recorder.h"
-
#include "video_core/pica.h"
-#include "video_core/shader/shader.h"
+
+namespace CiTrace {
+class Recorder;
+}
namespace Pica {
+namespace Shader {
+struct ShaderSetup;
+}
+
class DebugContext {
public:
enum class Event {
@@ -30,7 +40,7 @@ public:
PicaCommandProcessed,
IncomingPrimitiveBatch,
FinishedPrimitiveBatch,
- VertexLoaded,
+ VertexShaderInvocation,
IncomingDisplayTransfer,
GSPCommandProcessed,
BufferSwapped,
@@ -114,7 +124,15 @@ public:
* @param event Event which has happened
* @param data Optional data pointer (pass nullptr if unused). Needs to remain valid until Resume() is called.
*/
- void OnEvent(Event event, void* data);
+ void OnEvent(Event event, void* data) {
+ // This check is left in the header to allow the compiler to inline it.
+ if (!breakpoints[(int)event].enabled)
+ return;
+ // For the rest of event handling, call a separate function.
+ DoOnEvent(event, data);
+ }
+
+ void DoOnEvent(Event event, void *data);
/**
* Resume from the current breakpoint.
@@ -126,12 +144,14 @@ public:
* Delete all set breakpoints and resume emulation.
*/
void ClearBreakpoints() {
- breakpoints.clear();
+ for (auto &bp : breakpoints) {
+ bp.enabled = false;
+ }
Resume();
}
// TODO: Evaluate if access to these members should be hidden behind a public interface.
- std::map<Event, BreakPoint> breakpoints;
+ std::array<BreakPoint, (int)Event::NumEvents> breakpoints;
Event active_breakpoint;
bool at_breakpoint = false;
@@ -158,30 +178,9 @@ extern std::shared_ptr<DebugContext> g_debug_context; // TODO: Get rid of this g
namespace DebugUtils {
-#define PICA_DUMP_GEOMETRY 0
#define PICA_DUMP_TEXTURES 0
#define PICA_LOG_TEV 0
-// Simple utility class for dumping geometry data to an OBJ file
-class GeometryDumper {
-public:
- struct Vertex {
- std::array<float,3> pos;
- };
-
- void AddTriangle(Vertex& v0, Vertex& v1, Vertex& v2);
-
- void Dump();
-
-private:
- struct Face {
- int index[3];
- };
-
- std::vector<Vertex> vertices;
- std::vector<Face> faces;
-};
-
void DumpShader(const std::string& filename, const Regs::ShaderConfig& config,
const Shader::ShaderSetup& setup, const Regs::VSOutputAttributes* output_attributes);
@@ -227,6 +226,36 @@ void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data);
void DumpTevStageConfig(const std::array<Pica::Regs::TevStageConfig,6>& stages);
+/**
+ * Used in the vertex loader to merge access records. TODO: Investigate if actually useful.
+ */
+class MemoryAccessTracker {
+ /// Combine overlapping and close ranges
+ void SimplifyRanges() {
+ for (auto it = ranges.begin(); it != ranges.end(); ++it) {
+ // NOTE: We add 32 to the range end address to make sure "close" ranges are combined, too
+ auto it2 = std::next(it);
+ while (it2 != ranges.end() && it->first + it->second + 32 >= it2->first) {
+ it->second = std::max(it->second, it2->first + it2->second - it->first);
+ it2 = ranges.erase(it2);
+ }
+ }
+ }
+
+public:
+ /// Record a particular memory access in the list
+ void AddAccess(u32 paddr, u32 size) {
+ // Create new range or extend existing one
+ ranges[paddr] = std::max(ranges[paddr], size);
+
+ // Simplify ranges...
+ SimplifyRanges();
+ }
+
+ /// Map of accessed ranges (mapping start address to range size)
+ std::map<u32, u32> ranges;
+};
+
} // namespace
} // namespace