summaryrefslogtreecommitdiff
path: root/src/core/tracer/recorder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/tracer/recorder.cpp')
-rw-r--r--src/core/tracer/recorder.cpp187
1 files changed, 187 insertions, 0 deletions
diff --git a/src/core/tracer/recorder.cpp b/src/core/tracer/recorder.cpp
new file mode 100644
index 000000000..656706c0c
--- /dev/null
+++ b/src/core/tracer/recorder.cpp
@@ -0,0 +1,187 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <cstring>
6
7#include "common/assert.h"
8#include "common/file_util.h"
9#include "common/logging/log.h"
10
11#include "recorder.h"
12
13namespace CiTrace {
14
15Recorder::Recorder(const InitialState& initial_state) : initial_state(initial_state) {
16
17}
18
19void Recorder::Finish(const std::string& filename) {
20 // Setup CiTrace header
21 CTHeader header;
22 std::memcpy(header.magic, CTHeader::ExpectedMagicWord(), 4);
23 header.version = CTHeader::ExpectedVersion();
24 header.header_size = sizeof(CTHeader);
25
26 // Calculate file offsets
27 auto& initial = header.initial_state_offsets;
28
29 initial.gpu_registers_size = initial_state.gpu_registers.size();
30 initial.lcd_registers_size = initial_state.lcd_registers.size();
31 initial.pica_registers_size = initial_state.pica_registers.size();
32 initial.default_attributes_size = initial_state.default_attributes.size();
33 initial.vs_program_binary_size = initial_state.vs_program_binary.size();
34 initial.vs_swizzle_data_size = initial_state.vs_swizzle_data.size();
35 initial.vs_float_uniforms_size = initial_state.vs_float_uniforms.size();
36 initial.gs_program_binary_size = initial_state.gs_program_binary.size();
37 initial.gs_swizzle_data_size = initial_state.gs_swizzle_data.size();
38 initial.gs_float_uniforms_size = initial_state.gs_float_uniforms.size();
39 header.stream_size = stream.size();
40
41 initial.gpu_registers = sizeof(header);
42 initial.lcd_registers = initial.gpu_registers + initial.gpu_registers_size * sizeof(u32);
43 initial.pica_registers = initial.lcd_registers + initial.lcd_registers_size * sizeof(u32);;
44 initial.default_attributes = initial.pica_registers + initial.pica_registers_size * sizeof(u32);
45 initial.vs_program_binary = initial.default_attributes + initial.default_attributes_size * sizeof(u32);
46 initial.vs_swizzle_data = initial.vs_program_binary + initial.vs_program_binary_size * sizeof(u32);
47 initial.vs_float_uniforms = initial.vs_swizzle_data + initial.vs_swizzle_data_size * sizeof(u32);
48 initial.gs_program_binary = initial.vs_float_uniforms + initial.vs_float_uniforms_size * sizeof(u32);
49 initial.gs_swizzle_data = initial.gs_program_binary + initial.gs_program_binary_size * sizeof(u32);
50 initial.gs_float_uniforms = initial.gs_swizzle_data + initial.gs_swizzle_data_size * sizeof(u32);
51 header.stream_offset = initial.gs_float_uniforms + initial.gs_float_uniforms_size * sizeof(u32);
52
53 // Iterate through stream elements, update relevant stream element data
54 for (auto& stream_element : stream) {
55 switch (stream_element.data.type) {
56 case MemoryLoad:
57 {
58 auto& file_offset = memory_regions[stream_element.hash];
59 if (!stream_element.uses_existing_data) {
60 file_offset = header.stream_offset;
61 }
62 stream_element.data.memory_load.file_offset = file_offset;
63 break;
64 }
65
66 default:
67 // Other commands don't use any extra data
68 DEBUG_ASSERT(stream_element.extra_data.size() == 0);
69 break;
70 }
71 header.stream_offset += stream_element.extra_data.size();
72 }
73
74 try {
75 // Open file and write header
76 FileUtil::IOFile file(filename, "wb");
77 size_t written = file.WriteObject(header);
78 if (written != 1 || file.Tell() != initial.gpu_registers)
79 throw "Failed to write header";
80
81 // Write initial state
82 written = file.WriteArray(initial_state.gpu_registers.data(), initial_state.gpu_registers.size());
83 if (written != initial_state.gpu_registers.size() || file.Tell() != initial.lcd_registers)
84 throw "Failed to write GPU registers";
85
86 written = file.WriteArray(initial_state.lcd_registers.data(), initial_state.lcd_registers.size());
87 if (written != initial_state.lcd_registers.size() || file.Tell() != initial.pica_registers)
88 throw "Failed to write LCD registers";
89
90 written = file.WriteArray(initial_state.pica_registers.data(), initial_state.pica_registers.size());
91 if (written != initial_state.pica_registers.size() || file.Tell() != initial.default_attributes)
92 throw "Failed to write Pica registers";
93
94 written = file.WriteArray(initial_state.default_attributes.data(), initial_state.default_attributes.size());
95 if (written != initial_state.default_attributes.size() || file.Tell() != initial.vs_program_binary)
96 throw "Failed to write default vertex attributes";
97
98 written = file.WriteArray(initial_state.vs_program_binary.data(), initial_state.vs_program_binary.size());
99 if (written != initial_state.vs_program_binary.size() || file.Tell() != initial.vs_swizzle_data)
100 throw "Failed to write vertex shader program binary";
101
102 written = file.WriteArray(initial_state.vs_swizzle_data.data(), initial_state.vs_swizzle_data.size());
103 if (written != initial_state.vs_swizzle_data.size() || file.Tell() != initial.vs_float_uniforms)
104 throw "Failed to write vertex shader swizzle data";
105
106 written = file.WriteArray(initial_state.vs_float_uniforms.data(), initial_state.vs_float_uniforms.size());
107 if (written != initial_state.vs_float_uniforms.size() || file.Tell() != initial.gs_program_binary)
108 throw "Failed to write vertex shader float uniforms";
109
110 written = file.WriteArray(initial_state.gs_program_binary.data(), initial_state.gs_program_binary.size());
111 if (written != initial_state.gs_program_binary.size() || file.Tell() != initial.gs_swizzle_data)
112 throw "Failed to write geomtry shader program binary";
113
114 written = file.WriteArray(initial_state.gs_swizzle_data.data(), initial_state.gs_swizzle_data.size());
115 if (written != initial_state.gs_swizzle_data.size() || file.Tell() != initial.gs_float_uniforms)
116 throw "Failed to write geometry shader swizzle data";
117
118 written = file.WriteArray(initial_state.gs_float_uniforms.data(), initial_state.gs_float_uniforms.size());
119 if (written != initial_state.gs_float_uniforms.size() || file.Tell() != initial.gs_float_uniforms + sizeof(u32) * initial.gs_float_uniforms_size)
120 throw "Failed to write geometry shader float uniforms";
121
122 // Iterate through stream elements, write "extra data"
123 for (const auto& stream_element : stream) {
124 if (stream_element.extra_data.size() == 0)
125 continue;
126
127 written = file.WriteBytes(stream_element.extra_data.data(), stream_element.extra_data.size());
128 if (written != stream_element.extra_data.size())
129 throw "Failed to write extra data";
130 }
131
132 if (file.Tell() != header.stream_offset)
133 throw "Unexpected end of extra data";
134
135 // Write actual stream elements
136 for (const auto& stream_element : stream) {
137 if (1 != file.WriteObject(stream_element.data))
138 throw "Failed to write stream element";
139 }
140 } catch(const char* str) {
141 LOG_ERROR(HW_GPU, "Writing CiTrace file failed: %s", str);
142 }
143}
144
145void Recorder::FrameFinished() {
146 stream.push_back( { FrameMarker } );
147}
148
149void Recorder::MemoryAccessed(const u8* data, u32 size, u32 physical_address) {
150 StreamElement element = { MemoryLoad };
151 element.data.memory_load.size = size;
152 element.data.memory_load.physical_address = physical_address;
153
154 // Compute hash over given memory region to check if the contents are already stored internally
155 boost::crc_32_type result;
156 result.process_bytes(data, size);
157 element.hash = result.checksum();
158
159 element.uses_existing_data = (memory_regions.find(element.hash) != memory_regions.end());
160 if (!element.uses_existing_data) {
161 element.extra_data.resize(size);
162 memcpy(element.extra_data.data(), data, size);
163 memory_regions.insert({element.hash, 0}); // file offset will be initialized in Finish()
164 }
165
166 stream.push_back(element);
167}
168
169template<typename T>
170void Recorder::RegisterWritten(u32 physical_address, T value) {
171 StreamElement element = { RegisterWrite };
172 element.data.register_write.size = (sizeof(T) == 1) ? CTRegisterWrite::SIZE_8
173 : (sizeof(T) == 2) ? CTRegisterWrite::SIZE_16
174 : (sizeof(T) == 4) ? CTRegisterWrite::SIZE_32
175 : CTRegisterWrite::SIZE_64;
176 element.data.register_write.physical_address = physical_address;
177 element.data.register_write.value = value;
178
179 stream.push_back(element);
180}
181
182template void Recorder::RegisterWritten(u32,u8);
183template void Recorder::RegisterWritten(u32,u16);
184template void Recorder::RegisterWritten(u32,u32);
185template void Recorder::RegisterWritten(u32,u64);
186
187}