Merge pull request 'fix(vulkan): Combine Lanczos-CRT Constants & Fix MP4 Mountain Jitter' (#132) from fix/jitter/mp4 into main

Reviewed-on: https://git.citron-emu.org/Citron/Emulator/pulls/132
This commit is contained in:
Collecting
2026-02-10 08:58:41 +01:00
4 changed files with 36 additions and 34 deletions

View File

@@ -163,11 +163,10 @@ void WindowAdaptPass::CreateDescriptorSetLayout() {
} }
void WindowAdaptPass::CreatePipelineLayout() { void WindowAdaptPass::CreatePipelineLayout() {
// Support up to 3 push constant ranges: // Support up to 2 push constant ranges:
// 0: PresentPushConstants (vertex shader) // 0: PresentPushConstants (vertex shader)
// 1: Lanczos quality (fragment shader) - optional // 1: Fragment shader parameters (Lanczos + CRT)
// 2: CRT parameters (fragment shader) - optional std::array<VkPushConstantRange, 2> ranges{};
std::array<VkPushConstantRange, 3> ranges{};
// Range 0: The existing constants for the Vertex Shader // Range 0: The existing constants for the Vertex Shader
ranges[0] = { ranges[0] = {
@@ -176,16 +175,14 @@ void WindowAdaptPass::CreatePipelineLayout() {
.size = sizeof(PresentPushConstants), .size = sizeof(PresentPushConstants),
}; };
// Range 1: Lanczos quality for the Fragment Shader // Range 1: All parameters for the Fragment Shader (Lanczos + CRT)
ranges[1] = { // We combine them into a single range because Vulkan does not allow multiple ranges
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, // for the same stage if they are provided separately in some drivers/configs.
.offset = sizeof(PresentPushConstants), // Spec says: "For each shader stage, there must be at most one push constant range
.size = sizeof(s32), // that includes that stage in its stageFlags." - actually the spec says:
}; // "Each element of pPushConstantRanges must contain at least one stage flag in stageFlags"
// and "Any two elements of pPushConstantRanges must not include the same stage flag in
// Range 2: CRT parameters for the Fragment Shader // stageFlags"
// Offset after PresentPushConstants + Lanczos (if used)
// CRT constants: 8 floats + 1 int = 36 bytes
struct CRTPushConstants { struct CRTPushConstants {
float scanline_strength; float scanline_strength;
float curvature; float curvature;
@@ -197,10 +194,10 @@ void WindowAdaptPass::CreatePipelineLayout() {
float screen_width; float screen_width;
float screen_height; float screen_height;
}; };
ranges[2] = { ranges[1] = {
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
.offset = sizeof(PresentPushConstants) + sizeof(s32), .offset = sizeof(PresentPushConstants),
.size = sizeof(CRTPushConstants), .size = sizeof(s32) + sizeof(CRTPushConstants),
}; };
pipeline_layout = device.GetLogical().CreatePipelineLayout(VkPipelineLayoutCreateInfo{ pipeline_layout = device.GetLogical().CreatePipelineLayout(VkPipelineLayoutCreateInfo{

View File

@@ -8,10 +8,11 @@
#include <vector> #include <vector>
#include "common/alignment.h" #include "common/alignment.h"
#include "common/literals.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "common/literals.h"
#include "video_core/renderer_vulkan/vk_buffer_cache.h" #include "video_core/renderer_vulkan/vk_buffer_cache.h"
#include "video_core/renderer_vulkan/maxwell_to_vk.h" #include "video_core/renderer_vulkan/maxwell_to_vk.h"
#include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
@@ -660,7 +661,8 @@ vk::Buffer BufferCacheRuntime::CreateNullBuffer() {
.flags = 0, .flags = 0,
.size = 4, .size = 4,
.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT | .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT |
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE, .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0, .queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr, .pQueueFamilyIndices = nullptr,

View File

@@ -899,15 +899,17 @@ private:
cmdbuf.EndTransformFeedbackEXT(0, 0, nullptr, nullptr); cmdbuf.EndTransformFeedbackEXT(0, 0, nullptr, nullptr);
}); });
} else { } else {
scheduler.Record([this, scheduler.Record(
total = static_cast<u32>(buffers_count)](vk::CommandBuffer cmdbuf) { [this, total = static_cast<u32>(buffers_count)](vk::CommandBuffer cmdbuf) {
cmdbuf.EndTransformFeedbackEXT(0, total, counter_buffers.data(), offsets.data()); cmdbuf.EndTransformFeedbackEXT(0, total, counter_buffers.data(),
offsets.data());
}); });
} }
} catch (...) { } catch (...) {
// If query ending fails, we'll log it but continue // If query ending fails, we'll log it but continue
// This prevents crashes from malformed query states // This prevents crashes from malformed query states
LOG_WARNING(Render_Vulkan, "Failed to end transform feedback query, continuing execution"); LOG_WARNING(Render_Vulkan,
"Failed to end transform feedback query, continuing execution");
} }
} }
@@ -1188,10 +1190,9 @@ struct QueryCacheRuntimeImpl {
StagingBufferPool& staging_pool_, StagingBufferPool& staging_pool_,
ComputePassDescriptorQueue& compute_pass_descriptor_queue, ComputePassDescriptorQueue& compute_pass_descriptor_queue,
DescriptorPool& descriptor_pool) DescriptorPool& descriptor_pool)
: rasterizer{rasterizer_}, device_memory{device_memory_}, : rasterizer{rasterizer_}, device_memory{device_memory_}, buffer_cache{buffer_cache_},
buffer_cache{buffer_cache_}, device{device_}, device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_},
memory_allocator{memory_allocator_}, scheduler{scheduler_}, staging_pool{staging_pool_}, staging_pool{staging_pool_}, guest_streamer(0, runtime),
guest_streamer(0, runtime),
sample_streamer(static_cast<size_t>(QueryType::ZPassPixelCount64), runtime, rasterizer, sample_streamer(static_cast<size_t>(QueryType::ZPassPixelCount64), runtime, rasterizer,
device, scheduler, memory_allocator, compute_pass_descriptor_queue, device, scheduler, memory_allocator, compute_pass_descriptor_queue,
descriptor_pool), descriptor_pool),

View File

@@ -9,6 +9,7 @@
#include "video_core/renderer_vulkan/renderer_vulkan.h" #include "video_core/renderer_vulkan/renderer_vulkan.h"
#include "citron/util/title_ids.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/microprofile.h" #include "common/microprofile.h"
@@ -38,7 +39,7 @@
#include "video_core/texture_cache/texture_cache_base.h" #include "video_core/texture_cache/texture_cache_base.h"
#include "video_core/vulkan_common/vulkan_device.h" #include "video_core/vulkan_common/vulkan_device.h"
#include "video_core/vulkan_common/vulkan_wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
#include "citron/util/title_ids.h"
namespace Vulkan { namespace Vulkan {
@@ -66,13 +67,13 @@ struct DrawParams {
VkViewport GetViewportState(const Device& device, const Maxwell& regs, size_t index, float scale) { VkViewport GetViewportState(const Device& device, const Maxwell& regs, size_t index, float scale) {
const auto& src = regs.viewport_transform[index]; const auto& src = regs.viewport_transform[index];
const auto conv = [scale](float value) { const auto conv = [scale](float value) {
float new_value = value * scale; const double new_value = static_cast<double>(value) * static_cast<double>(scale);
if (scale < 1.0f) { if (scale < 1.0f) {
const bool sign = std::signbit(value); const bool sign = std::signbit(value);
new_value = std::round(std::abs(new_value)); double rounded = std::round(std::abs(new_value));
new_value = sign ? -new_value : new_value; return static_cast<float>(sign ? -rounded : rounded);
} }
return new_value; return static_cast<float>(new_value);
}; };
const float x = conv(src.translate_x - src.scale_x); const float x = conv(src.translate_x - src.scale_x);
const float width = conv(src.scale_x * 2.0f); const float width = conv(src.scale_x * 2.0f);
@@ -1107,7 +1108,8 @@ void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& reg
}; };
} }
scheduler.Record([this, viewport_list](vk::CommandBuffer cmdbuf) { scheduler.Record([this, viewport_list](vk::CommandBuffer cmdbuf) {
const u32 num_viewports = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports); const u32 num_viewports =
std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports);
const vk::Span<VkViewport> viewports(viewport_list.data(), num_viewports); const vk::Span<VkViewport> viewports(viewport_list.data(), num_viewports);
cmdbuf.SetViewport(0, viewports); cmdbuf.SetViewport(0, viewports);
}); });