aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/video_core
diff options
context:
space:
mode:
authorGravatar Tony Wasserka <NeoBrainX@gmail.com>2015-04-04 12:57:31 +0200
committerGravatar Tony Wasserka <NeoBrainX@gmail.com>2015-07-13 22:27:20 +0200
commit902fa4da52737d43e04c2a028658ad9840811a89 (patch)
tree0a2346b4e08b5865c3369247f5720453b170e0c6 /src/video_core
parent93d66475d491f0ed0070da0fc3bcc2d9bb066233 (diff)
Add CiTrace recording support.
This is exposed in the GUI as a new "CiTrace Recording" widget. Playback is implemented by a standalone 3DS homebrew application (which only runs reliably within Citra currently; on an actual 3DS it will often crash still).
Diffstat (limited to 'src/video_core')
-rw-r--r--src/video_core/command_processor.cpp55
-rw-r--r--src/video_core/debug_utils/debug_utils.h4
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp6
3 files changed, 63 insertions, 2 deletions
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp
index 110caec7..2095e7b1 100644
--- a/src/video_core/command_processor.cpp
+++ b/src/video_core/command_processor.cpp
@@ -123,12 +123,50 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
PrimitiveAssembler<VertexShader::OutputVertex> primitive_assembler(regs.triangle_topology.Value());
PrimitiveAssembler<DebugUtils::GeometryDumper::Vertex> dumping_primitive_assembler(regs.triangle_topology.Value());
+ if (g_debug_context) {
+ for (int i = 0; i < 3; ++i) {
+ const auto texture = regs.GetTextures()[i];
+ if (!texture.enabled)
+ continue;
+
+ u8* texture_data = Memory::GetPhysicalPointer(texture.config.GetPhysicalAddress());
+ if (g_debug_context && Pica::g_debug_context->recorder)
+ g_debug_context->recorder->MemoryAccessed(texture_data, Pica::Regs::NibblesPerPixel(texture.format) * texture.config.width / 2 * texture.config.height, texture.config.GetPhysicalAddress());
+ }
+ }
+
+ // map physical start address to size
+ std::map<u32, u32> accessed_ranges;
+ static auto SimplifyRanges = [](std::map<u32, u32>& ranges) {
+ for (auto it = ranges.begin(); it != ranges.end(); ++it) {
+
+ // Combine overlapping ranges ... artificially extend first range by 32 bytes to merge "close" ranges
+ 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);
+ }
+ }
+ };
+
+ static auto AddMemoryAccess = [](std::map<u32, u32>& ranges, u32 paddr, u32 size) {
+ // Create new range or extend existing one
+ ranges[paddr] = std::max(ranges[paddr], size);
+
+ // Simplify ranges...
+ SimplifyRanges(ranges);
+ };
+
for (unsigned int index = 0; index < regs.num_vertices; ++index)
{
unsigned int vertex = is_indexed ? (index_u16 ? index_address_16[index] : index_address_8[index]) : index;
if (is_indexed) {
// TODO: Implement some sort of vertex cache!
+ if (g_debug_context && Pica::g_debug_context->recorder) {
+ int size = index_u16 ? 2 : 1;
+ AddMemoryAccess(accessed_ranges, base_address + index_info.offset + size*index, size);
+ }
}
// Initialize data for the current vertex
@@ -151,7 +189,14 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
// Load per-vertex data from the loader arrays
for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
- const u8* srcdata = Memory::GetPhysicalPointer(vertex_attribute_sources[i] + vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i]);
+ u32 source_addr = vertex_attribute_sources[i] + vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i];
+ const u8* srcdata = Memory::GetPhysicalPointer(source_addr);
+
+ if (g_debug_context && Pica::g_debug_context->recorder) {
+ AddMemoryAccess(accessed_ranges, source_addr,
+ (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::FLOAT) ? 4
+ : (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::SHORT) ? 2 : 1);
+ }
const float srcval = (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::BYTE) ? *(s8*)srcdata :
(vertex_attribute_formats[i] == Regs::VertexAttributeFormat::UBYTE) ? *(u8*)srcdata :
@@ -213,14 +258,20 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
}
}
+ for (auto& range : accessed_ranges) {
+ g_debug_context->recorder->MemoryAccessed(Memory::GetPhysicalPointer(range.first),
+ range.second, range.first);
+ }
+
if (Settings::values.use_hw_renderer) {
VideoCore::g_renderer->hw_rasterizer->DrawTriangles();
}
geometry_dumper.Dump();
- if (g_debug_context)
+ if (g_debug_context) {
g_debug_context->OnEvent(DebugContext::Event::FinishedPrimitiveBatch, nullptr);
+ }
break;
}
diff --git a/src/video_core/debug_utils/debug_utils.h b/src/video_core/debug_utils/debug_utils.h
index 7926d64e..2573292e 100644
--- a/src/video_core/debug_utils/debug_utils.h
+++ b/src/video_core/debug_utils/debug_utils.h
@@ -14,6 +14,8 @@
#include "common/vector_math.h"
+#include "core/tracer/recorder.h"
+
#include "video_core/pica.h"
namespace Pica {
@@ -129,6 +131,8 @@ public:
Event active_breakpoint;
bool at_breakpoint = false;
+ std::shared_ptr<CiTrace::Recorder> recorder = nullptr;
+
private:
/**
* Private default constructor to make sure people always construct this through Construct()
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 9799f74f..96e12839 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -22,6 +22,8 @@
#include "video_core/renderer_opengl/gl_shader_util.h"
#include "video_core/renderer_opengl/gl_shaders.h"
+#include "video_core/debug_utils/debug_utils.h"
+
/**
* Vertex structure that the drawn screen rectangles are composed of.
*/
@@ -129,6 +131,10 @@ void RendererOpenGL::SwapBuffers() {
hw_rasterizer->Reset();
}
}
+
+ if (Pica::g_debug_context && Pica::g_debug_context->recorder) {
+ Pica::g_debug_context->recorder->FrameFinished();
+ }
}
/**