From 902fa4da52737d43e04c2a028658ad9840811a89 Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Sat, 4 Apr 2015 12:57:31 +0200 Subject: 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). --- src/video_core/command_processor.cpp | 55 +++++++++++++++++++++- src/video_core/debug_utils/debug_utils.h | 4 ++ src/video_core/renderer_opengl/renderer_opengl.cpp | 6 +++ 3 files changed, 63 insertions(+), 2 deletions(-) (limited to 'src/video_core') diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index 110caec76..2095e7b15 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 primitive_assembler(regs.triangle_topology.Value()); PrimitiveAssembler 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 accessed_ranges; + static auto SimplifyRanges = [](std::map& 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& 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 7926d64ec..2573292e2 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 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 9799f74fa..96e12839a 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(); + } } /** -- cgit v1.2.3 From 0799b40caad0deff18d5fd8cf82955156273f157 Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Thu, 21 May 2015 02:24:24 +0200 Subject: Clean up command_processor.cpp. --- src/video_core/command_processor.cpp | 49 ++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 22 deletions(-) (limited to 'src/video_core') diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index 2095e7b15..2a1c885a7 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp @@ -135,27 +135,32 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) { } } - // map physical start address to size - std::map accessed_ranges; - static auto SimplifyRanges = [](std::map& 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); + class { + /// 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); + } } } - }; - static auto AddMemoryAccess = [](std::map& ranges, u32 paddr, u32 size) { - // Create new range or extend existing one - ranges[paddr] = std::max(ranges[paddr], size); + 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(); + } - // Simplify ranges... - SimplifyRanges(ranges); - }; + /// Map of accessed ranges (mapping start address to range size) + std::map ranges; + } memory_accesses; for (unsigned int index = 0; index < regs.num_vertices; ++index) { @@ -165,7 +170,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) { // 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); + memory_accesses.AddAccess(base_address + index_info.offset + size * index, size); } } @@ -193,9 +198,9 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) { 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); + memory_accesses.AddAccess(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 : @@ -258,7 +263,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) { } } - for (auto& range : accessed_ranges) { + for (auto& range : memory_accesses.ranges) { g_debug_context->recorder->MemoryAccessed(Memory::GetPhysicalPointer(range.first), range.second, range.first); } -- cgit v1.2.3