aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRibbit <ribbit@eden-emu.dev>2025-10-26 01:38:08 +0200
committercrueter <crueter@eden-emu.dev>2025-10-26 01:38:08 +0200
commit6ba25b6cc0d738da8f9b9625f24d0af555e46380 (patch)
tree8f3223211d2a9020ef941c378f6da9f0c565af84
parent8d565d779393f917d42135396b77cf28526f3856 (diff)
[vk] Correct polygon draw topology mapping for line and point modes (#2834)
Co-authored-by: Ribbit <ribbit@placeholder.com> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2834 Reviewed-by: MaranBr <maranbr@eden-emu.dev> Reviewed-by: crueter <crueter@eden-emu.dev> Co-authored-by: Ribbit <ribbit@eden-emu.dev> Co-committed-by: Ribbit <ribbit@eden-emu.dev>
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h76
-rw-r--r--src/video_core/polygon_mode_utils.h46
-rw-r--r--src/video_core/renderer_vulkan/fixed_pipeline_state.cpp3
-rw-r--r--src/video_core/renderer_vulkan/line_loop_utils.h68
-rw-r--r--src/video_core/renderer_vulkan/maxwell_to_vk.cpp44
-rw-r--r--src/video_core/renderer_vulkan/maxwell_to_vk.h52
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp34
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp22
8 files changed, 296 insertions, 49 deletions
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index 39c56fb33f..ddd940c6d2 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -7,6 +7,7 @@
#pragma once
#include <algorithm>
+#include <cstring>
#include <memory>
#include <numeric>
@@ -15,6 +16,8 @@
#include "video_core/guest_memory.h"
#include "video_core/host1x/gpu_device_memory_manager.h"
#include "video_core/texture_cache/util.h"
+#include "video_core/polygon_mode_utils.h"
+#include "video_core/renderer_vulkan/line_loop_utils.h"
namespace VideoCommon {
@@ -353,14 +356,37 @@ void BufferCache<P>::UpdateComputeBuffers() {
template <class P>
void BufferCache<P>::BindHostGeometryBuffers(bool is_indexed) {
+ const auto& draw_state = maxwell3d->draw_manager->GetDrawState();
if (is_indexed) {
BindHostIndexBuffer();
- } else if constexpr (!HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) {
- const auto& draw_state = maxwell3d->draw_manager->GetDrawState();
- if (draw_state.topology == Maxwell::PrimitiveTopology::Quads ||
- draw_state.topology == Maxwell::PrimitiveTopology::QuadStrip) {
- runtime.BindQuadIndexBuffer(draw_state.topology, draw_state.vertex_buffer.first,
- draw_state.vertex_buffer.count);
+ } else {
+ if constexpr (!P::IS_OPENGL) {
+ const auto polygon_mode = VideoCore::EffectivePolygonMode(maxwell3d->regs);
+ if (draw_state.topology == Maxwell::PrimitiveTopology::Polygon &&
+ polygon_mode == Maxwell::PolygonMode::Line && draw_state.vertex_buffer.count > 1) {
+ const u32 vertex_count = draw_state.vertex_buffer.count;
+ const u32 generated_count = vertex_count + 1;
+ const bool use_u16 = vertex_count <= 0x10000;
+ const u32 element_size = use_u16 ? sizeof(u16) : sizeof(u32);
+ auto staging = runtime.UploadStagingBuffer(
+ static_cast<size_t>(generated_count) * element_size);
+ std::span<u8> dst_span{staging.mapped_span.data(),
+ generated_count * static_cast<size_t>(element_size)};
+ Vulkan::LineLoop::GenerateSequentialWithClosureRaw(dst_span, element_size);
+ const auto synthetic_format = use_u16 ? Maxwell::IndexFormat::UnsignedShort
+ : Maxwell::IndexFormat::UnsignedInt;
+ runtime.BindIndexBuffer(draw_state.topology, synthetic_format,
+ draw_state.vertex_buffer.first, generated_count,
+ staging.buffer, static_cast<u32>(staging.offset),
+ generated_count * element_size);
+ }
+ }
+ if constexpr (!HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) {
+ if (draw_state.topology == Maxwell::PrimitiveTopology::Quads ||
+ draw_state.topology == Maxwell::PrimitiveTopology::QuadStrip) {
+ runtime.BindQuadIndexBuffer(draw_state.topology, draw_state.vertex_buffer.first,
+ draw_state.vertex_buffer.count);
+ }
}
}
BindHostVertexBuffers();
@@ -689,6 +715,44 @@ void BufferCache<P>::BindHostIndexBuffer() {
const u32 offset = buffer.Offset(channel_state->index_buffer.device_addr);
const u32 size = channel_state->index_buffer.size;
const auto& draw_state = maxwell3d->draw_manager->GetDrawState();
+ if constexpr (!P::IS_OPENGL) {
+ const auto polygon_mode = VideoCore::EffectivePolygonMode(maxwell3d->regs);
+ const bool polygon_line =
+ draw_state.topology == Maxwell::PrimitiveTopology::Polygon &&
+ polygon_mode == Maxwell::PolygonMode::Line;
+ if (polygon_line && draw_state.index_buffer.count > 1) {
+ const u32 element_size = draw_state.index_buffer.FormatSizeInBytes();
+ const size_t src_bytes = static_cast<size_t>(draw_state.index_buffer.count) * element_size;
+ const size_t total_bytes = src_bytes + element_size;
+ auto staging = runtime.UploadStagingBuffer(total_bytes);
+ std::span<u8> dst_span{staging.mapped_span.data(), total_bytes};
+ std::span<const u8> src_span;
+ if (!draw_state.inline_index_draw_indexes.empty()) {
+ const u8* const src =
+ draw_state.inline_index_draw_indexes.data() +
+ static_cast<size_t>(draw_state.index_buffer.first) * element_size;
+ src_span = {src, src_bytes};
+ } else if (const u8* const cpu_base =
+ device_memory.GetPointer<u8>(channel_state->index_buffer.device_addr)) {
+ const u8* const src = cpu_base +
+ static_cast<size_t>(draw_state.index_buffer.first) * element_size;
+ src_span = {src, src_bytes};
+ } else {
+ const DAddr src_addr =
+ channel_state->index_buffer.device_addr +
+ static_cast<DAddr>(draw_state.index_buffer.first) * element_size;
+ device_memory.ReadBlockUnsafe(src_addr, dst_span.data(), src_bytes);
+ src_span = {dst_span.data(), src_bytes};
+ }
+ Vulkan::LineLoop::CopyWithClosureRaw(dst_span, src_span, element_size);
+ buffer.MarkUsage(offset, size);
+ runtime.BindIndexBuffer(draw_state.topology, draw_state.index_buffer.format,
+ draw_state.index_buffer.first, draw_state.index_buffer.count + 1,
+ staging.buffer, static_cast<u32>(staging.offset),
+ static_cast<u32>(total_bytes));
+ return;
+ }
+ }
if (!draw_state.inline_index_draw_indexes.empty()) [[unlikely]] {
if constexpr (USE_MEMORY_MAPS_FOR_UPLOADS) {
auto upload_staging = runtime.UploadStagingBuffer(size);
diff --git a/src/video_core/polygon_mode_utils.h b/src/video_core/polygon_mode_utils.h
new file mode 100644
index 0000000000..c44570693e
--- /dev/null
+++ b/src/video_core/polygon_mode_utils.h
@@ -0,0 +1,46 @@
+// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include "video_core/engines/maxwell_3d.h"
+
+namespace VideoCore {
+
+inline Tegra::Engines::Maxwell3D::Regs::PolygonMode EffectivePolygonMode(
+ const Tegra::Engines::Maxwell3D::Regs& regs) {
+ using Maxwell = Tegra::Engines::Maxwell3D::Regs;
+
+ const bool cull_enabled = regs.gl_cull_test_enabled != 0;
+ const auto cull_face = regs.gl_cull_face;
+ const bool cull_front = cull_enabled && (cull_face == Maxwell::CullFace::Front ||
+ cull_face == Maxwell::CullFace::FrontAndBack);
+ const bool cull_back = cull_enabled && (cull_face == Maxwell::CullFace::Back ||
+ cull_face == Maxwell::CullFace::FrontAndBack);
+
+ const bool render_front = !cull_front;
+ const bool render_back = !cull_back;
+
+ const auto front_mode = regs.polygon_mode_front;
+ const auto back_mode = regs.polygon_mode_back;
+
+ if (render_front && render_back && front_mode != back_mode) {
+ if (front_mode == Maxwell::PolygonMode::Line || back_mode == Maxwell::PolygonMode::Line) {
+ return Maxwell::PolygonMode::Line;
+ }
+ if (front_mode == Maxwell::PolygonMode::Point || back_mode == Maxwell::PolygonMode::Point) {
+ return Maxwell::PolygonMode::Point;
+ }
+ }
+
+ if (render_front) {
+ return front_mode;
+ }
+ if (render_back) {
+ return back_mode;
+ }
+ return front_mode;
+}
+
+} // namespace VideoCore
+
diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
index ff2dd90aff..453a3d942b 100644
--- a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
+++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
@@ -14,6 +14,7 @@
#include "video_core/engines/draw_manager.h"
#include "video_core/renderer_vulkan/fixed_pipeline_state.h"
#include "video_core/renderer_vulkan/vk_state_tracker.h"
+#include "video_core/polygon_mode_utils.h"
namespace Vulkan {
namespace {
@@ -64,7 +65,7 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, DynamicFe
dynamic_vertex_input.Assign(features.has_dynamic_vertex_input ? 1 : 0);
xfb_enabled.Assign(regs.transform_feedback_enabled != 0);
ndc_minus_one_to_one.Assign(regs.depth_mode == Maxwell::DepthMode::MinusOneToOne ? 1 : 0);
- polygon_mode.Assign(PackPolygonMode(regs.polygon_mode_front));
+ polygon_mode.Assign(PackPolygonMode(VideoCore::EffectivePolygonMode(regs)));
tessellation_primitive.Assign(static_cast<u32>(regs.tessellation.params.domain_type.Value()));
tessellation_spacing.Assign(static_cast<u32>(regs.tessellation.params.spacing.Value()));
tessellation_clockwise.Assign(regs.tessellation.params.output_primitives.Value() ==
diff --git a/src/video_core/renderer_vulkan/line_loop_utils.h b/src/video_core/renderer_vulkan/line_loop_utils.h
new file mode 100644
index 0000000000..71f4229d11
--- /dev/null
+++ b/src/video_core/renderer_vulkan/line_loop_utils.h
@@ -0,0 +1,68 @@
+// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include <algorithm>
+#include <cstring>
+#include <span>
+
+#include "common/assert.h"
+#include "common/common_types.h"
+
+namespace Vulkan::LineLoop {
+
+inline void CopyWithClosureRaw(std::span<u8> dst, std::span<const u8> src, size_t element_size) {
+ ASSERT_MSG(dst.size() == src.size() + element_size, "Invalid line loop copy sizes");
+ if (src.empty()) {
+ if (!dst.empty()) {
+ std::fill(dst.begin(), dst.end(), u8{0});
+ }
+ return;
+ }
+ std::memcpy(dst.data(), src.data(), src.size());
+ std::memcpy(dst.data() + src.size(), src.data(), element_size);
+}
+
+inline void GenerateSequentialWithClosureRaw(std::span<u8> dst, size_t element_size,
+ u64 start_value = 0) {
+ if (dst.empty()) {
+ return;
+ }
+ const size_t last = dst.size() - element_size;
+ size_t offset = 0;
+ u64 value = start_value;
+ while (offset < last) {
+ std::memcpy(dst.data() + offset, &value, element_size);
+ offset += element_size;
+ ++value;
+ }
+ std::memcpy(dst.data() + offset, &start_value, element_size);
+}
+
+template <typename T>
+inline void CopyWithClosure(std::span<T> dst, std::span<const T> src) {
+ ASSERT_MSG(dst.size() == src.size() + 1, "Invalid destination size for line loop copy");
+ if (src.empty()) {
+ if (!dst.empty()) {
+ dst.front() = {};
+ }
+ return;
+ }
+ std::copy(src.begin(), src.end(), dst.begin());
+ dst.back() = src.front();
+}
+
+template <typename T>
+inline void GenerateSequentialWithClosure(std::span<T> dst, T start_value = {}) {
+ if (dst.empty()) {
+ return;
+ }
+ const size_t last = dst.size() - 1;
+ for (size_t i = 0; i < last; ++i) {
+ dst[i] = static_cast<T>(start_value + static_cast<T>(i));
+ }
+ dst.back() = start_value;
+}
+
+} // namespace Vulkan::LineLoop
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
index a08f2f67f9..a7a878f18c 100644
--- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
+++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -326,44 +329,9 @@ VkShaderStageFlagBits ShaderStage(Shader::Stage stage) {
}
VkPrimitiveTopology PrimitiveTopology([[maybe_unused]] const Device& device,
- Maxwell::PrimitiveTopology topology) {
- switch (topology) {
- case Maxwell::PrimitiveTopology::Points:
- return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
- case Maxwell::PrimitiveTopology::Lines:
- return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
- case Maxwell::PrimitiveTopology::LineLoop:
- return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
- case Maxwell::PrimitiveTopology::LineStrip:
- return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
- case Maxwell::PrimitiveTopology::Triangles:
- return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
- case Maxwell::PrimitiveTopology::TriangleStrip:
- return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
- case Maxwell::PrimitiveTopology::TriangleFan:
- return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN;
- case Maxwell::PrimitiveTopology::LinesAdjacency:
- return VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY;
- case Maxwell::PrimitiveTopology::LineStripAdjacency:
- return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY;
- case Maxwell::PrimitiveTopology::TrianglesAdjacency:
- return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY;
- case Maxwell::PrimitiveTopology::TriangleStripAdjacency:
- return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY;
- case Maxwell::PrimitiveTopology::Quads:
- case Maxwell::PrimitiveTopology::QuadStrip:
- // TODO: Use VK_PRIMITIVE_TOPOLOGY_QUAD_LIST_EXT/VK_PRIMITIVE_TOPOLOGY_QUAD_STRIP_EXT
- // whenever it releases
- return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
- case Maxwell::PrimitiveTopology::Patches:
- return VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
- case Maxwell::PrimitiveTopology::Polygon:
- LOG_WARNING(Render_Vulkan, "Draw mode is Polygon with a polygon mode of lines should be a "
- "single body and not a bunch of triangles.");
- return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN;
- }
- UNIMPLEMENTED_MSG("Unimplemented topology={}", topology);
- return {};
+ Maxwell::PrimitiveTopology topology,
+ Maxwell::PolygonMode polygon_mode) {
+ return detail::PrimitiveTopologyNoDevice(topology, polygon_mode);
}
VkFormat VertexFormat(const Device& device, Maxwell::VertexAttribute::Type type,
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.h b/src/video_core/renderer_vulkan/maxwell_to_vk.h
index 6f65502d61..22108a3769 100644
--- a/src/video_core/renderer_vulkan/maxwell_to_vk.h
+++ b/src/video_core/renderer_vulkan/maxwell_to_vk.h
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -15,6 +18,52 @@ namespace Vulkan::MaxwellToVK {
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
using PixelFormat = VideoCore::Surface::PixelFormat;
+namespace detail {
+constexpr VkPrimitiveTopology PrimitiveTopologyNoDevice(Maxwell::PrimitiveTopology topology,
+ Maxwell::PolygonMode polygon_mode) {
+ switch (topology) {
+ case Maxwell::PrimitiveTopology::Points:
+ return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
+ case Maxwell::PrimitiveTopology::Lines:
+ return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
+ case Maxwell::PrimitiveTopology::LineLoop:
+ return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
+ case Maxwell::PrimitiveTopology::LineStrip:
+ return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
+ case Maxwell::PrimitiveTopology::Triangles:
+ return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+ case Maxwell::PrimitiveTopology::TriangleStrip:
+ return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
+ case Maxwell::PrimitiveTopology::TriangleFan:
+ return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN;
+ case Maxwell::PrimitiveTopology::LinesAdjacency:
+ return VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY;
+ case Maxwell::PrimitiveTopology::LineStripAdjacency:
+ return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY;
+ case Maxwell::PrimitiveTopology::TrianglesAdjacency:
+ return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY;
+ case Maxwell::PrimitiveTopology::TriangleStripAdjacency:
+ return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY;
+ case Maxwell::PrimitiveTopology::Quads:
+ case Maxwell::PrimitiveTopology::QuadStrip:
+ return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+ case Maxwell::PrimitiveTopology::Patches:
+ return VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
+ case Maxwell::PrimitiveTopology::Polygon:
+ switch (polygon_mode) {
+ case Maxwell::PolygonMode::Fill:
+ return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN;
+ case Maxwell::PolygonMode::Line:
+ return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
+ case Maxwell::PolygonMode::Point:
+ return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
+ }
+ break;
+ }
+ return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+}
+} // namespace detail
+
namespace Sampler {
VkFilter Filter(Tegra::Texture::TextureFilter filter);
@@ -46,7 +95,8 @@ struct FormatInfo {
VkShaderStageFlagBits ShaderStage(Shader::Stage stage);
-VkPrimitiveTopology PrimitiveTopology(const Device& device, Maxwell::PrimitiveTopology topology);
+VkPrimitiveTopology PrimitiveTopology(const Device& device, Maxwell::PrimitiveTopology topology,
+ Maxwell::PolygonMode polygon_mode);
VkFormat VertexFormat(const Device& device, Maxwell::VertexAttribute::Type type,
Maxwell::VertexAttribute::Size size);
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
index 745389213e..13ed1b585e 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
@@ -7,6 +7,7 @@
#include <algorithm>
#include <iostream>
#include <span>
+#include <string_view>
#include <boost/container/small_vector.hpp>
#include <boost/container/static_vector.hpp>
@@ -22,6 +23,7 @@
#include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_texture_cache.h"
#include "video_core/renderer_vulkan/vk_update_descriptor.h"
+#include "video_core/polygon_mode_utils.h"
#include "video_core/shader_notify.h"
#include "video_core/texture_cache/texture_cache.h"
#include "video_core/vulkan_common/vulkan_device.h"
@@ -614,7 +616,10 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
vertex_input_ci.pNext = &input_divisor_ci;
}
const bool has_tess_stages = spv_modules[1] || spv_modules[2];
- auto input_assembly_topology = MaxwellToVK::PrimitiveTopology(device, key.state.topology);
+ const auto polygon_mode =
+ FixedPipelineState::UnpackPolygonMode(key.state.polygon_mode.Value());
+ auto input_assembly_topology =
+ MaxwellToVK::PrimitiveTopology(device, key.state.topology, polygon_mode);
if (input_assembly_topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) {
if (!has_tess_stages) {
LOG_WARNING(Render_Vulkan, "Patch topology used without tessellation, using points");
@@ -629,6 +634,33 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
input_assembly_topology = VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
}
}
+ if (key.state.topology == Maxwell::PrimitiveTopology::Polygon) {
+ const auto polygon_mode_name = [polygon_mode]() -> std::string_view {
+ switch (polygon_mode) {
+ case Maxwell::PolygonMode::Fill:
+ return "Fill";
+ case Maxwell::PolygonMode::Line:
+ return "Line";
+ case Maxwell::PolygonMode::Point:
+ return "Point";
+ }
+ return "Unknown";
+ }();
+ const auto vk_topology_name = [input_assembly_topology]() -> std::string_view {
+ switch (input_assembly_topology) {
+ case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
+ return "TriangleFan";
+ case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
+ return "LineStrip";
+ case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
+ return "PointList";
+ default:
+ return "Unexpected";
+ }
+ }();
+ LOG_DEBUG(Render_Vulkan, "Polygon primitive in {} mode mapped to {}", polygon_mode_name,
+ vk_topology_name);
+ }
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci{
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
.pNext = nullptr,
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index 70ca9583f9..6bad5eca0b 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -37,6 +37,7 @@
#include "video_core/renderer_vulkan/vk_update_descriptor.h"
#include "video_core/shader_cache.h"
#include "video_core/texture_cache/texture_cache_base.h"
+#include "video_core/polygon_mode_utils.h"
#include "video_core/vulkan_common/vulkan_device.h"
#include "video_core/vulkan_common/vulkan_wrapper.h"
@@ -148,7 +149,8 @@ VkRect2D GetScissorState(const Maxwell& regs, size_t index, u32 up_scale = 1, u3
return scissor;
}
-DrawParams MakeDrawParams(const MaxwellDrawState& draw_state, u32 num_instances, bool is_indexed) {
+DrawParams MakeDrawParams(const MaxwellDrawState& draw_state, u32 num_instances, bool is_indexed,
+ Maxwell::PolygonMode polygon_mode) {
DrawParams params{
.base_instance = draw_state.base_instance,
.num_instances = num_instances,
@@ -168,6 +170,21 @@ DrawParams MakeDrawParams(const MaxwellDrawState& draw_state, u32 num_instances,
params.base_vertex = 0;
params.is_indexed = true;
}
+ const bool polygon_line =
+ draw_state.topology == Maxwell::PrimitiveTopology::Polygon &&
+ polygon_mode == Maxwell::PolygonMode::Line;
+ if (polygon_line) {
+ if (params.is_indexed) {
+ if (draw_state.index_buffer.count > 1) {
+ params.num_vertices = draw_state.index_buffer.count + 1;
+ }
+ } else if (draw_state.vertex_buffer.count > 1) {
+ params.num_vertices = draw_state.vertex_buffer.count + 1;
+ params.is_indexed = true;
+ params.first_index = 0;
+ params.base_vertex = draw_state.vertex_buffer.first;
+ }
+ }
return params;
}
} // Anonymous namespace
@@ -236,7 +253,8 @@ void RasterizerVulkan::Draw(bool is_indexed, u32 instance_count) {
PrepareDraw(is_indexed, [this, is_indexed, instance_count] {
const auto& draw_state = maxwell3d->draw_manager->GetDrawState();
const u32 num_instances{instance_count};
- const DrawParams draw_params{MakeDrawParams(draw_state, num_instances, is_indexed)};
+ const auto polygon_mode = VideoCore::EffectivePolygonMode(maxwell3d->regs);
+ const DrawParams draw_params{MakeDrawParams(draw_state, num_instances, is_indexed, polygon_mode)};
scheduler.Record([draw_params](vk::CommandBuffer cmdbuf) {
if (draw_params.is_indexed) {
cmdbuf.DrawIndexed(draw_params.num_vertices, draw_params.num_instances,