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
This commit is contained in:
FakeMichau committed 2026-09-14 23:13:38 +02:00
1 parent d394e4b000
commit ebc2d31dec
14 files changed
+455 -100

No files matched your search

+3
View File
@@ -333,6 +333,7 @@ copy NUL "$(SolutionDir)x64\Release\a\!! EXTRACT ALL FILES TO GAME FOLDER !!" /Y
<ClInclude Include="hooks\LibraryLoad_Hooks.h" />
<ClInclude Include="hooks\CommandBuffer_StateTracker.h" />
<ClInclude Include="framegen\nvngx\IFGNvngx.h" />
<ClInclude Include="shaders\hud_copy\HudCopy_Vk.h" />
<ClInclude Include="inputs\FG\Streamline_Inputs_Sl1_Dx12.h" />
<ClInclude Include="include\device_info\device_info.hpp" />
<ClInclude Include="inputs\FG\Upscaler_Inputs_Dx11wDx12.h" />
@@ -340,6 +341,7 @@ copy NUL "$(SolutionDir)x64\Release\a\!! EXTRACT ALL FILES TO GAME FOLDER !!" /Y
<ClInclude Include="low_latency\input\input_reflex.h" />
<ClInclude Include="low_latency\input\input_xell.h" />
<ClInclude Include="low_latency\input\input_antilag2.h" />
<ClInclude Include="shaders\hud_copy\precompile\HudCopy_Shader_Vk.h" />
<ClInclude Include="shaders\magnifier\Magnifier_Dx11.h" />
<ClInclude Include="menu\input\input_system.h" />
<ClInclude Include="menu\input\input_system_internal.h" />
@@ -621,6 +623,7 @@ copy NUL "$(SolutionDir)x64\Release\a\!! EXTRACT ALL FILES TO GAME FOLDER !!" /Y
<ClCompile Include="hooks\LibraryLoad_Hooks.cpp" />
<ClCompile Include="hooks\VulkanwDx12_Hooks.cpp" />
<ClCompile Include="hooks\Xell_Hooks.cpp" />
<ClCompile Include="shaders\hud_copy\HudCopy_Vk.cpp" />
<ClCompile Include="inputs\FG\Streamline_Inputs_Sl1_Dx12.cpp" />
<ClCompile Include="include\device_info\device_info.cpp" />
<ClCompile Include="inputs\FG\Upscaler_Inputs_Dx11wDx12.cpp" />
+9
View File
@@ -956,6 +956,12 @@
<ClInclude Include="shaders\magnifier\precompile\Magnifier_Shader_Vk.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="shaders\hud_copy\HudCopy_Vk.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="shaders\hud_copy\precompile\HudCopy_Shader_Vk.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Config.cpp">
@@ -1544,6 +1550,9 @@
<ClCompile Include="shaders\magnifier\Magnifier_Vk.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="shaders\hud_copy\HudCopy_Vk.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="OptiScaler.rc" />
+51 -3
View File
@@ -12,6 +12,7 @@
#include "Nvngx_FFX.h"
#include "Nvngx_Combo.h"
#include <imgui/ImGuiNotify.hpp>
#include <nvsdk_ngx_vk.h>
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_Dx12>("HudCopy", device);
if (_hudCopyDx12.get() == nullptr)
_hudCopyDx12 = std::make_unique<HudCopy_Dx12>("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_Vk>("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_Vk>("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_Vk>("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);
+3 -1
View File
@@ -5,6 +5,7 @@
#include "proxies/NVNGX_Proxy.h"
#include "proxies/Ntdll_Proxy.h"
#include <shaders/hud_copy/HudCopy_Dx12.h>
#include <shaders/hud_copy/HudCopy_Vk.h>
#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<IFGNvngx> _provider;
static inline std::unique_ptr<HudCopy_Dx12> _hudCopy;
static inline std::unique_ptr<HudCopy_Dx12> _hudCopyDx12;
static inline std::unique_ptr<HudCopy_Vk> _hudCopyVk;
static IFGNvngx* getProvider();
+1 -1
View File
@@ -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,
+43 -20
View File
@@ -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<float3> Hudless : register(t0);
Texture2D<float3> 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<float3> Present : register(u0);
#ifdef VK_MODE
[[vk::binding(1, 0)]]
#endif
Texture2D<float3> 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<float3> 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<float3> 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;
}
)";
};
+2 -2
View File
@@ -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 =
+2 -6
View File
@@ -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;
+142
View File
@@ -0,0 +1,142 @@
#include "pch.h"
#include "HudCopy_Vk.h"
#include <Config.h>
#include <State.h>
#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<VkDescriptorSetLayoutBinding> 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<VkDescriptorPoolSize> 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<char> 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, &copyRegion);
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<VkWriteDescriptorSet> 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<uint32_t>(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, &copyRegion);
// 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;
}
+17
View File
@@ -0,0 +1,17 @@
#pragma once
#include "HudCopy_Common.h"
#include <shaders/Shader_Vk.h>
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);
};
@@ -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<float3> Hudless : register(t0);
#ifdef VK_MODE
[[vk::binding(2, 0)]]
#endif
Texture2D<float3> PresentCopy : register(t1);
#ifdef VK_MODE
[[vk::binding(3, 0)]]
#endif
RWTexture2D<float3> Present : register(u0);
[numthreads(16, 16, 1)]
@@ -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
};
+78 -67
View File
@@ -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<float4> InTexture : register(t0);
#ifdef VK_MODE
[[vk::binding(2, 0)]]
#endif
RWTexture2D<float4> 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<float4> InTexture : register(t0);
RWTexture2D<float4> 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;
}
)";