From ebc2d31deccf63da7cb8af85481a0438cc336130 Mon Sep 17 00:00:00 2001 From: FakeMichau <49685661+FakeMichau@users.noreply.github.com> Date: Mon, 14 Sep 2026 23:13:38 +0200 Subject: [PATCH] Add Hudless fixup to No Man's Sky Seems like the same issue as with Cyberprank's DLSSG inputs Also enables hud cutoff on Vulkan NvngxFG --- OptiScaler/OptiScaler.vcxproj | 3 + OptiScaler/OptiScaler.vcxproj.filters | 9 ++ OptiScaler/framegen/nvngx/Nvngx_FG.cpp | 54 ++++++- OptiScaler/framegen/nvngx/Nvngx_FG.h | 4 +- OptiScaler/misc/Quirks.h | 2 +- OptiScaler/shaders/hud_copy/HudCopy_Common.h | 63 +++++--- OptiScaler/shaders/hud_copy/HudCopy_Dx12.cpp | 4 +- OptiScaler/shaders/hud_copy/HudCopy_Dx12.h | 8 +- OptiScaler/shaders/hud_copy/HudCopy_Vk.cpp | 142 +++++++++++++++++ OptiScaler/shaders/hud_copy/HudCopy_Vk.h | 17 ++ .../shaders/hud_copy/precompile/HudCopy.hlsl | 14 ++ .../hud_copy/precompile/HudCopy_Shader_Vk.h | 90 +++++++++++ .../hud_copy/precompile/HudCopy_Shader_Vk.spv | Bin 0 -> 1624 bytes .../shaders/magnifier/Magnifier_Common.h | 145 ++++++++++-------- 14 files changed, 455 insertions(+), 100 deletions(-) create mode 100644 OptiScaler/shaders/hud_copy/HudCopy_Vk.cpp create mode 100644 OptiScaler/shaders/hud_copy/HudCopy_Vk.h create mode 100644 OptiScaler/shaders/hud_copy/precompile/HudCopy_Shader_Vk.h create mode 100644 OptiScaler/shaders/hud_copy/precompile/HudCopy_Shader_Vk.spv diff --git a/OptiScaler/OptiScaler.vcxproj b/OptiScaler/OptiScaler.vcxproj index 3f5d2407..776dc29f 100644 --- a/OptiScaler/OptiScaler.vcxproj +++ b/OptiScaler/OptiScaler.vcxproj @@ -333,6 +333,7 @@ copy NUL "$(SolutionDir)x64\Release\a\!! EXTRACT ALL FILES TO GAME FOLDER !!" /Y + @@ -340,6 +341,7 @@ copy NUL "$(SolutionDir)x64\Release\a\!! EXTRACT ALL FILES TO GAME FOLDER !!" /Y + @@ -621,6 +623,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 f2f52381..48316feb 100644 --- a/OptiScaler/OptiScaler.vcxproj.filters +++ b/OptiScaler/OptiScaler.vcxproj.filters @@ -956,6 +956,12 @@ Header Files + + Header Files + + + Header Files + @@ -1544,6 +1550,9 @@ Source Files + + Source Files + diff --git a/OptiScaler/framegen/nvngx/Nvngx_FG.cpp b/OptiScaler/framegen/nvngx/Nvngx_FG.cpp index e137120a..09a43f37 100644 --- a/OptiScaler/framegen/nvngx/Nvngx_FG.cpp +++ b/OptiScaler/framegen/nvngx/Nvngx_FG.cpp @@ -12,6 +12,7 @@ #include "Nvngx_FFX.h" #include "Nvngx_Combo.h" #include +#include IFGNvngx* Nvngx_FG::getProvider() { @@ -363,10 +364,10 @@ NVSDK_NGX_Result Nvngx_FG::D3D12_EvaluateFeature(ID3D12GraphicsCommandList* InCm if (presentWithHud && hudlessResource && device) { - if (_hudCopy.get() == nullptr) - _hudCopy = std::make_unique("HudCopy", device); + if (_hudCopyDx12.get() == nullptr) + _hudCopyDx12 = std::make_unique("HudCopy", device); - if (auto hudCopy = _hudCopy.get(); hudCopy && hudCopy->IsInit()) + if (auto hudCopy = _hudCopyDx12.get(); hudCopy && hudCopy->IsInit()) { // In Cyberprank - DLSSG has noise issues, FSR FG has noise + vignetting // In Death Stranding 2 - DLSSG has wrong colormapping it seems, FSR FG is fine @@ -418,6 +419,9 @@ NVSDK_NGX_Result Nvngx_FG::VULKAN_Init(unsigned long long InApplicationId, const if (!provider) return NVSDK_NGX_Result_Fail; + if (!_hudCopyVk) + _hudCopyVk = std::make_unique("HudCopy", InDevice, InPD); + return provider->VULKAN_Init(InApplicationId, InApplicationDataPath, InInstance, InPD, InDevice, InGIPA, InGDPA, InFeatureInfo, InSDKVersion); } @@ -432,6 +436,9 @@ NVSDK_NGX_Result Nvngx_FG::VULKAN_Init_Ext(unsigned long long InApplicationId, c if (!provider) return NVSDK_NGX_Result_Fail; + if (!_hudCopyVk) + _hudCopyVk = std::make_unique("HudCopy", InDevice, InPD); + return provider->VULKAN_Init_Ext(InApplicationId, InApplicationDataPath, InInstance, InPD, InDevice, InSDKVersion, InFeatureInfo); } @@ -447,6 +454,9 @@ NVSDK_NGX_Result Nvngx_FG::VULKAN_Init_Ext2(unsigned long long InApplicationId, if (!provider) return NVSDK_NGX_Result_Fail; + if (!_hudCopyVk) + _hudCopyVk = std::make_unique("HudCopy", InDevice, InPD); + return provider->VULKAN_Init_Ext2(InApplicationId, InApplicationDataPath, InInstance, InPD, InDevice, InGIPA, InGDPA, InSDKVersion, InFeatureInfo); } @@ -583,6 +593,44 @@ NVSDK_NGX_Result Nvngx_FG::VULKAN_EvaluateFeature(VkCommandBuffer InCmdList, con Nvngx_FG_Handle* ourHandle = (Nvngx_FG_Handle*) InFeatureHandle; std::shared_lock lock(ourHandle->handleMutex); + bool applyHudCutoff = Config::Instance()->FGHudCutoff.value_or_default() > 0.0f || + State::Instance().gameQuirks & GameQuirk::FSRFGHudlessMismatchFixup; + + uint32_t frameIndex = 1; + InParameters->Get("DLSSG.MultiFrameIndex", &frameIndex); + + if (applyHudCutoff && frameIndex == 1) + { + NVSDK_NGX_Resource_VK* presentWithHud = nullptr; + InParameters->Get("DLSSG.Backbuffer", (void**) &presentWithHud); + VkImageLayout presentWithHudLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + NVSDK_NGX_Resource_VK* hudlessResource = nullptr; + InParameters->Get("DLSSG.HUDLess", (void**) &hudlessResource); + VkImageLayout hudlessLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + + if (presentWithHud && hudlessResource) + { + if (auto hudCopy = _hudCopyVk.get(); hudCopy && hudCopy->IsInit()) + { + float hudDetectionThreshold = 0.03f; + + if (Config::Instance()->FGHudCutoff.value_or_default() > 0.0f) + hudDetectionThreshold = Config::Instance()->FGHudCutoff.value_or_default() / 10.0f; + + VkImageInfo presentWithHudInfo = *(VkImageInfo*) &presentWithHud->Resource.ImageViewInfo; + VkImageInfo hudlessResourceInfo = *(VkImageInfo*) &hudlessResource->Resource.ImageViewInfo; + + hudCopy->Dispatch(InCmdList, hudlessResourceInfo, hudlessLayout, presentWithHudInfo, + presentWithHudLayout, hudDetectionThreshold); + } + } + else + { + LOG_WARN("Couldn't run hudless fixup"); + } + } + if (Config::Instance()->NvngxFGDisableHudless.value_or_default()) InParameters->Set("DLSSG.HUDLess", (void*) nullptr); diff --git a/OptiScaler/framegen/nvngx/Nvngx_FG.h b/OptiScaler/framegen/nvngx/Nvngx_FG.h index d59a493f..0982f60e 100644 --- a/OptiScaler/framegen/nvngx/Nvngx_FG.h +++ b/OptiScaler/framegen/nvngx/Nvngx_FG.h @@ -5,6 +5,7 @@ #include "proxies/NVNGX_Proxy.h" #include "proxies/Ntdll_Proxy.h" #include +#include #include "IFGNvngx.h" class Nvngx_FG @@ -21,7 +22,8 @@ class Nvngx_FG static inline std::atomic_uint32_t lastIdCreated = 0; static inline std::unique_ptr _provider; - static inline std::unique_ptr _hudCopy; + static inline std::unique_ptr _hudCopyDx12; + static inline std::unique_ptr _hudCopyVk; static IFGNvngx* getProvider(); diff --git a/OptiScaler/misc/Quirks.h b/OptiScaler/misc/Quirks.h index 2650a3ca..779f1861 100644 --- a/OptiScaler/misc/Quirks.h +++ b/OptiScaler/misc/Quirks.h @@ -569,7 +569,7 @@ static const QuirkEntry quirkTable[] = { // No Man's Sky QUIRK_ENTRY("nms.exe", GameQuirk::KernelBaseHooks, GameQuirk::VulkanDLSSBarrierFixup, - GameQuirk::EnableVulkanSpoofing), + GameQuirk::EnableVulkanSpoofing, GameQuirk::FSRFGHudlessMismatchFixup), // RTX Remix QUIRK_ENTRY("nvremixbridge.exe", GameQuirk::DisableDxgiSpoofing, GameQuirk::LoadVulkanManually, diff --git a/OptiScaler/shaders/hud_copy/HudCopy_Common.h b/OptiScaler/shaders/hud_copy/HudCopy_Common.h index 4239e4de..70649240 100644 --- a/OptiScaler/shaders/hud_copy/HudCopy_Common.h +++ b/OptiScaler/shaders/hud_copy/HudCopy_Common.h @@ -2,32 +2,55 @@ #include "pch.h" -static std::string shaderCode = R"( -cbuffer Params : register(b0) +class HudCopy_Common { - float DiffThreshold; -}; + protected: + struct alignas(256) InternalHudCopyParams + { + float DiffThreshold = 0.02f; + }; -Texture2D Hudless : register(t0); -Texture2D PresentCopy : register(t1); + const std::string shaderCode = R"( + #ifdef VK_MODE + cbuffer Params : register(b0, space0) + #else + cbuffer Params : register(b0) + #endif + { + float DiffThreshold; + }; -RWTexture2D Present : register(u0); + #ifdef VK_MODE + [[vk::binding(1, 0)]] + #endif + Texture2D Hudless : register(t0); -[numthreads(16, 16, 1)] -void CSMain(uint3 dispatchThreadID : SV_DispatchThreadID) -{ - uint2 pixelCoord = dispatchThreadID.xy; + #ifdef VK_MODE + [[vk::binding(2, 0)]] + #endif + Texture2D PresentCopy : register(t1); - float3 hudless = Hudless.Load(int3(pixelCoord, 0)); - float3 present = PresentCopy.Load(int3(pixelCoord, 0)); + #ifdef VK_MODE + [[vk::binding(3, 0)]] + #endif + RWTexture2D Present : register(u0); + + [numthreads(16, 16, 1)] + void CSMain(uint3 dispatchThreadID : SV_DispatchThreadID) + { + uint2 pixelCoord = dispatchThreadID.xy; + + float3 hudless = Hudless.Load(int3(pixelCoord, 0)); + float3 present = PresentCopy.Load(int3(pixelCoord, 0)); - float3 diff = abs(hudless - present); - float delta = max(max(diff.r, diff.g), diff.b); + float3 diff = abs(hudless - present); + float delta = max(max(diff.r, diff.g), diff.b); - float uiMask = smoothstep(DiffThreshold, DiffThreshold * 2.0f, delta); + float uiMask = smoothstep(DiffThreshold, DiffThreshold * 2.0f, delta); - float3 ui = (present - hudless) * uiMask; + float3 ui = (present - hudless) * uiMask; - Present[pixelCoord] = hudless + ui; -} -)"; + Present[pixelCoord] = hudless + ui; + } + )"; +}; \ No newline at end of file diff --git a/OptiScaler/shaders/hud_copy/HudCopy_Dx12.cpp b/OptiScaler/shaders/hud_copy/HudCopy_Dx12.cpp index 66f9277a..232d6318 100644 --- a/OptiScaler/shaders/hud_copy/HudCopy_Dx12.cpp +++ b/OptiScaler/shaders/hud_copy/HudCopy_Dx12.cpp @@ -65,7 +65,7 @@ bool HudCopy_Dx12::Dispatch(ID3D12GraphicsCommandList* cmdList, ID3D12Resource* CreateShaderResourceView(_device, present, currentHeap.GetSrvCPU(1)); CreateUnorderedAccessView(_device, _buffer, currentHeap.GetUavCPU(0), 0); - InternalCompareParams constants {}; + InternalHudCopyParams constants {}; constants.DiffThreshold = hudDetectionThreshold; if (!CreateConstantsBuffer(_device, _constantBuffer, constants, currentHeap.GetCbvCPU(0))) @@ -117,7 +117,7 @@ HudCopy_Dx12::HudCopy_Dx12(std::string InName, ID3D12Device* InDevice) : Shader_ return; } - D3D12_RESOURCE_DESC desc = CD3DX12_RESOURCE_DESC::Buffer(sizeof(InternalCompareParams)); + D3D12_RESOURCE_DESC desc = CD3DX12_RESOURCE_DESC::Buffer(sizeof(InternalHudCopyParams)); auto heapProps = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD); auto result = diff --git a/OptiScaler/shaders/hud_copy/HudCopy_Dx12.h b/OptiScaler/shaders/hud_copy/HudCopy_Dx12.h index a647a871..0b91be70 100644 --- a/OptiScaler/shaders/hud_copy/HudCopy_Dx12.h +++ b/OptiScaler/shaders/hud_copy/HudCopy_Dx12.h @@ -1,4 +1,5 @@ #pragma once +#include "HudCopy_Common.h" #include "SysUtils.h" @@ -10,14 +11,9 @@ #define HudCopy_NUM_OF_HEAPS 2 -class HudCopy_Dx12 : public Shader_Dx12 +class HudCopy_Dx12 : public Shader_Dx12, public HudCopy_Common { private: - struct alignas(256) InternalCompareParams - { - float DiffThreshold = 0.02f; - }; - FrameDescriptorHeap _frameHeaps[HudCopy_NUM_OF_HEAPS]; ID3D12Resource* _buffer = nullptr; diff --git a/OptiScaler/shaders/hud_copy/HudCopy_Vk.cpp b/OptiScaler/shaders/hud_copy/HudCopy_Vk.cpp new file mode 100644 index 00000000..f4169824 --- /dev/null +++ b/OptiScaler/shaders/hud_copy/HudCopy_Vk.cpp @@ -0,0 +1,142 @@ +#include "pch.h" +#include "HudCopy_Vk.h" +#include +#include +#include "precompile/HudCopy_Shader_Vk.h" + +HudCopy_Vk::HudCopy_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 (0: Params, 1: Hudless, 2: PresentCopy, 3: PresentOut) + CreateSampler(VK_FILTER_NEAREST, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE); + CreateConstantBuffer(sizeof(InternalHudCopyParams)); + + std::vector bindings = { CreateBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER), + CreateBinding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER), + CreateBinding(2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER), + CreateBinding(3, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) }; + CreateLayouts(bindings); + + std::vector poolSizes = { { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, _maxFramesInFlight }, + { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + _maxFramesInFlight * 2 }, + { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, _maxFramesInFlight } }; + CreateDescriptorPool(poolSizes, _maxFramesInFlight); + CreateDescriptorSets(_descriptorSetLayout, _descriptorPool, _descriptorSets); + + std::vector shaderCode(HudCopy_spv, HudCopy_spv + sizeof(HudCopy_spv)); + if (!CreateComputePipeline(_device, _pipelineLayout, &_pipeline, shaderCode)) + { + LOG_ERROR("[{0}] Failed to create pipeline!", _name); + _init = false; + return; + } + + _init = true; +} + +bool HudCopy_Vk::Dispatch(VkCommandBuffer InCmdList, const VkImageInfo& InHudlessInfo, VkImageLayout HudlessState, + const VkImageInfo& InPresentInfo, VkImageLayout PresentState, float HudDetectionThreshold) +{ + if (!_init || InCmdList == VK_NULL_HANDLE || InHudlessInfo.Image == VK_NULL_HANDLE || + InPresentInfo.Image == VK_NULL_HANDLE) + return false; + + if (!CreateImageResource(InPresentInfo.Width, InPresentInfo.Height, InPresentInfo.Format, + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT)) + { + LOG_ERROR("[{0}] Failed to create or resize intermediate buffer", _name); + return false; + } + + _currentSetIndex = (_currentSetIndex + 1) % _maxFramesInFlight; + + VkImageSubresourceRange copySubresourceRange = InPresentInfo.SubresourceRange; + copySubresourceRange.baseMipLevel = 0; + copySubresourceRange.levelCount = 1; + copySubresourceRange.baseArrayLayer = 0; + copySubresourceRange.layerCount = 1; + + SetImageLayout(InCmdList, InPresentInfo.Image, PresentState, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + copySubresourceRange); + SetImageLayout(InCmdList, _intermediateImage, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + copySubresourceRange); + + VkImageCopy copyRegion {}; + copyRegion.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 }; + copyRegion.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 }; + copyRegion.extent = { InPresentInfo.Width, InPresentInfo.Height, 1 }; + + vkCmdCopyImage(InCmdList, InPresentInfo.Image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, _intermediateImage, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Region); + + SetImageLayout(InCmdList, InPresentInfo.Image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, copySubresourceRange); + SetImageLayout(InCmdList, _intermediateImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL, + copySubresourceRange); + SetImageLayout(InCmdList, InHudlessInfo.Image, HudlessState, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + InHudlessInfo.SubresourceRange); + + InternalHudCopyParams constants {}; + constants.DiffThreshold = HudDetectionThreshold; + + if (_mappedConstantBuffer) + memcpy(_mappedConstantBuffer, &constants, sizeof(InternalHudCopyParams)); + + VkDescriptorSet descriptorSet = _descriptorSets[_currentSetIndex]; + + VkDescriptorBufferInfo bufferInfo { _constantBuffer, 0, sizeof(InternalHudCopyParams) }; + VkDescriptorImageInfo hudlessInfo { _textureSampler, InHudlessInfo.ImageView, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }; + VkDescriptorImageInfo presentInfo { _textureSampler, InPresentInfo.ImageView, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }; + VkDescriptorImageInfo destUAVInfo { 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_UNIFORM_BUFFER, + nullptr, &bufferInfo, nullptr }, + { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr, descriptorSet, 1, 0, 1, + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &hudlessInfo, nullptr, nullptr }, + { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr, descriptorSet, 2, 0, 1, + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &presentInfo, nullptr, nullptr }, + { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr, descriptorSet, 3, 0, 1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + &destUAVInfo, nullptr, nullptr } + }; + + vkUpdateDescriptorSets(_device, static_cast(descriptorWritesBuffer.size()), descriptorWritesBuffer.data(), + 0, nullptr); + + // Bind & Dispatch + vkCmdBindPipeline(InCmdList, VK_PIPELINE_BIND_POINT_COMPUTE, _pipeline); + vkCmdBindDescriptorSets(InCmdList, VK_PIPELINE_BIND_POINT_COMPUTE, _pipelineLayout, 0, 1, &descriptorSet, 0, + nullptr); + + uint32_t dispatchWidth = (InPresentInfo.Width + InNumThreadsX - 1) / InNumThreadsX; + uint32_t dispatchHeight = (InPresentInfo.Height + InNumThreadsY - 1) / InNumThreadsY; + vkCmdDispatch(InCmdList, dispatchWidth, dispatchHeight, 1); + + // 3. Transition and copy the internal computed target back to 'present' + SetImageLayout(InCmdList, _intermediateImage, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + copySubresourceRange); + SetImageLayout(InCmdList, InPresentInfo.Image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, copySubresourceRange); + + vkCmdCopyImage(InCmdList, _intermediateImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, InPresentInfo.Image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Region); + + // 4. Restore original resource states + SetImageLayout(InCmdList, InPresentInfo.Image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, PresentState, + copySubresourceRange); + SetImageLayout(InCmdList, InHudlessInfo.Image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, HudlessState, + InHudlessInfo.SubresourceRange); + + return true; +} diff --git a/OptiScaler/shaders/hud_copy/HudCopy_Vk.h b/OptiScaler/shaders/hud_copy/HudCopy_Vk.h new file mode 100644 index 00000000..7ed90bee --- /dev/null +++ b/OptiScaler/shaders/hud_copy/HudCopy_Vk.h @@ -0,0 +1,17 @@ +#pragma once +#include "HudCopy_Common.h" + +#include + +class HudCopy_Vk : public Shader_Vk, public HudCopy_Common +{ + uint32_t InNumThreadsX = 16; + uint32_t InNumThreadsY = 16; + + public: + HudCopy_Vk(std::string InName, VkDevice InDevice, VkPhysicalDevice InPhysicalDevice); + virtual ~HudCopy_Vk() = default; + + bool Dispatch(VkCommandBuffer InCmdList, const VkImageInfo& InHudlessInfo, VkImageLayout HudlessState, + const VkImageInfo& InPresentInfo, VkImageLayout PresentState, float HudDetectionThreshold); +}; diff --git a/OptiScaler/shaders/hud_copy/precompile/HudCopy.hlsl b/OptiScaler/shaders/hud_copy/precompile/HudCopy.hlsl index 03d281e8..dfbae936 100644 --- a/OptiScaler/shaders/hud_copy/precompile/HudCopy.hlsl +++ b/OptiScaler/shaders/hud_copy/precompile/HudCopy.hlsl @@ -1,11 +1,25 @@ +#ifdef VK_MODE +cbuffer Params : register(b0, space0) +#else cbuffer Params : register(b0) +#endif { float DiffThreshold; }; +#ifdef VK_MODE +[[vk::binding(1, 0)]] +#endif Texture2D Hudless : register(t0); + +#ifdef VK_MODE +[[vk::binding(2, 0)]] +#endif Texture2D PresentCopy : register(t1); +#ifdef VK_MODE +[[vk::binding(3, 0)]] +#endif RWTexture2D Present : register(u0); [numthreads(16, 16, 1)] diff --git a/OptiScaler/shaders/hud_copy/precompile/HudCopy_Shader_Vk.h b/OptiScaler/shaders/hud_copy/precompile/HudCopy_Shader_Vk.h new file mode 100644 index 00000000..cb77725d --- /dev/null +++ b/OptiScaler/shaders/hud_copy/precompile/HudCopy_Shader_Vk.h @@ -0,0 +1,90 @@ +#pragma once + +inline static const unsigned char HudCopy_spv[] = { + 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x11, 0x00, 0x02, 0x00, 0x38, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, + 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x06, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x43, 0x53, 0x4d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x06, 0x00, 0x02, 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, 0x05, 0x00, 0x04, 0x00, 0x00, 0x00, 0x74, 0x79, 0x70, 0x65, 0x2e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x00, + 0x06, 0x00, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x69, 0x66, 0x66, 0x54, 0x68, 0x72, + 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x05, 0x00, 0x00, 0x00, 0x50, 0x61, + 0x72, 0x61, 0x6d, 0x73, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x74, 0x79, 0x70, 0x65, 0x2e, + 0x32, 0x64, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x48, 0x75, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x00, 0x05, 0x00, 0x05, 0x00, 0x08, 0x00, 0x00, 0x00, 0x50, 0x72, 0x65, + 0x73, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x70, 0x79, 0x00, 0x05, 0x00, 0x06, 0x00, 0x09, 0x00, 0x00, 0x00, 0x74, 0x79, + 0x70, 0x65, 0x2e, 0x32, 0x64, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x0a, + 0x00, 0x00, 0x00, 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x00, 0x05, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x43, 0x53, 0x4d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, + 0x00, 0x1c, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, + 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x21, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x05, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x05, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x05, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x47, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x0b, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x2b, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1e, 0x00, 0x03, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0d, 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, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x19, 0x00, 0x09, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, + 0x12, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, + 0x00, 0x12, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x15, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x16, + 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x17, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, + 0x04, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x1b, + 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, + 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x1d, 0x00, + 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x4f, + 0x00, 0x07, 0x00, 0x17, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, 0x21, 0x00, + 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x22, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, + 0x21, 0x00, 0x00, 0x00, 0x50, 0x00, 0x06, 0x00, 0x19, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, + 0x00, 0x23, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x25, 0x00, + 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3d, + 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x07, 0x00, + 0x1b, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x0c, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x08, 0x00, 0x18, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x27, 0x00, + 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x3d, + 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x07, 0x00, + 0x1b, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x0c, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x08, 0x00, 0x18, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x2a, 0x00, + 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x83, + 0x00, 0x05, 0x00, 0x18, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x06, 0x00, 0x18, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x2c, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x2d, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x2d, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, + 0x00, 0x0d, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x07, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x30, + 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, + 0x00, 0x33, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x34, 0x00, + 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, + 0x83, 0x00, 0x05, 0x00, 0x18, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, + 0x00, 0x8e, 0x00, 0x05, 0x00, 0x18, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x36, 0x00, + 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x18, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x38, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x63, 0x00, 0x05, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00 +}; diff --git a/OptiScaler/shaders/hud_copy/precompile/HudCopy_Shader_Vk.spv b/OptiScaler/shaders/hud_copy/precompile/HudCopy_Shader_Vk.spv new file mode 100644 index 0000000000000000000000000000000000000000..b81c6e3852d689871753d954e63f67110c47b10e GIT binary patch literal 1624 zcmZ{kOHY$g5QYzJxk=?B0^$W*>K(0$fK_6m!2}i*Y59@3 z(NI)mu`w|H=mmIf`%SZR5VGhveti@0cw}o9`H25Ou%Ax}{p9qhUEgXRH}|__4Q4*v z;dN(c=l$++ySsb1*TNQUZiJ!_@QL}0t$Js_`MDi&3>P-OwD#KFF1Y?MWFDp32PbQX zN2git@PBg8{l$VS{WIG-w$qQmS7B{?&BIc%tLVC5j3n0cUqDu1X$E@|sn7k0zlgM_{z*oz<~UzoXDGXmJ25Us zvW}Qk>n^%GOttQz>pQE~0)FGNlxlrvC*J*i*nZ;5oK)WfSe$ok++BIUb=a7cd=JqR zzRYam{Btya3pPhg!aqhApU<4*7qJuGTrscc>Dzh&`<~p7^ILxj*8d}(YdQM-y_VUG zm=)NX))FtqK56c!=+5lyKdIx~4OqXq-=gmsx)@{j_qX^Q_RW3*qwbp%C;g^t1O5Xr C5K-R% literal 0 HcmV?d00001 diff --git a/OptiScaler/shaders/magnifier/Magnifier_Common.h b/OptiScaler/shaders/magnifier/Magnifier_Common.h index e435ef37..040bc76f 100644 --- a/OptiScaler/shaders/magnifier/Magnifier_Common.h +++ b/OptiScaler/shaders/magnifier/Magnifier_Common.h @@ -21,75 +21,86 @@ class Magnifier_Common float Padding[3]; // Padding to maintain 16-byte alignment }; + const std::string shaderCode = R"( + #ifdef VK_MODE + cbuffer Params : register(b0, space0) + #else + cbuffer MagnifierCB : register(b0) + #endif + { + float2 Resolution; // Screen or texture resolution in pixels + float2 CursorPos; // Cursor position in pixel coordinates + float2 Offset; // Offset of the lens relative to the cursor (in pixels) + float Radius; // Radius of the magnifying glass (in pixels) + int ZoomFactor; // Integer scaling multiplier (e.g., 2, 3, 4) + float BorderThickness; // Thickness of the black border (in pixels) + float3 Padding; // Padding to maintain 16-byte alignment + }; + + #ifdef VK_MODE + [[vk::binding(1, 0)]] + #endif + Texture2D InTexture : register(t0); + + #ifdef VK_MODE + [[vk::binding(2, 0)]] + #endif + RWTexture2D OutTexture : register(u0); + + [numthreads(16, 16, 1)] + void CSMain(uint3 dispatchThreadId : SV_DispatchThreadID) + { + // 1. Boundary Guard: Ensure threads outside the texture dimensions do not execute + if (dispatchThreadId.x >= (uint) Resolution.x || dispatchThreadId.y >= (uint) Resolution.y) + { + return; + } + + // 2. Determine the current pixel coordinate + int2 currentPixelInt = dispatchThreadId.xy; + float2 currentPixel = float2(currentPixelInt); + + // 3. Calculate the center of the magnifying lens + float2 lensCenter = CursorPos + Offset; + + // 4. Find the distance from the current pixel to the lens center + float2 vecToCenter = currentPixel - lensCenter; + float dist = length(vecToCenter); + + float4 finalColor; + + // 5. Outside the magnifier: Render the normal, unscaled image + if (dist > Radius) + { + finalColor = InTexture.Load(int3(currentPixelInt, 0)); + } + // 6. Border: Render a black outline + else if (dist > Radius - BorderThickness) + { + finalColor = float4(0.0f, 0.0f, 0.0f, 1.0f); // Black border + } + // 7. Inside the magnifier: Apply integer scaling + else + { + int maxZoom = max(1, ZoomFactor); // Prevent division by zero + float2 scaledOffset = floor(vecToCenter / (float) maxZoom); + + // Calculate the source pixel coordinate around the actual cursor position + int2 srcPixel = int2(CursorPos + scaledOffset); + + // Clamp coordinates to ensure we don't sample outside the texture bounds + srcPixel = clamp(srcPixel, int2(0, 0), int2(Resolution) - int2(1, 1)); + + finalColor = InTexture.Load(int3(srcPixel, 0)); + } + + // 8. Write the final calculated pixel back to the UAV + OutTexture[currentPixelInt] = finalColor; + } + )"; + void FilloutStruct(float Width, float Height, InternalMagnifierParams& InternalStruct); public: bool ShouldRun(); }; - -static std::string shaderCode = R"( -cbuffer MagnifierCB : register(b0) -{ - float2 Resolution; // Screen or texture resolution in pixels - float2 CursorPos; // Cursor position in pixel coordinates - float2 Offset; // Offset of the lens relative to the cursor (in pixels) - float Radius; // Radius of the magnifying glass (in pixels) - int ZoomFactor; // Integer scaling multiplier (e.g., 2, 3, 4) - float BorderThickness; // Thickness of the black border (in pixels) - float3 Padding; // Padding to maintain 16-byte alignment -}; - -Texture2D InTexture : register(t0); -RWTexture2D OutTexture : register(u0); - -[numthreads(16, 16, 1)] -void CSMain(uint3 dispatchThreadId : SV_DispatchThreadID) -{ - // 1. Boundary Guard: Ensure threads outside the texture dimensions do not execute - if (dispatchThreadId.x >= (uint) Resolution.x || dispatchThreadId.y >= (uint) Resolution.y) - { - return; - } - - // 2. Determine the current pixel coordinate - int2 currentPixelInt = dispatchThreadId.xy; - float2 currentPixel = float2(currentPixelInt); - - // 3. Calculate the center of the magnifying lens - float2 lensCenter = CursorPos + Offset; - - // 4. Find the distance from the current pixel to the lens center - float2 vecToCenter = currentPixel - lensCenter; - float dist = length(vecToCenter); - - float4 finalColor; - - // 5. Outside the magnifier: Render the normal, unscaled image - if (dist > Radius) - { - finalColor = InTexture.Load(int3(currentPixelInt, 0)); - } - // 6. Border: Render a black outline - else if (dist > Radius - BorderThickness) - { - finalColor = float4(0.0f, 0.0f, 0.0f, 1.0f); // Black border - } - // 7. Inside the magnifier: Apply integer scaling - else - { - int maxZoom = max(1, ZoomFactor); // Prevent division by zero - float2 scaledOffset = floor(vecToCenter / (float) maxZoom); - - // Calculate the source pixel coordinate around the actual cursor position - int2 srcPixel = int2(CursorPos + scaledOffset); - - // Clamp coordinates to ensure we don't sample outside the texture bounds - srcPixel = clamp(srcPixel, int2(0, 0), int2(Resolution) - int2(1, 1)); - - finalColor = InTexture.Load(int3(srcPixel, 0)); - } - - // 8. Write the final calculated pixel back to the UAV - OutTexture[currentPixelInt] = finalColor; -} -)";