diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 8f8ca783a1..0798b1b10f 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -12,6 +12,7 @@ #include "common/settings.h" #include "core/core.h" #include "core/core_timing.h" +#include "shader_recompiler/program_header.h" #include "video_core/dirty_flags.h" #include "video_core/engines/draw_manager.h" #include "video_core/engines/maxwell_3d.h" @@ -22,6 +23,37 @@ namespace Tegra::Engines { +namespace { + +[[nodiscard]] Maxwell3D::Regs::PrimitiveTopology PrimitiveTopologyFromGeometryOutput( + Shader::OutputTopology topology) { + switch (topology) { + case Shader::OutputTopology::PointList: + return Maxwell3D::Regs::PrimitiveTopology::Points; + case Shader::OutputTopology::LineStrip: + return Maxwell3D::Regs::PrimitiveTopology::LineStrip; + case Shader::OutputTopology::TriangleStrip: + return Maxwell3D::Regs::PrimitiveTopology::TriangleStrip; + } + return Maxwell3D::Regs::PrimitiveTopology::Triangles; +} + +[[nodiscard]] Maxwell3D::Regs::PrimitiveTopology PrimitiveTopologyFromTessellationOutput( + Maxwell3D::Regs::Tessellation::OutputPrimitives topology) { + switch (topology) { + case Maxwell3D::Regs::Tessellation::OutputPrimitives::Points: + return Maxwell3D::Regs::PrimitiveTopology::Points; + case Maxwell3D::Regs::Tessellation::OutputPrimitives::Lines: + return Maxwell3D::Regs::PrimitiveTopology::Lines; + case Maxwell3D::Regs::Tessellation::OutputPrimitives::Triangles_CW: + case Maxwell3D::Regs::Tessellation::OutputPrimitives::Triangles_CCW: + return Maxwell3D::Regs::PrimitiveTopology::Triangles; + } + return Maxwell3D::Regs::PrimitiveTopology::Triangles; +} + +} // namespace + /// First register id that is actually a Macro call. constexpr u32 MacroRegistersStart = 0xE00; @@ -666,6 +698,22 @@ Texture::TSCEntry Maxwell3D::GetTSCEntry(u32 tsc_index) const { return tsc_entry; } +Maxwell3D::Regs::PrimitiveTopology Maxwell3D::GetTransformFeedbackOutputTopology() const { + if (regs.IsShaderConfigEnabled(Regs::ShaderType::Geometry)) { + const GPUVAddr shader_addr = regs.program_region.Address() + + regs.pipelines[static_cast(Regs::ShaderType::Geometry)] + .offset; + Shader::ProgramHeader sph{}; + memory_manager.ReadBlockUnsafe(shader_addr, &sph, sizeof(sph)); + return PrimitiveTopologyFromGeometryOutput(sph.common3.output_topology.Value()); + } + if (regs.IsShaderConfigEnabled(Regs::ShaderType::Tessellation)) { + return PrimitiveTopologyFromTessellationOutput( + regs.tessellation.params.output_primitives.Value()); + } + return draw_manager->GetDrawState().topology; +} + u32 Maxwell3D::GetRegisterValue(u32 method) const { ASSERT(method < Regs::NUM_REGS && "Invalid Maxwell3D register"); return regs.reg_array[method]; diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index b73082b7ef..076a498d6b 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -3153,6 +3153,8 @@ private: /// Retrieves information about a specific TSC entry from the TSC buffer. Texture::TSCEntry GetTSCEntry(u32 tsc_index) const; + [[nodiscard]] Regs::PrimitiveTopology GetTransformFeedbackOutputTopology() const; + /** * Call a macro on this engine. * diff --git a/src/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp index 29b8d3ce67..a5eebb77ef 100644 --- a/src/video_core/renderer_vulkan/vk_query_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp @@ -957,7 +957,7 @@ private: streams_mask = 0; // reset previously recorded streams runtime.View3DRegs([this](Maxwell3D& maxwell3d) { buffers_count = 0; - out_topology = maxwell3d.draw_manager->GetDrawState().topology; + out_topology = maxwell3d.GetTransformFeedbackOutputTopology(); for (size_t i = 0; i < Maxwell3D::Regs::NumTransformFeedbackBuffers; i++) { const auto& tf = maxwell3d.regs.transform_feedback; if (tf.buffers[i].enable == 0) { @@ -968,7 +968,9 @@ private: LOG_WARNING(Render_Vulkan, "TransformFeedback stream {} out of range", stream); continue; } - last_queries_stride[stream] += tf.controls[i].stride; + if (last_queries_stride[stream] == 0) { + last_queries_stride[stream] = tf.controls[i].stride; + } streams_mask |= 1ULL << stream; buffers_count = std::max(buffers_count, stream + 1); } @@ -1177,7 +1179,8 @@ public: if (tf.controls[i].stream != subreport) { continue; } - new_query->stride += tf.controls[i].stride; + new_query->stride = tf.controls[i].stride; + break; } }); }