diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index f5502c7d39..b5ce1850d0 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -61,6 +61,26 @@ struct DrawParams { bool is_indexed; }; +VkViewport ClampViewport(const Device& device, VkViewport viewport) { + const auto max_dims = device.GetMaxViewportDimensions(); + const auto bounds = device.GetViewportBoundsRange(); + const auto clamp_abs = [](float value, float max_abs) { + const float clamped = std::min(std::abs(value), max_abs); + return std::copysign(clamped, value); + }; + + viewport.width = viewport.width == 0.0f ? 1.0f : viewport.width; + viewport.height = viewport.height == 0.0f ? 1.0f : viewport.height; + + viewport.width = clamp_abs(viewport.width, static_cast(max_dims[0])); + viewport.height = clamp_abs(viewport.height, static_cast(max_dims[1])); + + viewport.x = std::clamp(viewport.x, bounds[0], bounds[1]); + viewport.y = std::clamp(viewport.y, bounds[0], bounds[1]); + + return viewport; +} + VkViewport GetViewportState(const Device& device, const Maxwell& regs, size_t index, float scale) { const auto& src = regs.viewport_transform[index]; const auto conv = [scale](float value) { @@ -106,7 +126,7 @@ VkViewport GetViewportState(const Device& device, const Maxwell& regs, size_t in viewport.minDepth = std::clamp(viewport.minDepth, 0.0f, 1.0f); viewport.maxDepth = std::clamp(viewport.maxDepth, 0.0f, 1.0f); } - return viewport; + return ClampViewport(device, viewport); } VkRect2D GetScissorState(const Maxwell& regs, size_t index, u32 up_scale = 1, u32 down_shift = 0) { @@ -225,6 +245,9 @@ void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) { std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex}; buffer_cache_runtime.SetUseDynamicVertexBindingStride( pipeline->UsesExtendedDynamicState() && !pipeline->HasDynamicVertexInput()); + if (device.IsExtProvokingVertexDynamicStateSupported()) { + state_tracker.InvalidateProvokingVertex(); + } // update engine as channel may be different. pipeline->SetEngine(maxwell3d, gpu_memory); if (!pipeline->Configure(is_indexed)) @@ -1133,8 +1156,9 @@ void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& reg .minDepth = 0.0f, .maxDepth = 1.0f, }; - scheduler.Record([viewport](vk::CommandBuffer cmdbuf) { - cmdbuf.SetViewport(0, viewport); + const VkViewport clamped = ClampViewport(device, viewport); + scheduler.Record([clamped](vk::CommandBuffer cmdbuf) { + cmdbuf.SetViewport(0, clamped); }); return; } diff --git a/src/video_core/renderer_vulkan/vk_state_tracker.h b/src/video_core/renderer_vulkan/vk_state_tracker.h index a7c453b5d0..fee48ea2b8 100644 --- a/src/video_core/renderer_vulkan/vk_state_tracker.h +++ b/src/video_core/renderer_vulkan/vk_state_tracker.h @@ -102,6 +102,10 @@ public: (*flags)[Dirty::StateEnable] = true; } + void InvalidateProvokingVertex() { + (*flags)[Dirty::ProvokingVertex] = true; + } + bool TouchViewports() { const bool dirty_viewports = Exchange(Dirty::Viewports, false); const bool rescale_viewports = Exchange(VideoCommon::Dirty::RescaleViewports, false); diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 8d37b6e0a6..ff7087d78a 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -488,10 +488,10 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR if (is_qualcomm) { must_emulate_scaled_formats = true; LOG_WARNING(Render_Vulkan, - "Qualcomm drivers require scaled vertex format emulation; forcing fallback"); + "Qualcomm drivers require scaled vertex format emulation"); LOG_WARNING(Render_Vulkan, - "Disabling shader float controls and 64-bit integer features on Qualcomm proprietary drivers"); + "Disabling shaderFloatControls and 64-bit integer features on Qualcomm proprietary drivers"); RemoveExtension(extensions.shader_float_controls, VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME); RemoveExtensionFeature(extensions.shader_atomic_int64, features.shader_atomic_int64, VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME); diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index 82f925d450..f569521315 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -6,6 +6,7 @@ #pragma once +#include #include #include #include @@ -820,6 +821,16 @@ public: return properties.properties.limits.maxViewports; } + std::array GetMaxViewportDimensions() const { + return {properties.properties.limits.maxViewportDimensions[0], + properties.properties.limits.maxViewportDimensions[1]}; + } + + std::array GetViewportBoundsRange() const { + return {properties.properties.limits.viewportBoundsRange[0], + properties.properties.limits.viewportBoundsRange[1]}; + } + u32 GetMaxUserClipDistances() const { return properties.properties.limits.maxClipDistances; }