diff --git a/OptiScaler/OptiScaler.vcxproj b/OptiScaler/OptiScaler.vcxproj
index e6c8c056..ddb2c9d8 100644
--- a/OptiScaler/OptiScaler.vcxproj
+++ b/OptiScaler/OptiScaler.vcxproj
@@ -366,6 +366,8 @@ copy NUL "$(SolutionDir)x64\Release\a\!! EXTRACT ALL FILES TO GAME FOLDER !!" /Y
+
+
@@ -660,6 +662,7 @@ copy NUL "$(SolutionDir)x64\Release\a\!! EXTRACT ALL FILES TO GAME FOLDER !!" /Y
+
diff --git a/OptiScaler/OptiScaler.vcxproj.filters b/OptiScaler/OptiScaler.vcxproj.filters
index 9509101c..c880f91f 100644
--- a/OptiScaler/OptiScaler.vcxproj.filters
+++ b/OptiScaler/OptiScaler.vcxproj.filters
@@ -704,6 +704,12 @@
Header Files
+
+ Header Files
+
+
+ Header Files
+
Header Files
@@ -1580,6 +1586,9 @@
Source Files
+
+ Source Files
+
Source Files
diff --git a/OptiScaler/shaders/velocity_convert/VC_Vk.cpp b/OptiScaler/shaders/velocity_convert/VC_Vk.cpp
new file mode 100644
index 00000000..f52164f6
--- /dev/null
+++ b/OptiScaler/shaders/velocity_convert/VC_Vk.cpp
@@ -0,0 +1,98 @@
+#include
+#include "VC_Vk.h"
+#include "precompile/vc_Shader_Vk.h"
+
+VelocityConvert_Vk::VelocityConvert_Vk(std::string InName, VkDevice InDevice, VkPhysicalDevice InPhysicalDevice)
+ : Shader_Vk(InName, InDevice, InPhysicalDevice)
+{
+ if (InDevice == VK_NULL_HANDLE)
+ {
+ LOG_ERROR("InDevice is nullptr!");
+ return;
+ }
+
+ LOG_DEBUG("{0} start!", _name);
+
+ // Setup descriptor layouts
+ std::vector bindings = { CreateBinding(0, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE),
+ CreateBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) };
+ CreateLayouts(bindings);
+
+ // Setup descriptor pool sizes and allocate sets
+ std::vector poolSizes = { { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, _maxFramesInFlight },
+ { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, _maxFramesInFlight } };
+ CreateDescriptorPool(poolSizes, _maxFramesInFlight);
+ CreateDescriptorSets(_descriptorSetLayout, _descriptorPool, _descriptorSets);
+
+ // Load precompiled shader and create compute pipeline
+ std::vector shaderCode(vc_spv, vc_spv + sizeof(vc_spv));
+ if (!CreateComputePipeline(_device, _pipelineLayout, &_pipeline, shaderCode))
+ {
+ LOG_ERROR("[{0}] Failed to create pipeline!", _name);
+ _init = false;
+ return;
+ }
+
+ _init = true;
+}
+
+bool VelocityConvert_Vk::Dispatch(VkCommandBuffer InCmdList, VkImageView InResourceView, VkExtent2D InExtent)
+{
+ if (!_init || InCmdList == VK_NULL_HANDLE || InResourceView == VK_NULL_HANDLE)
+ return false;
+
+ if (!CreateImageResource(InExtent.width, InExtent.height, VK_FORMAT_R16G16_SFLOAT,
+ VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT))
+ {
+ LOG_ERROR("[{0}] Failed to create intermediate image!", _name);
+ return false;
+ }
+
+ VkImageMemoryBarrier barrier { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
+ barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ barrier.image = _intermediateImage;
+ barrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
+
+ // Whole image gets overwritten, previous contents can be discarded.
+ // Only an execution dependency is needed against the previous frame's reads
+ barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
+ barrier.srcAccessMask = 0;
+ barrier.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
+ vkCmdPipelineBarrier(InCmdList, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0,
+ nullptr, 0, nullptr, 1, &barrier);
+
+ _currentSetIndex = (_currentSetIndex + 1) % _maxFramesInFlight;
+
+ VkDescriptorSet descriptorSet = _descriptorSets[_currentSetIndex];
+ VkDescriptorImageInfo sourceInfo { VK_NULL_HANDLE, InResourceView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL };
+ VkDescriptorImageInfo destInfo { VK_NULL_HANDLE, _intermediateImageView, VK_IMAGE_LAYOUT_GENERAL };
+
+ std::vector descriptorWritesBuffer = {
+ { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr, descriptorSet, 0, 0, 1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
+ &sourceInfo, nullptr, nullptr },
+ { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr, descriptorSet, 1, 0, 1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
+ &destInfo, nullptr, nullptr }
+ };
+
+ vkUpdateDescriptorSets(_device, static_cast(descriptorWritesBuffer.size()), descriptorWritesBuffer.data(),
+ 0, nullptr);
+
+ vkCmdBindPipeline(InCmdList, VK_PIPELINE_BIND_POINT_COMPUTE, _pipeline);
+ vkCmdBindDescriptorSets(InCmdList, VK_PIPELINE_BIND_POINT_COMPUTE, _pipelineLayout, 0, 1, &descriptorSet, 0,
+ nullptr);
+
+ uint32_t dispatchWidth = (InExtent.width + InNumThreadsX - 1) / InNumThreadsX;
+ uint32_t dispatchHeight = (InExtent.height + InNumThreadsY - 1) / InNumThreadsY;
+ vkCmdDispatch(InCmdList, dispatchWidth, dispatchHeight, 1);
+
+ barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
+ barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
+ barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
+ vkCmdPipelineBarrier(InCmdList, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0,
+ nullptr, 0, nullptr, 1, &barrier);
+
+ return true;
+}
diff --git a/OptiScaler/shaders/velocity_convert/VC_Vk.h b/OptiScaler/shaders/velocity_convert/VC_Vk.h
new file mode 100644
index 00000000..af5b13e7
--- /dev/null
+++ b/OptiScaler/shaders/velocity_convert/VC_Vk.h
@@ -0,0 +1,17 @@
+#pragma once
+#include
+#include
+
+class VelocityConvert_Vk : public Shader_Vk
+{
+ uint32_t InNumThreadsX = 16;
+ uint32_t InNumThreadsY = 16;
+
+ public:
+ VelocityConvert_Vk(std::string InName, VkDevice InDevice, VkPhysicalDevice InPhysicalDevice);
+ ~VelocityConvert_Vk() = default;
+
+ // Copies InResourceView into the R16G16_SFLOAT intermediate image (GetImage()),
+ // left in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
+ bool Dispatch(VkCommandBuffer InCmdList, VkImageView InResourceView, VkExtent2D InExtent);
+};
diff --git a/OptiScaler/shaders/velocity_convert/precompile/vc.hlsl b/OptiScaler/shaders/velocity_convert/precompile/vc.hlsl
new file mode 100644
index 00000000..328342ce
--- /dev/null
+++ b/OptiScaler/shaders/velocity_convert/precompile/vc.hlsl
@@ -0,0 +1,21 @@
+#ifdef VK_MODE
+[[vk::binding(0, 0)]]
+#endif
+Texture2D SourceTexture : register(t0);
+
+#ifdef VK_MODE
+[[vk::binding(1, 0)]]
+[[vk::image_format("rg16f")]]
+#endif
+RWTexture2D DestinationTexture : register(u0);
+
+[numthreads(16, 16, 1)]
+void CSMain(uint3 dispatchThreadID : SV_DispatchThreadID)
+{
+ uint width, height;
+ DestinationTexture.GetDimensions(width, height);
+ if (dispatchThreadID.x >= width || dispatchThreadID.y >= height)
+ return;
+
+ DestinationTexture[dispatchThreadID.xy] = SourceTexture.Load(int3(dispatchThreadID.xy, 0));
+}
diff --git a/OptiScaler/shaders/velocity_convert/precompile/vc_Shader_Vk.h b/OptiScaler/shaders/velocity_convert/precompile/vc_Shader_Vk.h
new file mode 100644
index 00000000..daca769d
--- /dev/null
+++ b/OptiScaler/shaders/velocity_convert/precompile/vc_Shader_Vk.h
@@ -0,0 +1,78 @@
+#pragma once
+
+inline static const unsigned char vc_spv[] = {
+ 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x31, 0x00, 0x00, 0x00, 0x11, 0x00,
+ 0x02, 0x00, 0x32, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f,
+ 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x43, 0x53, 0x4d, 0x61, 0x69, 0x6e, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x05, 0x00, 0x00, 0x00, 0x58, 0x02,
+ 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x74, 0x79, 0x70, 0x65, 0x2e, 0x32, 0x64, 0x2e, 0x69,
+ 0x6d, 0x61, 0x67, 0x65, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x04, 0x00, 0x00, 0x00, 0x53, 0x6f, 0x75, 0x72,
+ 0x63, 0x65, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00,
+ 0x00, 0x74, 0x79, 0x70, 0x65, 0x2e, 0x32, 0x64, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x00, 0x00, 0x00, 0x05, 0x00,
+ 0x07, 0x00, 0x06, 0x00, 0x00, 0x00, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x65,
+ 0x78, 0x74, 0x75, 0x72, 0x65, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x43, 0x53, 0x4d, 0x61,
+ 0x69, 0x6e, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00,
+ 0x00, 0x47, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00,
+ 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x06,
+ 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, 0x09, 0x00, 0x00, 0x00, 0x29, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a,
+ 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x16, 0x00, 0x03, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0x03, 0x00, 0x00,
+ 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0x05, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+ 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00,
+ 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17,
+ 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
+ 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x12, 0x00, 0x00,
+ 0x00, 0x21, 0x00, 0x03, 0x00, 0x13, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x14, 0x00,
+ 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x07,
+ 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+ 0x00, 0x17, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x3b, 0x00,
+ 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x0e,
+ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00,
+ 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13,
+ 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x1c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xfb, 0x00, 0x03, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x1e, 0x00,
+ 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x05, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x68,
+ 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00,
+ 0x0f, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05,
+ 0x00, 0x0f, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x41, 0x00,
+ 0x05, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x3d,
+ 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x05, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03,
+ 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x27, 0x00,
+ 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x27, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x1a,
+ 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,
+ 0x0f, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xae, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x2a, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x26, 0x00,
+ 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x26, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x07, 0x00, 0x09, 0x00, 0x00, 0x00, 0x2b,
+ 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,
+ 0xf7, 0x00, 0x03, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0x2b, 0x00, 0x00,
+ 0x00, 0x2d, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x2d, 0x00, 0x00, 0x00, 0xf9, 0x00,
+ 0x02, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x0f,
+ 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00,
+ 0x0f, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x04,
+ 0x00, 0x07, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x04, 0x00, 0x07, 0x00,
+ 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x50, 0x00, 0x06, 0x00, 0x15, 0x00, 0x00, 0x00, 0x32,
+ 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00,
+ 0x16, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x03, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x04, 0x00,
+ 0x00, 0x00, 0x5f, 0x00, 0x07, 0x00, 0x17, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x33,
+ 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x36, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x4f, 0x00, 0x07, 0x00, 0x14, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1c, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x05, 0x00, 0x00, 0x00, 0x38,
+ 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x63, 0x00, 0x05, 0x00, 0x38, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00,
+ 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02,
+ 0x00, 0x1d, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00
+};
diff --git a/OptiScaler/shaders/velocity_convert/precompile/vc_Shader_Vk.spv b/OptiScaler/shaders/velocity_convert/precompile/vc_Shader_Vk.spv
new file mode 100644
index 00000000..2c54c772
Binary files /dev/null and b/OptiScaler/shaders/velocity_convert/precompile/vc_Shader_Vk.spv differ
diff --git a/OptiScaler/spoofing/Vulkan_Spoofing.cpp b/OptiScaler/spoofing/Vulkan_Spoofing.cpp
index f3d1e1da..83021cb2 100644
--- a/OptiScaler/spoofing/Vulkan_Spoofing.cpp
+++ b/OptiScaler/spoofing/Vulkan_Spoofing.cpp
@@ -612,6 +612,8 @@ struct VulkanDeviceFeatureState::Impl
features != &features2);
EnableFeatureValue(modifiedFeatures, features->features.shaderStorageImageWriteWithoutFormat,
supported.features.shaderStorageImageWriteWithoutFormat, features != &features2);
+ EnableFeatureValue(modifiedFeatures, features->features.shaderStorageImageExtendedFormats,
+ supported.features.shaderStorageImageExtendedFormats, features != &features2);
return;
}
@@ -624,6 +626,9 @@ struct VulkanDeviceFeatureState::Impl
if (supported.features.shaderStorageImageWriteWithoutFormat == VK_TRUE)
coreFeatures.shaderStorageImageWriteWithoutFormat = VK_TRUE;
+ if (supported.features.shaderStorageImageExtendedFormats == VK_TRUE)
+ coreFeatures.shaderStorageImageExtendedFormats = VK_TRUE;
+
pCreateInfo->pEnabledFeatures = &coreFeatures;
}
diff --git a/OptiScaler/upscalers/ffx/FFXFeature_Vk.cpp b/OptiScaler/upscalers/ffx/FFXFeature_Vk.cpp
index e189747b..a20a3bb2 100644
--- a/OptiScaler/upscalers/ffx/FFXFeature_Vk.cpp
+++ b/OptiScaler/upscalers/ffx/FFXFeature_Vk.cpp
@@ -305,9 +305,25 @@ bool FFXFeatureVk::EvaluateInternal(VkCommandBuffer InCmdBuffer, NVSDK_NGX_Param
{
LOG_DEBUG("MotionVectors exist..");
- params.motionVectors = ffxApiGetResourceVK(paramVelocity->Resource.ImageViewInfo.Image,
- ffxApiGetImageResourceDescriptionVKLocal(paramVelocity),
- FFX_API_RESOURCE_STATE_COMPUTE_READ);
+ auto& mvInfo = paramVelocity->Resource.ImageViewInfo;
+ auto mvDesc = ffxApiGetImageResourceDescriptionVKLocal(paramVelocity);
+ VkImage mvImage = mvInfo.Image;
+
+ // Normalized 16-bit MV formats get copied into an R16G16_SFLOAT image
+ if (mvInfo.Format == VK_FORMAT_R16G16_SNORM || mvInfo.Format == VK_FORMAT_R16G16_UNORM)
+ {
+ if (!_velocityConvert)
+ _velocityConvert = std::make_unique("VelocityConvert", Device, PhysicalDevice);
+
+ if (_velocityConvert->CanRender() &&
+ _velocityConvert->Dispatch(InCmdBuffer, mvInfo.ImageView, { mvInfo.Width, mvInfo.Height }))
+ {
+ mvImage = _velocityConvert->GetImage();
+ mvDesc.format = FFX_API_SURFACE_FORMAT_R16G16_FLOAT;
+ }
+ }
+
+ params.motionVectors = ffxApiGetResourceVK(mvImage, mvDesc, FFX_API_RESOURCE_STATE_COMPUTE_READ);
}
else
{
diff --git a/OptiScaler/upscalers/ffx/FFXFeature_Vk.h b/OptiScaler/upscalers/ffx/FFXFeature_Vk.h
index 0ad23eea..818782d9 100644
--- a/OptiScaler/upscalers/ffx/FFXFeature_Vk.h
+++ b/OptiScaler/upscalers/ffx/FFXFeature_Vk.h
@@ -4,6 +4,7 @@
#include "vk/ffx_api_vk.h"
#include
+#include
class FFXFeatureVk : public FFXFeature, public IFeature_Vk
{
@@ -11,6 +12,8 @@ class FFXFeatureVk : public FFXFeature, public IFeature_Vk
// amd_fidelityfx_vk.dll or the driver provided upscaler
FfxModule* _ffx = nullptr;
+ std::unique_ptr _velocityConvert = nullptr;
+
// Last logged inputs of the driver provided FSR 4
std::string _lastFsr4Inputs;