diff --git a/src/xenia/gpu/gl4/gl4_trace_viewer_main.cc b/src/xenia/gpu/gl4/gl4_trace_viewer_main.cc index 6a684a064..c7d24001c 100644 --- a/src/xenia/gpu/gl4/gl4_trace_viewer_main.cc +++ b/src/xenia/gpu/gl4/gl4_trace_viewer_main.cc @@ -56,6 +56,43 @@ class GL4TraceViewer : public TraceViewer { auto texture = entry_view->texture; return static_cast(texture->handle); } + + size_t QueryVSOutputSize() override { + auto command_processor = static_cast( + graphics_system_->command_processor()); + auto draw_batcher = command_processor->draw_batcher(); + + return draw_batcher->QueryTFBSize(); + } + + size_t QueryVSOutputElementSize() override { + // vec4 always has 4 elements. + return 4; + } + + bool QueryVSOutput(void* buffer, size_t size) override { + auto command_processor = static_cast( + graphics_system_->command_processor()); + auto draw_batcher = command_processor->draw_batcher(); + + return draw_batcher->ReadbackTFB(buffer, size); + } + + bool Setup() override { + if (!TraceViewer::Setup()) { + return false; + } + + // Enable TFB + auto command_processor = static_cast( + graphics_system_->command_processor()); + auto draw_batcher = command_processor->draw_batcher(); + draw_batcher->set_tfb_enabled(true); + + return true; + } + + private: }; int trace_viewer_main(const std::vector& args) { diff --git a/src/xenia/gpu/trace_viewer.cc b/src/xenia/gpu/trace_viewer.cc index 87225a156..276acabcd 100644 --- a/src/xenia/gpu/trace_viewer.cc +++ b/src/xenia/gpu/trace_viewer.cc @@ -680,7 +680,7 @@ void TraceViewer::DrawVertexFetcher(Shader* shader, const Shader::VertexBinding& vertex_binding, const xe_gpu_vertex_fetch_t* fetch) { const uint8_t* addr = memory_->TranslatePhysical(fetch->address << 2); - uint32_t vertex_count = (fetch->size * 4) / vertex_binding.stride_words; + uint32_t vertex_count = fetch->size / vertex_binding.stride_words; int column_count = 0; for (const auto& attrib : vertex_binding.attributes) { switch (attrib.fetch_instr.attributes.data_format) { @@ -715,9 +715,9 @@ void TraceViewer::DrawVertexFetcher(Shader* shader, } } ImGui::BeginChild("#indices", ImVec2(0, 300)); - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(10, 0)); int display_start, display_end; - ImGui::CalcListClipping(1 + vertex_count, ImGui::GetTextLineHeight(), + ImGui::CalcListClipping(vertex_count, ImGui::GetTextLineHeight(), &display_start, &display_end); ImGui::SetCursorPosY(ImGui::GetCursorPosY() + (display_start)*ImGui::GetTextLineHeight()); @@ -1274,6 +1274,8 @@ void TraceViewer::DrawStateUI() { static_cast((color_info[i] >> 16) & 0xF); ImVec2 button_size(256, 256); if (write_mask) { + // FIXME: Valid color targets with alpha=0 don't show up. + auto color_target = GetColorRenderTarget(surface_pitch, surface_msaa, color_base, color_format); if (ImGui::ImageButton(ImTextureID(color_target), button_size, @@ -1373,6 +1375,55 @@ void TraceViewer::DrawStateUI() { } ImGui::EndChild(); } + if (ImGui::CollapsingHeader("Vertex Shader Output")) { + auto size = QueryVSOutputSize(); + auto el_size = QueryVSOutputElementSize(); + if (size > 0) { + std::vector vertices; + vertices.resize(size / 4); + QueryVSOutput(vertices.data(), size); + + ImGui::Text("%d output vertices", vertices.size()); + ImGui::SameLine(); + static bool normalize = false; + ImGui::Checkbox("Normalize", &normalize); + + ImGui::BeginChild("#vsvertices", ImVec2(0, 300)); + + int display_start, display_end; + ImGui::CalcListClipping(int(vertices.size() / 4), + ImGui::GetTextLineHeight(), &display_start, + &display_end); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + + (display_start)*ImGui::GetTextLineHeight()); + + ImGui::Columns(int(el_size), "#vsvertices", true); + for (size_t i = display_start; i < display_end; i++) { + size_t start_vtx = i * el_size; + float verts[4] = {vertices[start_vtx], vertices[start_vtx + 1], + vertices[start_vtx + 2], vertices[start_vtx + 3]}; + assert_true(el_size <= xe::countof(verts)); + if (normalize) { + for (int j = 0; j < el_size; j++) { + verts[j] /= verts[3]; + } + } + + for (int j = 0; j < el_size; j++) { + ImGui::Text("%.3f", verts[j]); + ImGui::NextColumn(); + } + } + ImGui::Columns(1); + + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + + ((vertices.size() / 4) - display_end) * + ImGui::GetTextLineHeight()); + ImGui::EndChild(); + } else { + ImGui::Text("No vertex shader output"); + } + } if (ImGui::CollapsingHeader("Pixel Shader")) { ShaderDisplayType shader_display_type = DrawShaderTypeUI(); ImGui::BeginChild("#pixel_shader_text", ImVec2(0, 400)); @@ -1507,7 +1558,7 @@ void TraceViewer::DrawStateUI() { ImGui::TextColored(kColorError, "ERROR: no vertex shader set"); } } - if (ImGui::CollapsingHeader("Textures")) { + if (ImGui::CollapsingHeader("Pixel Textures")) { auto shader = command_processor->active_pixel_shader(); if (shader) { const auto& texture_bindings = shader->texture_bindings(); diff --git a/src/xenia/gpu/trace_viewer.h b/src/xenia/gpu/trace_viewer.h index fa066414f..5a5c1b104 100644 --- a/src/xenia/gpu/trace_viewer.h +++ b/src/xenia/gpu/trace_viewer.h @@ -54,6 +54,12 @@ class TraceViewer { virtual uintptr_t GetTextureEntry(const TextureInfo& texture_info, const SamplerInfo& sampler_info) = 0; + virtual size_t QueryVSOutputSize() = 0; + virtual size_t QueryVSOutputElementSize() = 0; + virtual bool QueryVSOutput(void* buffer, size_t size) = 0; + + virtual bool Setup(); + std::unique_ptr loop_; std::unique_ptr window_; std::unique_ptr emulator_; @@ -68,7 +74,6 @@ class TraceViewer { kHostDisasm, }; - bool Setup(); bool Load(std::wstring trace_file_path); void Run();