From 3859b0a091495275f46a01d3e22ca7f70ffdeea9 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Mon, 18 Jan 2016 20:57:36 -0600 Subject: [PATCH 1/5] Add an option for the draw batcher to collect vertex shader output. Disabled by default. --- src/xenia/gpu/gl4/draw_batcher.cc | 180 ++++++++++++++++++++++++++++-- src/xenia/gpu/gl4/draw_batcher.h | 22 ++++ 2 files changed, 192 insertions(+), 10 deletions(-) diff --git a/src/xenia/gpu/gl4/draw_batcher.cc b/src/xenia/gpu/gl4/draw_batcher.cc index d69ac7dad..7faa663a5 100644 --- a/src/xenia/gpu/gl4/draw_batcher.cc +++ b/src/xenia/gpu/gl4/draw_batcher.cc @@ -48,13 +48,92 @@ bool DrawBatcher::Initialize(CircularBuffer* array_data_buffer) { if (!state_buffer_.Initialize()) { return false; } + if (!InitializeTFB()) { + return false; + } + glBindBuffer(GL_DRAW_INDIRECT_BUFFER, command_buffer_.handle()); return true; } +// Initializes a transform feedback object +// We use this to capture vertex data straight from the vertex/geometry shader. +bool DrawBatcher::InitializeTFB() { + glGenBuffers(1, &tfvbo_); + if (!tfvbo_) { + return false; + } + + glGenTransformFeedbacks(1, &tfbo_); + if (!tfbo_) { + return false; + } + + glGenQueries(1, &tfqo_); + if (!tfqo_) { + return false; + } + + // TODO(DrChat): Calculate this based on the number of primitives drawn. + glBindBuffer(GL_ARRAY_BUFFER, tfvbo_); + glBufferData(GL_ARRAY_BUFFER, 16384 * 4, nullptr, GL_STATIC_READ); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + return true; +} + +void DrawBatcher::ShutdownTFB() { + glDeleteBuffers(1, &tfvbo_); + glDeleteTransformFeedbacks(1, &tfbo_); + glDeleteQueries(1, &tfqo_); + + tfvbo_ = 0; + tfbo_ = 0; + tfqo_ = 0; +} + +size_t DrawBatcher::QueryTFBSize() { + if (!tfb_enabled_) { + return 0; + } + + size_t size = 0; + switch (tfb_prim_type_gl_) { + case GL_POINTS: + size = tfb_prim_count_ * 1 * 4 * 4; + break; + case GL_LINES: + size = tfb_prim_count_ * 2 * 4 * 4; + break; + case GL_TRIANGLES: + size = tfb_prim_count_ * 3 * 4 * 4; + break; + } + + return size; +} + +bool DrawBatcher::ReadbackTFB(void* buffer, size_t size) { + if (!tfb_enabled_) { + XELOGW("DrawBatcher::ReadbackTFB called when TFB was disabled!"); + return false; + } + + glBindBuffer(GL_ARRAY_BUFFER, tfvbo_); + void* data = glMapBufferRange(GL_ARRAY_BUFFER, 0, size, GL_MAP_READ_BIT); + + std::memcpy(buffer, data, size); + + glUnmapBuffer(GL_ARRAY_BUFFER); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + return true; +} + void DrawBatcher::Shutdown() { command_buffer_.Shutdown(); state_buffer_.Shutdown(); + ShutdownTFB(); } bool DrawBatcher::ReconfigurePipeline(GL4Shader* vertex_shader, @@ -242,6 +321,84 @@ bool DrawBatcher::CommitDraw() { return true; } +void DrawBatcher::TFBBegin(PrimitiveType prim_type) { + if (!tfb_enabled_) { + return; + } + + // Translate the primitive typename to something compatible with TFB. + GLenum gl_prim_type = 0; + switch (prim_type) { + case PrimitiveType::kLineList: + gl_prim_type = GL_LINES; + break; + case PrimitiveType::kLineStrip: + gl_prim_type = GL_LINES; + break; + case PrimitiveType::kLineLoop: + gl_prim_type = GL_LINES; + break; + case PrimitiveType::kPointList: + // The geometry shader associated with this writes out triangles. + gl_prim_type = GL_TRIANGLES; + break; + case PrimitiveType::kTriangleList: + gl_prim_type = GL_TRIANGLES; + break; + case PrimitiveType::kTriangleStrip: + gl_prim_type = GL_TRIANGLES; + break; + case PrimitiveType::kRectangleList: + gl_prim_type = GL_TRIANGLES; + break; + case PrimitiveType::kTriangleFan: + gl_prim_type = GL_TRIANGLES; + break; + case PrimitiveType::kQuadList: + // FIXME: In some cases the geometry shader will output lines. + // See: GL4CommandProcessor::UpdateShaders + gl_prim_type = GL_TRIANGLES; + break; + default: + assert_unhandled_case(prim_type); + break; + } + + // TODO(DrChat): Resize the TFVBO here. + // Could draw a 2nd time with the rasterizer disabled once we have a primitive + // count. + + tfb_prim_type_ = prim_type; + tfb_prim_type_gl_ = gl_prim_type; + + glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, tfbo_); + + // Bind the buffer to the TFB object. + glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, tfvbo_); + + // Begin a query for # prims written + glBeginQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, 0, tfqo_); + + // Begin capturing. + glBeginTransformFeedback(gl_prim_type); +} + +void DrawBatcher::TFBEnd() { + if (!tfb_enabled_) { + return; + } + + glEndTransformFeedback(); + glEndQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, 0); + glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0); + glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0); + + // Cache the query size as query objects aren't shared. + GLint prim_count = 0; + glGetQueryObjectiv(tfqo_, GL_QUERY_RESULT, &prim_count); + tfb_prim_count_ = prim_count; +} + bool DrawBatcher::Flush(FlushMode mode) { GLboolean cull_enabled = 0; if (batch_state_.draw_count) { @@ -263,6 +420,7 @@ bool DrawBatcher::Flush(FlushMode mode) { batch_state_.state_range_length); GLenum prim_type = 0; + bool valid_prim = true; switch (batch_state_.prim_type) { case PrimitiveType::kPointList: prim_type = GL_POINTS; @@ -291,8 +449,6 @@ bool DrawBatcher::Flush(FlushMode mode) { // assert_true( // (register_file_->values[XE_GPU_REG_PA_SU_SC_MODE_CNTL].u32 // & 0x3) == 0); - cull_enabled = glIsEnabled(GL_CULL_FACE); - glDisable(GL_CULL_FACE); break; case PrimitiveType::kQuadList: prim_type = GL_LINES_ADJACENCY; @@ -300,17 +456,21 @@ bool DrawBatcher::Flush(FlushMode mode) { default: case PrimitiveType::kUnknown0x07: prim_type = GL_POINTS; + valid_prim = false; XELOGE("unsupported primitive type %d", batch_state_.prim_type); assert_unhandled_case(batch_state_.prim_type); - DiscardDraw(); - return false; + break; } // Fast path for single draws. void* indirect_offset = reinterpret_cast(batch_state_.command_range_start); - if (batch_state_.draw_count == 1) { + if (tfb_enabled_) { + TFBBegin(batch_state_.prim_type); + } + + if (valid_prim && batch_state_.draw_count == 1) { // Fast path for one draw. Removes MDI overhead when not required. if (batch_state_.indexed) { auto& cmd = active_draw_.draw_elements_cmd; @@ -326,7 +486,7 @@ bool DrawBatcher::Flush(FlushMode mode) { cmd->count, cmd->instance_count, cmd->base_instance); } - } else { + } else if (valid_prim) { // Full multi-draw. if (batch_state_.indexed) { glMultiDrawElementsIndirect(prim_type, batch_state_.index_type, @@ -339,6 +499,10 @@ bool DrawBatcher::Flush(FlushMode mode) { } } + if (tfb_enabled_) { + TFBEnd(); + } + batch_state_.command_range_start = UINTPTR_MAX; batch_state_.command_range_length = 0; batch_state_.state_range_start = UINTPTR_MAX; @@ -346,10 +510,6 @@ bool DrawBatcher::Flush(FlushMode mode) { batch_state_.draw_count = 0; } - if (batch_state_.prim_type == PrimitiveType::kRectangleList && cull_enabled) { - glEnable(GL_CULL_FACE); - } - if (mode == FlushMode::kReconfigure) { // Reset - we'll update it as soon as we have all the information. batch_state_.needs_reconfigure = true; diff --git a/src/xenia/gpu/gl4/draw_batcher.h b/src/xenia/gpu/gl4/draw_batcher.h index 902b049e4..fdecfb9da 100644 --- a/src/xenia/gpu/gl4/draw_batcher.h +++ b/src/xenia/gpu/gl4/draw_batcher.h @@ -99,7 +99,21 @@ class DrawBatcher { bool CommitDraw(); bool Flush(FlushMode mode); + // TFB - Filled with vertex shader output from the last flush. + size_t QueryTFBSize(); + bool ReadbackTFB(void* buffer, size_t size); + + GLuint tfvbo() { return tfvbo_; } + bool is_tfb_enabled() const { return tfb_enabled_; } + void set_tfb_enabled(bool enabled) { tfb_enabled_ = enabled; } + private: + bool InitializeTFB(); + void ShutdownTFB(); + + void TFBBegin(PrimitiveType prim_type); + void TFBEnd(); + bool BeginDraw(); void CopyConstants(); @@ -108,6 +122,14 @@ class DrawBatcher { CircularBuffer state_buffer_; CircularBuffer* array_data_buffer_; + GLuint tfbo_ = 0; + GLuint tfvbo_ = 0; + GLuint tfqo_ = 0; + PrimitiveType tfb_prim_type_ = PrimitiveType::kNone; + GLenum tfb_prim_type_gl_ = 0; + GLint tfb_prim_count_ = 0; + bool tfb_enabled_ = false; + struct BatchState { bool needs_reconfigure; PrimitiveType prim_type; From a34e82c77f8955839f1b7bad2f408b50c3bef949 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Mon, 18 Jan 2016 21:00:58 -0600 Subject: [PATCH 2/5] Disable GL cull on rectangle lists --- src/xenia/gpu/gl4/gl4_command_processor.cc | 19 +++++++++++++++---- src/xenia/gpu/gl4/gl4_command_processor.h | 6 ++++-- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/xenia/gpu/gl4/gl4_command_processor.cc b/src/xenia/gpu/gl4/gl4_command_processor.cc index de191e371..b494ff77c 100644 --- a/src/xenia/gpu/gl4/gl4_command_processor.cc +++ b/src/xenia/gpu/gl4/gl4_command_processor.cc @@ -578,7 +578,7 @@ bool GL4CommandProcessor::IssueDraw(PrimitiveType prim_type, return true; } - status = UpdateState(); + status = UpdateState(draw_batcher_.prim_type()); CHECK_ISSUE_UPDATE_STATUS(status, mismatch, "Unable to setup render state"); status = PopulateSamplers(); CHECK_ISSUE_UPDATE_STATUS(status, mismatch, @@ -665,6 +665,7 @@ GL4CommandProcessor::UpdateStatus GL4CommandProcessor::UpdateShaders( // Normal vertex shaders only, for now. // TODO(benvanik): transform feedback/memexport. + // https://github.com/freedreno/freedreno/blob/master/includes/a2xx.xml.h // 0 = normal // 2 = point size assert_true(program_cntl.vs_export_mode == 0 || @@ -871,7 +872,8 @@ GL4CommandProcessor::UpdateStatus GL4CommandProcessor::UpdateRenderTargets() { return UpdateStatus::kMismatch; } -GL4CommandProcessor::UpdateStatus GL4CommandProcessor::UpdateState() { +GL4CommandProcessor::UpdateStatus GL4CommandProcessor::UpdateState( + PrimitiveType prim_type) { bool mismatch = false; #define CHECK_UPDATE_STATUS(status, mismatch, error_message) \ @@ -887,7 +889,7 @@ GL4CommandProcessor::UpdateStatus GL4CommandProcessor::UpdateState() { UpdateStatus status; status = UpdateViewportState(); CHECK_UPDATE_STATUS(status, mismatch, "Unable to update viewport state"); - status = UpdateRasterizerState(); + status = UpdateRasterizerState(prim_type); CHECK_UPDATE_STATUS(status, mismatch, "Unable to update rasterizer state"); status = UpdateBlendState(); CHECK_UPDATE_STATUS(status, mismatch, "Unable to update blend state"); @@ -1055,7 +1057,8 @@ GL4CommandProcessor::UpdateStatus GL4CommandProcessor::UpdateViewportState() { return UpdateStatus::kMismatch; } -GL4CommandProcessor::UpdateStatus GL4CommandProcessor::UpdateRasterizerState() { +GL4CommandProcessor::UpdateStatus GL4CommandProcessor::UpdateRasterizerState( + PrimitiveType prim_type) { auto& regs = update_rasterizer_state_regs_; bool dirty = false; @@ -1067,10 +1070,13 @@ GL4CommandProcessor::UpdateStatus GL4CommandProcessor::UpdateRasterizerState() { XE_GPU_REG_PA_SC_SCREEN_SCISSOR_BR); dirty |= SetShadowRegister(®s.multi_prim_ib_reset_index, XE_GPU_REG_VGT_MULTI_PRIM_IB_RESET_INDX); + dirty |= regs.prim_type != prim_type; if (!dirty) { return UpdateStatus::kCompatible; } + regs.prim_type = prim_type; + SCOPE_profile_cpu_f("gpu"); draw_batcher_.Flush(DrawBatcher::FlushMode::kStateChange); @@ -1113,6 +1119,11 @@ GL4CommandProcessor::UpdateStatus GL4CommandProcessor::UpdateRasterizerState() { glFrontFace(GL_CCW); } + if (prim_type == PrimitiveType::kRectangleList) { + // Rectangle lists aren't culled. There may be other things they skip too. + glDisable(GL_CULL_FACE); + } + static const GLenum kFillModes[3] = { GL_POINT, GL_LINE, GL_FILL, }; diff --git a/src/xenia/gpu/gl4/gl4_command_processor.h b/src/xenia/gpu/gl4/gl4_command_processor.h index c92a1dc66..1d3d3e6c9 100644 --- a/src/xenia/gpu/gl4/gl4_command_processor.h +++ b/src/xenia/gpu/gl4/gl4_command_processor.h @@ -49,6 +49,7 @@ class GL4CommandProcessor : public CommandProcessor { // HACK: for debugging; would be good to have this in a base type. TextureCache* texture_cache() { return &texture_cache_; } + DrawBatcher* draw_batcher() { return &draw_batcher_; } GLuint GetColorRenderTarget(uint32_t pitch, MsaaSamples samples, uint32_t base, ColorRenderTargetFormat format); @@ -115,9 +116,9 @@ class GL4CommandProcessor : public CommandProcessor { IndexBufferInfo* index_buffer_info) override; UpdateStatus UpdateShaders(PrimitiveType prim_type); UpdateStatus UpdateRenderTargets(); - UpdateStatus UpdateState(); + UpdateStatus UpdateState(PrimitiveType prim_type); UpdateStatus UpdateViewportState(); - UpdateStatus UpdateRasterizerState(); + UpdateStatus UpdateRasterizerState(PrimitiveType prim_type); UpdateStatus UpdateBlendState(); UpdateStatus UpdateDepthStencilState(); UpdateStatus PopulateIndexBuffer(IndexBufferInfo* index_buffer_info); @@ -191,6 +192,7 @@ class GL4CommandProcessor : public CommandProcessor { uint32_t pa_sc_screen_scissor_tl; uint32_t pa_sc_screen_scissor_br; uint32_t multi_prim_ib_reset_index; + PrimitiveType prim_type; UpdateRasterizerStateRegisters() { Reset(); } void Reset() { std::memset(this, 0, sizeof(*this)); } From 47f58960899ae6f40099c6daf81f39aaafe2af32 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Mon, 18 Jan 2016 22:22:15 -0600 Subject: [PATCH 3/5] Add TFB support to the trace viewer --- src/xenia/gpu/gl4/gl4_trace_viewer_main.cc | 37 ++++++++++++++ src/xenia/gpu/trace_viewer.cc | 59 ++++++++++++++++++++-- src/xenia/gpu/trace_viewer.h | 7 ++- 3 files changed, 98 insertions(+), 5 deletions(-) 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(); From 9ed093412337861bed6ee3c4edd80c34d0d3e3a3 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Tue, 19 Jan 2016 18:31:36 -0600 Subject: [PATCH 4/5] Swap to modern OpenGL for TFB usage. --- src/xenia/gpu/gl4/draw_batcher.cc | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/xenia/gpu/gl4/draw_batcher.cc b/src/xenia/gpu/gl4/draw_batcher.cc index 7faa663a5..478f937b8 100644 --- a/src/xenia/gpu/gl4/draw_batcher.cc +++ b/src/xenia/gpu/gl4/draw_batcher.cc @@ -59,25 +59,23 @@ bool DrawBatcher::Initialize(CircularBuffer* array_data_buffer) { // Initializes a transform feedback object // We use this to capture vertex data straight from the vertex/geometry shader. bool DrawBatcher::InitializeTFB() { - glGenBuffers(1, &tfvbo_); + glCreateBuffers(1, &tfvbo_); if (!tfvbo_) { return false; } - glGenTransformFeedbacks(1, &tfbo_); + glCreateTransformFeedbacks(1, &tfbo_); if (!tfbo_) { return false; } - glGenQueries(1, &tfqo_); + glCreateQueries(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, 1, &tfqo_); if (!tfqo_) { return false; } // TODO(DrChat): Calculate this based on the number of primitives drawn. - glBindBuffer(GL_ARRAY_BUFFER, tfvbo_); - glBufferData(GL_ARRAY_BUFFER, 16384 * 4, nullptr, GL_STATIC_READ); - glBindBuffer(GL_ARRAY_BUFFER, 0); + glNamedBufferData(tfvbo_, 16384 * 4, nullptr, GL_STATIC_READ); return true; } @@ -119,13 +117,9 @@ bool DrawBatcher::ReadbackTFB(void* buffer, size_t size) { return false; } - glBindBuffer(GL_ARRAY_BUFFER, tfvbo_); - void* data = glMapBufferRange(GL_ARRAY_BUFFER, 0, size, GL_MAP_READ_BIT); - + void* data = glMapNamedBufferRange(tfvbo_, 0, size, GL_MAP_READ_BIT); std::memcpy(buffer, data, size); - - glUnmapBuffer(GL_ARRAY_BUFFER); - glBindBuffer(GL_ARRAY_BUFFER, 0); + glUnmapNamedBuffer(tfvbo_); return true; } From 8710b105bf66aea0e483a0b62c7c0e16738b5300 Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Tue, 19 Jan 2016 18:50:50 -0600 Subject: [PATCH 5/5] Draw smaller floating point formats in the trace viewer. --- src/xenia/gpu/trace_viewer.cc | 76 ++++++++++++++++++++++++----------- 1 file changed, 52 insertions(+), 24 deletions(-) diff --git a/src/xenia/gpu/trace_viewer.cc b/src/xenia/gpu/trace_viewer.cc index 276acabcd..f04b42905 100644 --- a/src/xenia/gpu/trace_viewer.cc +++ b/src/xenia/gpu/trace_viewer.cc @@ -13,6 +13,7 @@ #include +#include "third_party/half/include/half.hpp" #include "third_party/imgui/imgui.h" #include "xenia/base/clock.h" #include "xenia/base/logging.h" @@ -789,16 +790,25 @@ void TraceViewer::DrawVertexFetcher(Shader* shader, ImGui::NextColumn(); break; case VertexFormat::k_32_FLOAT: - ImGui::Text("%.2f", LOADEL(float, 0)); + ImGui::Text("%.3f", LOADEL(float, 0)); ImGui::NextColumn(); break; - case VertexFormat::k_16_16: - case VertexFormat::k_16_16_FLOAT: - ImGui::Text("??"); + case VertexFormat::k_16_16: { + auto e0 = LOADEL(uint32_t, 0); + ImGui::Text("%.4X", (e0 >> 16) & 0xFFFF); ImGui::NextColumn(); - ImGui::Text("??"); + ImGui::Text("%.4X", (e0 >> 0) & 0xFFFF); ImGui::NextColumn(); - break; + } break; + case VertexFormat::k_16_16_FLOAT: { + auto e0 = LOADEL(uint32_t, 0); + ImGui::Text("%.2f", + half_float::detail::half2float((e0 >> 16) & 0xFFFF)); + ImGui::NextColumn(); + ImGui::Text("%.2f", + half_float::detail::half2float((e0 >> 0) & 0xFFFF)); + ImGui::NextColumn(); + } break; case VertexFormat::k_32_32: ImGui::Text("%.8X", LOADEL(uint32_t, 0)); ImGui::NextColumn(); @@ -806,9 +816,9 @@ void TraceViewer::DrawVertexFetcher(Shader* shader, ImGui::NextColumn(); break; case VertexFormat::k_32_32_FLOAT: - ImGui::Text("%.2f", LOADEL(float, 0)); + ImGui::Text("%.3f", LOADEL(float, 0)); ImGui::NextColumn(); - ImGui::Text("%.2f", LOADEL(float, 1)); + ImGui::Text("%.3f", LOADEL(float, 1)); ImGui::NextColumn(); break; case VertexFormat::k_10_11_11: @@ -821,19 +831,19 @@ void TraceViewer::DrawVertexFetcher(Shader* shader, ImGui::NextColumn(); break; case VertexFormat::k_32_32_32_FLOAT: - ImGui::Text("%.2f", LOADEL(float, 0)); + ImGui::Text("%.3f", LOADEL(float, 0)); ImGui::NextColumn(); - ImGui::Text("%.2f", LOADEL(float, 1)); + ImGui::Text("%.3f", LOADEL(float, 1)); ImGui::NextColumn(); - ImGui::Text("%.2f", LOADEL(float, 2)); + ImGui::Text("%.3f", LOADEL(float, 2)); ImGui::NextColumn(); break; case VertexFormat::k_8_8_8_8: ImGui::Text("%.8X", LOADEL(uint32_t, 0)); ImGui::NextColumn(); break; - case VertexFormat::k_2_10_10_10: - case VertexFormat::k_16_16_16_16: + case VertexFormat::k_2_10_10_10: { + auto e0 = LOADEL(uint32_t, 0); ImGui::Text("??"); ImGui::NextColumn(); ImGui::Text("??"); @@ -842,7 +852,19 @@ void TraceViewer::DrawVertexFetcher(Shader* shader, ImGui::NextColumn(); ImGui::Text("??"); ImGui::NextColumn(); - break; + } break; + case VertexFormat::k_16_16_16_16: { + auto e0 = LOADEL(uint32_t, 0); + auto e1 = LOADEL(uint32_t, 1); + ImGui::Text("%.4X", (e0 >> 16) & 0xFFFF); + ImGui::NextColumn(); + ImGui::Text("%.4X", (e0 >> 0) & 0xFFFF); + ImGui::NextColumn(); + ImGui::Text("%.4X", (e1 >> 16) & 0xFFFF); + ImGui::NextColumn(); + ImGui::Text("%.4X", (e1 >> 0) & 0xFFFF); + ImGui::NextColumn(); + } break; case VertexFormat::k_32_32_32_32: ImGui::Text("%.8X", LOADEL(uint32_t, 0)); ImGui::NextColumn(); @@ -853,24 +875,30 @@ void TraceViewer::DrawVertexFetcher(Shader* shader, ImGui::Text("%.8X", LOADEL(uint32_t, 3)); ImGui::NextColumn(); break; - case VertexFormat::k_16_16_16_16_FLOAT: - ImGui::Text("??"); + case VertexFormat::k_16_16_16_16_FLOAT: { + auto e0 = LOADEL(uint32_t, 0); + auto e1 = LOADEL(uint32_t, 1); + ImGui::Text("%.2f", + half_float::detail::half2float((e0 >> 16) & 0xFFFF)); ImGui::NextColumn(); - ImGui::Text("??"); + ImGui::Text("%.2f", + half_float::detail::half2float((e0 >> 0) & 0xFFFF)); ImGui::NextColumn(); - ImGui::Text("??"); + ImGui::Text("%.2f", + half_float::detail::half2float((e1 >> 16) & 0xFFFF)); ImGui::NextColumn(); - ImGui::Text("??"); + ImGui::Text("%.2f", + half_float::detail::half2float((e1 >> 0) & 0xFFFF)); ImGui::NextColumn(); - break; + } break; case VertexFormat::k_32_32_32_32_FLOAT: - ImGui::Text("%.2f", LOADEL(float, 0)); + ImGui::Text("%.3f", LOADEL(float, 0)); ImGui::NextColumn(); - ImGui::Text("%.2f", LOADEL(float, 1)); + ImGui::Text("%.3f", LOADEL(float, 1)); ImGui::NextColumn(); - ImGui::Text("%.2f", LOADEL(float, 2)); + ImGui::Text("%.3f", LOADEL(float, 2)); ImGui::NextColumn(); - ImGui::Text("%.2f", LOADEL(float, 3)); + ImGui::Text("%.3f", LOADEL(float, 3)); ImGui::NextColumn(); break; case VertexFormat::kUndefined: