Hacktastic GPU trace viewer; textures, shaders, state, etc.

This commit is contained in:
Ben Vanik
2015-03-01 12:26:11 -08:00
parent 4a211a4195
commit 41174b0e64
19 changed files with 4026 additions and 2536 deletions

View File

@@ -54,6 +54,7 @@ CommandProcessor::CommandProcessor(GL4GraphicsSystem* graphics_system)
graphics_system_(graphics_system),
register_file_(graphics_system_->register_file()),
trace_writer_(graphics_system->memory()->membase()),
trace_state_(TraceState::kDisabled),
worker_running_(true),
swap_mode_(SwapMode::kNormal),
time_base_(0),
@@ -118,12 +119,40 @@ void CommandProcessor::Shutdown() {
context_.reset();
}
void CommandProcessor::RequestFrameTrace(const std::wstring& root_path) {
if (trace_state_ == TraceState::kStreaming) {
XELOGE("Streaming trace; cannot also trace frame.");
return;
}
if (trace_state_ == TraceState::kSingleFrame) {
XELOGE("Frame trace already pending; ignoring.");
return;
}
trace_state_ = TraceState::kSingleFrame;
trace_frame_path_ = root_path;
}
void CommandProcessor::BeginTracing(const std::wstring& root_path) {
std::wstring path = poly::join_paths(root_path, L"gpu_trace");
if (trace_state_ == TraceState::kStreaming) {
XELOGE("Streaming already active; ignoring request.");
return;
}
if (trace_state_ == TraceState::kSingleFrame) {
XELOGE("Frame trace pending; ignoring streaming request.");
return;
}
std::wstring path = poly::join_paths(root_path, L"stream");
trace_state_ = TraceState::kStreaming;
trace_writer_.Open(path);
}
void CommandProcessor::EndTracing() { trace_writer_.Close(); }
void CommandProcessor::EndTracing() {
if (!trace_writer_.is_open()) {
return;
}
assert_true(trace_state_ == TraceState::kStreaming);
trace_writer_.Close();
}
void CommandProcessor::CallInThread(std::function<void()> fn) {
if (pending_fns_.empty() &&
@@ -862,8 +891,20 @@ bool CommandProcessor::ExecutePacketType3_XE_SWAP(RingbufferReader* reader,
IssueSwap();
}
trace_writer_.WriteEvent(EventType::kSwap);
trace_writer_.Flush();
if (trace_writer_.is_open()) {
trace_writer_.WriteEvent(EventType::kSwap);
trace_writer_.Flush();
if (trace_state_ == TraceState::kSingleFrame) {
trace_state_ = TraceState::kDisabled;
trace_writer_.Close();
}
} else if (trace_state_ == TraceState::kSingleFrame) {
// New trace request - we only start tracing at the beginning of a frame.
auto frame_number = L"frame_" + std::to_wstring(counter_);
auto path = trace_frame_path_ + frame_number;
trace_writer_.Open(path);
}
++counter_;
return true;
}
@@ -1098,7 +1139,6 @@ bool CommandProcessor::ExecutePacketType3_EVENT_WRITE_EXT(
}
bool CommandProcessor::ExecutePacketType3_DRAW_INDX(RingbufferReader* reader,
uint32_t packet,
uint32_t count) {
// initiate fetch of index buffer and draw
@@ -1107,7 +1147,6 @@ bool CommandProcessor::ExecutePacketType3_DRAW_INDX(RingbufferReader* reader,
uint32_t dword1 = reader->Read();
uint32_t index_count = dword1 >> 16;
auto prim_type = static_cast<PrimitiveType>(dword1 & 0x3F);
uint32_t src_sel = (dword1 >> 6) & 0x3;
if (src_sel == 0x0) {
// Indexed draw.
@@ -1655,12 +1694,12 @@ CommandProcessor::UpdateStatus CommandProcessor::UpdateViewportState() {
// http://fossies.org/dox/MesaLib-10.3.5/fd2__gmem_8c_source.html
// http://www.x.org/docs/AMD/old/evergreen_3D_registers_v2.pdf
uint32_t mode_control = regs[XE_GPU_REG_PA_SU_SC_MODE_CNTL].u32;
uint32_t pa_su_sc_mode_cntl = regs[XE_GPU_REG_PA_SU_SC_MODE_CNTL].u32;
// Window parameters.
// See r200UpdateWindow:
// https://github.com/freedreno/mesa/blob/master/src/mesa/drivers/dri/r200/r200_state.c
if ((mode_control >> 17) & 1) {
if ((pa_su_sc_mode_cntl >> 17) & 1) {
uint32_t window_offset = regs[XE_GPU_REG_PA_SC_WINDOW_OFFSET].u32;
draw_batcher_.set_window_offset(window_offset & 0x7FFF,
(window_offset >> 16) & 0x7FFF);

View File

@@ -68,6 +68,7 @@ class CommandProcessor {
void set_swap_mode(SwapMode swap_mode) { swap_mode_ = swap_mode; }
void IssueSwap();
void RequestFrameTrace(const std::wstring& root_path);
void BeginTracing(const std::wstring& root_path);
void EndTracing();
@@ -78,6 +79,11 @@ class CommandProcessor {
void ExecutePacket(uint32_t ptr, uint32_t count);
// HACK: for debugging; would be good to have this in a base type.
TextureCache* texture_cache() { return &texture_cache_; }
GL4Shader* active_vertex_shader() const { return active_vertex_shader_; }
GL4Shader* active_pixel_shader() const { return active_pixel_shader_; }
private:
class RingbufferReader;
@@ -208,6 +214,13 @@ class CommandProcessor {
RegisterFile* register_file_;
TraceWriter trace_writer_;
enum class TraceState {
kDisabled,
kStreaming,
kSingleFrame,
};
TraceState trace_state_;
std::wstring trace_frame_path_;
std::thread worker_thread_;
std::atomic<bool> worker_running_;

View File

@@ -72,10 +72,6 @@ X_STATUS GL4GraphicsSystem::Setup(cpu::Processor* processor,
command_processor_->set_swap_handler(
[this](const SwapParameters& swap_params) { SwapHandler(swap_params); });
if (!FLAGS_trace_gpu.empty()) {
command_processor_->BeginTracing(poly::to_wstring(FLAGS_trace_gpu));
}
// Let the processor know we want register access callbacks.
memory_->AddMappedRange(
0x7FC80000, 0xFFFF0000, 0x0000FFFF, this,
@@ -93,11 +89,15 @@ X_STATUS GL4GraphicsSystem::Setup(cpu::Processor* processor,
(WAITORTIMERCALLBACK)VsyncCallbackThunk, this, 16,
timer_period, WT_EXECUTEINPERSISTENTTHREAD);
if (FLAGS_trace_gpu_stream) {
BeginTracing();
}
return X_STATUS_SUCCESS;
}
void GL4GraphicsSystem::Shutdown() {
command_processor_->EndTracing();
EndTracing();
DeleteTimerQueueTimer(timer_queue_, vsync_timer_, nullptr);
DeleteTimerQueue(timer_queue_);
@@ -126,6 +126,17 @@ void GL4GraphicsSystem::RequestSwap() {
command_processor_->CallInThread([&]() { command_processor_->IssueSwap(); });
}
void GL4GraphicsSystem::RequestFrameTrace() {
command_processor_->RequestFrameTrace(
poly::to_wstring(FLAGS_trace_gpu_prefix));
}
void GL4GraphicsSystem::BeginTracing() {
command_processor_->BeginTracing(poly::to_wstring(FLAGS_trace_gpu_prefix));
}
void GL4GraphicsSystem::EndTracing() { command_processor_->EndTracing(); }
void GL4GraphicsSystem::PlayTrace(const uint8_t* trace_data, size_t trace_size,
TracePlaybackMode playback_mode) {
command_processor_->CallInThread(

View File

@@ -32,12 +32,18 @@ class GL4GraphicsSystem : public GraphicsSystem {
void Shutdown() override;
RegisterFile* register_file() { return &register_file_; }
CommandProcessor* command_processor() const {
return command_processor_.get();
}
void InitializeRingBuffer(uint32_t ptr, uint32_t page_count) override;
void EnableReadPointerWriteBack(uint32_t ptr, uint32_t block_size) override;
void RequestSwap() override;
void RequestFrameTrace() override;
void BeginTracing() override;
void EndTracing() override;
void PlayTrace(const uint8_t* trace_data, size_t trace_size,
TracePlaybackMode playback_mode) override;

View File

@@ -170,11 +170,11 @@ GL4ProfilerDisplay::GL4ProfilerDisplay(WGLControl* control)
// Watch for toggle/mode keys and such.
control->on_key_down.AddListener([](poly::ui::KeyEvent& e) {
Profiler::OnKeyDown(e.key_code());
e.set_handled(true);
//e.set_handled(true);
});
control->on_key_up.AddListener([](poly::ui::KeyEvent& e) {
Profiler::OnKeyUp(e.key_code());
e.set_handled(true);
//e.set_handled(true);
});
}

View File

@@ -352,29 +352,30 @@ bool GL4Shader::CompileProgram(std::string source) {
glGetProgramBinary(program_, binary_length, &binary_length, &binary_format,
translated_binary_.data());
// If we are on nvidia, we can find the disassembly string.
// I haven't been able to figure out from the format how to do this
// without a search like this.
const char* disasm_start = nullptr;
size_t search_offset = 0;
char* search_start = reinterpret_cast<char*>(translated_binary_.data());
while (true) {
auto p = reinterpret_cast<char*>(
memchr(translated_binary_.data() + search_offset, '!',
translated_binary_.size() - search_offset));
if (!p) {
break;
}
if (p[0] == '!' && p[1] == '!' && p[2] == 'N' && p[3] == 'V') {
disasm_start = p;
break;
}
search_offset = p - search_start;
++search_offset;
}
host_disassembly_ = std::string(disasm_start);
// Append to shader dump.
if (FLAGS_dump_shaders.size()) {
// If we are on nvidia, we can find the disassembly string.
// I haven't been able to figure out from the format how to do this
// without a search like this.
const char* disasm_start = nullptr;
size_t search_offset = 0;
char* search_start = reinterpret_cast<char*>(translated_binary_.data());
while (true) {
auto p = reinterpret_cast<char*>(
memchr(translated_binary_.data() + search_offset, '!',
translated_binary_.size() - search_offset));
if (!p) {
break;
}
if (p[0] == '!' && p[1] == '!' && p[2] == 'N' && p[3] == 'V') {
disasm_start = p;
break;
}
search_offset = p - search_start;
++search_offset;
}
if (disasm_start) {
FILE* f = fopen(file_name, "a");
fprintf(f, "\n\n/*\n");

View File

@@ -108,6 +108,7 @@ TextureCache::TextureEntryView* TextureCache::Demand(
}
auto view = std::make_unique<TextureEntryView>();
view->texture = texture_entry;
view->sampler = sampler_entry;
view->sampler_hash = sampler_hash;
view->texture_sampler_handle = 0;

View File

@@ -26,11 +26,13 @@ namespace gl4 {
class TextureCache {
public:
struct TextureEntry;
struct SamplerEntry {
SamplerInfo sampler_info;
GLuint handle;
};
struct TextureEntryView {
TextureEntry* texture;
SamplerEntry* sampler;
uint64_t sampler_hash;
GLuint64 texture_sampler_handle;