Burton2000 commited on
Commit
3feb49c
·
1 Parent(s): ad93d33

nss_v1_update (#11)

Browse files

- Update for NSS v1 (72afdb859e1e1b400cdca9b913417626ea9e8123)

This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. README.md +97 -56
  2. v1/nss_v1_high_fp32.pt → nss_v1_high_fp32.pt +0 -0
  3. v1/nss_v1_high_int8.pt → nss_v1_high_int8.pt +0 -0
  4. v1/nss_v1_mid_low_fp32.pt → nss_v1_high_int8.vgf +2 -2
  5. nss_v1_high_int8_metadata.json +36 -0
  6. v1/nss_v1_mid_low_int8.pt → nss_v1_mid_low_int8.pt +2 -2
  7. nss_v1_mid_low_int8.vgf +3 -0
  8. nss_v1_mid_low_int8_metadata.json +36 -0
  9. scenario/0_depth_scatter.comp +234 -0
  10. scenario/0_depth_scatter_init.comp +43 -0
  11. scenario/0_disocclusion_mask_lq.frag +30 -0
  12. scenario/0_disocclusion_mask_lq_shared.h +167 -0
  13. scenario/1_pre_process.frag +88 -0
  14. scenario/1_pre_process_shared.h +910 -0
  15. scenario/3_post_process.frag +69 -0
  16. scenario/3_post_process_shared.h +945 -0
  17. scenario/assets/960x540_1920x1080/0_depth_scatter_push_consts__960x540_1920x1080_high_fragment.npy +3 -0
  18. scenario/assets/960x540_1920x1080/0_depth_scatter_push_consts__960x540_1920x1080_low_fragment.npy +3 -0
  19. scenario/assets/960x540_1920x1080/0_depth_scatter_push_consts__960x540_1920x1080_mid_fragment.npy +3 -0
  20. scenario/assets/960x540_1920x1080/1_pre_process_push_consts__960x540_1920x1080_high_fragment.npy +3 -0
  21. scenario/assets/960x540_1920x1080/1_pre_process_push_consts__960x540_1920x1080_low_fragment.npy +3 -0
  22. scenario/assets/960x540_1920x1080/1_pre_process_push_consts__960x540_1920x1080_mid_fragment.npy +3 -0
  23. scenario/assets/960x540_1920x1080/2_nss-480x270-kpn16-v1_0_1.vgf +3 -0
  24. scenario/assets/960x540_1920x1080/2_nss-960x540-v1_0_1.vgf +3 -0
  25. scenario/assets/960x540_1920x1080/3_post_process_push_consts__960x540_1920x1080_high_fragment.npy +3 -0
  26. scenario/assets/960x540_1920x1080/3_post_process_push_consts__960x540_1920x1080_low_fragment.npy +3 -0
  27. scenario/assets/960x540_1920x1080/3_post_process_push_consts__960x540_1920x1080_mid_fragment.npy +3 -0
  28. scenario/assets/960x540_1920x1080/in_colour.dds +3 -0
  29. scenario/assets/960x540_1920x1080/in_depth.dds +3 -0
  30. scenario/assets/960x540_1920x1080/in_depth_scatter_init-240x135__960x540_1920x1080_low_fragment.dds +3 -0
  31. scenario/assets/960x540_1920x1080/in_depth_scatter_init-240x135__960x540_1920x1080_mid_fragment.dds +3 -0
  32. scenario/assets/960x540_1920x1080/in_depth_scatter_init-480x270__960x540_1920x1080_high_fragment.dds +3 -0
  33. scenario/assets/960x540_1920x1080/in_derivative_tm1-480x272__960x540_1920x1080_low_fragment.dds +3 -0
  34. scenario/assets/960x540_1920x1080/in_derivative_tm1-480x272__960x540_1920x1080_mid_fragment.dds +3 -0
  35. scenario/assets/960x540_1920x1080/in_derivative_tm1-960x544__960x540_1920x1080_high_fragment.dds +3 -0
  36. scenario/assets/960x540_1920x1080/in_history.dds +3 -0
  37. scenario/assets/960x540_1920x1080/in_motion.dds +3 -0
  38. scenario/assets/960x540_1920x1080/in_temporal_tm1-480x272__960x540_1920x1080_low_fragment.dds +3 -0
  39. scenario/assets/960x540_1920x1080/in_temporal_tm1-480x272__960x540_1920x1080_mid_fragment.dds +3 -0
  40. scenario/assets/960x540_1920x1080/in_temporal_tm1-960x544__960x540_1920x1080_high_fragment.dds +3 -0
  41. scenario/common.h +52 -97
  42. scenario/configs/960x540_1920x1080_high_fragment.json +722 -0
  43. scenario/configs/960x540_1920x1080_low_fragment.json +838 -0
  44. scenario/configs/960x540_1920x1080_mid_fragment.json +838 -0
  45. scenario/fullscreen_triangle.vert +24 -0
  46. scenario/typedefs.h +13 -12
  47. nss_v0.1.0_fp32.pt → v0_1/nss_v0.1.0_fp32.pt +0 -0
  48. nss_v0.1.1_int8.pt → v0_1/nss_v0.1.1_int8.pt +0 -0
  49. nss_v0.1.1_int8.vgf → v0_1/nss_v0.1.1_int8.vgf +0 -0
  50. nss_v0.1.1_int8_metadata.json → v0_1/nss_v0.1.1_int8_metadata.json +0 -0
README.md CHANGED
@@ -12,9 +12,22 @@ language:
12
 
13
  # Neural Super Sampling (NSS)
14
 
15
- Neural Super Sampling (NSS) is an innovative, efficient network for temporal super sampling on mobile devices. Content rendered at 540p can be upscaled to 1080p, resulting in up to 50% GPU savings. With our retraining tools content creators and game studios can build derivatives of the model suited to artwork style and performance requirements.
16
-
17
- ### 🎥 Neural Super Sampling Demo
 
 
 
 
 
 
 
 
 
 
 
 
 
18
 
19
  <video controls width="100%">
20
  <source src="https://huggingface.co/Arm/neural-super-sampling/resolve/main/resources/Enchanted_Castle_NSS_Demo.mp4" type="video/mp4">
@@ -25,53 +38,57 @@ Neural Super Sampling (NSS) is an innovative, efficient network for temporal sup
25
 
26
  Neural Super Sampling (NSS) is a parameter prediction model for real-time temporal super sampling developed by Arm, optimized for execution on Neural Accelerators (NX) in mobile GPUs. It enables high-resolution rendering at a lower compute cost by reconstructing high-quality output frames from low-resolution temporal inputs. NSS is particularly suited for mobile gaming, XR, and other power-constrained graphics use cases.
27
 
28
- - **Developed by:** Arm Limited
29
- - **Model type:** Temporal image super sampling
30
- - **License:** Other
31
- - **Repository:** [Neural Graphics Model Gym](https://github.com/arm/neural-graphics-model-gym)
32
- - **Blog:** [How Neural Super Sampling Works](https://community.arm.com/arm-community-blogs/b/mobile-graphics-and-gaming-blog/posts/how-arm-neural-super-sampling-works)
33
- - **Paper:** [Mobile Neural Super Sampling](https://huggingface.co/Arm/neural-super-sampling/blob/main/2025-neural-super-sampling.pdf)
34
- - **Quickstart with ML extensions for Vulkan®**: [ML extensions for Vulkan® Quickstart Guide](https://learn.arm.com/learning-paths/mobile-graphics-and-gaming/vulkan-ml-sample/)
35
- - **Quickstart with Unreal**: [Neural Super Sampling Quickstart Guide](https://learn.arm.com/learning-paths/mobile-graphics-and-gaming/nss-unreal/) for NSS integration into Unreal Engine
36
 
37
- NSS is under active development with regular updates planned. As we increase the size and diversity of the training dataset we expect to see significant quality improvements. Follow Arm to stay up to date on the latest releases.
38
 
39
- The model is released under Arm's [AI Model Community License](https://huggingface.co/Arm/neural-super-sampling/blob/main/Arm_AI_Model_Community_License_v1_0_PRE-1154.pdf) which allows NSS to be retrained on datasets captured from your own content. Future releases of the [Neural Graphics Model Gym](https://github.com/arm/neural-graphics-model-gym) will provide the tools to capture and convert content for use in (re)retraining.
 
 
 
 
 
 
 
 
 
40
 
41
- ## Uses
42
 
43
- NSS can be directly integrated into graphics pipelines using ML extensions for Vulkan®. See included ML SDK for Vulkan [scenario](https://huggingface.co/Arm/neural-super-sampling/tree/main/scenario) for the simplest way to evaluate the model. The scenario includes the necessary pre- and post-processing compute shaders along with a single frame worth of input data.
44
 
45
- The recommended way of integrating the model into a graphics pipeline is by using the [VGF Library](https://github.com/arm/ai-ml-sdk-vgf-library/tree/main) from the ML SDK for Vulkan.
46
 
47
- NSS is released under a [permissive license](https://huggingface.co/Arm/neural-super-sampling/blob/main/Arm_AI_Model_Community_License_v1_0_PRE-1154.pdf) designed to foster innovation in the graphics industry and provide differentiation to content creators.
48
 
49
- ### Direct Use
50
 
51
- NSS has been integrated into Unreal Engine via the [NSS Plugin for Unreal Engine](https://github.com/arm/neural-graphics-for-unreal/). See our [quick start guide](https://learn.arm.com/learning-paths/mobile-graphics-and-gaming/nss-unreal/) for step-by-step instructions on how to use NSS in Unreal® Engine.
52
 
53
- ### Out-of-Scope Use
54
 
55
- - Not suited for non-temporal tasks such as a standalone image upsampling
56
 
57
- ## Bias, Risks, and Limitations
58
 
59
- - Requires accurate motion vectors and frame history for stable output
60
- - May underperform in extremely low framerate scenarios (<10 FPS) with fast camera movement
61
- - Padding of the input is needed if input dimensions are not divisible by 8
62
 
63
- ### Recommendations
64
 
65
- For ultra-low-FPS use cases, reduce the camera speed, acceleration, or both so that the relative motion between frames mimics the
66
- application running at a higher frame rate.
 
67
 
68
- ## How to Get Started with the Model
69
 
70
- This repository contains pre-trained weights and a compiled NSS model in VGF format, ready for integration with Vulkan applications.
71
 
72
- The included Scenario demonstrates full execution of the model on a Vulkan compute-capable system. An Emulation Layer is provided to implement ML Extensions for Vulkan where it is not supported by the native Vulkan driver.
73
 
74
- ### Download and Prepare the Scenario
75
 
76
  These instructions will work on both Windows and Linux. On Windows, we strongly recommend the use of PowerShell over `cmd.exe` ("Command Prompt").
77
 
@@ -84,7 +101,7 @@ cd neural-super-sampling
84
  git lfs pull
85
  ```
86
 
87
- ### Install the Scenario Runner and Emulation Layers
88
 
89
  1. Follow the steps in the Python documentation's ["Create a new virtual environment"](https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/#create-a-new-virtual-environment) guide. We will assume below that you installed this environment into a `.venv` subdirectory.
90
 
@@ -97,48 +114,69 @@ git lfs pull
97
  pip install ai-ml-sdk-scenario-runner ai-ml-emulation-layer-for-vulkan
98
  ```
99
 
100
- 4. The Emulation Layer's documentation explains how its environment variables should be configured on [Linux](https://github.com/arm/ai-ml-emulation-layer-for-vulkan/blob/main/README.md#usage-on-linux) and on [Windows](https://github.com/arm/ai-ml-emulation-layer-for-vulkan/blob/main/README.md#usage-on-windows). The following is a simplified summary, assuming that you are at the root of the NSS model repository.
 
 
 
 
 
 
 
101
 
102
- * On Linux, enter these commands into Bash:
103
- ```bash
104
- EMULATION_LAYER_DIR=$(find $PWD/.venv -name emulation_layer -type d)
105
- export LD_LIBRARY_PATH="$EMULATION_LAYER_DIR/deploy/lib:$LD_LIBRARY_PATH"
106
- export VK_LAYER_PATH="$EMULATION_LAYER_DIR/deploy/share/vulkan/explicit_layer.d:$VK_LAYER_PATH"
107
- export VK_INSTANCE_LAYERS="VK_LAYER_ML_Graph_Emulation:VK_LAYER_ML_Tensor_Emulation"
108
- ```
109
 
110
- * On Windows, enter these commands into PowerShell (`cmd.exe` requires a different syntax):
111
- ```powershell
112
- $env:VK_LAYER_PATH="$pwd\.venv\Lib\site-packages\emulation_layer\deploy\bin;$env:VK_LAYER_PATH"
113
- $env:VK_INSTANCE_LAYERS="VK_LAYER_ML_Graph_Emulation;VK_LAYER_ML_Tensor_Emulation"
114
- ```
115
 
116
- ### Run the Scenario
117
 
118
- - Execute the Scenario Runner:
119
 
120
  ```bash
121
- scenario-runner --scenario scenario/scenario.json --output out
122
  ```
123
 
124
- - Output images are encoded as `B10G11R11_UFLOAT`. This format is common for framebuffers but not widely supported by image viewers. Use [RenderDoc](https://renderdoc.org/) to view these images.
 
 
 
 
 
 
 
 
 
 
 
125
 
126
  ## Training and Evaluation
127
 
128
  For background on NSS architecture and training read our blog: [How Neural Super Sampling Works](https://community.arm.com/arm-community-blogs/b/mobile-graphics-and-gaming-blog/posts/how-arm-neural-super-sampling-works)
129
 
130
- Training and evaluation details, including model architecture code, training pipeline, and test configurations, are available at:
131
 
132
  - Model training code: <https://github.com/arm/neural-graphics-model-gym>
133
  - Examples and tutorials: <https://github.com/arm/neural-graphics-model-gym-examples>
134
  - Sample dataset: <https://huggingface.co/datasets/Arm/neural-graphics-dataset>
 
135
 
136
- ### 🔎 Model Explorer VGF extension
137
 
138
- The [VGF extension to Model Explorer](https://github.com/arm/vgf-adapter-model-explorer) provides a simple interface to visualize model and analyse VGF composition.
139
 
140
  ![Model Explorer screenshot](resources/model-explorer-screenshot.png)
141
 
 
 
 
 
 
 
 
 
 
 
 
 
142
  ## License
143
 
144
  - The license for the model source code can be found [here](https://github.com/arm/neural-graphics-model-gym/blob/main/LICENSES/Apache-2.0.txt).
@@ -148,13 +186,16 @@ The [VGF extension to Model Explorer](https://github.com/arm/vgf-adapter-model-e
148
 
149
  🧑‍🔬 More technical details about the model can be found in the [NSS Guide](https://developer.arm.com/documentation/111009/latest/).
150
 
151
- 👩🏽‍💻 Our [Neural Graphics Development Kit](https://developer.arm.com/mobile-graphics-and-gaming/neural-graphics) contains engine plugins, model training tools, code examples and extensive developer documentation.
152
 
153
  🙋🏻‍♀️ For questions or feedback please [start a discussion](https://huggingface.co/Arm/neural-super-sampling/discussions)
154
 
155
- ## Trademark notice
 
 
156
 
157
  * Arm® is a registered trademark of Arm Limited (or its subsidiaries) in the US and/or elsewhere.
158
  * Python® is a registered trademark of the Python Software Foundation.
159
- * Vulkan® is a registered trademark of the [Khronos® Group](https://www.khronos.org/legal/trademarks).
 
160
  * Windows® is a trademark of the Microsoft group of companies.
 
12
 
13
  # Neural Super Sampling (NSS)
14
 
15
+ <table>
16
+ <tr>
17
+ <td style="padding:12px">
18
+ <strong>⚡ NSS v1 is now available</strong><br>
19
+ • New architecture and trained weights.<br>
20
+ • Higher image quality compared to NSS v0.1, with comparable runtime performance.<br>
21
+ • Three quality modes (High, Mid, and Low) let you balance image quality and performance.<br>
22
+ • Updated example scenarios using fragment shaders.
23
+ </td>
24
+ </tr>
25
+ </table>
26
+ Neural Super Sampling (NSS) is an innovative, efficient network for temporal super sampling on mobile devices. Content rendered at a low resolution can be upscaled to a higher resolution, resulting in up to 50% GPU savings.
27
+
28
+ With our [retraining tools](https://github.com/arm/neural-graphics-model-gym) content creators and game studios can build derivatives of the model suited to artwork style and performance requirements.
29
+
30
+ ## 🎥 Neural Super Sampling Demo
31
 
32
  <video controls width="100%">
33
  <source src="https://huggingface.co/Arm/neural-super-sampling/resolve/main/resources/Enchanted_Castle_NSS_Demo.mp4" type="video/mp4">
 
38
 
39
  Neural Super Sampling (NSS) is a parameter prediction model for real-time temporal super sampling developed by Arm, optimized for execution on Neural Accelerators (NX) in mobile GPUs. It enables high-resolution rendering at a lower compute cost by reconstructing high-quality output frames from low-resolution temporal inputs. NSS is particularly suited for mobile gaming, XR, and other power-constrained graphics use cases.
40
 
41
+ NSS v1 provides three quality modes that allow you to balance image quality and runtime performance:
42
+ * `high`: highest runtime cost but best-quality option. Checks the current frame and depth/motion detail more thoroughly, uses a larger image filter for clean-up, and samples previous frames more accurately.
43
+ * `low`: lowest runtime cost but lowest-quality option. Uses lighter current-frame and depth/motion checks, and samples previous frames less accurately. May show more flicker or motion artifacts around fine detail and moving objects.
44
+ * `mid`: balanced option. Similar to `low` but samples previous frames more accurately, like `high`.
 
 
 
 
45
 
46
+ For a more detailed explanation of these quality modes, refer to the [Neural Graphics Model Gym documentation](https://github.com/arm/neural-graphics-model-gym/blob/main/docs/nss/nss_configuration.md).
47
 
48
+ <table>
49
+ <tr><td><strong>Developed By</strong></td><td>Arm Limited</td></tr>
50
+ <tr><td><strong>Model Type</strong></td><td>Temporal image super sampling</td></tr>
51
+ <tr><td><strong>License</strong></td><td>Other</td></tr>
52
+ <tr><td><strong>Repository</strong></td><td><a href="https://github.com/arm/neural-graphics-model-gym">Neural Graphics Model Gym</a></td></tr>
53
+ <tr><td><strong>Blog</strong></td><td><a href="https://community.arm.com/arm-community-blogs/b/mobile-graphics-and-gaming-blog/posts/how-arm-neural-super-sampling-works">How Neural Super Sampling Works</a></td></tr>
54
+ <tr><td><strong>Paper</strong></td><td><a href="https://huggingface.co/Arm/neural-super-sampling/blob/main/2025-neural-super-sampling.pdf">Mobile Neural Super Sampling</a></td></tr>
55
+ <tr><td><strong>Quickstart with ML Extensions for Vulkan®</strong></td><td><a href="https://learn.arm.com/learning-paths/mobile-graphics-and-gaming/vulkan-ml-sample/">ML Extensions for Vulkan® Learning Path</a></td></tr>
56
+ <tr><td><strong>Quickstart with Unreal®</strong></td><td><a href="https://learn.arm.com/learning-paths/mobile-graphics-and-gaming/nss-unreal/">NSS integration into Unreal® Engine Learning Path</a></td></tr>
57
+ </table>
58
 
59
+ NSS is under active development with regular updates planned. As we increase the size and diversity of the training dataset we expect to see significant quality improvements. Follow Arm to stay up to date on the latest releases.
60
 
61
+ The model is released under Arm's permissive [AI Model Community License](https://huggingface.co/Arm/neural-super-sampling/blob/main/Arm_AI_Model_Community_License_v1_0_PRE-1154.pdf), designed to foster innovation in the graphics industry and provide differentiation to content creators. It allows NSS to be retrained on datasets captured from your own content.
62
 
63
+ A [plugin](https://github.com/arm/neural-graphics-data-capture-for-unreal) for capturing data in Unreal Engine is available to capture your own content for use in (re)training or evaluation in the [Neural Graphics Model Gym](https://github.com/arm/neural-graphics-model-gym).
64
 
65
+ ------------------------------------------------------------------------
66
 
67
+ ## Integration
68
 
69
+ NSS can be directly integrated into graphics pipelines using ML Extensions for Vulkan.
70
 
71
+ The recommended way of integrating the model into a graphics pipeline is by using the [VGF Library](https://github.com/arm/ai-ml-sdk-vgf-library/tree/main) from the ML SDK for Vulkan.
72
 
73
+ ### Integration in Game Engines
74
 
75
+ NSS has been integrated into Unreal Engine via the [NSS Plugin for Unreal Engine](https://github.com/arm/neural-graphics-for-unreal/). See the [Learning Path](https://learn.arm.com/learning-paths/mobile-graphics-and-gaming/nss-unreal/) for step-by-step instructions on how to use NSS in Unreal Engine.
76
 
77
+ It is also available to use as part of the [Neural Graphics SDK for Game Engines](https://github.com/arm/neural-graphics-sdk-for-game-engines). This is designed to help integrate NSS across a wide variety of game engines.
 
 
78
 
79
+ ------------------------------------------------------------------------
80
 
81
+ ## Getting Started
82
+
83
+ This repository contains pre-trained weights and compiled NSS models in VGF format, ready for integration with Vulkan applications. These VGF models are unshaped, so will require developers to shape-specialize them before use. An example of how to do this can be seen in the [Neural Graphics SDK for Game Engines](https://github.com/arm/neural-graphics-sdk-for-game-engines/blob/f8df12935ef5743d7c7979751cef0c9a9c2f4e9d/sdk/src/backends/vk/ffx_vk.cpp#L137).
84
 
85
+ See the included ML SDK for Vulkan [scenarios](https://huggingface.co/Arm/neural-super-sampling/tree/main/scenario) for the simplest way to evaluate the model. The scenarios include the necessary pre- and post-processing fragment shaders along with a single frame worth of input data.
86
 
87
+ They demonstrate full execution of NSS on a Vulkan compute-capable system. The Emulation Layer can be used to implement ML Extensions for Vulkan where it is not supported by the native Vulkan driver.
88
 
89
+ Three different scenarios for high, mid, and low quality modes of NSS are provided. For demonstration purposes these work on a fixed size input, performing upsampling from 540p to 1080p.
90
 
91
+ ### 1. Clone the Repository
92
 
93
  These instructions will work on both Windows and Linux. On Windows, we strongly recommend the use of PowerShell over `cmd.exe` ("Command Prompt").
94
 
 
101
  git lfs pull
102
  ```
103
 
104
+ ### 2. Install the Scenario Runner and Emulation Layers
105
 
106
  1. Follow the steps in the Python documentation's ["Create a new virtual environment"](https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/#create-a-new-virtual-environment) guide. We will assume below that you installed this environment into a `.venv` subdirectory.
107
 
 
114
  pip install ai-ml-sdk-scenario-runner ai-ml-emulation-layer-for-vulkan
115
  ```
116
 
117
+ 4. The Emulation Layer package provides a helper, that prints the commands to set environment variables for your current platform and virtual environment:
118
+
119
+ * Enter the following command:
120
+ ```bash
121
+ emulation_layer --help
122
+ ```
123
+
124
+ Copy and run the commands it prints in the same shell you will use for scenario-runner.
125
 
126
+ On Linux this will set LD_LIBRARY_PATH, VK_LAYER_PATH, and VK_INSTANCE_LAYERS. On Windows it will set the equivalent PowerShell $env:VK_LAYER_PATH and $env:VK_INSTANCE_LAYERS variables.
 
 
 
 
 
 
127
 
128
+ For more help, the Emulation Layer's documentation explains how its environment variables should be configured on [Linux](https://github.com/arm/ai-ml-emulation-layer-for-vulkan/blob/main/README.md#usage-on-linux) and on [Windows](https://github.com/arm/ai-ml-emulation-layer-for-vulkan/blob/main/README.md#usage-on-windows).
 
 
 
 
129
 
130
+ ### 3. Run the Scenario
131
 
132
+ 1. Change your working directory to the `scenario` folder:
133
 
134
  ```bash
135
+ cd scenario
136
  ```
137
 
138
+ 2. Execute the Scenario Runner with your scenario of choice:
139
+
140
+ ```bash
141
+ scenario-runner --scenario configs/960x540_1920x1080_high_fragment.json --output out_high
142
+ scenario-runner --scenario configs/960x540_1920x1080_mid_fragment.json --output out_mid
143
+ scenario-runner --scenario configs/960x540_1920x1080_low_fragment.json --output out_low
144
+ ```
145
+
146
+ 3. Use [RenderDoc](https://renderdoc.org/) to view these images.
147
+ Output images are encoded as `B10G11R11_UFLOAT`. This format is common for framebuffers but not widely supported by image viewers.
148
+
149
+ ------------------------------------------------------------------------
150
 
151
  ## Training and Evaluation
152
 
153
  For background on NSS architecture and training read our blog: [How Neural Super Sampling Works](https://community.arm.com/arm-community-blogs/b/mobile-graphics-and-gaming-blog/posts/how-arm-neural-super-sampling-works)
154
 
155
+ Training and evaluation details, including model architecture code, training pipeline, test configurations and dataset capture plugins, are available at:
156
 
157
  - Model training code: <https://github.com/arm/neural-graphics-model-gym>
158
  - Examples and tutorials: <https://github.com/arm/neural-graphics-model-gym-examples>
159
  - Sample dataset: <https://huggingface.co/datasets/Arm/neural-graphics-dataset>
160
+ - Dataset capture plugin: <https://github.com/arm/neural-graphics-data-capture-for-unreal>
161
 
162
+ ## 🔎 Model Explorer VGF Extension
163
 
164
+ The [VGF extension to Model Explorer](https://github.com/arm/vgf-adapter-model-explorer) provides a simple interface to visualize and analyse the NSS model and any other VGF model.
165
 
166
  ![Model Explorer screenshot](resources/model-explorer-screenshot.png)
167
 
168
+ ## Biases, Risks, Limitations and Out-of-Scope Use
169
+
170
+ - Not suited for non-temporal tasks such as a standalone image upsampling
171
+ - Requires accurate motion vectors and frame history for stable output
172
+ - May underperform in extremely low framerate scenarios (<10 FPS) with fast camera movement
173
+ - Padding of the input is needed if input dimensions are not divisible by 8
174
+
175
+ ### Recommendations
176
+
177
+ For ultra-low-FPS use cases, reduce the camera speed, acceleration, or both so that the relative motion between frames mimics the
178
+ application running at a higher frame rate.
179
+
180
  ## License
181
 
182
  - The license for the model source code can be found [here](https://github.com/arm/neural-graphics-model-gym/blob/main/LICENSES/Apache-2.0.txt).
 
186
 
187
  🧑‍🔬 More technical details about the model can be found in the [NSS Guide](https://developer.arm.com/documentation/111009/latest/).
188
 
189
+ 👩🏽‍💻 Our [Neural Graphics Development Kit](https://developer.arm.com/mobile-graphics-and-gaming/neural-technology) contains engine plugins, model training tools, code examples and extensive developer documentation.
190
 
191
  🙋🏻‍♀️ For questions or feedback please [start a discussion](https://huggingface.co/Arm/neural-super-sampling/discussions)
192
 
193
+ ------------------------------------------------------------------------
194
+
195
+ ## Trademark Notice
196
 
197
  * Arm® is a registered trademark of Arm Limited (or its subsidiaries) in the US and/or elsewhere.
198
  * Python® is a registered trademark of the Python Software Foundation.
199
+ * Unreal® is a trademark or registered trademark of Epic Games, Inc. in the United States of America and elsewhere.
200
+ * Vulkan and the Vulkan logo are registered trademarks of the [Khronos Group Inc.](https://www.khronos.org/legal/trademarks).
201
  * Windows® is a trademark of the Microsoft group of companies.
v1/nss_v1_high_fp32.pt → nss_v1_high_fp32.pt RENAMED
File without changes
v1/nss_v1_high_int8.pt → nss_v1_high_int8.pt RENAMED
File without changes
v1/nss_v1_mid_low_fp32.pt → nss_v1_high_int8.vgf RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:2cc70c7d12ba1a2461d91f1b6d1150aa4b59012affef4666963b782323e9fe9a
3
- size 580519
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0aee36b193b5417c94f230e6a6d2abc78c1c293b689c34a9ceee7f59f9da6a42
3
+ size 164608
nss_v1_high_int8_metadata.json ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "inputs": {
3
+ "_PreprocessTensor": {
4
+ "SINT": {
5
+ "scale": 0.003912401385605335,
6
+ "zero_point": -128
7
+ },
8
+ "SNORM": {
9
+ "scale": 0.4968749759718776,
10
+ "zero_point": -1.0078740157480315
11
+ }
12
+ }
13
+ },
14
+ "outputs": {
15
+ "_KpnCoefficients": {
16
+ "SINT": {
17
+ "scale": 0.003937007859349251,
18
+ "zero_point": -127
19
+ },
20
+ "SNORM": {
21
+ "scale": 0.49999999813735485,
22
+ "zero_point": -1.0
23
+ }
24
+ },
25
+ "_TemporalTensor": {
26
+ "SINT": {
27
+ "scale": 0.003937007859349251,
28
+ "zero_point": -127
29
+ },
30
+ "SNORM": {
31
+ "scale": 0.49999999813735485,
32
+ "zero_point": -1.0
33
+ }
34
+ }
35
+ }
36
+ }
v1/nss_v1_mid_low_int8.pt → nss_v1_mid_low_int8.pt RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:1a0400453b70fb4a10bd6db18a37e7786071aa475305469ae66794bc597971be
3
- size 660665
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a313f05d4444ff318a495d16709f4f85c3bddec309d9e4ad591edb2a7570ac9e
3
+ size 662393
nss_v1_mid_low_int8.vgf ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1fab7a42b08f40ed859275106ddcd84a85855ae400ab5e6bf18ec7ec0eed5308
3
+ size 158800
nss_v1_mid_low_int8_metadata.json ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "inputs": {
3
+ "_PreprocessTensor": {
4
+ "SINT": {
5
+ "scale": 0.003919049631804228,
6
+ "zero_point": -128
7
+ },
8
+ "SNORM": {
9
+ "scale": 0.49771930323913693,
10
+ "zero_point": -1.0078740157480315
11
+ }
12
+ }
13
+ },
14
+ "outputs": {
15
+ "_KpnCoefficients": {
16
+ "SINT": {
17
+ "scale": 0.003937007859349251,
18
+ "zero_point": -127
19
+ },
20
+ "SNORM": {
21
+ "scale": 0.49999999813735485,
22
+ "zero_point": -1.0
23
+ }
24
+ },
25
+ "_TemporalTensor": {
26
+ "SINT": {
27
+ "scale": 0.003937007859349251,
28
+ "zero_point": -127
29
+ },
30
+ "SNORM": {
31
+ "scale": 0.49999999813735485,
32
+ "zero_point": -1.0
33
+ }
34
+ }
35
+ }
36
+ }
scenario/0_depth_scatter.comp ADDED
@@ -0,0 +1,234 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //
2
+ // -----------------------------------------------------------------------------
3
+ // The proprietary software and information contained in this file is
4
+ // confidential and may only be used by an authorized person under a valid
5
+ // licensing agreement from Arm Limited or its affiliates.
6
+ //
7
+ // Copyright (C) 2026 Arm Limited or its affiliates. All rights reserved.
8
+ //
9
+ // This entire notice must be reproduced on all copies of this file and
10
+ // copies of this file may only be made by an authorized person under a valid
11
+ // licensing agreement from Arm Limited or its affiliates.
12
+ // -----------------------------------------------------------------------------
13
+ //
14
+
15
+ #version 460
16
+ #extension GL_EXT_shader_16bit_storage : require
17
+ #extension GL_EXT_shader_explicit_arithmetic_types : require
18
+ #extension GL_EXT_shader_explicit_arithmetic_types_float16 : require
19
+ #extension GL_EXT_shader_explicit_arithmetic_types_float32 : require
20
+ #extension GL_GOOGLE_include_directive : enable
21
+
22
+ #include "typedefs.h"
23
+ // NSS v1 depth scatter shader.
24
+
25
+ #ifndef NSS_DEPTH_SCATTER_QUARTER_RES_INPUT
26
+ #define NSS_DEPTH_SCATTER_QUARTER_RES_INPUT 0
27
+ #endif // !NSS_DEPTH_SCATTER_QUARTER_RES_INPUT
28
+
29
+ //-----------------------------------------------------------------------------
30
+ // Resources
31
+ //-----------------------------------------------------------------------------
32
+ // Inputs are low-resolution frame-space textures.
33
+ // Output stores reconstructed previous-frame depth in uint format so we can
34
+ // use imageAtomics to merge multiple scatter contributions safely.
35
+ layout (set=0, binding=0) uniform mediump sampler2D _MotionTex; // 540p->1080p HQ/Low/Mid: 960x540 | R16G16_SFLOAT 32bpp | 1.978 MiB
36
+ layout (set=0, binding=1) uniform highp sampler2D _DepthTex; // 540p->1080p HQ/Low/Mid: 960x540 | R32_SFLOAT 32bpp | 1.978 MiB
37
+
38
+ layout (set=1, binding=0, r32ui) uniform uimage2D _OutDepth; // 540p->1080p HQ: 480x270 | R32_UINT 32bpp | imageAtomicMin target | 0.494 MiB ; Low/Mid: 240x135 | 0.124 MiB
39
+
40
+ //-----------------------------------------------------------------------------
41
+ // Push constants
42
+ //-----------------------------------------------------------------------------
43
+ // Mirrors the Slang struct layout exactly. `_RenderDims` is present for parity
44
+ // with Slang even though this GLSL path does not consume it directly.
45
+ layout(push_constant, std430) uniform PushConstants {
46
+ // ─────────────── 8-byte aligned ───────────────
47
+ // Source depth/motion extent divided by output depth-scatter extent.
48
+ layout(offset = 0) float2 _Scale; // 8 B
49
+ // Inverse of `_Scale`.
50
+ layout(offset = 8) float2 _InvScale; // 8 B
51
+ // Previous-depth output dimensions.
52
+ layout(offset = 16) int32_t2 _OutputDims; // 8 B
53
+ // Render-resolution dimensions kept for parity with the Slang path.
54
+ layout(offset = 24) float2 _RenderDims; // 8 B
55
+ // Inverse of `_OutputDims`.
56
+ layout(offset = 32) float2 _InvOutputDims; // 8 B
57
+ // Total: **40 bytes**
58
+ };
59
+
60
+ struct BilinearSamplingData {
61
+ int32_t2 iOffsets[4];
62
+ float fWeights[4];
63
+ int32_t2 iBasePos;
64
+ };
65
+
66
+ const float kMotionThreshold = 0.1;
67
+ const float kBilinearWeightThreshold = 0.1;
68
+ const float kDepthIntScale = 2147483647.0;
69
+ // 0 = original 4-tap bilinear scatter, 1 = fast single-tap scatter.
70
+ #define NSS_DEPTH_SCATTER_MODE 0
71
+
72
+ //-----------------------------------------------------------------------------
73
+ // Helpers
74
+ //-----------------------------------------------------------------------------
75
+ bool IsOnScreen(int32_t2 pos, int32_t2 size)
76
+ {
77
+ return all(lessThan(pos, size)) && all(greaterThanEqual(pos, int32_t2(0)));
78
+ }
79
+
80
+ BilinearSamplingData GetBilinearSamplingData(float2 uv, int32_t2 size)
81
+ {
82
+ BilinearSamplingData data;
83
+ float2 px = uv * float2(size) - float2(0.5);
84
+ data.iBasePos = int32_t2(floor(px));
85
+ float2 frac_px = fract(px);
86
+
87
+ data.iOffsets[0] = int32_t2(0, 0);
88
+ data.iOffsets[1] = int32_t2(1, 0);
89
+ data.iOffsets[2] = int32_t2(0, 1);
90
+ data.iOffsets[3] = int32_t2(1, 1);
91
+
92
+ data.fWeights[0] = (1.0 - frac_px.x) * (1.0 - frac_px.y);
93
+ data.fWeights[1] = frac_px.x * (1.0 - frac_px.y);
94
+ data.fWeights[2] = (1.0 - frac_px.x) * frac_px.y;
95
+ data.fWeights[3] = frac_px.x * frac_px.y;
96
+ return data;
97
+ }
98
+
99
+ void StoreReconstructedDepth(int32_t2 pixel, float depth)
100
+ {
101
+ // Lower depth wins for normal (non-inverted) depth.
102
+ // Keep integer encoding consistent with Slang's InterlockedMin path.
103
+ uint32_t i_depth = uint32_t(clamp(depth, 0.0, 1.0) * kDepthIntScale);
104
+ imageAtomicMin(_OutDepth, pixel, i_depth);
105
+ }
106
+
107
+ void ReconstructPrevDepth(float depth, float2 reprojected_uv)
108
+ {
109
+ int32_t2 out_size = _OutputDims;
110
+ #if (NSS_DEPTH_SCATTER_MODE == 1)
111
+ // Fast mode: single nearest tap (fewer atomics, lower LS pressure).
112
+ float2 px = reprojected_uv * float2(out_size) - float2(0.5);
113
+ int32_t2 base = int32_t2(floor(px));
114
+ float2 frac_px = fract(px);
115
+ int32_t2 nearest = base + int32_t2(int32_t(frac_px.x >= 0.5), int32_t(frac_px.y >= 0.5));
116
+ if (IsOnScreen(nearest, out_size)) {
117
+ StoreReconstructedDepth(nearest, depth);
118
+ }
119
+ #else
120
+ // Scatter one reprojected depth sample into up to 4 bilinear neighbors.
121
+ // This lets the later depth-clip stage read a denser previous-depth map.
122
+ BilinearSamplingData bilinear = GetBilinearSamplingData(reprojected_uv, out_size);
123
+
124
+ for (int32_t i = 0; i < 4; ++i) {
125
+ float w = bilinear.fWeights[i];
126
+ if (w > kBilinearWeightThreshold) {
127
+ int32_t2 store_pos = bilinear.iBasePos + bilinear.iOffsets[i];
128
+ if (IsOnScreen(store_pos, out_size)) {
129
+ StoreReconstructedDepth(store_pos, depth);
130
+ }
131
+ }
132
+ }
133
+ #endif // (NSS_DEPTH_SCATTER_MODE == 1)
134
+ }
135
+
136
+ layout(local_size_x = 8, local_size_y = 8) in;
137
+
138
+ void main()
139
+ {
140
+ //-------------------------------------------------------------------------
141
+ // 1) Dispatch guard and UV setup
142
+ //-------------------------------------------------------------------------
143
+ int32_t2 pixel = int32_t2(gl_GlobalInvocationID.xy);
144
+ if (any(greaterThanEqual(pixel, _OutputDims))) {
145
+ return;
146
+ }
147
+
148
+ float2 uv = (float2(pixel) + float2(0.5)) * _InvOutputDims;
149
+
150
+ //-------------------------------------------------------------------------
151
+ // 2) Select the nearest source sample inside the source footprint
152
+ //-------------------------------------------------------------------------
153
+ #if NSS_DEPTH_SCATTER_QUARTER_RES_INPUT
154
+ int32_t2 src_size = int32_t2(round(float2(_OutputDims) * _Scale));
155
+ int32_t2 src_base = int32_t2(float2(pixel) * _Scale);
156
+ float2 inv_src_size = _InvOutputDims * _InvScale;
157
+
158
+ // Use 4 gathers to cover the quarter-res 4x4 input footprint:
159
+ // q00: (0,0) (1,0) (0,1) (1,1)
160
+ // q10: (2,0) (3,0) (2,1) (3,1)
161
+ // q01: (0,2) (1,2) (0,3) (1,3)
162
+ // q11: (2,2) (3,2) (2,3) (3,3)
163
+ float4 d00 = textureGather(_DepthTex, (float2(src_base + int32_t2(0, 0)) + float2(0.5)) * inv_src_size, 0).wzxy;
164
+ float4 x00 = textureGather(_MotionTex, (float2(src_base + int32_t2(0, 0)) + float2(0.5)) * inv_src_size, 0).wzxy;
165
+ float4 y00 = textureGather(_MotionTex, (float2(src_base + int32_t2(0, 0)) + float2(0.5)) * inv_src_size, 1).wzxy;
166
+ float4 d10 = textureGather(_DepthTex, (float2(src_base + int32_t2(2, 0)) + float2(0.5)) * inv_src_size, 0).wzxy;
167
+ float4 x10 = textureGather(_MotionTex, (float2(src_base + int32_t2(2, 0)) + float2(0.5)) * inv_src_size, 0).wzxy;
168
+ float4 y10 = textureGather(_MotionTex, (float2(src_base + int32_t2(2, 0)) + float2(0.5)) * inv_src_size, 1).wzxy;
169
+ float4 d01 = textureGather(_DepthTex, (float2(src_base + int32_t2(0, 2)) + float2(0.5)) * inv_src_size, 0).wzxy;
170
+ float4 x01 = textureGather(_MotionTex, (float2(src_base + int32_t2(0, 2)) + float2(0.5)) * inv_src_size, 0).wzxy;
171
+ float4 y01 = textureGather(_MotionTex, (float2(src_base + int32_t2(0, 2)) + float2(0.5)) * inv_src_size, 1).wzxy;
172
+ float4 d11 = textureGather(_DepthTex, (float2(src_base + int32_t2(2, 2)) + float2(0.5)) * inv_src_size, 0).wzxy;
173
+ float4 x11 = textureGather(_MotionTex, (float2(src_base + int32_t2(2, 2)) + float2(0.5)) * inv_src_size, 0).wzxy;
174
+ float4 y11 = textureGather(_MotionTex, (float2(src_base + int32_t2(2, 2)) + float2(0.5)) * inv_src_size, 1).wzxy;
175
+
176
+ float3 result = float3(x00.x, y00.x, d00.x);
177
+
178
+ #define NSS_UPDATE_NEAREST_STEP(OFF_X, OFF_Y, DEPTH, MOTION_X, MOTION_Y) \
179
+ { \
180
+ int32_t2 _src = src_base + int32_t2((OFF_X), (OFF_Y)); \
181
+ float _d = (DEPTH); \
182
+ float _take = float(IsOnScreen(_src, src_size)) * step(_d, result.z); \
183
+ result = mix(result, float3((MOTION_X), (MOTION_Y), _d), _take); \
184
+ }
185
+
186
+ NSS_UPDATE_NEAREST_STEP(1, 0, d00.y, x00.y, y00.y);
187
+ NSS_UPDATE_NEAREST_STEP(0, 1, d00.z, x00.z, y00.z);
188
+ NSS_UPDATE_NEAREST_STEP(1, 1, d00.w, x00.w, y00.w);
189
+ NSS_UPDATE_NEAREST_STEP(2, 0, d10.x, x10.x, y10.x);
190
+ NSS_UPDATE_NEAREST_STEP(3, 0, d10.y, x10.y, y10.y);
191
+ NSS_UPDATE_NEAREST_STEP(2, 1, d10.z, x10.z, y10.z);
192
+ NSS_UPDATE_NEAREST_STEP(3, 1, d10.w, x10.w, y10.w);
193
+ NSS_UPDATE_NEAREST_STEP(0, 2, d01.x, x01.x, y01.x);
194
+ NSS_UPDATE_NEAREST_STEP(1, 2, d01.y, x01.y, y01.y);
195
+ NSS_UPDATE_NEAREST_STEP(0, 3, d01.z, x01.z, y01.z);
196
+ NSS_UPDATE_NEAREST_STEP(1, 3, d01.w, x01.w, y01.w);
197
+ NSS_UPDATE_NEAREST_STEP(2, 2, d11.x, x11.x, y11.x);
198
+ NSS_UPDATE_NEAREST_STEP(3, 2, d11.y, x11.y, y11.y);
199
+ NSS_UPDATE_NEAREST_STEP(2, 3, d11.z, x11.z, y11.z);
200
+ NSS_UPDATE_NEAREST_STEP(3, 3, d11.w, x11.w, y11.w);
201
+
202
+ #undef NSS_UPDATE_NEAREST_STEP
203
+ #else
204
+ // Match Slang gather ordering by swizzling GLSL `textureGather` result.
205
+ // The target order is TL, TR, BL, BR.
206
+ float4 dquad = textureGather(_DepthTex, uv, 0).wzxy;
207
+ float4 xquad = textureGather(_MotionTex, uv, 0).wzxy;
208
+ float4 yquad = textureGather(_MotionTex, uv, 1).wzxy;
209
+
210
+ // Choose the motion/depth sample corresponding to nearest depth.
211
+ float3 result = float3(xquad.x, yquad.x, dquad.x);
212
+ result = mix(result, float3(xquad.y, yquad.y, dquad.y), step(dquad.y, result.z));
213
+ result = mix(result, float3(xquad.z, yquad.z, dquad.z), step(dquad.z, result.z));
214
+ result = mix(result, float3(xquad.w, yquad.w, dquad.w), step(dquad.w, result.z));
215
+ #endif // NSS_DEPTH_SCATTER_QUARTER_RES_INPUT
216
+
217
+ //-------------------------------------------------------------------------
218
+ // 3) Motion conditioning and reprojection
219
+ //-------------------------------------------------------------------------
220
+ float depth_dilated = result.z;
221
+ float2 motion = result.xy * _InvScale;
222
+ #if NSS_DEPTH_SCATTER_QUARTER_RES_INPUT
223
+ motion *= float(length(result.xy) > kMotionThreshold); // suppress tiny vectors before 135p scaling
224
+ #else
225
+ motion *= float(length(motion) > kMotionThreshold); // suppress tiny vectors
226
+ #endif // NSS_DEPTH_SCATTER_QUARTER_RES_INPUT
227
+ motion *= _InvOutputDims; // px -> uv
228
+
229
+ //-------------------------------------------------------------------------
230
+ // 4) Scatter reconstructed previous depth
231
+ //-------------------------------------------------------------------------
232
+ float2 reproj_uv = uv - motion;
233
+ ReconstructPrevDepth(depth_dilated, reproj_uv);
234
+ }
scenario/0_depth_scatter_init.comp ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //
2
+ // -----------------------------------------------------------------------------
3
+ // The proprietary software and information contained in this file is
4
+ // confidential and may only be used by an authorized person under a valid
5
+ // licensing agreement from Arm Limited or its affiliates.
6
+ //
7
+ // Copyright (C) 2026 Arm Limited or its affiliates. All rights reserved.
8
+ //
9
+ // This entire notice must be reproduced on all copies of this file and
10
+ // copies of this file may only be made by an authorized person under a valid
11
+ // licensing agreement from Arm Limited or its affiliates.
12
+ // -----------------------------------------------------------------------------
13
+ //
14
+
15
+ #version 460
16
+ #extension GL_EXT_shader_explicit_arithmetic_types : require
17
+ #extension GL_GOOGLE_include_directive : enable
18
+
19
+ #include "typedefs.h"
20
+
21
+ layout(set=0, binding=0, r32ui) uniform uimage2D _OutDepth; // 540p->1080p HQ: 480x270 | R32_UINT 32bpp | depth-scatter clear target | 0.494 MiB ; Low/Mid: 240x135 | 0.124 MiB
22
+
23
+ layout(push_constant, std430) uniform PushConstants {
24
+ // ─────────────── 16-byte ABI prefix reused from depth scatter ───────────────
25
+ // Offsets [0, 15] belong to the full depth-scatter push-constant blob and
26
+ // are intentionally ignored by this clear pass.
27
+
28
+ // ─────────────── 8-byte aligned ───────────────
29
+ // Previous-depth output dimensions used for the clear-pass dispatch guard.
30
+ layout(offset = 16) int32_t2 _OutputDims; // 8 B
31
+ // Total accessed range: **24 bytes** (shared ABI blob is 40 bytes)
32
+ };
33
+
34
+ layout(local_size_x = 8, local_size_y = 8) in;
35
+
36
+ void main()
37
+ {
38
+ int32_t2 pixel = int32_t2(gl_GlobalInvocationID.xy);
39
+ if (any(greaterThanEqual(pixel, _OutputDims))) {
40
+ return;
41
+ }
42
+ imageStore(_OutDepth, pixel, uvec4(uint(0x7fffffff), 0u, 0u, 0u));
43
+ }
scenario/0_disocclusion_mask_lq.frag ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //
2
+ // -----------------------------------------------------------------------------
3
+ // The proprietary software and information contained in this file is
4
+ // confidential and may only be used by an authorized person under a valid
5
+ // licensing agreement from Arm Limited or its affiliates.
6
+ //
7
+ // Copyright (C) 2026 Arm Limited or its affiliates. All rights reserved.
8
+ //
9
+ // This entire notice must be reproduced on all copies of this file and
10
+ // copies of this file may only be made by an authorized person under a valid
11
+ // licensing agreement from Arm Limited or its affiliates.
12
+ // -----------------------------------------------------------------------------
13
+ //
14
+
15
+ #version 460
16
+ #extension GL_EXT_shader_explicit_arithmetic_types : require
17
+ #extension GL_EXT_shader_explicit_arithmetic_types_float32 : require
18
+ #extension GL_GOOGLE_include_directive : enable
19
+
20
+ #include "0_disocclusion_mask_lq_shared.h"
21
+
22
+ layout(location = 0) out mediump float _OutDisocclusionMask;
23
+
24
+ void main()
25
+ {
26
+ int32_t2 pixel = int32_t2(gl_FragCoord.xy);
27
+ int32_t2 depth_size = textureSize(_DepthTm1Tex, 0);
28
+
29
+ _OutDisocclusionMask = LqDisocclusionComputeMask(pixel, depth_size);
30
+ }
scenario/0_disocclusion_mask_lq_shared.h ADDED
@@ -0,0 +1,167 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //
2
+ // -----------------------------------------------------------------------------
3
+ // The proprietary software and information contained in this file is
4
+ // confidential and may only be used by an authorized person under a valid
5
+ // licensing agreement from Arm Limited or its affiliates.
6
+ //
7
+ // Copyright (C) 2026 Arm Limited or its affiliates. All rights reserved.
8
+ //
9
+ // This entire notice must be reproduced on all copies of this file and
10
+ // copies of this file may only be made by an authorized person under a valid
11
+ // licensing agreement from Arm Limited or its affiliates.
12
+ // -----------------------------------------------------------------------------
13
+ //
14
+
15
+ #ifndef NSS_V1_DISOCCLUSION_MASK_LQ_SHARED_H
16
+ #define NSS_V1_DISOCCLUSION_MASK_LQ_SHARED_H
17
+
18
+ #include "typedefs.h"
19
+ #include "common.h"
20
+
21
+ layout (set=0, binding=0) uniform mediump sampler2D _MotionTex;
22
+ layout (set=0, binding=1) uniform highp sampler2D _DepthTex;
23
+ layout (set=0, binding=2) uniform highp usampler2D _DepthTm1Tex;
24
+
25
+ layout(push_constant, std430) uniform PushConstants {
26
+ layout(offset = 0) float4 _DeviceToViewDepth;
27
+ layout(offset = 16) float4 _JitterOffset;
28
+ layout(offset = 32) float4 _JitterOffsetTm1;
29
+ layout(offset = 48) float2 _Scale;
30
+ layout(offset = 56) float2 _InvScale;
31
+ layout(offset = 64) int32_t2 _OutputDims;
32
+ layout(offset = 72) int32_t2 _InputDims;
33
+ layout(offset = 80) int32_t2 _PaddedDims;
34
+ layout(offset = 88) float2 _InvOutputDims;
35
+ layout(offset = 96) float2 _InvInputDims;
36
+ layout(offset = 104) float2 _InvPaddedDims;
37
+ layout(offset = 112) float2 _InvDepthTm1Dims;
38
+ layout(offset = 120) float2 _RenderSize;
39
+ layout(offset = 128) float2 _Exposure;
40
+ layout(offset = 136) float _DepthClipRequiredSepScale;
41
+ layout(offset = 140) float _DepthClipPower;
42
+ };
43
+
44
+ const float kLqDisocclusionEps = 1e-7;
45
+ const float kLqDisocclusionDepthScale = 2147483647.0;
46
+ const float kLqDisocclusionInvDepthScale = 1.0 / kLqDisocclusionDepthScale;
47
+ const float kLqDisocclusionMotionThreshold = 0.1;
48
+
49
+ #ifndef NSS_LQ_DISOCCLUSION_DEPTH_GRADIENT_TOLERANCE_SCALE
50
+ #define NSS_LQ_DISOCCLUSION_DEPTH_GRADIENT_TOLERANCE_SCALE 1.0
51
+ #endif
52
+
53
+ bool LqDisocclusionIsOnScreen(int32_t2 pos, int32_t2 size)
54
+ {
55
+ return all(lessThan(pos, size)) && all(greaterThanEqual(pos, int32_t2(0)));
56
+ }
57
+
58
+ float LqDisocclusionGetViewSpaceDepth(float depth, float4 device_to_view)
59
+ {
60
+ return device_to_view.y / (depth - device_to_view.x);
61
+ }
62
+
63
+ void LqDisocclusionFindClosestDepthMotion4x4(
64
+ int32_t2 dst_pos,
65
+ int32_t2 dst_size,
66
+ out float closest_depth,
67
+ out float2 closest_motion,
68
+ out float local_view_depth_range)
69
+ {
70
+ int32_t2 src_base = int32_t2(float2(dst_pos) * (float2(_InputDims) / float2(dst_size)));
71
+ int32_t2 src_pos = clamp(src_base, int32_t2(0), _InputDims - int32_t2(1));
72
+
73
+ closest_depth = texelFetch(_DepthTex, src_pos, 0).r;
74
+ closest_motion = texelFetch(_MotionTex, src_pos, 0).xy;
75
+ // Grazing planes can span a large view-depth range inside one LQ footprint.
76
+ float src_view_depth = LqDisocclusionGetViewSpaceDepth(closest_depth, _DeviceToViewDepth);
77
+ float min_view_depth = src_view_depth;
78
+ float max_view_depth = src_view_depth;
79
+
80
+ for (int y = 0; y < 4; ++y) {
81
+ for (int x = 0; x < 4; ++x) {
82
+ int32_t2 sample_pos = src_base + int32_t2(x, y);
83
+ if (LqDisocclusionIsOnScreen(sample_pos, _InputDims)) {
84
+ float sample_depth = texelFetch(_DepthTex, sample_pos, 0).r;
85
+ float sample_view_depth = LqDisocclusionGetViewSpaceDepth(sample_depth, _DeviceToViewDepth);
86
+ min_view_depth = min(min_view_depth, sample_view_depth);
87
+ max_view_depth = max(max_view_depth, sample_view_depth);
88
+ if (sample_depth < closest_depth) {
89
+ closest_depth = sample_depth;
90
+ closest_motion = texelFetch(_MotionTex, sample_pos, 0).xy;
91
+ }
92
+ }
93
+ }
94
+ }
95
+
96
+ local_view_depth_range = max_view_depth - min_view_depth;
97
+ }
98
+
99
+ float LqDisocclusionComputeDepthClipInt(
100
+ float2 uv,
101
+ float current_depth,
102
+ float local_view_depth_range,
103
+ int32_t2 depth_size)
104
+ {
105
+ const float bilinear_weight_threshold = 0.1;
106
+ float current_view_depth = LqDisocclusionGetViewSpaceDepth(current_depth, _DeviceToViewDepth);
107
+ // Allow same-surface 4x4 depth slope before treating the min-depth envelope as a disocclusion.
108
+ float local_depth_tolerance = local_view_depth_range * NSS_LQ_DISOCCLUSION_DEPTH_GRADIENT_TOLERANCE_SCALE;
109
+ float2 sample_px = (uv * float2(depth_size)) - float2(0.5);
110
+ int32_t2 sample_base = int32_t2(floor(sample_px));
111
+ float2 sample_frac = fract(sample_px);
112
+
113
+ float w00 = (1.0 - sample_frac.x) * (1.0 - sample_frac.y);
114
+ float w10 = sample_frac.x * (1.0 - sample_frac.y);
115
+ float w01 = (1.0 - sample_frac.x) * sample_frac.y;
116
+ float w11 = sample_frac.x * sample_frac.y;
117
+
118
+ float f_depth = 0.0;
119
+ float f_weight_sum = 0.0;
120
+
121
+ #define NSS_LQ_DISOCCLUSION_DEPTH_CLIP_SAMPLE_BLOCK(SAMPLE_POS, SAMPLE_WEIGHT) \
122
+ { \
123
+ int32_t2 sample_pos = (SAMPLE_POS); \
124
+ float weight = (SAMPLE_WEIGHT); \
125
+ bool onscreen = LqDisocclusionIsOnScreen(sample_pos, depth_size); \
126
+ f_weight_sum += onscreen ? 0.0 : weight; \
127
+ if (onscreen && weight > bilinear_weight_threshold) { \
128
+ float prev_depth = float(texelFetch(_DepthTm1Tex, sample_pos, 0).r) * kLqDisocclusionInvDepthScale; \
129
+ float prev_view_depth = LqDisocclusionGetViewSpaceDepth(prev_depth, _DeviceToViewDepth); \
130
+ float depth_diff = current_view_depth - prev_view_depth; \
131
+ if (depth_diff > 0.0) { \
132
+ float depth_threshold = max(current_view_depth, prev_view_depth); \
133
+ float required_sep = (_DepthClipRequiredSepScale * depth_threshold) + local_depth_tolerance; \
134
+ float sep_ratio = saturate(required_sep / max(depth_diff, kLqDisocclusionEps)); \
135
+ f_depth += pow(sep_ratio, _DepthClipPower) * weight; \
136
+ f_weight_sum += weight; \
137
+ } \
138
+ } \
139
+ }
140
+
141
+ NSS_LQ_DISOCCLUSION_DEPTH_CLIP_SAMPLE_BLOCK(sample_base + int32_t2(0, 0), w00);
142
+ NSS_LQ_DISOCCLUSION_DEPTH_CLIP_SAMPLE_BLOCK(sample_base + int32_t2(1, 0), w10);
143
+ NSS_LQ_DISOCCLUSION_DEPTH_CLIP_SAMPLE_BLOCK(sample_base + int32_t2(0, 1), w01);
144
+ NSS_LQ_DISOCCLUSION_DEPTH_CLIP_SAMPLE_BLOCK(sample_base + int32_t2(1, 1), w11);
145
+
146
+ #undef NSS_LQ_DISOCCLUSION_DEPTH_CLIP_SAMPLE_BLOCK
147
+
148
+ return f_weight_sum > 0.0 ? saturate(1.0 - f_depth / f_weight_sum) : 0.0;
149
+ }
150
+
151
+ float LqDisocclusionComputeMask(int32_t2 pixel, int32_t2 depth_size)
152
+ {
153
+ float current_depth = 0.0;
154
+ float2 motion = float2(0.0);
155
+ float local_view_depth_range = 0.0;
156
+ LqDisocclusionFindClosestDepthMotion4x4(pixel, depth_size, current_depth, motion, local_view_depth_range);
157
+
158
+ float2 inv_depth_size = rcp(float2(depth_size));
159
+ float2 uv = (float2(pixel) + float2(0.5)) * inv_depth_size;
160
+ float2 motion_depth_pixels = motion * (float2(depth_size) / float2(_InputDims));
161
+ motion_depth_pixels *= float(length(motion) > kLqDisocclusionMotionThreshold);
162
+ float2 reproj_uv = uv - (motion_depth_pixels * inv_depth_size);
163
+
164
+ return LqDisocclusionComputeDepthClipInt(reproj_uv, current_depth, local_view_depth_range, depth_size);
165
+ }
166
+
167
+ #endif // NSS_V1_DISOCCLUSION_MASK_LQ_SHARED_H
scenario/1_pre_process.frag ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //
2
+ // -----------------------------------------------------------------------------
3
+ // The proprietary software and information contained in this file is
4
+ // confidential and may only be used by an authorized person under a valid
5
+ // licensing agreement from Arm Limited or its affiliates.
6
+ //
7
+ // Copyright (C) 2026 Arm Limited or its affiliates. All rights reserved.
8
+ //
9
+ // This entire notice must be reproduced on all copies of this file and
10
+ // copies of this file may only be made by an authorized person under a valid
11
+ // licensing agreement from Arm Limited or its affiliates.
12
+ // -----------------------------------------------------------------------------
13
+ //
14
+
15
+ #version 460
16
+ #extension GL_EXT_shader_8bit_storage : require
17
+ #extension GL_EXT_shader_16bit_storage : require
18
+ #extension GL_EXT_shader_explicit_arithmetic_types : require
19
+ #extension GL_EXT_shader_explicit_arithmetic_types_int8 : require
20
+ #extension GL_EXT_shader_explicit_arithmetic_types_float16 : require
21
+ #extension GL_EXT_shader_explicit_arithmetic_types_float32 : require
22
+ #extension GL_GOOGLE_include_directive : enable
23
+
24
+ #include "typedefs.h"
25
+ #include "common.h"
26
+
27
+ #ifndef NSS_INPUT_LAYOUT
28
+ #define NSS_INPUT_LAYOUT 0
29
+ #endif // !NSS_INPUT_LAYOUT
30
+ #ifndef NSS_V1_FULL_RES_LUMA_DERIVATIVE
31
+ #define NSS_V1_FULL_RES_LUMA_DERIVATIVE (NSS_INPUT_LAYOUT == 0)
32
+ #endif // !NSS_V1_FULL_RES_LUMA_DERIVATIVE
33
+ #ifndef NSS_V1_HALF_RES_LUMA_DERIVATIVE
34
+ #define NSS_V1_HALF_RES_LUMA_DERIVATIVE (NSS_INPUT_LAYOUT == 1)
35
+ #endif // !NSS_V1_HALF_RES_LUMA_DERIVATIVE
36
+ #ifndef NSS_YCOCG_LUMA_DERIVATIVE
37
+ #define NSS_YCOCG_LUMA_DERIVATIVE (NSS_V1_FULL_RES_LUMA_DERIVATIVE || NSS_V1_HALF_RES_LUMA_DERIVATIVE)
38
+ #endif // !NSS_YCOCG_LUMA_DERIVATIVE
39
+
40
+ layout(location = 0) in vec2 vUV;
41
+
42
+ //-----------------------------------------------------------------------------
43
+ // Resources
44
+ //-----------------------------------------------------------------------------
45
+ layout (set=0, binding=0) uniform mediump sampler2D _ColourTex; // 540p->1080p HQ/Low/Mid: 960x540 | R11G11B10 32bpp | 1.978 MiB
46
+ layout (set=0, binding=1) uniform highp sampler2D _DepthTex; // 540p->1080p HQ/Low/Mid: 960x540 | R32_SFLOAT 32bpp | 1.978 MiB
47
+ layout (set=0, binding=2) uniform mediump sampler2D _MotionVectorTex; // 540p->1080p HQ/Low/Mid: 960x540 | R16G16_SFLOAT 32bpp | 1.978 MiB
48
+ layout (set=0, binding=3) uniform mediump sampler2D _HistoryTex; // 540p->1080p HQ/Low/Mid: 1920x1080 | R11G11B10 32bpp | 7.910 MiB
49
+ layout (set=0, binding=4) uniform lowp sampler2D _FeedbackTensor; // 540p->1080p HQ: 960x544 | R8G8B8A8_SNORM 32bpp | Tensor->Texture Alias (Linear) | 1.992 MiB ; Low/Mid: 480x272 | 0.498 MiB
50
+ layout (set=0, binding=5) uniform highp usampler2D _DepthTm1Tex; // 540p->1080p HQ: 480x270 | R32_UINT 32bpp | previous-depth scatter result | 0.494 MiB ; Low/Mid: 240x135 | 0.124 MiB
51
+ layout (set=0, binding=6) uniform lowp sampler2D _LumaDerivTm1Tex; // 540p->1080p HQ: 960x544 | R8G8B8A8_SNORM 32bpp | derivative history | 1.992 MiB ; Low/Mid: 480x272 | 0.498 MiB
52
+ #if NSS_INPUT_LAYOUT == 1
53
+ layout (set=0, binding=7) uniform highp sampler2D _DisocclusionMaskLQTex; // Low/Mid 135p depth-domain disocclusion mask
54
+ #endif // NSS_INPUT_LAYOUT == 1
55
+
56
+ layout (set=1, binding=0, std430) buffer InputTensorBuffer {
57
+ int8_t4 data[];
58
+ } _InputTensorBuffer; // 540p->1080p HQ: 960x544x12 | int8 NHWC std430 buffer alias | 5.977 MiB ; Low/Mid: 480x272x12 | 1.494 MiB
59
+
60
+ layout(location = 0) out mediump vec4 _LumaDerivOut; // 540p->1080p HQ: 960x544 | R8G8B8A8_SNORM 32bpp render target | 1.992 MiB ; Low/Mid: 480x272 | 0.498 MiB
61
+ layout(location = 1) out mediump vec4 _NearestDepthOffsetOut; // 540p->1080p HQ: 960x544 | R8_UNORM 8bpp render target | 0.498 MiB ; Low/Mid: 480x272 | R8G8_UNORM 16bpp | 0.249 MiB
62
+
63
+ #include "1_pre_process_shared.h"
64
+
65
+ void WriteInputTensorPacked(int32_t2 coord, int8_t4 t_vec0, int8_t4 t_vec1, int8_t4 t_vec2)
66
+ {
67
+ uint32_t base = (uint32_t(coord.y) * uint32_t(_PaddedDims.x) + uint32_t(coord.x)) * 3u;
68
+ _InputTensorBuffer.data[base + 0u] = t_vec0;
69
+ _InputTensorBuffer.data[base + 1u] = t_vec1;
70
+ _InputTensorBuffer.data[base + 2u] = t_vec2;
71
+ }
72
+
73
+ void WriteLumaDerivativeOut(int32_t2 coord, half4 luma)
74
+ {
75
+ _LumaDerivOut = vec4(float4(luma));
76
+ }
77
+
78
+ void WriteNearestOffsetOut(int32_t2 coord, float4 encoded_nearest_offset)
79
+ {
80
+ _NearestDepthOffsetOut = vec4(encoded_nearest_offset);
81
+ }
82
+
83
+ void main()
84
+ {
85
+ _LumaDerivOut = vec4(float4(EmptyDerivativeStateForStorage()));
86
+ _NearestDepthOffsetOut = vec4(0.0, 0.0, 0.0, 1.0);
87
+ PreProcessMain(int32_t2(gl_FragCoord.xy));
88
+ }
scenario/1_pre_process_shared.h ADDED
@@ -0,0 +1,910 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //
2
+ // -----------------------------------------------------------------------------
3
+ // The proprietary software and information contained in this file is
4
+ // confidential and may only be used by an authorized person under a valid
5
+ // licensing agreement from Arm Limited or its affiliates.
6
+ //
7
+ // Copyright (C) 2026 Arm Limited or its affiliates. All rights reserved.
8
+ //
9
+ // This entire notice must be reproduced on all copies of this file and
10
+ // copies of this file may only be made by an authorized person under a valid
11
+ // licensing agreement from Arm Limited or its affiliates.
12
+ // -----------------------------------------------------------------------------
13
+ //
14
+
15
+ #ifndef NSS_V1_PRE_PROCESS_SHARED_H
16
+ #define NSS_V1_PRE_PROCESS_SHARED_H
17
+
18
+ #ifndef NSS_INPUT_LAYOUT
19
+ // 0: full-resolution preprocess outputs, 1: half-resolution outputs with packed nearest-depth offsets.
20
+ #define NSS_INPUT_LAYOUT 0
21
+ #endif // !NSS_INPUT_LAYOUT
22
+ #ifndef NSS_V1_FULL_RES_LUMA_DERIVATIVE
23
+ #define NSS_V1_FULL_RES_LUMA_DERIVATIVE (NSS_INPUT_LAYOUT == 0)
24
+ #endif // !NSS_V1_FULL_RES_LUMA_DERIVATIVE
25
+ #ifndef NSS_V1_HALF_RES_LUMA_DERIVATIVE
26
+ #define NSS_V1_HALF_RES_LUMA_DERIVATIVE (NSS_INPUT_LAYOUT == 1)
27
+ #endif // !NSS_V1_HALF_RES_LUMA_DERIVATIVE
28
+ #ifndef NSS_YCOCG_LUMA_DERIVATIVE
29
+ #define NSS_YCOCG_LUMA_DERIVATIVE (NSS_V1_FULL_RES_LUMA_DERIVATIVE || NSS_V1_HALF_RES_LUMA_DERIVATIVE)
30
+ #endif // !NSS_YCOCG_LUMA_DERIVATIVE
31
+
32
+ // Layout mirrors Slang's `PushConsts` exactly to preserve parity and avoid
33
+ // driver-dependent packing surprises.
34
+ layout(push_constant, std430) uniform PushConstants {
35
+ // ─────────────── 16-byte aligned ───────────────
36
+ // Projection params used to reconstruct view-space depth/position.
37
+ layout(offset = 0) float4 _DeviceToViewDepth; // 16 B
38
+ // Current-frame jitter as (x, y, x/input_w, y/input_h).
39
+ layout(offset = 16) float4 _JitterOffset; // 16 B
40
+ // Previous-frame jitter in the same packed layout as `_JitterOffset`.
41
+ layout(offset = 32) float4 _JitterOffsetTm1; // 16 B
42
+
43
+ // ─────────────── 8-byte aligned ───────────────
44
+ // Logical preprocess extent divided by low-res input extent.
45
+ layout(offset = 48) float2 _Scale; // 8 B
46
+ // Inverse of `_Scale`.
47
+ layout(offset = 56) float2 _InvScale; // 8 B
48
+ // Logical pre-process output dimensions.
49
+ layout(offset = 64) int32_t2 _OutputDims; // 8 B
50
+ // Low-resolution input dimensions.
51
+ layout(offset = 72) int32_t2 _InputDims; // 8 B
52
+ // Padded graph/input-tensor dimensions.
53
+ layout(offset = 80) int32_t2 _PaddedDims; // 8 B
54
+ // Inverse of `_OutputDims`.
55
+ layout(offset = 88) float2 _InvOutputDims; // 8 B
56
+ // Inverse of `_InputDims`.
57
+ layout(offset = 96) float2 _InvInputDims; // 8 B
58
+ // Inverse of `_PaddedDims`.
59
+ layout(offset = 104) float2 _InvPaddedDims; // 8 B
60
+ // Inverse dimensions of the previous-depth feedback surface.
61
+ layout(offset = 112) float2 _InvDepthTm1Dims; // 8 B
62
+ // Render-resolution dimensions used by depth-clip shaping.
63
+ layout(offset = 120) float2 _RenderSize; // 8 B
64
+ // Exposure packed as (exposure, 1/exposure).
65
+ layout(offset = 128) float2 _Exposure; // 8 B
66
+
67
+ // ─────────────── 4-byte aligned ───────────────
68
+ // Depth-clip separation scale precomputed on the host.
69
+ layout(offset = 136) float _DepthClipRequiredSepScale; // 4 B
70
+ // Depth-clip power/exponent precomputed on the host.
71
+ layout(offset = 140) float _DepthClipPower; // 4 B
72
+ // Total: **144 bytes**
73
+ };
74
+
75
+ const float kEps = 1e-7;
76
+ const float kDepthScale = 2147483647.0;
77
+ const float kInvDepthScale = 1.0 / kDepthScale;
78
+ const float kMotionThreshold = 0.1;
79
+ const float kMotionThresholdSq = kMotionThreshold * kMotionThreshold;
80
+ // QAT metadata (`_PreprocessTensor` SINT).
81
+ const half2 kPreprocessQuant = half2(1.0 / 0.003908163867890835, -128.0);
82
+ // Temporal feedback is stored as SNORM alias of the graph int8 output, so
83
+ // convert sampled [-1, 1] values back into the model's [0, 1] domain.
84
+ const half2 kTemporalFeedbackQuant = half2(0.49999999813735485, -1.0);
85
+
86
+ #if !NSS_YCOCG_LUMA_DERIVATIVE
87
+ const half kDerivativeDisThresh = 0.01HF;
88
+ const half kDerivMin = 0.05HF;
89
+ const half kDerivMax = 0.3HF;
90
+ const half kDerivAlpha = 0.1HF;
91
+ #endif // !NSS_YCOCG_LUMA_DERIVATIVE
92
+
93
+ #ifdef INVERTED_DEPTH
94
+ #define NSS_NEAREST_STEP(curr_depth, cand_depth) step(curr_depth, cand_depth)
95
+ #define NSS_PLANE_DEPTH(prev_depth, curr_depth) min(prev_depth, curr_depth)
96
+ #else
97
+ #define NSS_NEAREST_STEP(curr_depth, cand_depth) step(cand_depth, curr_depth)
98
+ #define NSS_PLANE_DEPTH(prev_depth, curr_depth) max(prev_depth, curr_depth)
99
+ #endif // INVERTED_DEPTH
100
+
101
+ bool IsOnScreen(int32_t2 pos, int32_t2 size)
102
+ {
103
+ return all(lessThan(pos, size)) && all(greaterThanEqual(pos, int32_t2(0)));
104
+ }
105
+
106
+ int32_t ReflectIndex(int32_t coord, int32_t size)
107
+ {
108
+ return coord < 0 ? -coord - 1 : (coord >= size ? (2 * size - coord - 1) : coord);
109
+ }
110
+
111
+ int32_t2 ReflectIndex(int32_t2 coord, int32_t2 size)
112
+ {
113
+ // Matches PyTorch reflect padding used by model-side preprocessing.
114
+ return int32_t2(ReflectIndex(coord.x, size.x), ReflectIndex(coord.y, size.y));
115
+ }
116
+
117
+ int32_t2 GetProcessDims()
118
+ {
119
+ return _OutputDims;
120
+ }
121
+
122
+ float2 GetDepthTm1DimsF()
123
+ {
124
+ return rcp(max(_InvDepthTm1Dims, float2(kEps)));
125
+ }
126
+
127
+ int32_t2 GetDepthTm1DimsI()
128
+ {
129
+ return int32_t2(round(GetDepthTm1DimsF()));
130
+ }
131
+
132
+ int32_t2 ProcessCoordToInputCoord(int32_t2 process_coord)
133
+ {
134
+ #if NSS_INPUT_LAYOUT == 1
135
+ float2 scaled = (float2(process_coord) + float2(0.5)) * _InvScale;
136
+ return clamp(int32_t2(floor(scaled)), int32_t2(0), _InputDims - int32_t2(1));
137
+ #else
138
+ return clamp(process_coord, int32_t2(0), _InputDims - int32_t2(1));
139
+ #endif // NSS_INPUT_LAYOUT == 1
140
+ }
141
+
142
+ int32_t2 InputCoordToDepthCoord(int32_t2 input_coord)
143
+ {
144
+ int32_t2 depth_size = GetDepthTm1DimsI();
145
+ float2 scaled = (float2(input_coord) + float2(0.5)) * GetDepthTm1DimsF() * _InvInputDims;
146
+ return clamp(int32_t2(floor(scaled)), int32_t2(0), depth_size - int32_t2(1));
147
+ }
148
+
149
+ float2 MotionToPaddedUvDelta(float2 motion)
150
+ {
151
+ #if NSS_INPUT_LAYOUT == 1
152
+ return motion * _Scale * _InvPaddedDims;
153
+ #else
154
+ return motion * _InvPaddedDims;
155
+ #endif // NSS_INPUT_LAYOUT == 1
156
+ }
157
+
158
+ struct BilinearSamplingData {
159
+ int32_t2 iOffsets[4];
160
+ float fWeights[4];
161
+ int32_t2 iBasePos;
162
+ };
163
+
164
+ BilinearSamplingData GetBilinearSamplingData(float2 uv, int32_t2 size)
165
+ {
166
+ // Convert uv -> bilinear footprint (base coordinate + 4 weights).
167
+ BilinearSamplingData data;
168
+
169
+ float2 fPxSample = (uv * float2(size)) - float2(0.5);
170
+ data.iBasePos = int32_t2(floor(fPxSample));
171
+ float2 fPxFrac = fract(fPxSample);
172
+
173
+ data.iOffsets[0] = int32_t2(0, 0);
174
+ data.iOffsets[1] = int32_t2(1, 0);
175
+ data.iOffsets[2] = int32_t2(0, 1);
176
+ data.iOffsets[3] = int32_t2(1, 1);
177
+
178
+ data.fWeights[0] = (1.0 - fPxFrac.x) * (1.0 - fPxFrac.y);
179
+ data.fWeights[1] = fPxFrac.x * (1.0 - fPxFrac.y);
180
+ data.fWeights[2] = (1.0 - fPxFrac.x) * fPxFrac.y;
181
+ data.fWeights[3] = fPxFrac.x * fPxFrac.y;
182
+ return data;
183
+ }
184
+
185
+ float2 ComputeNdc(float2 pixPos, int32_t2 size)
186
+ {
187
+ // Vulkan-style viewport mapping with Y flip.
188
+ return pixPos / float2(size) * float2(2.0, -2.0) + float2(-1.0, 1.0);
189
+ }
190
+
191
+ float GetViewSpaceDepth(float depth, float4 device_to_view)
192
+ {
193
+ return device_to_view.y / (depth - device_to_view.x);
194
+ }
195
+
196
+ float3 GetViewSpacePosition(int32_t2 viewport_pos, int32_t2 viewport_size, float device_depth, float4 device_to_view)
197
+ {
198
+ // Reconstruct view-space position from depth and projection params.
199
+ float z = GetViewSpaceDepth(device_depth, device_to_view);
200
+ float2 ndc = ComputeNdc(float2(viewport_pos), viewport_size);
201
+ float x = device_to_view.z * ndc.x * z;
202
+ float y = device_to_view.w * ndc.y * z;
203
+ return float3(x, y, z);
204
+ }
205
+
206
+ void FindNearestDepth_4x4_FromPixel(
207
+ int32_t2 px,
208
+ int32_t2 size,
209
+ out float nearest_depth,
210
+ out int32_t2 nearest_offset)
211
+ {
212
+ //-------------------------------------------------------------------------
213
+ // Depth dilation:
214
+ // Search a 4x4-ish local neighborhood around the current pixel and pick
215
+ // the sample closest to camera. This stabilizes motion/depth decisions at
216
+ // geometric edges and thin features.
217
+ //-------------------------------------------------------------------------
218
+ float2 inv_size = rcp(float2(size));
219
+
220
+ float nearest_depth_local = 0.0;
221
+ float2 nearest_offset_f = float2(0.0);
222
+
223
+ #define NSS_UPDATE_NEAREST_STEP(OFF_X, OFF_Y, DEPTH) \
224
+ { \
225
+ int32_t2 _offset_i = int32_t2((OFF_X), (OFF_Y)); \
226
+ int32_t2 _pos_i = px + _offset_i; \
227
+ float _on_screen = float(IsOnScreen(_pos_i, size)); \
228
+ float _d = (DEPTH); \
229
+ float _take = _on_screen * NSS_NEAREST_STEP(nearest_depth_local, _d); \
230
+ nearest_depth_local = mix(nearest_depth_local, _d, _take); \
231
+ nearest_offset_f = mix(nearest_offset_f, float2(_offset_i), _take); \
232
+ }
233
+
234
+ // q00 covers offsets: (-1,-1), (0,-1), (-1,0), (0,0)
235
+ float4 q00 = textureGather(_DepthTex, (float2(px + int32_t2(-1, -1)) + float2(0.5)) * inv_size, 0).wzxy;
236
+ nearest_depth_local = q00.w; // (0,0)
237
+ NSS_UPDATE_NEAREST_STEP(-1, +0, q00.z); // (-1, 0)
238
+ NSS_UPDATE_NEAREST_STEP(+0, -1, q00.y); // ( 0, -1)
239
+ NSS_UPDATE_NEAREST_STEP(-1, -1, q00.x); // (-1, -1)
240
+
241
+ // q10 covers offsets: (1,-1), (2,-1), (1,0), (2,0)
242
+ float4 q10 = textureGather(_DepthTex, (float2(px + int32_t2(+1, -1)) + float2(0.5)) * inv_size, 0).wzxy;
243
+ NSS_UPDATE_NEAREST_STEP(+1, +0, q10.z); // ( 1, 0)
244
+ NSS_UPDATE_NEAREST_STEP(+1, -1, q10.x); // ( 1, -1)
245
+ NSS_UPDATE_NEAREST_STEP(+2, -1, q10.y); // ( 2, -1)
246
+ NSS_UPDATE_NEAREST_STEP(+2, +0, q10.w); // ( 2, 0)
247
+
248
+ // q01 covers offsets: (-1,1), (0,1), (-1,2), (0,2)
249
+ float4 q01 = textureGather(_DepthTex, (float2(px + int32_t2(-1, +1)) + float2(0.5)) * inv_size, 0).wzxy;
250
+ NSS_UPDATE_NEAREST_STEP(+0, +1, q01.y); // ( 0, 1)
251
+ NSS_UPDATE_NEAREST_STEP(-1, +1, q01.x); // (-1, 1)
252
+ NSS_UPDATE_NEAREST_STEP(+0, +2, q01.w); // ( 0, 2)
253
+ NSS_UPDATE_NEAREST_STEP(-1, +2, q01.z); // (-1, 2)
254
+
255
+ // q11 covers offsets: (1,1), (2,1), (1,2), (2,2)
256
+ float4 q11 = textureGather(_DepthTex, (float2(px + int32_t2(+1, +1)) + float2(0.5)) * inv_size, 0).wzxy;
257
+ NSS_UPDATE_NEAREST_STEP(+1, +1, q11.x); // ( 1, 1)
258
+ NSS_UPDATE_NEAREST_STEP(+2, +1, q11.y); // ( 2, 1)
259
+ NSS_UPDATE_NEAREST_STEP(+1, +2, q11.z); // ( 1, 2)
260
+ NSS_UPDATE_NEAREST_STEP(+2, +2, q11.w); // ( 2, 2)
261
+
262
+ #undef NSS_UPDATE_NEAREST_STEP
263
+
264
+ nearest_depth = nearest_depth_local;
265
+ nearest_offset = int32_t2(nearest_offset_f);
266
+ }
267
+
268
+ void FindNearestDepth_4x4(
269
+ float2 uv,
270
+ out float nearest_depth,
271
+ out int32_t2 nearest_offset)
272
+ {
273
+ int32_t2 px = int32_t2(uv * float2(_InputDims));
274
+ FindNearestDepth_4x4_FromPixel(px, _InputDims, nearest_depth, nearest_offset);
275
+ }
276
+
277
+ float ComputeDepthClipInt(
278
+ float2 uv,
279
+ float depth_current,
280
+ float2 render_size,
281
+ float4 device_to_view)
282
+ {
283
+ //-------------------------------------------------------------------------
284
+ // Depth clip (best-effort integer previous-depth variant):
285
+ // Estimate disocclusion by comparing current depth to reprojected previous
286
+ // depth neighborhood with FOV/resolution-aware thresholds.
287
+ //-------------------------------------------------------------------------
288
+ const float bilinear_weight_threshold = 0.1;
289
+ int32_t2 depth_tm1_size = GetDepthTm1DimsI();
290
+ float current_view_depth = GetViewSpaceDepth(depth_current, device_to_view);
291
+ float2 sample_px = (uv * float2(depth_tm1_size)) - float2(0.5);
292
+ int32_t2 sample_base = int32_t2(floor(sample_px));
293
+ float2 sample_frac = fract(sample_px);
294
+
295
+ float w00 = (1.0 - sample_frac.x) * (1.0 - sample_frac.y);
296
+ float w10 = sample_frac.x * (1.0 - sample_frac.y);
297
+ float w01 = (1.0 - sample_frac.x) * sample_frac.y;
298
+ float w11 = sample_frac.x * sample_frac.y;
299
+
300
+ float required_sep_scale = _DepthClipRequiredSepScale;
301
+ float depth_clip_power = _DepthClipPower;
302
+
303
+ float fDepth = 0.0;
304
+ float fWeightSum = 0.0;
305
+
306
+ #define NSS_DEPTH_CLIP_SAMPLE_BLOCK(SAMPLE_POS, SAMPLE_WEIGHT) \
307
+ { \
308
+ int32_t2 sample_pos = (SAMPLE_POS); \
309
+ float weight = (SAMPLE_WEIGHT); \
310
+ bool onscreen = IsOnScreen(sample_pos, depth_tm1_size); \
311
+ fWeightSum += onscreen ? 0.0 : weight; \
312
+ if (onscreen && weight > bilinear_weight_threshold) { \
313
+ float prev_depth = float(texelFetch(_DepthTm1Tex, sample_pos, 0).r) * kInvDepthScale; \
314
+ float prev_view_depth = GetViewSpaceDepth(prev_depth, device_to_view); \
315
+ float depth_diff = current_view_depth - prev_view_depth; \
316
+ if (depth_diff > 0.0) { \
317
+ float depth_threshold = max(current_view_depth, prev_view_depth); \
318
+ float required_sep = required_sep_scale * depth_threshold; \
319
+ float sep_ratio = saturate(required_sep / max(depth_diff, kEps)); \
320
+ fDepth += pow(sep_ratio, depth_clip_power) * weight; \
321
+ fWeightSum += weight; \
322
+ } \
323
+ } \
324
+ }
325
+
326
+ NSS_DEPTH_CLIP_SAMPLE_BLOCK(sample_base + int32_t2(0, 0), w00);
327
+ NSS_DEPTH_CLIP_SAMPLE_BLOCK(sample_base + int32_t2(1, 0), w10);
328
+ NSS_DEPTH_CLIP_SAMPLE_BLOCK(sample_base + int32_t2(0, 1), w01);
329
+ NSS_DEPTH_CLIP_SAMPLE_BLOCK(sample_base + int32_t2(1, 1), w11);
330
+
331
+ #undef NSS_DEPTH_CLIP_SAMPLE_BLOCK
332
+
333
+ return fWeightSum > 0.0 ? saturate(1.0 - fDepth / fWeightSum) : 0.0;
334
+ }
335
+
336
+ float2 LoadMotion(int32_t2 pixel)
337
+ {
338
+ pixel = clamp(pixel, int32_t2(0), _InputDims - int32_t2(1));
339
+ float2 v = texelFetch(_MotionVectorTex, pixel, 0).xy;
340
+ v *= float(dot(v, v) > kMotionThresholdSq);
341
+ return v;
342
+ }
343
+
344
+ half3 LoadColourUnjittered(float2 uv)
345
+ {
346
+ // Exposure + Karis tonemap keeps network input numerically bounded.
347
+ return Tonemap(SafeColour(half3(textureLod(_ColourTex, uv, 0.0).rgb) * half3(_Exposure.x)));
348
+ }
349
+
350
+ half3 LoadColourForDerivativeAtResolvedPixel(int32_t2 sample_coord)
351
+ {
352
+ half3 c = half3(texelFetch(_ColourTex, sample_coord, 0).rgb);
353
+ c = max(c * half(_Exposure.x), half3(0.HF));
354
+ return sqrt(c);
355
+ }
356
+
357
+ half3 LoadColourForDerivativeAtPixel(int32_t2 pixel)
358
+ {
359
+ return LoadColourForDerivativeAtResolvedPixel(ReflectIndex(pixel, _InputDims));
360
+ }
361
+
362
+ half3 WarpHistory(float2 uv)
363
+ {
364
+ return Tonemap(SafeColour(half3(textureLod(_HistoryTex, uv, 0.0).rgb) * half3(_Exposure.x)));
365
+ }
366
+
367
+ half4 WarpFeedback(float2 uv, half disocclusion_mask)
368
+ {
369
+ // Reset temporal features when disoccluded to avoid ghost carry-over.
370
+ half4 feedback = Dequantize(half4(textureLod(_FeedbackTensor, uv, 0.0)), kTemporalFeedbackQuant);
371
+ return mix(feedback, half4(0.HF), half(disocclusion_mask > 0.01HF));
372
+ }
373
+
374
+ half4 LoadDerivativeTm1(float2 uv)
375
+ {
376
+ return half4(textureLod(_LumaDerivTm1Tex, uv, 0.0));
377
+ }
378
+
379
+ half CalculateMotionDetector(float2 vector, float2 render_size)
380
+ {
381
+ // Convert motion magnitude into a bounded [0,1] detector feature.
382
+ float2 inv_render_size = rcp(render_size);
383
+ float k_pix_min = length(inv_render_size);
384
+ float k_pix_max = 200.0 * k_pix_min;
385
+ float k_pix_denom = rcp(max(k_pix_max - k_pix_min, kEps));
386
+
387
+ float2 motion_norm = vector * inv_render_size;
388
+ float motion_length = length(motion_norm);
389
+ return half(sqrt((clamp(motion_length, k_pix_min, k_pix_max) - k_pix_min) * k_pix_denom));
390
+ }
391
+
392
+ #if NSS_YCOCG_LUMA_DERIVATIVE
393
+
394
+ // Derivative history is persisted through an R8G8B8A8_SNORM image. These
395
+ // constants map between sampled SNORM values and the detector's state:
396
+ // Y=[0, 8], Co/Cg=[-8, 8], instability=[0, 1].
397
+ const half4 kDerivativeStorageDecodeScale = half4(4.HF, 8.HF, 8.HF, 0.5HF);
398
+ const half4 kDerivativeStorageDecodeBias = half4(4.HF, 0.HF, 0.HF, 0.5HF);
399
+ const half4 kDerivativeStorageEncodeScale = half4(0.25HF, 0.125HF, 0.125HF, 2.HF);
400
+ const half4 kDerivativeStorageEncodeBias = half4(-1.HF, 0.HF, 0.HF, -1.HF);
401
+ const half4 kDerivativeStorageZeroState = half4(-1.HF, 0.HF, 0.HF, -1.HF);
402
+
403
+ half4 RGBToYCoCg(half3 rgb)
404
+ {
405
+ half co = rgb.r - rgb.b;
406
+ half t = rgb.b + co * 0.5HF;
407
+ half cg = rgb.g - t;
408
+ half y = t + cg * 0.5HF;
409
+ return half4(y, co, cg, 0.HF);
410
+ }
411
+
412
+ half ComputeDerivativeDelta(half4 ycocg_a, half4 ycocg_b, half4 delta_weight)
413
+ {
414
+ half4 delta = ycocg_a - ycocg_b;
415
+ return sqrt(dot(delta * delta, delta_weight));
416
+ }
417
+
418
+ half4 DecodeDerivativeStateFromStorage(half4 stored)
419
+ {
420
+ // Previous derivative state is sampled from the SNORM history image in
421
+ // [-1, 1]. Decode it back into the detector's YCoCg/instability domain
422
+ // before comparing it against the current frame.
423
+ return stored * kDerivativeStorageDecodeScale + kDerivativeStorageDecodeBias;
424
+ }
425
+
426
+ half4 EncodeDerivativeStateForStorage(half4 state)
427
+ {
428
+ // The side-output image is R8G8B8A8_SNORM, not a float history buffer.
429
+ // Encode the HDR-derived YCoCg state into fixed SNORM ranges, while keeping
430
+ // instability linear so the network-visible derivative preserves precision.
431
+ return state * kDerivativeStorageEncodeScale + kDerivativeStorageEncodeBias;
432
+ }
433
+
434
+ half4 EmptyDerivativeStateForStorage()
435
+ {
436
+ return kDerivativeStorageZeroState;
437
+ }
438
+
439
+ half4 CalculateLumaDerivative(
440
+ int32_t2 ref_coord,
441
+ float2 derivative_uv,
442
+ float2 derivative_inv_dims,
443
+ half4 deriv_tm1_h,
444
+ half disocclusion_mask,
445
+ out half instability_out)
446
+ {
447
+ const half derivative_dis_thresh = 0.01HF;
448
+ const half4 delta_weight = half4(1.HF, 1.5625HF, 1.5625HF, 0.HF);
449
+ const half recall_floor = 0.065HF;
450
+ const half recall_ceil = 0.420HF;
451
+ const half excursion_floor = 0.025HF;
452
+ const half excursion_ceil = 0.160HF;
453
+ const half mean_gate_floor = 0.070HF;
454
+ const half mean_gate_ceil = 0.230HF;
455
+ const half sustain_cold_floor = 0.177HF;
456
+ const half sustain_cold_ceil = 0.330HF;
457
+ const half sustain_hot_floor = 0.157HF;
458
+ const half sustain_hot_ceil = 0.305HF;
459
+ const half sustain_hysteresis_floor = 0.110HF;
460
+ const half sustain_hysteresis_ceil = 0.210HF;
461
+ const half sustain_support_alpha = 0.30HF;
462
+ const half hot_hold_floor = 0.180HF;
463
+ const half hot_hold_ceil = 0.280HF;
464
+ const half sustain_min_hot_hold = 0.12HF;
465
+ const half decay_min_hot_gate = 0.50HF;
466
+ const half sustain_strength = 0.80HF;
467
+ const half instability_rise_alpha_min = 0.08HF;
468
+ const half instability_rise_alpha_max = 0.22HF;
469
+ const half instability_fast_fall_alpha = 0.24HF;
470
+ const half instability_fall_alpha = 0.05HF;
471
+ const half spatial_support_scale = 0.75HF;
472
+ const half spatial_support_blend = 0.30HF;
473
+ #if NSS_V1_HALF_RES_LUMA_DERIVATIVE
474
+ const half moire_temporal_floor = 0.10HF;
475
+ const half moire_temporal_ceil = 0.30HF;
476
+ const half moire_range_floor = 0.99HF;
477
+ const half moire_range_ceil = 0.999HF;
478
+ const half moire_range_scale = 0.50HF;
479
+ const half flat_temporal_floor = 0.015HF;
480
+ const half flat_temporal_ceil = 0.030HF;
481
+ const half flat_range_floor = 0.040HF;
482
+ const half flat_range_ceil = 0.120HF;
483
+ const half flat_blue_floor = 0.220HF;
484
+ const half flat_blue_ceil = 0.300HF;
485
+ const half flat_luma_floor = 0.450HF;
486
+ const half flat_luma_ceil = 1.050HF;
487
+ const half flat_rgb_b_floor = 0.800HF;
488
+ const half flat_rgb_b_ceil = 1.400HF;
489
+ const half flat_flicker_scale = 0.75HF;
490
+ #endif // NSS_V1_HALF_RES_LUMA_DERIVATIVE
491
+
492
+ half4 deriv_tm1 = DecodeDerivativeStateFromStorage(deriv_tm1_h);
493
+ half raw_zero_state = half(dot(abs(deriv_tm1_h), half4(1.HF)) < 1e-4HF);
494
+ half decoded_zero_state = half(dot(abs(deriv_tm1), half4(1.HF)) < 1e-4HF);
495
+ half uninitialized_state = max(raw_zero_state, decoded_zero_state);
496
+ half4 ycocg_c = RGBToYCoCg(LoadColourForDerivativeAtResolvedPixel(ref_coord));
497
+ half4 ycocg_n = RGBToYCoCg(LoadColourForDerivativeAtPixel(ref_coord + int32_t2(0, -1)));
498
+ half4 ycocg_s = RGBToYCoCg(LoadColourForDerivativeAtPixel(ref_coord + int32_t2(0, 1)));
499
+ half4 ycocg_e = RGBToYCoCg(LoadColourForDerivativeAtPixel(ref_coord + int32_t2(1, 0)));
500
+ half4 ycocg_w = RGBToYCoCg(LoadColourForDerivativeAtPixel(ref_coord + int32_t2(-1, 0)));
501
+ half d_center = ComputeDerivativeDelta(ycocg_c, half4(deriv_tm1.xyz, 0.HF), delta_weight);
502
+ half d_n = ComputeDerivativeDelta(ycocg_c, ycocg_n, delta_weight);
503
+ half d_s = ComputeDerivativeDelta(ycocg_c, ycocg_s, delta_weight);
504
+ half d_e = ComputeDerivativeDelta(ycocg_c, ycocg_e, delta_weight);
505
+ half d_w = ComputeDerivativeDelta(ycocg_c, ycocg_w, delta_weight);
506
+ half4 spatial_deltas = half4(d_n, d_s, d_e, d_w);
507
+ half spatial_delta_sum = dot(spatial_deltas, half4(1.HF));
508
+ half spatial_delta_max = max(max(spatial_deltas.x, spatial_deltas.y), max(spatial_deltas.z, spatial_deltas.w));
509
+ half prev_instability = deriv_tm1.w;
510
+
511
+ #if NSS_V1_HALF_RES_LUMA_DERIVATIVE
512
+ int32_t2 temporal_input_step = max(int32_t2(_InvScale + float2(0.5)), int32_t2(1));
513
+ int32_t2 moire_input_step = temporal_input_step;
514
+ float2 moire_derivative_step = derivative_inv_dims;
515
+ half4 ycocg_tn = RGBToYCoCg(LoadColourForDerivativeAtPixel(ref_coord + int32_t2(0, -moire_input_step.y)));
516
+ half4 ycocg_ts = RGBToYCoCg(LoadColourForDerivativeAtPixel(ref_coord + int32_t2(0, moire_input_step.y)));
517
+ half4 ycocg_te = RGBToYCoCg(LoadColourForDerivativeAtPixel(ref_coord + int32_t2(moire_input_step.x, 0)));
518
+ half4 ycocg_tw = RGBToYCoCg(LoadColourForDerivativeAtPixel(ref_coord + int32_t2(-moire_input_step.x, 0)));
519
+ half4 deriv_tm1_n = DecodeDerivativeStateFromStorage(
520
+ LoadDerivativeTm1(derivative_uv + float2(0.0, -moire_derivative_step.y))
521
+ );
522
+ half4 deriv_tm1_s = DecodeDerivativeStateFromStorage(
523
+ LoadDerivativeTm1(derivative_uv + float2(0.0, moire_derivative_step.y))
524
+ );
525
+ half4 deriv_tm1_e = DecodeDerivativeStateFromStorage(
526
+ LoadDerivativeTm1(derivative_uv + float2(moire_derivative_step.x, 0.0))
527
+ );
528
+ half4 deriv_tm1_w = DecodeDerivativeStateFromStorage(
529
+ LoadDerivativeTm1(derivative_uv + float2(-moire_derivative_step.x, 0.0))
530
+ );
531
+ half d_tn = ComputeDerivativeDelta(ycocg_tn, half4(deriv_tm1_n.xyz, 0.HF), delta_weight);
532
+ half d_ts = ComputeDerivativeDelta(ycocg_ts, half4(deriv_tm1_s.xyz, 0.HF), delta_weight);
533
+ half d_te = ComputeDerivativeDelta(ycocg_te, half4(deriv_tm1_e.xyz, 0.HF), delta_weight);
534
+ half d_tw = ComputeDerivativeDelta(ycocg_tw, half4(deriv_tm1_w.xyz, 0.HF), delta_weight);
535
+ half r_tn = ComputeDerivativeDelta(ycocg_c, ycocg_tn, delta_weight);
536
+ half r_ts = ComputeDerivativeDelta(ycocg_c, ycocg_ts, delta_weight);
537
+ half r_te = ComputeDerivativeDelta(ycocg_c, ycocg_te, delta_weight);
538
+ half r_tw = ComputeDerivativeDelta(ycocg_c, ycocg_tw, delta_weight);
539
+ half temporal_moire_max = max(max(d_center, d_tn), max(max(d_ts, d_te), d_tw));
540
+ half current_moire_range = max(max(r_tn, r_ts), max(r_te, r_tw));
541
+ half flat_temporal_min = min(min(d_center, d_tn), min(min(d_ts, d_te), d_tw));
542
+ #endif // NSS_V1_HALF_RES_LUMA_DERIVATIVE
543
+
544
+ half spatial_support = max(spatial_delta_sum - spatial_delta_max, 0.HF) * (1.HF / 3.HF);
545
+ half supported_instability = mix(d_center, spatial_support, spatial_support_blend) * spatial_support_scale;
546
+ #if NSS_V1_HALF_RES_LUMA_DERIVATIVE
547
+ half moire_temporal_gate = saturate(
548
+ (temporal_moire_max - moire_temporal_floor) * rcp(moire_temporal_ceil - moire_temporal_floor)
549
+ );
550
+ half moire_range_entry = saturate(
551
+ (current_moire_range - moire_range_floor) * rcp(moire_range_ceil - moire_range_floor)
552
+ ) * moire_temporal_gate * moire_range_scale;
553
+ half flat_temporal_gate = saturate(
554
+ (flat_temporal_min - flat_temporal_floor) * rcp(flat_temporal_ceil - flat_temporal_floor)
555
+ );
556
+ half flat_range_gate = 1.HF - saturate(
557
+ (current_moire_range - flat_range_floor) * rcp(flat_range_ceil - flat_range_floor)
558
+ );
559
+ half flat_blue_bias = (-0.75HF * ycocg_c.y) - (0.5HF * ycocg_c.z);
560
+ half flat_blue_gate = saturate((flat_blue_bias - flat_blue_floor) * rcp(flat_blue_ceil - flat_blue_floor));
561
+ half flat_luma_gate = saturate((ycocg_c.x - flat_luma_floor) * rcp(0.10HF))
562
+ * (1.HF - saturate((ycocg_c.x - flat_luma_ceil) * rcp(0.20HF)));
563
+ half flat_rgb_b = ycocg_c.x - (0.5HF * (ycocg_c.y + ycocg_c.z));
564
+ half flat_rgb_b_gate = saturate((flat_rgb_b - flat_rgb_b_floor) * rcp(0.10HF))
565
+ * (1.HF - saturate((flat_rgb_b - flat_rgb_b_ceil) * rcp(0.20HF)));
566
+ half flat_surface_gate = flat_range_gate * flat_blue_gate * flat_luma_gate * flat_rgb_b_gate;
567
+ half flat_flicker_entry = flat_temporal_gate * flat_surface_gate * flat_flicker_scale;
568
+ #endif // NSS_V1_HALF_RES_LUMA_DERIVATIVE
569
+
570
+ half recall_excursion = max(supported_instability - prev_instability, 0.HF);
571
+ half recall_score = saturate((supported_instability - recall_floor) * rcp(recall_ceil - recall_floor));
572
+ half excursion_score = saturate((recall_excursion - excursion_floor) * rcp(excursion_ceil - excursion_floor));
573
+ half mean_gate = saturate((supported_instability - mean_gate_floor) * rcp(mean_gate_ceil - mean_gate_floor));
574
+ half raw_entry = sqrt(recall_score) * sqrt(excursion_score) * mean_gate;
575
+ #if NSS_V1_HALF_RES_LUMA_DERIVATIVE
576
+ raw_entry = max(raw_entry, max(moire_range_entry, flat_flicker_entry));
577
+ #endif // NSS_V1_HALF_RES_LUMA_DERIVATIVE
578
+
579
+ half sustain_heat = saturate(
580
+ (prev_instability - sustain_hysteresis_floor) * rcp(sustain_hysteresis_ceil - sustain_hysteresis_floor)
581
+ );
582
+ half sustain_support = mix(prev_instability, supported_instability, sustain_support_alpha);
583
+ half sustain_floor = mix(sustain_cold_floor, sustain_hot_floor, sustain_heat);
584
+ half sustain_ceil = mix(sustain_cold_ceil, sustain_hot_ceil, sustain_heat);
585
+ half sustain_gate = saturate((sustain_support - sustain_floor) * rcp(sustain_ceil - sustain_floor));
586
+ sustain_gate *= sustain_gate;
587
+ half hot_hold = saturate((prev_instability - hot_hold_floor) * rcp(hot_hold_ceil - hot_hold_floor));
588
+ hot_hold *= hot_hold;
589
+ half hot_hold_gate = hot_hold * sustain_min_hot_hold;
590
+ half carry_gate = max(sustain_gate, hot_hold_gate);
591
+ half raw_sustain = prev_instability * carry_gate * sustain_strength;
592
+ half raw_instability = max(raw_entry, raw_sustain);
593
+
594
+ half decay_gate = max(sustain_gate, sustain_heat * sustain_heat * decay_min_hot_gate);
595
+ half fall_alpha = mix(instability_fast_fall_alpha, instability_fall_alpha, decay_gate);
596
+ half rise_support = sqrt(recall_score * mean_gate);
597
+ half rise_alpha = mix(instability_rise_alpha_min, instability_rise_alpha_max, rise_support);
598
+ half instability_alpha = raw_instability > prev_instability ? rise_alpha : fall_alpha;
599
+ half filtered_instability = mix(prev_instability, raw_instability, instability_alpha);
600
+
601
+ half output_rise_alpha = 0.75HF;
602
+ half output_fall_alpha = 0.80HF;
603
+ half output_alpha = filtered_instability > prev_instability ? output_rise_alpha : output_fall_alpha;
604
+ half visible_instability = mix(prev_instability, filtered_instability, output_alpha);
605
+ #if NSS_V1_HALF_RES_LUMA_DERIVATIVE
606
+ visible_instability = max(visible_instability, max(moire_range_entry, flat_flicker_entry));
607
+ #endif // NSS_V1_HALF_RES_LUMA_DERIVATIVE
608
+
609
+ half4 derivative_state = half4(ycocg_c.xyz, filtered_instability);
610
+ half instability = visible_instability;
611
+
612
+ half disocclusion_binary = half(disocclusion_mask > derivative_dis_thresh);
613
+ half reset_history = max(disocclusion_binary, uninitialized_state);
614
+ instability *= 1.HF - reset_history;
615
+
616
+ half4 reset_state = half4(ycocg_c.xyz, 0.HF);
617
+ instability_out = instability;
618
+ return EncodeDerivativeStateForStorage(mix(derivative_state, reset_state, reset_history));
619
+ }
620
+
621
+ #else
622
+
623
+ half4 EmptyDerivativeStateForStorage()
624
+ {
625
+ return half4(0.HF);
626
+ }
627
+
628
+ half4 CalculateLumaDerivative(
629
+ half3 unjittered_colour,
630
+ half4 deriv_tm1,
631
+ half disocclusion_mask,
632
+ out half instability)
633
+ {
634
+ //-------------------------------------------------------------------------
635
+ // Temporal luma derivative:
636
+ // 1) compute current |delta luma|
637
+ // 2) threshold + clip + power curve
638
+ // 3) accumulate with adaptive alpha
639
+ // 4) zero derivative in disoccluded regions
640
+ //-------------------------------------------------------------------------
641
+ half deriv_max_pow_r = rcp(kDerivMax * sqrt(kDerivMax));
642
+ half luma_tm1 = deriv_tm1.y;
643
+ half luma_derivative_tm1 = deriv_tm1.x;
644
+ half luma_t = Luminance(unjittered_colour);
645
+
646
+ half luma_derivative_t = abs(luma_t - luma_tm1);
647
+ half clipped = min(luma_derivative_t, kDerivMax);
648
+ clipped *= step(kDerivMin, luma_derivative_t);
649
+ half curved = clipped * sqrt(clipped) * deriv_max_pow_r;
650
+
651
+ half applied_d_alpha = mix(
652
+ kDerivAlpha,
653
+ kDerivAlpha * 0.1HF,
654
+ clamp(luma_derivative_tm1, 0.HF, kDerivMax) * rcp(kDerivMax)
655
+ );
656
+ half luma_derivative = mix(luma_derivative_tm1, curved, applied_d_alpha);
657
+
658
+ luma_derivative *= step(disocclusion_mask, kDerivativeDisThresh);
659
+ instability = luma_derivative;
660
+ return half4(luma_derivative, luma_t, 0.HF, 0.HF);
661
+ }
662
+
663
+ #endif // NSS_YCOCG_LUMA_DERIVATIVE
664
+
665
+ float EncodeNearestDepthCoordUNorm(int32_t2 nearest_offset)
666
+ {
667
+ // Pack [-2,2]^2 into a single R8_UNORM code.
668
+ int32_t2 clamped = clamp(nearest_offset, int32_t2(-2), int32_t2(2));
669
+ int32_t code = ((clamped.y + 2) << 3) | (clamped.x + 2);
670
+ return float(code) / 255.0;
671
+ }
672
+
673
+ float4 EncodeNearestOffsetQuadUNormRG8(
674
+ int32_t2 offset_00,
675
+ int32_t2 offset_10,
676
+ int32_t2 offset_01,
677
+ int32_t2 offset_11)
678
+ {
679
+ // Low-quality packed quad path stores four {-1..2}^2 offsets in RG8:
680
+ // R = lane00 | lane10<<4, G = lane01 | lane11<<4.
681
+ int32_t byte_r = int32_t(EncodeNearestDepthCoordNibble(offset_00))
682
+ | (int32_t(EncodeNearestDepthCoordNibble(offset_10)) << 4);
683
+ int32_t byte_g = int32_t(EncodeNearestDepthCoordNibble(offset_01))
684
+ | (int32_t(EncodeNearestDepthCoordNibble(offset_11)) << 4);
685
+ return float4(float(byte_r), float(byte_g), 0.0, 255.0) / 255.0;
686
+ }
687
+
688
+ void WriteInputTensorPacked(int32_t2 coord, int8_t4 t_vec0, int8_t4 t_vec1, int8_t4 t_vec2);
689
+
690
+ void WriteToTensor(
691
+ int32_t2 coord,
692
+ half3 history,
693
+ half3 colour,
694
+ half motion_detector,
695
+ half4 feedback,
696
+ half luma_derivative)
697
+ {
698
+ // Network input layout (12 channels):
699
+ // history.rgb | colour.rgb | motion_detector | feedback.rgba | luma_deriv
700
+ // Stored as int8 for `1_nss` graph input, matching QAT metadata.
701
+ int8_t4 t_vec0 = Quantize(half4(history.rgb, colour.r), kPreprocessQuant);
702
+ int8_t4 t_vec1 = Quantize(half4(colour.gb, motion_detector, feedback.r), kPreprocessQuant);
703
+ int8_t4 t_vec2 = Quantize(half4(feedback.gba, luma_derivative), kPreprocessQuant);
704
+ WriteInputTensorPacked(coord, t_vec0, t_vec1, t_vec2);
705
+ }
706
+
707
+ void WriteLumaDerivativeOut(int32_t2 coord, half4 luma);
708
+ void WriteNearestOffsetOut(int32_t2 coord, float4 encoded_nearest_offset);
709
+
710
+ struct PreProcessLaneData
711
+ {
712
+ int32_t2 input_coord;
713
+ int32_t2 nearest_offset;
714
+ float depth_dilated;
715
+ float2 motion;
716
+ float2 uv;
717
+ float2 reproj_uv;
718
+ };
719
+
720
+ PreProcessLaneData BuildPreProcessLaneData(int32_t2 input_coord)
721
+ {
722
+ PreProcessLaneData lane;
723
+ lane.input_coord = clamp(input_coord, int32_t2(0), _InputDims - int32_t2(1));
724
+ lane.uv = (float2(lane.input_coord) + float2(0.5)) * _InvInputDims;
725
+
726
+ lane.depth_dilated = 0.0;
727
+ lane.nearest_offset = int32_t2(0);
728
+ FindNearestDepth_4x4_FromPixel(lane.input_coord, _InputDims, lane.depth_dilated, lane.nearest_offset);
729
+
730
+ int32_t2 nearest_input_coord = clamp(
731
+ lane.input_coord + lane.nearest_offset,
732
+ int32_t2(0),
733
+ _InputDims - int32_t2(1)
734
+ );
735
+ lane.motion = LoadMotion(nearest_input_coord);
736
+ lane.reproj_uv = lane.uv - (lane.motion * _InvInputDims);
737
+ return lane;
738
+ }
739
+
740
+ half3 AverageWarpedHistory2x2(
741
+ PreProcessLaneData lane_00,
742
+ PreProcessLaneData lane_10,
743
+ PreProcessLaneData lane_01,
744
+ PreProcessLaneData lane_11)
745
+ {
746
+ return (
747
+ WarpHistory(lane_00.reproj_uv) +
748
+ WarpHistory(lane_10.reproj_uv) +
749
+ WarpHistory(lane_01.reproj_uv) +
750
+ WarpHistory(lane_11.reproj_uv)
751
+ ) * 0.25HF;
752
+ }
753
+
754
+ int32_t2 HalfResProcessCoordToBaseInputCoord(int32_t2 process_coord)
755
+ {
756
+ return clamp(process_coord * int32_t2(2), int32_t2(0), _InputDims - int32_t2(1));
757
+ }
758
+
759
+ void PreProcessMain(int32_t2 padded_coord)
760
+ {
761
+ //-------------------------------------------------------------------------
762
+ // 1) Dispatch/padding guard
763
+ //-------------------------------------------------------------------------
764
+ if (any(greaterThanEqual(padded_coord, _PaddedDims))) {
765
+ return;
766
+ }
767
+
768
+ int32_t2 process_dims = GetProcessDims();
769
+ int32_t2 process_coord = ReflectIndex(padded_coord, process_dims);
770
+ int32_t2 ref_coord = ProcessCoordToInputCoord(process_coord);
771
+ float2 uv = (float2(ref_coord) + float2(0.5)) * _InvInputDims;
772
+ float2 uv_pad = (float2(padded_coord) + float2(0.5)) * _InvPaddedDims;
773
+
774
+ //-------------------------------------------------------------------------
775
+ // 2) Depth dilation and nearest-coordinate selection
776
+ //-------------------------------------------------------------------------
777
+ float depth_dilated = 0.0;
778
+ int32_t2 nearest_offset = int32_t2(0);
779
+ FindNearestDepth_4x4(uv, depth_dilated, nearest_offset);
780
+
781
+ //-------------------------------------------------------------------------
782
+ // 3) Motion sampling and reprojection setup
783
+ //-------------------------------------------------------------------------
784
+ // SHADER_ACCURATE parity: sample motion at nearest-depth-dilated texel.
785
+ int32_t2 nearest_input_coord = clamp(ref_coord + nearest_offset, int32_t2(0), _InputDims - int32_t2(1));
786
+ float2 motion = LoadMotion(nearest_input_coord);
787
+
788
+ float2 reproj_uv = uv - (motion * _InvInputDims);
789
+ float2 unjitter_uv = uv - (_JitterOffset.xy * _InvInputDims);
790
+ int32_t2 depth_coord = InputCoordToDepthCoord(ref_coord);
791
+ float2 reproj_270p_uv = ((float2(depth_coord) + float2(0.5)) * _InvDepthTm1Dims) - (motion * _InvInputDims);
792
+ float2 reproj_pad_uv = uv_pad - MotionToPaddedUvDelta(motion);
793
+
794
+ //-------------------------------------------------------------------------
795
+ // 4) Disocclusion
796
+ //-------------------------------------------------------------------------
797
+ #if NSS_INPUT_LAYOUT == 1
798
+ float2 disocclusion_uv = (float2(process_coord) + float2(0.5)) * _InvOutputDims;
799
+ half disocclusion_mask = half(textureLod(_DisocclusionMaskLQTex, disocclusion_uv, 0.0).r);
800
+ #else
801
+ half disocclusion_mask = half(ComputeDepthClipInt(
802
+ reproj_270p_uv,
803
+ depth_dilated,
804
+ _RenderSize,
805
+ _DeviceToViewDepth
806
+ ));
807
+ #endif // NSS_INPUT_LAYOUT == 1
808
+
809
+ //-------------------------------------------------------------------------
810
+ // 5) Feature preparation for network input tensor
811
+ //-------------------------------------------------------------------------
812
+ half3 unjittered_colour_h = LoadColourUnjittered(unjitter_uv);
813
+ half3 lr_warped_history_h;
814
+ #if NSS_INPUT_LAYOUT == 1
815
+ {
816
+ int32_t2 history_base_input_coord = HalfResProcessCoordToBaseInputCoord(process_coord);
817
+ int32_t2 history_lane_input_00 = history_base_input_coord;
818
+ int32_t2 history_lane_input_10 = min(history_base_input_coord + int32_t2(1, 0), _InputDims - int32_t2(1));
819
+ int32_t2 history_lane_input_01 = min(history_base_input_coord + int32_t2(0, 1), _InputDims - int32_t2(1));
820
+ int32_t2 history_lane_input_11 = min(history_base_input_coord + int32_t2(1, 1), _InputDims - int32_t2(1));
821
+
822
+ PreProcessLaneData history_lane_00 = BuildPreProcessLaneData(history_lane_input_00);
823
+ PreProcessLaneData history_lane_10 = BuildPreProcessLaneData(history_lane_input_10);
824
+ PreProcessLaneData history_lane_01 = BuildPreProcessLaneData(history_lane_input_01);
825
+ PreProcessLaneData history_lane_11 = BuildPreProcessLaneData(history_lane_input_11);
826
+ lr_warped_history_h = AverageWarpedHistory2x2(
827
+ history_lane_00,
828
+ history_lane_10,
829
+ history_lane_01,
830
+ history_lane_11
831
+ );
832
+ }
833
+ #else
834
+ lr_warped_history_h = WarpHistory(reproj_uv);
835
+ #endif // NSS_INPUT_LAYOUT == 1
836
+ half4 deriv_tm1 = LoadDerivativeTm1(reproj_pad_uv);
837
+ half instability = 0.HF;
838
+ #if NSS_YCOCG_LUMA_DERIVATIVE
839
+ float2 derivative_uv = reproj_uv;
840
+ float2 derivative_inv_dims = _InvInputDims;
841
+ #if NSS_INPUT_LAYOUT == 1
842
+ derivative_uv = reproj_pad_uv;
843
+ derivative_inv_dims = _InvPaddedDims;
844
+ #endif // NSS_INPUT_LAYOUT == 1
845
+ half4 luma = CalculateLumaDerivative(
846
+ ref_coord,
847
+ derivative_uv,
848
+ derivative_inv_dims,
849
+ deriv_tm1,
850
+ disocclusion_mask,
851
+ instability
852
+ );
853
+ #else
854
+ half4 luma = CalculateLumaDerivative(unjittered_colour_h, deriv_tm1, disocclusion_mask, instability);
855
+ #endif // NSS_YCOCG_LUMA_DERIVATIVE
856
+ half4 feedback_h = WarpFeedback(reproj_pad_uv, disocclusion_mask);
857
+ half motion_detector = CalculateMotionDetector(motion, _RenderSize);
858
+
859
+ //-------------------------------------------------------------------------
860
+ // 6) Write network tensor for padded domain
861
+ //-------------------------------------------------------------------------
862
+ WriteToTensor(
863
+ padded_coord,
864
+ lr_warped_history_h,
865
+ unjittered_colour_h,
866
+ motion_detector,
867
+ feedback_h,
868
+ instability
869
+ );
870
+
871
+ //-------------------------------------------------------------------------
872
+ // 7) Write per-frame auxiliary outputs for non-padded region only
873
+ //-------------------------------------------------------------------------
874
+ if (any(greaterThanEqual(padded_coord, process_dims))) {
875
+ WriteLumaDerivativeOut(padded_coord, EmptyDerivativeStateForStorage());
876
+ return;
877
+ }
878
+ WriteLumaDerivativeOut(padded_coord, luma);
879
+ #if NSS_INPUT_LAYOUT == 1
880
+ int32_t2 base_input_coord = clamp(process_coord * int32_t2(2), int32_t2(0), _InputDims - int32_t2(1));
881
+ int32_t2 lane_input_00 = base_input_coord;
882
+ int32_t2 lane_input_10 = min(base_input_coord + int32_t2(1, 0), _InputDims - int32_t2(1));
883
+ int32_t2 lane_input_01 = min(base_input_coord + int32_t2(0, 1), _InputDims - int32_t2(1));
884
+ int32_t2 lane_input_11 = min(base_input_coord + int32_t2(1, 1), _InputDims - int32_t2(1));
885
+ int32_t2 quad_offset_00 = int32_t2(0);
886
+ int32_t2 quad_offset_10 = int32_t2(0);
887
+ int32_t2 quad_offset_01 = int32_t2(0);
888
+ int32_t2 quad_offset_11 = int32_t2(0);
889
+ float quad_depth_unused = 0.0;
890
+ FindNearestDepth_4x4_FromPixel(lane_input_00, _InputDims, quad_depth_unused, quad_offset_00);
891
+ FindNearestDepth_4x4_FromPixel(lane_input_10, _InputDims, quad_depth_unused, quad_offset_10);
892
+ FindNearestDepth_4x4_FromPixel(lane_input_01, _InputDims, quad_depth_unused, quad_offset_01);
893
+ FindNearestDepth_4x4_FromPixel(lane_input_11, _InputDims, quad_depth_unused, quad_offset_11);
894
+
895
+ float4 encoded_quad = EncodeNearestOffsetQuadUNormRG8(
896
+ quad_offset_00,
897
+ quad_offset_10,
898
+ quad_offset_01,
899
+ quad_offset_11
900
+ );
901
+ WriteNearestOffsetOut(padded_coord, encoded_quad);
902
+ #else
903
+ WriteNearestOffsetOut(
904
+ padded_coord,
905
+ float4(EncodeNearestDepthCoordUNorm(nearest_offset), 0.0, 0.0, 1.0)
906
+ );
907
+ #endif // NSS_INPUT_LAYOUT == 1
908
+ }
909
+
910
+ #endif // NSS_V1_PRE_PROCESS_SHARED_H
scenario/3_post_process.frag ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //
2
+ // -----------------------------------------------------------------------------
3
+ // The proprietary software and information contained in this file is
4
+ // confidential and may only be used by an authorized person under a valid
5
+ // licensing agreement from Arm Limited or its affiliates.
6
+ //
7
+ // Copyright (C) 2026 Arm Limited or its affiliates. All rights reserved.
8
+ //
9
+ // This entire notice must be reproduced on all copies of this file and
10
+ // copies of this file may only be made by an authorized person under a valid
11
+ // licensing agreement from Arm Limited or its affiliates.
12
+ // -----------------------------------------------------------------------------
13
+ //
14
+
15
+ #version 460
16
+ #extension GL_EXT_shader_8bit_storage : require
17
+ #extension GL_EXT_shader_16bit_storage : require
18
+ #extension GL_EXT_shader_explicit_arithmetic_types : require
19
+ #extension GL_EXT_shader_explicit_arithmetic_types_int8 : require
20
+ #extension GL_EXT_shader_explicit_arithmetic_types_float16 : require
21
+ #extension GL_EXT_shader_explicit_arithmetic_types_float32 : require
22
+ #extension GL_GOOGLE_include_directive : enable
23
+
24
+ #include "typedefs.h"
25
+ #include "common.h"
26
+
27
+ // Compile-time option:
28
+ // -DSIMULATE_R11G11B10_BEFORE_WRITE
29
+
30
+ layout(location = 0) in vec2 vUV;
31
+
32
+ //-----------------------------------------------------------------------------
33
+ // Resources
34
+ //-----------------------------------------------------------------------------
35
+ layout (set=0, binding=0) uniform mediump sampler2D _ColourTex; // 540p->1080p HQ/Low/Mid: 960x540 | R11G11B10 32bpp | 1.978 MiB
36
+ layout (set=0, binding=1) uniform mediump sampler2D _HistoryTex; // 540p->1080p HQ/Low/Mid: 1920x1080 | R11G11B10 32bpp | 7.910 MiB
37
+ layout (set=0, binding=2, std430) readonly buffer KpnParamsBuffer {
38
+ int8_t data[];
39
+ } _KpnParamsBuffer; // 540p->1080p HQ: 240x136x36 | int8 NHWC std430 buffer alias | 1.121 MiB ; Low/Mid: 120x68x16 | 0.125 MiB
40
+ layout (set=0, binding=3) uniform lowp sampler2D _TemporalTensor; // 540p->1080p HQ: 960x544 | R8G8B8A8_SNORM 32bpp | Tensor->Texture Alias (Linear) | 1.992 MiB ; Low/Mid: 480x272 | 0.498 MiB
41
+ layout (set=0, binding=4) uniform mediump sampler2D _MotionVectorTex; // 540p->1080p HQ/Low/Mid: 960x540 | R16G16_SFLOAT 32bpp | 1.978 MiB
42
+ layout (set=0, binding=5) uniform lowp sampler2D _NearestDepthOffsetTex; // 540p->1080p HQ: 960x544 | R8_UNORM 8bpp | nearest-depth offset render target | 0.498 MiB ; Low/Mid: 480x272 | R8G8_UNORM 16bpp | 0.249 MiB
43
+ #if (NSS_FILTER_MODE == 2) || (NSS_FILTER_MODE == 3)
44
+ layout (set=0, binding=6) uniform highp usampler2D _OffsetLutUint4Tex;
45
+ #endif // (NSS_FILTER_MODE == 2) || (NSS_FILTER_MODE == 3)
46
+
47
+ layout(location = 0) out mediump vec4 _ColourOut; // 540p->1080p HQ/Low/Mid: 1920x1080 | R11G11B10 32bpp render target | 7.910 MiB
48
+
49
+ #define NSS_USE_KPN_BASE_X 1
50
+ #include "3_post_process_shared.h"
51
+
52
+ int8_t ReadKpnParamsInt8FromBase(int32_t kpn_texel_base_x, int32_t kpn_y, int32_t channel)
53
+ {
54
+ // SSBO path binds tight NHWC int8 tensor memory.
55
+ int32_t linear_base = ((kpn_y * _KpnDims.x) + kpn_texel_base_x) * kKpnChannels;
56
+ int8_t qv = _KpnParamsBuffer.data[uint32_t(linear_base + channel)];
57
+ return int8_t(qv);
58
+ }
59
+
60
+ void WriteColourOutTarget(int32_t2 coord, half3 out_linear)
61
+ {
62
+ _ColourOut = vec4(float3(out_linear), 1.0);
63
+ }
64
+
65
+ void main()
66
+ {
67
+ _ColourOut = vec4(0.0, 0.0, 0.0, 1.0);
68
+ PostProcessMain(int32_t2(gl_FragCoord.xy));
69
+ }
scenario/3_post_process_shared.h ADDED
@@ -0,0 +1,945 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //
2
+ // -----------------------------------------------------------------------------
3
+ // The proprietary software and information contained in this file is
4
+ // confidential and may only be used by an authorized person under a valid
5
+ // licensing agreement from Arm Limited or its affiliates.
6
+ //
7
+ // Copyright (C) 2026 Arm Limited or its affiliates. All rights reserved.
8
+ //
9
+ // This entire notice must be reproduced on all copies of this file and
10
+ // copies of this file may only be made by an authorized person under a valid
11
+ // licensing agreement from Arm Limited or its affiliates.
12
+ // -----------------------------------------------------------------------------
13
+ //
14
+
15
+ #ifndef NSS_V1_POST_PROCESS_SHARED_H
16
+ #define NSS_V1_POST_PROCESS_SHARED_H
17
+
18
+ // Post-process build define matrix.
19
+ //
20
+ // This lists the defines consumed by this shared post-process header. Defaults
21
+ // may be omitted by the scenario JSON, but the effective values should match
22
+ // the entries below.
23
+ //
24
+ // static LUT / exact 2x | high quality:
25
+ // -DNSS_FILTER_MODE=0
26
+ // -DNSS_INPUT_LAYOUT=0
27
+ // -DNSS_USE_HISTORY_CATMULL=1
28
+ // -DNSS_V1_SHARP_THETA=1
29
+ //
30
+ // static LUT / exact 2x | mid quality:
31
+ // -DNSS_FILTER_MODE=1
32
+ // -DNSS_INPUT_LAYOUT=1
33
+ // -DNSS_USE_HISTORY_CATMULL=1
34
+ // -DNSS_V1_SHARP_THETA=1
35
+ //
36
+ // static LUT / exact 2x | low quality:
37
+ // -DNSS_FILTER_MODE=1
38
+ // -DNSS_INPUT_LAYOUT=1
39
+ // -DNSS_USE_HISTORY_CATMULL=0
40
+ // -DNSS_V1_SHARP_THETA=1
41
+ //
42
+ // non-integer dynamic LUT | high quality:
43
+ // post-process:
44
+ // -DNSS_FILTER_MODE=2
45
+ // -DNSS_INPUT_LAYOUT=0
46
+ // -DNSS_USE_HISTORY_CATMULL=1
47
+ // -DNSS_V1_SHARP_THETA=1
48
+ // paired LUT generator:
49
+ // -DNSS_FILTER_MODE=2
50
+ //
51
+ // non-integer dynamic LUT | mid quality:
52
+ // post-process:
53
+ // -DNSS_FILTER_MODE=3
54
+ // -DNSS_INPUT_LAYOUT=1
55
+ // -DNSS_USE_HISTORY_CATMULL=1
56
+ // -DNSS_V1_SHARP_THETA=1
57
+ // paired LUT generator:
58
+ // -DNSS_FILTER_MODE=3
59
+ //
60
+ // non-integer dynamic LUT | low quality:
61
+ // post-process:
62
+ // -DNSS_FILTER_MODE=3
63
+ // -DNSS_INPUT_LAYOUT=1
64
+ // -DNSS_USE_HISTORY_CATMULL=0
65
+ // -DNSS_V1_SHARP_THETA=1
66
+ // paired LUT generator:
67
+ // -DNSS_FILTER_MODE=3
68
+
69
+ #ifndef NSS_USE_HISTORY_CATMULL
70
+ #define NSS_USE_HISTORY_CATMULL 1
71
+ #endif // !NSS_USE_HISTORY_CATMULL
72
+ #ifndef NSS_FILTER_MODE
73
+ // 0: static 2x high, 1: static 2x sparse, 2: dynamic dense LUT, 3: dynamic sparse LUT.
74
+ #define NSS_FILTER_MODE 0
75
+ #endif // !NSS_FILTER_MODE
76
+ #ifndef NSS_INPUT_LAYOUT
77
+ // 0: full-resolution preprocess outputs, 1: half-resolution outputs with packed nearest-depth offsets.
78
+ #define NSS_INPUT_LAYOUT 0
79
+ #endif // !NSS_INPUT_LAYOUT
80
+ #ifndef NSS_V1_SHARP_THETA
81
+ #define NSS_V1_SHARP_THETA 1
82
+ #endif // !NSS_V1_SHARP_THETA
83
+
84
+ #if (NSS_FILTER_MODE < 0) || (NSS_FILTER_MODE > 3)
85
+ #error "NSS_FILTER_MODE must be 0 (static 2x high), 1 (static 2x sparse), 2 (dynamic dense LUT), or 3 (dynamic sparse LUT)."
86
+ #endif // filter implementation selection
87
+
88
+ // Matches Slang layout and includes both geometric scales and temporal controls.
89
+ layout(push_constant, std430) uniform PushConstants {
90
+ // ─────────────── 8-byte aligned ───────────────
91
+ // High-res output extent divided by low-res input extent.
92
+ layout(offset = 0) float2 _Scale; // 8 B
93
+ // Inverse of `_Scale`.
94
+ layout(offset = 8) float2 _InvScale; // 8 B
95
+ // High-resolution output dimensions.
96
+ layout(offset = 16) int32_t2 _OutputDims; // 8 B
97
+ // Low-resolution input dimensions.
98
+ layout(offset = 24) int32_t2 _InputDims; // 8 B
99
+ // KPN tensor dimensions.
100
+ layout(offset = 32) int32_t2 _KpnDims; // 8 B
101
+ // Inverse of `_OutputDims`.
102
+ layout(offset = 40) float2 _InvOutputDims; // 8 B
103
+ // Inverse of `_InputDims`.
104
+ layout(offset = 48) float2 _InvInputDims; // 8 B
105
+ // Inverse of `_KpnDims`.
106
+ layout(offset = 56) float2 _InvKpnDims; // 8 B
107
+ // UV scale from preprocess space into temporal-feedback space.
108
+ layout(offset = 64) float2 _PaddedUvScale; // 8 B
109
+ // UV scale from temporal-feedback space into KPN space.
110
+ layout(offset = 72) float2 _KpnScale; // 8 B
111
+ // Tile modulo used for offset-LUT pattern selection.
112
+ layout(offset = 80) int32_t2 _IdxModulo; // 8 B
113
+ // Exposure packed as (exposure, 1/exposure).
114
+ layout(offset = 88) float2 _Exposure; // 8 B
115
+
116
+ // ─────────────── 4-byte aligned ───────────────
117
+ // Temporal reset / history blending gate.
118
+ layout(offset = 96) float _Reset; // 4 B
119
+
120
+ // ─────────────── padding to next 8-byte member ───────────────
121
+ // Offsets [100, 103] are implicit pad to preserve Slang parity.
122
+
123
+ // ─────────────── 8-byte aligned ───────────────
124
+ // Jitter-dependent tile remap offset inside the modulo lattice.
125
+ layout(offset = 104) int32_t2 _LutOffset; // 8 B
126
+ // Logical preprocess dimensions used to address temporal feedback.
127
+ layout(offset = 112) int32_t2 _PreprocessDims; // 8 B
128
+ // Total: **120 bytes**
129
+ };
130
+
131
+ const float kEps = 1e-7;
132
+ const half kMotionThreshold = 0.1HF;
133
+ const float kMotionThresholdSq = float(kMotionThreshold) * float(kMotionThreshold);
134
+ #if (NSS_FILTER_MODE == 1) || (NSS_FILTER_MODE == 3) || (NSS_INPUT_LAYOUT == 1)
135
+ const int32_t kKpnChannels = 16;
136
+ #else
137
+ const int32_t kKpnChannels = 36;
138
+ #endif // (NSS_FILTER_MODE == 1) || (NSS_FILTER_MODE == 3) || (NSS_INPUT_LAYOUT == 1)
139
+ const int32_t kKpnPackedChannelsPerTexel = 4;
140
+ const int32_t kKpnPackedTexelsPerPixel = kKpnChannels / kKpnPackedChannelsPerTexel;
141
+ const int32_t kKpnPackedChannelShift = 2;
142
+ const int32_t kKpnPackedChannelMask = kKpnPackedChannelsPerTexel - 1;
143
+ const int32_t kKpnLaneX = 0;
144
+ const int32_t kKpnLaneY = 1;
145
+ const int32_t kKpnLaneZ = 2;
146
+ const bool kUseMotionThreshold = false;
147
+ // QAT metadata (`_KpnCoefficients` / `_TemporalTensor` SINT).
148
+ const half2 kKpnQuant = half2(0.003937007859349251, -127.0);
149
+ // Temporal params are sampled from SNORM image alias, so use SNORM dequant.
150
+ const half2 kTemporalQuant = half2(0.49999999813735485, -1.0);
151
+ const int32_t kLutPatternCount = 4;
152
+
153
+ struct KernelPattern
154
+ {
155
+ int16_t2 base_offset;
156
+ int16_t base_channel;
157
+ int16_t _pad0;
158
+ };
159
+
160
+ #if NSS_FILTER_MODE == 0
161
+ const int16_t4 kTapDx0 = int16_t4(0, 0, 0, 2);
162
+ const int16_t4 kTapDy0 = int16_t4(0, 2, 4, 0);
163
+ const int16_t4 kTapCh0 = int16_t4(0, 2, 4, 12);
164
+ const int16_t4 kTapDx1 = int16_t4(2, 2, 4, 4);
165
+ const int16_t4 kTapDy1 = int16_t4(2, 4, 0, 2);
166
+ const int16_t4 kTapCh1 = int16_t4(14, 16, 24, 26);
167
+ const int16_t2 kTapD2 = int16_t2(4, 4);
168
+ const int16_t kTapCh2 = int16_t(28);
169
+
170
+ // 2x scale patterns from generated NSS v1 LUT for jitter in [-0.5, 0.5), with jitter-driven tile remap via _LutOffset.
171
+ const KernelPattern kKernelLut[kLutPatternCount] = KernelPattern[kLutPatternCount](
172
+ KernelPattern(
173
+ int16_t2(-1, -1), int16_t(7), int16_t(0)
174
+ ),
175
+ KernelPattern(
176
+ int16_t2(-2, -1), int16_t(1), int16_t(0)
177
+ ),
178
+ KernelPattern(
179
+ int16_t2(-1, -2), int16_t(6), int16_t(0)
180
+ ),
181
+ KernelPattern(
182
+ int16_t2(-2, -2), int16_t(0), int16_t(0)
183
+ )
184
+ );
185
+ #endif // NSS_FILTER_MODE == 0
186
+
187
+ #if NSS_FILTER_MODE == 1
188
+ // 2x2 sparse low-quality mode keeps the centered 4x4 subset of the original
189
+ // 6x6 KPN, preserving the generated offset-LUT tap order after pruning.
190
+ const int16_t4 kTap2x2Dx[kLutPatternCount] = int16_t4[kLutPatternCount](
191
+ int16_t4(-1, -1, +1, +1),
192
+ int16_t4(+0, +0, +2, +2),
193
+ int16_t4(-1, +1, -1, +1),
194
+ int16_t4(+0, +0, +2, +2)
195
+ );
196
+ const int16_t4 kTap2x2Dy[kLutPatternCount] = int16_t4[kLutPatternCount](
197
+ int16_t4(-1, +1, -1, +1),
198
+ int16_t4(-1, +1, -1, +1),
199
+ int16_t4(+0, +0, +2, +2),
200
+ int16_t4(+0, +2, +0, +2)
201
+ );
202
+ const int16_t4 kTap2x2Ch[kLutPatternCount] = int16_t4[kLutPatternCount](
203
+ int16_t4(0, 2, 8, 10),
204
+ int16_t4(4, 6, 12, 14),
205
+ int16_t4(1, 9, 3, 11),
206
+ int16_t4(5, 7, 13, 15)
207
+ );
208
+ #endif // NSS_FILTER_MODE == 1
209
+
210
+ #if (NSS_FILTER_MODE == 2) || (NSS_FILTER_MODE == 3)
211
+ struct OffsetLutTap
212
+ {
213
+ int32_t2 lr_offset;
214
+ int32_t tap_channel;
215
+ bool valid;
216
+ bool center;
217
+ };
218
+
219
+ int32_t DecodePackedI8(uint32_t packed, uint32_t shift)
220
+ {
221
+ return bitfieldExtract(int32_t(packed), int32_t(shift), int32_t(8));
222
+ }
223
+
224
+ OffsetLutTap DecodePackedOffsetLutTap(uint32_t packed)
225
+ {
226
+ OffsetLutTap tap;
227
+ tap.lr_offset = int32_t2(
228
+ DecodePackedI8(packed, uint32_t(0)),
229
+ DecodePackedI8(packed, uint32_t(8))
230
+ );
231
+ tap.tap_channel = int32_t((packed >> uint32_t(16)) & uint32_t(0x3F));
232
+ tap.valid = ((packed >> uint32_t(22)) & uint32_t(1)) != uint32_t(0);
233
+ tap.center = ((packed >> uint32_t(23)) & uint32_t(1)) != uint32_t(0);
234
+ return tap;
235
+ }
236
+
237
+ uint32_t4 LoadOffsetLutPacked4(int32_t lut_idx, int32_t group_idx)
238
+ {
239
+ return texelFetch(_OffsetLutUint4Tex, int32_t2(group_idx, lut_idx), 0);
240
+ }
241
+ #endif // (NSS_FILTER_MODE == 2) || (NSS_FILTER_MODE == 3)
242
+
243
+ //-----------------------------------------------------------------------------
244
+ // Numeric helpers
245
+ //-----------------------------------------------------------------------------
246
+ half MaxHalf(half x)
247
+ {
248
+ // Clamp to fp16 max to mimic storage/arith limits used in runtime.
249
+ return min(x, 65504.HF);
250
+ }
251
+
252
+ half3 MaxHalf(half3 x)
253
+ {
254
+ return min(x, half3(65504.HF));
255
+ }
256
+
257
+ half4 MaxHalf(half4 x)
258
+ {
259
+ return min(x, half4(65504.HF));
260
+ }
261
+
262
+ int32_t2 DecodeNearestOffset(int32_t2 pixel)
263
+ {
264
+ // Decode packed nearest-depth offset from R8_UNORM or low-quality RG8 quad packing.
265
+ float norm_code = 0.0;
266
+ #if NSS_INPUT_LAYOUT == 1
267
+ int32_t2 texel = clamp(
268
+ int32_t2(floor((float2(pixel) + float2(0.5)) * float2(_PreprocessDims) * _InvInputDims)),
269
+ int32_t2(0),
270
+ _PreprocessDims - int32_t2(1)
271
+ );
272
+ float2 norm_code_pair = texelFetch(_NearestDepthOffsetTex, texel, 0).rg;
273
+ int32_t lane_idx = (pixel.y & int32_t(1)) * int32_t(2) + (pixel.x & int32_t(1));
274
+ int32_t packed_byte = lane_idx < int32_t(2)
275
+ ? int32_t(norm_code_pair.x * 255.0 + 0.5)
276
+ : int32_t(norm_code_pair.y * 255.0 + 0.5);
277
+ int32_t packed_nibble = (lane_idx & int32_t(1)) == int32_t(0)
278
+ ? (packed_byte & 0xF)
279
+ : ((packed_byte >> 4) & 0xF);
280
+ return DecodeNearestDepthCoordNibble(packed_nibble);
281
+ #else
282
+ // Use logical input domain (not physical image extent) so padded fragment
283
+ // outputs preserve compute-path sampling behaviour.
284
+ pixel = clamp(pixel, int32_t2(0), _InputDims - int32_t2(1));
285
+ norm_code = texelFetch(_NearestDepthOffsetTex, pixel, 0).r;
286
+ #endif // NSS_INPUT_LAYOUT == 1
287
+ int32_t code = int32_t(norm_code * 255.0 + 0.5);
288
+ int32_t x = (code & 0x7) - 2;
289
+ int32_t y = ((code >> 3) & 0x7) - 2;
290
+ return int32_t2(x, y);
291
+ }
292
+
293
+ half2 LoadMotion(int32_t2 output_coord)
294
+ {
295
+ // Reproject motion lookup using nearest-depth dilated coordinate.
296
+ int32_t2 input_coord = int32_t2(float2(output_coord) * _InvScale);
297
+ int32_t2 dilation_offset = DecodeNearestOffset(input_coord);
298
+ int32_t2 dilated_coord = clamp(input_coord + dilation_offset, int32_t2(0), _InputDims - int32_t2(1));
299
+
300
+ half2 v = half2(texelFetch(_MotionVectorTex, dilated_coord, 0).xy) * half2(_Scale);
301
+ if (kUseMotionThreshold) {
302
+ v *= half(dot(float2(v), float2(v)) > kMotionThresholdSq);
303
+ }
304
+ return v;
305
+ }
306
+
307
+ half3 LoadColourTap(int32_t2 lr_tap)
308
+ {
309
+ return half3(texelFetch(_ColourTex, lr_tap, 0).rgb);
310
+ }
311
+
312
+ half4 LoadColourTap4(int32_t2 lr_tap)
313
+ {
314
+ return half4(LoadColourTap(lr_tap), 1.HF);
315
+ }
316
+
317
+ int8_t ReadKpnParamsInt8(int32_t2 kpn_tap, int32_t channel);
318
+ int8_t ReadKpnParamsInt8FromBase(int32_t kpn_texel_base_x, int32_t kpn_y, int32_t channel);
319
+
320
+ int32_t KpnCoordFromInputCoord(int32_t input_coord, int32_t input_dim, int32_t kpn_dim)
321
+ {
322
+ int32_t safe_input_dim = max(input_dim, int32_t(1));
323
+ return min((input_coord * kpn_dim) / safe_input_dim, kpn_dim - int32_t(1));
324
+ }
325
+
326
+ int16_t4 KpnCoordFromInputCoord4(int16_t4 input_coord, int32_t input_dim, int32_t kpn_dim)
327
+ {
328
+ int32_t safe_input_dim = max(input_dim, int32_t(1));
329
+ int32_t4 scaled = (int32_t4(input_coord) * int32_t4(kpn_dim)) / int32_t4(safe_input_dim);
330
+ return int16_t4(min(scaled, int32_t4(kpn_dim - int32_t(1))));
331
+ }
332
+
333
+ int32_t KpnCoordFromScaledTap(int32_t tap_coord, float scale, int32_t kpn_dim)
334
+ {
335
+ int32_t scaled = int32_t(floor((float(tap_coord) + 0.5 + 1e-3) * scale));
336
+ return min(scaled, kpn_dim - int32_t(1));
337
+ }
338
+
339
+ int16_t4 KpnCoordFromScaledTap4(int16_t4 tap_coord, float scale, int32_t kpn_dim)
340
+ {
341
+ int32_t4 scaled = int32_t4(floor((float4(tap_coord) + float4(0.5 + 1e-3)) * float4(scale)));
342
+ return int16_t4(min(scaled, int32_t4(kpn_dim - int32_t(1))));
343
+ }
344
+
345
+ half SampleKpnWeight(int32_t tap_z, int32_t2 kpn_tap)
346
+ {
347
+ // KPN comes from `1_nss` as an int8 tensor with `kKpnChannels` channels.
348
+ int8_t q = ReadKpnParamsInt8FromBase(kpn_tap.x, kpn_tap.y, tap_z);
349
+ return max(Dequantize(half(q), kKpnQuant), EPS);
350
+ }
351
+
352
+ half4 LoadWarpedHistory(float2 uv)
353
+ {
354
+ return half4(texture(_HistoryTex, uv).rgb, 1.HF);
355
+ }
356
+
357
+ #if NSS_USE_HISTORY_CATMULL
358
+ half4 LoadWarpedHistoryCatmull(float2 uv)
359
+ {
360
+ //------------------------------------------------------------------------------------
361
+ // 1) Compute Catmull–Rom weights
362
+ //------------------------------------------------------------------------------------
363
+ float2 scaledUV = uv * _OutputDims;
364
+ float2 baseFloor = floor(scaledUV - 0.5) + 0.5;
365
+
366
+ half2 f = half2(scaledUV - baseFloor);
367
+ half2 f2 = f * f;
368
+ half2 f3 = f2 * f;
369
+
370
+ // Catmull–Rom basis terms used by the 5-tap cross filter.
371
+ half2 w0 = f2 - 0.5HF * (f3 + f);
372
+ half2 w3 = 0.5HF * (f3 - f2);
373
+ half2 w2 = 0.5HF * f + f2 * (2.0HF - 1.5HF * f);
374
+ half2 w12 = 1.0HF + 0.5HF * f - 0.5HF * f2; // w1 + w2
375
+
376
+ // Keep axis-combination math in half2 to improve vector utilization.
377
+ half2 wx02 = half2(w0.x, w3.x); // left/right X weights
378
+ half2 wy02 = half2(w0.y, w3.y); // up/down Y weights
379
+ half2 w_ud = half2(w12.x) * wy02; // up, down
380
+ half2 w_lr = half2(w12.y) * wx02; // left, right
381
+ half wCenter = w12.x * w12.y;
382
+
383
+ // Fractional offsets for the center sample location.
384
+ half2 dxy = w2 / max(w12, half2(EPS));
385
+
386
+ //------------------------------------------------------------------------------------
387
+ // 2) Gather the 5 taps
388
+ //------------------------------------------------------------------------------------
389
+ float2 base_uv = baseFloor * _InvOutputDims;
390
+ float2 center_uv = base_uv + float2(dxy) * _InvOutputDims;
391
+ float left_x = base_uv.x - _InvOutputDims.x;
392
+ float right_x = base_uv.x + 2.0 * _InvOutputDims.x;
393
+ float up_y = base_uv.y - _InvOutputDims.y;
394
+ float down_y = base_uv.y + 2.0 * _InvOutputDims.y;
395
+
396
+ half4 left = half4(texture(_HistoryTex, float2(left_x, center_uv.y)).rgb, 1.HF);
397
+ half4 up = half4(texture(_HistoryTex, float2(center_uv.x, up_y)).rgb, 1.HF);
398
+ half4 center = half4(texture(_HistoryTex, center_uv).rgb, 1.HF);
399
+ half4 right = half4(texture(_HistoryTex, float2(right_x, center_uv.y)).rgb, 1.HF);
400
+ half4 down = half4(texture(_HistoryTex, float2(center_uv.x, down_y)).rgb, 1.HF);
401
+
402
+ //------------------------------------------------------------------------------------
403
+ // 3) Accumulate and track min/max
404
+ //------------------------------------------------------------------------------------
405
+ half4 accum = up * w_ud.x +
406
+ left * w_lr.x +
407
+ center* wCenter +
408
+ right * w_lr.y +
409
+ down * w_ud.y;
410
+ half4 cmin4 = min(up, min(left, min(center, min(right, down))));
411
+ half4 cmax4 = max(up, max(left, max(center, max(right, down))));
412
+
413
+ //------------------------------------------------------------------------------------
414
+ // 4) Final color
415
+ //------------------------------------------------------------------------------------
416
+ half3 color = accum.rgb * rcp(accum.w);
417
+
418
+ // dering in the case where we have negative values, we don't do this all the time
419
+ // as it can impose unnecessary blurring on the output
420
+ color = any(lessThan(color, half3(0.HF))) ? clamp(color, cmin4.rgb, cmax4.rgb) : color;
421
+ return half4(color, 1.HF);
422
+ }
423
+ #endif // NSS_USE_HISTORY_CATMULL
424
+
425
+ half4 SampleKpnWeight4(int16_t4 tap_z, int16_t4 kpn_x, int16_t4 kpn_y)
426
+ {
427
+ int8_t4 q = int8_t4(
428
+ ReadKpnParamsInt8FromBase(kpn_x.x, kpn_y.x, tap_z.x),
429
+ ReadKpnParamsInt8FromBase(kpn_x.y, kpn_y.y, tap_z.y),
430
+ ReadKpnParamsInt8FromBase(kpn_x.z, kpn_y.z, tap_z.z),
431
+ ReadKpnParamsInt8FromBase(kpn_x.w, kpn_y.w, tap_z.w)
432
+ );
433
+ return max(Dequantize(half4(q), kKpnQuant), half4(EPS));
434
+ }
435
+
436
+ #define NSS_SQ_MAT(_M) \
437
+ f16mat4x4(_M[0] * _M[0], _M[1] * _M[1], _M[2] * _M[2], _M[3] * _M[3])
438
+
439
+ #define NSS_LOAD_TAPS_4(TAP_X, TAP_Y, OUT_MAT) \
440
+ { \
441
+ OUT_MAT[0] = LoadColourTap4(int32_t2(TAP_X.x, TAP_Y.x)); \
442
+ OUT_MAT[1] = LoadColourTap4(int32_t2(TAP_X.y, TAP_Y.y)); \
443
+ OUT_MAT[2] = LoadColourTap4(int32_t2(TAP_X.z, TAP_Y.z)); \
444
+ OUT_MAT[3] = LoadColourTap4(int32_t2(TAP_X.w, TAP_Y.w)); \
445
+ }
446
+
447
+ void NormalizeFilterMoments(
448
+ half4 accum_m1,
449
+ half4 accum_m2,
450
+ out half4 m1,
451
+ out half4 m2)
452
+ {
453
+ half denom = max(accum_m1.a, EPS);
454
+ m1 = half4(accum_m1.rgb * rcp(denom), 0.HF);
455
+ m2 = half4(accum_m2.rgb * rcp(denom), 0.HF);
456
+ }
457
+
458
+ int32_t2 KpnCoordForDenseFilter(int32_t2 lr_tap, int32_t2 kpn_max)
459
+ {
460
+ #if NSS_INPUT_LAYOUT == 1
461
+ return clamp(
462
+ int32_t2(
463
+ KpnCoordFromInputCoord(lr_tap.x, _InputDims.x, _KpnDims.x),
464
+ KpnCoordFromInputCoord(lr_tap.y, _InputDims.y, _KpnDims.y)
465
+ ),
466
+ int32_t2(0),
467
+ kpn_max
468
+ );
469
+ #else
470
+ return clamp(
471
+ int32_t2(
472
+ KpnCoordFromScaledTap(lr_tap.x, _KpnScale.x, _KpnDims.x),
473
+ KpnCoordFromScaledTap(lr_tap.y, _KpnScale.y, _KpnDims.y)
474
+ ),
475
+ int32_t2(0),
476
+ kpn_max
477
+ );
478
+ #endif // NSS_INPUT_LAYOUT == 1
479
+ }
480
+
481
+ void KpnCoordsForDenseFilter4(
482
+ int16_t4 tap_x,
483
+ int16_t4 tap_y,
484
+ int16_t4 zero4,
485
+ int16_t4 kpn_max_x4,
486
+ int16_t4 kpn_max_y4,
487
+ out int16_t4 kpn_x,
488
+ out int16_t4 kpn_y)
489
+ {
490
+ #if NSS_INPUT_LAYOUT == 1
491
+ kpn_x = clamp(KpnCoordFromInputCoord4(tap_x, _InputDims.x, _KpnDims.x), zero4, kpn_max_x4);
492
+ kpn_y = clamp(KpnCoordFromInputCoord4(tap_y, _InputDims.y, _KpnDims.y), zero4, kpn_max_y4);
493
+ #else
494
+ kpn_x = clamp(KpnCoordFromScaledTap4(tap_x, _KpnScale.x, _KpnDims.x), zero4, kpn_max_x4);
495
+ kpn_y = clamp(KpnCoordFromScaledTap4(tap_y, _KpnScale.y, _KpnDims.y), zero4, kpn_max_y4);
496
+ #endif // NSS_INPUT_LAYOUT == 1
497
+ }
498
+
499
+ #if (NSS_FILTER_MODE == 2) || (NSS_FILTER_MODE == 3)
500
+ int32_t2 PackedOffsetLutModulo()
501
+ {
502
+ return max(int32_t2(_IdxModulo.y, _IdxModulo.x), int32_t2(1));
503
+ }
504
+
505
+ void AccumulatePackedLrOffsetTap(
506
+ OffsetLutTap lut_tap,
507
+ int32_t2 lr_base,
508
+ int32_t2 colour_max,
509
+ int32_t2 kpn_max,
510
+ inout half4 accum_m1,
511
+ inout half4 accum_m2,
512
+ inout half4 center_sample)
513
+ {
514
+ if (!lut_tap.valid && !lut_tap.center) {
515
+ return;
516
+ }
517
+ int32_t2 lr_tap = clamp(lr_base + lut_tap.lr_offset, int32_t2(0), colour_max);
518
+ half4 tap_col = LoadColourTap4(lr_tap);
519
+ if (lut_tap.center) {
520
+ center_sample = tap_col;
521
+ }
522
+ if (!lut_tap.valid) {
523
+ return;
524
+ }
525
+ int32_t2 kpn_tap = KpnCoordForDenseFilter(lr_tap, kpn_max);
526
+ half tap_weight = SampleKpnWeight(lut_tap.tap_channel, kpn_tap);
527
+ accum_m1 += tap_col * tap_weight;
528
+ accum_m2 += (tap_col * tap_col) * tap_weight;
529
+ }
530
+ #endif // (NSS_FILTER_MODE == 2) || (NSS_FILTER_MODE == 3)
531
+
532
+ #if NSS_FILTER_MODE == 2
533
+ void FilterColour(
534
+ int32_t2 output_px,
535
+ out half4 m1,
536
+ out half4 m2,
537
+ out half4 center_sample)
538
+ {
539
+ //-------------------------------------------------------------------------
540
+ // Non-integer fastest path: the LUT stores final LR offsets, tap channel,
541
+ // valid, and center bits. The LUT is generated on GPU and consumed as three
542
+ // RGBA32_UINT texels per modulo tile.
543
+ //-------------------------------------------------------------------------
544
+ int32_t2 colour_max = _InputDims - int32_t2(1);
545
+ int32_t2 kpn_max = _KpnDims - int32_t2(1);
546
+ int32_t2 idx_mod_xy = PackedOffsetLutModulo();
547
+ int32_t2 tile_idx = output_px % idx_mod_xy;
548
+ int32_t lut_idx = tile_idx.y * idx_mod_xy.x + tile_idx.x;
549
+ int32_t2 lr_base = int32_t2(floor(float2(output_px) * _InvScale));
550
+
551
+ half4 accum_m1 = half4(0.HF);
552
+ half4 accum_m2 = half4(0.HF);
553
+ center_sample = half4(0.HF);
554
+
555
+ uint32_t4 packed_taps0 = LoadOffsetLutPacked4(lut_idx, int32_t(0));
556
+ AccumulatePackedLrOffsetTap(
557
+ DecodePackedOffsetLutTap(packed_taps0.x), lr_base, colour_max, kpn_max, accum_m1, accum_m2, center_sample
558
+ );
559
+ AccumulatePackedLrOffsetTap(
560
+ DecodePackedOffsetLutTap(packed_taps0.y), lr_base, colour_max, kpn_max, accum_m1, accum_m2, center_sample
561
+ );
562
+ AccumulatePackedLrOffsetTap(
563
+ DecodePackedOffsetLutTap(packed_taps0.z), lr_base, colour_max, kpn_max, accum_m1, accum_m2, center_sample
564
+ );
565
+ AccumulatePackedLrOffsetTap(
566
+ DecodePackedOffsetLutTap(packed_taps0.w), lr_base, colour_max, kpn_max, accum_m1, accum_m2, center_sample
567
+ );
568
+
569
+ uint32_t4 packed_taps1 = LoadOffsetLutPacked4(lut_idx, int32_t(1));
570
+ AccumulatePackedLrOffsetTap(
571
+ DecodePackedOffsetLutTap(packed_taps1.x), lr_base, colour_max, kpn_max, accum_m1, accum_m2, center_sample
572
+ );
573
+ AccumulatePackedLrOffsetTap(
574
+ DecodePackedOffsetLutTap(packed_taps1.y), lr_base, colour_max, kpn_max, accum_m1, accum_m2, center_sample
575
+ );
576
+ AccumulatePackedLrOffsetTap(
577
+ DecodePackedOffsetLutTap(packed_taps1.z), lr_base, colour_max, kpn_max, accum_m1, accum_m2, center_sample
578
+ );
579
+ AccumulatePackedLrOffsetTap(
580
+ DecodePackedOffsetLutTap(packed_taps1.w), lr_base, colour_max, kpn_max, accum_m1, accum_m2, center_sample
581
+ );
582
+
583
+ uint32_t4 packed_taps2 = LoadOffsetLutPacked4(lut_idx, int32_t(2));
584
+ AccumulatePackedLrOffsetTap(
585
+ DecodePackedOffsetLutTap(packed_taps2.x), lr_base, colour_max, kpn_max, accum_m1, accum_m2, center_sample
586
+ );
587
+
588
+ NormalizeFilterMoments(accum_m1, accum_m2, m1, m2);
589
+ }
590
+ #endif // NSS_FILTER_MODE == 2
591
+
592
+ #if NSS_FILTER_MODE == 3
593
+ int16_t4 DecodePackedI8x4(uint32_t4 packed, uint32_t shift)
594
+ {
595
+ return int16_t4(bitfieldExtract(int32_t4(packed), int32_t(shift), int32_t(8)));
596
+ }
597
+
598
+ int16_t4 DecodePackedTapChannel4(uint32_t4 packed)
599
+ {
600
+ return int16_t4((packed >> uint32_t4(16)) & uint32_t4(0x3F));
601
+ }
602
+
603
+ half4 DecodePackedValidMask4(uint32_t4 packed)
604
+ {
605
+ return half4((packed >> uint32_t4(22)) & uint32_t4(1));
606
+ }
607
+
608
+ void FilterColour(
609
+ int32_t2 output_px,
610
+ out half4 m1,
611
+ out half4 m2,
612
+ out half4 center_sample)
613
+ {
614
+ //-------------------------------------------------------------------------
615
+ // Non-integer sparse path: one RGBA32_UINT LUT texel stores the 4 selected
616
+ // 2x2 taps for the modulo tile. The tap payload is identical to the dense
617
+ // dynamic path, but the generator has already pruned the 4x4 KPN window.
618
+ //-------------------------------------------------------------------------
619
+ int32_t2 colour_max = _InputDims - int32_t2(1);
620
+ int32_t2 kpn_max = _KpnDims - int32_t2(1);
621
+ int32_t2 idx_mod_xy = PackedOffsetLutModulo();
622
+ int32_t2 tile_idx = output_px % idx_mod_xy;
623
+ int32_t lut_idx = tile_idx.y * idx_mod_xy.x + tile_idx.x;
624
+ int32_t2 lr_base = int32_t2(floor(float2(output_px) * _InvScale));
625
+
626
+ half4 accum_m1 = half4(0.HF);
627
+ half4 accum_m2 = half4(0.HF);
628
+ center_sample = half4(0.HF);
629
+
630
+ uint32_t4 packed_taps = LoadOffsetLutPacked4(lut_idx, int32_t(0));
631
+ int32_t4 lr_tap_x = clamp(
632
+ int32_t4(lr_base.x) + int32_t4(DecodePackedI8x4(packed_taps, uint32_t(0))),
633
+ int32_t4(0),
634
+ int32_t4(colour_max.x)
635
+ );
636
+ int32_t4 lr_tap_y = clamp(
637
+ int32_t4(lr_base.y) + int32_t4(DecodePackedI8x4(packed_taps, uint32_t(8))),
638
+ int32_t4(0),
639
+ int32_t4(colour_max.y)
640
+ );
641
+ int16_t4 tap_x = int16_t4(lr_tap_x);
642
+ int16_t4 tap_y = int16_t4(lr_tap_y);
643
+ int16_t4 kpn_x;
644
+ int16_t4 kpn_y;
645
+ KpnCoordsForDenseFilter4(
646
+ tap_x,
647
+ tap_y,
648
+ int16_t4(0),
649
+ int16_t4(kpn_max.x),
650
+ int16_t4(kpn_max.y),
651
+ kpn_x,
652
+ kpn_y
653
+ );
654
+
655
+ f16mat4x4 taps;
656
+ NSS_LOAD_TAPS_4(tap_x, tap_y, taps);
657
+ half4 weights = SampleKpnWeight4(DecodePackedTapChannel4(packed_taps), kpn_x, kpn_y);
658
+ weights *= DecodePackedValidMask4(packed_taps);
659
+
660
+ uint32_t4 center_bits = (packed_taps >> uint32_t4(23)) & uint32_t4(1);
661
+ if (center_bits.x != uint32_t(0)) {
662
+ center_sample = taps[0];
663
+ } else if (center_bits.y != uint32_t(0)) {
664
+ center_sample = taps[1];
665
+ } else if (center_bits.z != uint32_t(0)) {
666
+ center_sample = taps[2];
667
+ } else if (center_bits.w != uint32_t(0)) {
668
+ center_sample = taps[3];
669
+ }
670
+ accum_m1 += taps * weights;
671
+ accum_m2 += NSS_SQ_MAT(taps) * weights;
672
+
673
+ NormalizeFilterMoments(accum_m1, accum_m2, m1, m2);
674
+ }
675
+ #endif // NSS_FILTER_MODE == 3
676
+
677
+ #if NSS_FILTER_MODE == 1
678
+ void FilterColour(
679
+ int32_t2 output_px,
680
+ out half4 m1,
681
+ out half4 m2,
682
+ out half4 center_sample)
683
+ {
684
+ //-------------------------------------------------------------------------
685
+ // Mid-quality path: sparse 2x2 subset of the 6x6 KPN.
686
+ //-------------------------------------------------------------------------
687
+ int32_t2 colour_max = _InputDims - int32_t2(1);
688
+ int32_t2 kpn_max = _KpnDims - int32_t2(1);
689
+ int16_t4 colour_max_x4 = int16_t4(colour_max.x);
690
+ int16_t4 colour_max_y4 = int16_t4(colour_max.y);
691
+ int16_t4 kpn_max_x4 = int16_t4(kpn_max.x);
692
+ int16_t4 kpn_max_y4 = int16_t4(kpn_max.y);
693
+ int16_t4 zero4 = int16_t4(0);
694
+ int16_t2 out_px16 = int16_t2(output_px);
695
+ int32_t2 tile_idx = (output_px + _LutOffset) & int32_t2(1);
696
+ int32_t lut_idx = (tile_idx.y << int32_t(1)) + tile_idx.x;
697
+
698
+ half4 accum_m1 = half4(0.HF);
699
+ half4 accum_m2 = half4(0.HF);
700
+
701
+ int16_t4 tap_x = clamp((int16_t4(out_px16.x) + kTap2x2Dx[lut_idx]) >> int16_t(1), zero4, colour_max_x4);
702
+ int16_t4 tap_y = clamp((int16_t4(out_px16.y) + kTap2x2Dy[lut_idx]) >> int16_t(1), zero4, colour_max_y4);
703
+ int16_t4 kpn_x = clamp(KpnCoordFromInputCoord4(tap_x, _InputDims.x, _KpnDims.x), zero4, kpn_max_x4);
704
+ int16_t4 kpn_y = clamp(KpnCoordFromInputCoord4(tap_y, _InputDims.y, _KpnDims.y), zero4, kpn_max_y4);
705
+
706
+ f16mat4x4 taps;
707
+ NSS_LOAD_TAPS_4(tap_x, tap_y, taps);
708
+ half4 weights = SampleKpnWeight4(kTap2x2Ch[lut_idx], kpn_x, kpn_y);
709
+ center_sample = (lut_idx == int32_t(3)) ? taps[0] : half4(0.HF);
710
+ accum_m1 += taps * weights;
711
+ accum_m2 += NSS_SQ_MAT(taps) * weights;
712
+
713
+ NormalizeFilterMoments(accum_m1, accum_m2, m1, m2);
714
+ }
715
+ #endif // NSS_FILTER_MODE == 1
716
+
717
+ #if NSS_FILTER_MODE == 0
718
+ void FilterColour(
719
+ int32_t2 output_px,
720
+ out half4 m1,
721
+ out half4 m2,
722
+ out half4 center_sample)
723
+ {
724
+ //-------------------------------------------------------------------------
725
+ // High-quality 2x path: static generated 6x6 KPN tap pattern.
726
+ //-------------------------------------------------------------------------
727
+ int32_t2 colour_max = _InputDims - int32_t2(1);
728
+ int32_t2 kpn_max = _KpnDims - int32_t2(1);
729
+ int16_t4 colour_max_x4 = int16_t4(colour_max.x);
730
+ int16_t4 colour_max_y4 = int16_t4(colour_max.y);
731
+ int16_t4 kpn_max_x4 = int16_t4(kpn_max.x);
732
+ int16_t4 kpn_max_y4 = int16_t4(kpn_max.y);
733
+ int16_t4 zero4 = int16_t4(0);
734
+ int16_t2 out_px16 = int16_t2(output_px);
735
+ int32_t2 tile_idx = (output_px + _LutOffset) & int32_t2(1);
736
+ int32_t lut_idx = (tile_idx.y << int32_t(1)) + tile_idx.x;
737
+
738
+ half4 accum_m1 = half4(0.HF);
739
+ half4 accum_m2 = half4(0.HF);
740
+ center_sample = half4(0.HF);
741
+ KernelPattern lut = kKernelLut[lut_idx];
742
+
743
+ int16_t4 tap_x0 = clamp((int16_t4(out_px16.x + lut.base_offset.x) + kTapDx0) >> int16_t(1), zero4, colour_max_x4);
744
+ int16_t4 tap_y0 = clamp((int16_t4(out_px16.y + lut.base_offset.y) + kTapDy0) >> int16_t(1), zero4, colour_max_y4);
745
+ int16_t4 kpn_x0;
746
+ int16_t4 kpn_y0;
747
+ KpnCoordsForDenseFilter4(tap_x0, tap_y0, zero4, kpn_max_x4, kpn_max_y4, kpn_x0, kpn_y0);
748
+
749
+ f16mat4x4 taps0;
750
+ NSS_LOAD_TAPS_4(tap_x0, tap_y0, taps0);
751
+ half4 w0 = SampleKpnWeight4(kTapCh0 + int16_t4(lut.base_channel), kpn_x0, kpn_y0);
752
+ accum_m1 += taps0 * w0;
753
+ accum_m2 += NSS_SQ_MAT(taps0) * w0;
754
+
755
+ int16_t4 tap_x1 = clamp((int16_t4(out_px16.x + lut.base_offset.x) + kTapDx1) >> int16_t(1), zero4, colour_max_x4);
756
+ int16_t4 tap_y1 = clamp((int16_t4(out_px16.y + lut.base_offset.y) + kTapDy1) >> int16_t(1), zero4, colour_max_y4);
757
+ int16_t4 kpn_x1;
758
+ int16_t4 kpn_y1;
759
+ KpnCoordsForDenseFilter4(tap_x1, tap_y1, zero4, kpn_max_x4, kpn_max_y4, kpn_x1, kpn_y1);
760
+
761
+ f16mat4x4 taps1;
762
+ NSS_LOAD_TAPS_4(tap_x1, tap_y1, taps1);
763
+ half4 w1 = SampleKpnWeight4(kTapCh1 + int16_t4(lut.base_channel), kpn_x1, kpn_y1);
764
+ center_sample = (lut_idx == int32_t(3)) ? taps1[0] : half4(0.HF);
765
+ accum_m1 += taps1 * w1;
766
+ accum_m2 += NSS_SQ_MAT(taps1) * w1;
767
+
768
+ int32_t2 tap2 = output_px + int32_t2(lut.base_offset) + int32_t2(kTapD2);
769
+ int32_t2 lr_tap2 = clamp(tap2 >> int32_t(1), int32_t2(0), colour_max);
770
+ int32_t2 kpn_tap2 = KpnCoordForDenseFilter(lr_tap2, kpn_max);
771
+ half4 tap2_col = LoadColourTap4(lr_tap2);
772
+ half tap2_w = SampleKpnWeight(int32_t(lut.base_channel + kTapCh2), kpn_tap2);
773
+ accum_m1 += tap2_col * tap2_w;
774
+ accum_m2 += (tap2_col * tap2_col) * tap2_w;
775
+
776
+ NormalizeFilterMoments(accum_m1, accum_m2, m1, m2);
777
+ }
778
+ #endif // NSS_FILTER_MODE == 0
779
+
780
+ #undef NSS_LOAD_TAPS_4
781
+ #undef NSS_SQ_MAT
782
+
783
+ void SampleTemporalParams(float2 uv, out half theta, out half alpha, out half gamma)
784
+ {
785
+ // Temporal params live over the logical preprocess domain and may be backed
786
+ // by a padded image in the scenario runtime.
787
+ float2 uv_temporal = uv * _PaddedUvScale;
788
+ half4 params = Dequantize(half4(textureLod(_TemporalTensor, uv_temporal, 0.0)), kTemporalQuant);
789
+ #if NSS_V1_SHARP_THETA
790
+ half theta_in = clamp(params.x, 0.HF, 1.HF);
791
+ half theta_inv = 1.HF - theta_in;
792
+ half theta_a = theta_in * theta_in;
793
+ half theta_b = theta_inv * theta_inv;
794
+ theta = theta_a * rcp(max(theta_a + theta_b, 1e-6HF));
795
+ #else
796
+ theta = params.x;
797
+ #endif // NSS_V1_SHARP_THETA
798
+ alpha = params.y * 0.35HF + 0.05HF;
799
+ gamma = params.z * 2.0HF;
800
+ }
801
+
802
+ void WarpHistory(
803
+ int32_t2 output_px,
804
+ float2 uv,
805
+ out half4 warped_colour,
806
+ out half onscreen)
807
+ {
808
+ // Reproject history with motion; report if sample stayed on-screen.
809
+ half2 motion = LoadMotion(output_px);
810
+ float2 reproj_uv = uv - (float2(motion) * _InvOutputDims);
811
+ onscreen = half(all(greaterThanEqual(reproj_uv, float2(0.0))) && all(lessThanEqual(reproj_uv, float2(1.0))));
812
+ #if NSS_USE_HISTORY_CATMULL
813
+ warped_colour = LoadWarpedHistoryCatmull(reproj_uv);
814
+ #else
815
+ warped_colour = LoadWarpedHistory(reproj_uv);
816
+ #endif // NSS_USE_HISTORY_CATMULL
817
+ }
818
+
819
+ void ClampHistoryToStats(
820
+ half4 m1,
821
+ half4 m2,
822
+ half4 warped_history,
823
+ half theta,
824
+ half gamma,
825
+ half reset,
826
+ half onscreen,
827
+ out half4 rectified)
828
+ {
829
+ //-------------------------------------------------------------------------
830
+ // Statistical clamp (AABB):
831
+ // Clamp reprojected history using local filtered moments to reduce ghosts.
832
+ //-------------------------------------------------------------------------
833
+ half4 sigma_4 = sqrt(max(abs(m2 - m1 * m1), half4(EPS))) * half4(gamma);
834
+ sigma_4.a = 0.HF;
835
+ half4 aabb_min = m1 - sigma_4;
836
+ half4 aabb_max = m1 + sigma_4;
837
+ half4 history_clamped = mix(m1, clamp(warped_history, aabb_min, aabb_max), half4(reset));
838
+ rectified = mix(history_clamped, warped_history, half4(theta * onscreen * reset));
839
+ }
840
+
841
+ half3 ClampToInvertibleRange(half3 accumulated, half inv_exposure)
842
+ {
843
+ // Keep value within invertible Karis range, then restore linear domain.
844
+ half3 clamped_output = clamp(accumulated, half3(0.HF), half3(1.HF - EPS));
845
+ return SafeColour(MaxHalf(InverseTonemap(clamped_output) * half3(inv_exposure)));
846
+ }
847
+
848
+ half4 Tonemap4(half4 x)
849
+ {
850
+ x = clamp(x, half4(0.HF), half4(MAX_FP16));
851
+ half m = max(max(x.r, x.g), x.b);
852
+ return x * rcp(half4(1.HF + m));
853
+ }
854
+
855
+ half3 SimulateR11G11B10Precision(half3 rgb)
856
+ {
857
+ const float epsilon = 1e-12;
858
+ const int32_t3 m_bits = int32_t3(6, 6, 5);
859
+ const int32_t exp_bits = 5;
860
+ const float3 bias = float3((1 << (exp_bits - 1)) - 1); // 15.0
861
+ const float3 exp_max = float3((1 << exp_bits) - 1);
862
+
863
+ float3 val = max(float3(rgb), float3(epsilon));
864
+ float3 exp_unclamped = floor(log2(val));
865
+ float3 exp_clipped = clamp(exp_unclamped, -bias, bias + 1.0);
866
+ float3 mant = val / exp2(exp_clipped) - 1.0;
867
+
868
+ float3 scale = float3(int32_t3(1) << m_bits);
869
+ float3 rgb_exp = clamp(exp_clipped + bias, float3(0.0), exp_max) - bias;
870
+ float3 rgb_mant = clamp(round(mant * scale), float3(0.0), scale - 1.0) / scale;
871
+ float3 rgb_out = (1.0 + rgb_mant) * exp2(rgb_exp);
872
+ return half3(rgb_out);
873
+ }
874
+
875
+ void WriteColourOutTarget(int32_t2 coord, half3 out_linear);
876
+
877
+ void WriteColourOut(int32_t2 coord, half3 out_linear)
878
+ {
879
+ half3 to_write = SafeColour(out_linear);
880
+ #ifdef SIMULATE_R11G11B10_BEFORE_WRITE
881
+ to_write = SimulateR11G11B10Precision(to_write);
882
+ #endif // SIMULATE_R11G11B10_BEFORE_WRITE
883
+ WriteColourOutTarget(coord, to_write);
884
+ }
885
+
886
+ void PostProcessMain(int32_t2 output_px)
887
+ {
888
+ //-------------------------------------------------------------------------
889
+ // 1) Per-pixel setup
890
+ //-------------------------------------------------------------------------
891
+ half exposure = half(_Exposure.x);
892
+ half reset = half(_Reset);
893
+ float2 uv = (float2(output_px) + float2(0.5)) * _InvOutputDims;
894
+
895
+ //-------------------------------------------------------------------------
896
+ // 2) Spatial filtering (KPN) + local moments
897
+ //-------------------------------------------------------------------------
898
+ half4 m1;
899
+ half4 m2;
900
+ half4 center_sample;
901
+ FilterColour(output_px, m1, m2, center_sample);
902
+
903
+ //-------------------------------------------------------------------------
904
+ // 3) Read temporal controls and reproject history
905
+ //-------------------------------------------------------------------------
906
+ half theta;
907
+ half alpha;
908
+ half gamma;
909
+ SampleTemporalParams(uv, theta, alpha, gamma);
910
+
911
+ half4 warped_colour;
912
+ half onscreen;
913
+ WarpHistory(output_px, uv, warped_colour, onscreen);
914
+
915
+ //-------------------------------------------------------------------------
916
+ // 4) Clamp and rectify history
917
+ //-------------------------------------------------------------------------
918
+ half4 rectified;
919
+ ClampHistoryToStats(
920
+ m1,
921
+ m2,
922
+ warped_colour,
923
+ theta,
924
+ gamma,
925
+ reset,
926
+ onscreen,
927
+ rectified
928
+ );
929
+
930
+ //-------------------------------------------------------------------------
931
+ // 5) Tonemapped accumulation
932
+ //-------------------------------------------------------------------------
933
+ half4 rectified_tm4 = Tonemap4(MaxHalf(rectified * half4(exposure)));
934
+ half learnt_masked_alpha = alpha * center_sample.a * reset;
935
+ half4 colour_to_accum_tm4 = Tonemap4(MaxHalf(center_sample * half4(exposure)));
936
+ half4 accumulated4 = mix(rectified_tm4, colour_to_accum_tm4, half4(learnt_masked_alpha));
937
+
938
+ //-------------------------------------------------------------------------
939
+ // 6) Convert back to linear and write outputs
940
+ //-------------------------------------------------------------------------
941
+ half3 out_linear = ClampToInvertibleRange(accumulated4.rgb, half(_Exposure.y));
942
+ WriteColourOut(output_px, out_linear);
943
+ }
944
+
945
+ #endif // NSS_V1_POST_PROCESS_SHARED_H
scenario/assets/960x540_1920x1080/0_depth_scatter_push_consts__960x540_1920x1080_high_fragment.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5af43f7973aabf48a32e0eaa413aec53b80eec0193be3273f49503604a9ec56e
3
+ size 168
scenario/assets/960x540_1920x1080/0_depth_scatter_push_consts__960x540_1920x1080_low_fragment.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:bdffbf5e316c94c1d932c88fcb7ed1f99feb8463fedeff8f436c253c9e6080b2
3
+ size 168
scenario/assets/960x540_1920x1080/0_depth_scatter_push_consts__960x540_1920x1080_mid_fragment.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:bdffbf5e316c94c1d932c88fcb7ed1f99feb8463fedeff8f436c253c9e6080b2
3
+ size 168
scenario/assets/960x540_1920x1080/1_pre_process_push_consts__960x540_1920x1080_high_fragment.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:54dffde79c845b0b63fc437649b8a9ffbb2ed931aa794d55245c740e745988de
3
+ size 272
scenario/assets/960x540_1920x1080/1_pre_process_push_consts__960x540_1920x1080_low_fragment.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:009d3c0ebc92d895d527c2238fd7a27f34cae91ebc1e27d2f6988f9209a101fb
3
+ size 272
scenario/assets/960x540_1920x1080/1_pre_process_push_consts__960x540_1920x1080_mid_fragment.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:009d3c0ebc92d895d527c2238fd7a27f34cae91ebc1e27d2f6988f9209a101fb
3
+ size 272
scenario/assets/960x540_1920x1080/2_nss-480x270-kpn16-v1_0_1.vgf ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:27adc4c836c6f5c872fc5a09ed360a194ff4c5fae1ec395d34bcc1ad29bf5f39
3
+ size 159792
scenario/assets/960x540_1920x1080/2_nss-960x540-v1_0_1.vgf ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6c3ac39dd496d28d8b0f3bb54cd8314d73ad95cc78f46c825cd0a19ad179b9f5
3
+ size 165696
scenario/assets/960x540_1920x1080/3_post_process_push_consts__960x540_1920x1080_high_fragment.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:22055216bafa3df6cd1077480c68d446c2a8f2522f3e8c9e78a286a4229bda3d
3
+ size 248
scenario/assets/960x540_1920x1080/3_post_process_push_consts__960x540_1920x1080_low_fragment.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5e0d679a75e48023959d6c70f8691dfe5d90687c91cc18d25700b38127a9f957
3
+ size 248
scenario/assets/960x540_1920x1080/3_post_process_push_consts__960x540_1920x1080_mid_fragment.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5e0d679a75e48023959d6c70f8691dfe5d90687c91cc18d25700b38127a9f957
3
+ size 248
scenario/assets/960x540_1920x1080/in_colour.dds ADDED

Git LFS Details

  • SHA256: 1c2aeb9346e567f36c1a5f8688c58abba5df69dd1b81a2abc25506c96cdebaae
  • Pointer size: 132 Bytes
  • Size of remote file: 2.07 MB
scenario/assets/960x540_1920x1080/in_depth.dds ADDED

Git LFS Details

  • SHA256: a24efadf525fdf83af23cdf6524b8ef653bb8746145fec2eb4ebdf177c09d556
  • Pointer size: 132 Bytes
  • Size of remote file: 2.07 MB
scenario/assets/960x540_1920x1080/in_depth_scatter_init-240x135__960x540_1920x1080_low_fragment.dds ADDED

Git LFS Details

  • SHA256: de7c3019db1c77260fd56057e8d18a2d87c286d71624fa540373fc6ad1d457a9
  • Pointer size: 131 Bytes
  • Size of remote file: 130 kB
scenario/assets/960x540_1920x1080/in_depth_scatter_init-240x135__960x540_1920x1080_mid_fragment.dds ADDED

Git LFS Details

  • SHA256: de7c3019db1c77260fd56057e8d18a2d87c286d71624fa540373fc6ad1d457a9
  • Pointer size: 131 Bytes
  • Size of remote file: 130 kB
scenario/assets/960x540_1920x1080/in_depth_scatter_init-480x270__960x540_1920x1080_high_fragment.dds ADDED

Git LFS Details

  • SHA256: 9547130a780717e21aefa1bd833bf066d36d0e1530e50f6a1828e55eae78d569
  • Pointer size: 131 Bytes
  • Size of remote file: 519 kB
scenario/assets/960x540_1920x1080/in_derivative_tm1-480x272__960x540_1920x1080_low_fragment.dds ADDED

Git LFS Details

  • SHA256: 2e212451ee5c1a7900e41fc86e425ba2561204c08a1ad64666224bb8bd93a286
  • Pointer size: 131 Bytes
  • Size of remote file: 522 kB
scenario/assets/960x540_1920x1080/in_derivative_tm1-480x272__960x540_1920x1080_mid_fragment.dds ADDED

Git LFS Details

  • SHA256: 2e212451ee5c1a7900e41fc86e425ba2561204c08a1ad64666224bb8bd93a286
  • Pointer size: 131 Bytes
  • Size of remote file: 522 kB
scenario/assets/960x540_1920x1080/in_derivative_tm1-960x544__960x540_1920x1080_high_fragment.dds ADDED

Git LFS Details

  • SHA256: 6a8a15035be7d70e72f18f1dc1670cfbf7d39efbd7e13923bce73890d88cff66
  • Pointer size: 132 Bytes
  • Size of remote file: 2.09 MB
scenario/assets/960x540_1920x1080/in_history.dds ADDED

Git LFS Details

  • SHA256: 179140d9bf016974e840c510733f7701466c7d287a0e0e33f2adfccbdec6302b
  • Pointer size: 132 Bytes
  • Size of remote file: 8.29 MB
scenario/assets/960x540_1920x1080/in_motion.dds ADDED

Git LFS Details

  • SHA256: 058e6fdad73fc71c056a92de1b918e411712ebef2939476e2c6516fcc9284e08
  • Pointer size: 132 Bytes
  • Size of remote file: 2.07 MB
scenario/assets/960x540_1920x1080/in_temporal_tm1-480x272__960x540_1920x1080_low_fragment.dds ADDED

Git LFS Details

  • SHA256: 04bc9ff0ab0edba806c6ec2683e1ee665091596bacb51acadfb371945c545096
  • Pointer size: 131 Bytes
  • Size of remote file: 522 kB
scenario/assets/960x540_1920x1080/in_temporal_tm1-480x272__960x540_1920x1080_mid_fragment.dds ADDED

Git LFS Details

  • SHA256: 04bc9ff0ab0edba806c6ec2683e1ee665091596bacb51acadfb371945c545096
  • Pointer size: 131 Bytes
  • Size of remote file: 522 kB
scenario/assets/960x540_1920x1080/in_temporal_tm1-960x544__960x540_1920x1080_high_fragment.dds ADDED

Git LFS Details

  • SHA256: 1fcab71d41c36aed9eee59c2b3e7fae8cf958efa38c21177ad8dbd705650e80f
  • Pointer size: 132 Bytes
  • Size of remote file: 2.09 MB
scenario/common.h CHANGED
@@ -4,13 +4,14 @@
4
  // confidential and may only be used by an authorized person under a valid
5
  // licensing agreement from Arm Limited or its affiliates.
6
  //
7
- // Copyright (C) 2025. Arm Limited or its affiliates. All rights reserved.
8
  //
9
  // This entire notice must be reproduced on all copies of this file and
10
  // copies of this file may only be made by an authorized person under a valid
11
  // licensing agreement from Arm Limited or its affiliates.
12
  // -----------------------------------------------------------------------------
13
  //
 
14
  #ifndef NSS_COMMON
15
  #define NSS_COMMON
16
 
@@ -19,142 +20,96 @@
19
  #define MAX_FP16 65504.HF
20
  #define EPS 1e-7HF
21
 
22
-
23
  // Activation Functions
24
- // ──────────────────────────────────────────────────────────────────────────────────────────
25
-
26
-
27
- half Sigmoid(half x)
28
- {
29
- return rcp(half(1.0) + exp(-x));
30
- }
31
-
32
-
33
- half2 Sigmoid(half2 x)
34
- {
35
- return rcp(half2(1.0) + exp(-x));
36
- }
37
-
38
-
39
- half3 Sigmoid(half3 x)
40
- {
41
- return rcp(half3(1.0) + exp(-x));
42
- }
43
-
44
-
45
- half4 Sigmoid(half4 x)
46
- {
47
- return rcp(half4(1.0) + exp(-x));
48
- }
49
-
50
-
51
- // Quantize/Dequantize
52
- // ──────────────────────────────────────────────────────────────────────────────────────────
53
- // all expect .x = scale, .y = zero point, quantize methods expect to receive: .x = rcp(scale)
54
-
55
- half Dequantize(half i, half2 quant_params)
56
- {
57
- return (i - quant_params.y) * quant_params.x;
58
- }
59
-
60
-
61
- half2 Dequantize(half2 i, half2 quant_params)
62
- {
63
- return (i - quant_params.y) * quant_params.x;
64
- }
65
-
66
-
67
- half3 Dequantize(half3 i, half2 quant_params)
68
- {
69
- return (i - quant_params.y) * quant_params.x;
70
- }
71
-
72
-
73
- half4 Dequantize(half4 i, half2 quant_params)
74
- {
75
- return (i - quant_params.y) * quant_params.x;
76
- }
77
-
78
 
79
- int8_t Quantize(half f, half2 quant_params)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
  {
81
- return int8_t(clamp(round(f * quant_params.x + quant_params.y), -128.HF, 127.HF));
 
 
82
  }
83
 
84
-
85
- int8_t2 Quantize(half2 f, half2 quant_params)
86
  {
87
- return int8_t2(clamp(round(f * quant_params.x + quant_params.y), -128.HF, 127.HF));
 
 
88
  }
89
 
90
-
91
- int8_t3 Quantize(half3 f, half2 quant_params)
92
  {
93
- return int8_t3(clamp(round(f * quant_params.x + quant_params.y), -128.HF, 127.HF));
 
 
 
94
  }
95
 
96
-
97
- int8_t4 Quantize(half4 f, half2 quant_params)
98
  {
99
- return int8_t4(clamp(round(f * quant_params.x + quant_params.y), -128.HF, 127.HF));
 
 
100
  }
101
 
102
-
103
- // Encode/Decode
104
- // ─────────────────────────────────────���────────────────────────────────────────────────────
105
- // Note: both encode/decode methods are currently bound to 3x3 windows, they should be
106
- // expandable in future if needed. The most likely to need this would be the jitter
107
- // encoding, where 3x3 may not be enough for larger than 3x3 scale factors.
108
-
109
-
110
- uint8_t EncodeNearestDepthCoord(int32_t2 o)
111
  {
112
- // o {-1, 0, 1
113
- o = clamp(o, ivec2(-1), ivec2( 1));
114
- return uint8_t((o.y + 1) << 2 | (o.x + 1)); // 0-15
115
  }
116
 
117
-
118
- int32_t2 DecodeNearestDepthCoord(int32_t code)
119
  {
120
- int32_t x = int32_t( code & 0x3) - 1; // bits 0-1
121
- int32_t y = int32_t((code >> 2) & 0x3) - 1; // bits 2-3
 
 
 
122
  return int32_t2(x, y);
123
  }
124
 
125
-
126
  // Image Operations
127
- // ──────────────────────────────────────────────────────────────────────────────────────────
128
-
129
  half Luminance(half3 rgb)
130
  {
131
- // ITU-R BT.709: `0.2126 * R + 0.7152 * G + 0.0722 * B`
132
  return dot(rgb, half3(0.2126, 0.7152, 0.0722));
133
  }
134
 
135
-
136
  half3 Tonemap(half3 x)
137
  {
138
- // Karis tonemapper
139
- // http://graphicrants.blogspot.com/2013/12/tone-mapping.html
140
- x = max(x, half3(0.HF));
141
  return x * rcp(half3(1.HF) + max(max(x.r, x.g), x.b));
142
  }
143
 
144
-
145
  half3 InverseTonemap(half3 x)
146
  {
147
- // Karis tonemapper inverse
148
- // http://graphicrants.blogspot.com/2013/12/tone-mapping.html
149
- x = clamp(x, half3(0.HF), Tonemap(half3(MAX_FP16)));
150
  return x * rcp(half3(1.HF) - max(max(x.r, x.g), x.b));
151
  }
152
 
153
-
154
  half3 SafeColour(half3 x)
155
  {
156
  return clamp(x, half3(0.HF), half3(MAX_FP16));
157
  }
158
 
159
-
160
  #endif // NSS_COMMON
 
4
  // confidential and may only be used by an authorized person under a valid
5
  // licensing agreement from Arm Limited or its affiliates.
6
  //
7
+ // Copyright (C) 2026 Arm Limited or its affiliates. All rights reserved.
8
  //
9
  // This entire notice must be reproduced on all copies of this file and
10
  // copies of this file may only be made by an authorized person under a valid
11
  // licensing agreement from Arm Limited or its affiliates.
12
  // -----------------------------------------------------------------------------
13
  //
14
+
15
  #ifndef NSS_COMMON
16
  #define NSS_COMMON
17
 
 
20
  #define MAX_FP16 65504.HF
21
  #define EPS 1e-7HF
22
 
 
23
  // Activation Functions
24
+ // -----------------------------------------------------------------------------
25
+ half Sigmoid(half x) { return rcp(half(1.0) + exp(-x)); }
26
+ half2 Sigmoid(half2 x) { return rcp(half2(1.0) + exp(-x)); }
27
+ half3 Sigmoid(half3 x) { return rcp(half3(1.0) + exp(-x)); }
28
+ half4 Sigmoid(half4 x) { return rcp(half4(1.0) + exp(-x)); }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
 
30
+ // Quantize/Dequantize
31
+ // -----------------------------------------------------------------------------
32
+ // all expect .x = scale, .y = zero point
33
+ half Dequantize(half i, half2 quant_params) { return (i - quant_params.y) * quant_params.x; }
34
+ half2 Dequantize(half2 i, half2 quant_params) { return (i - quant_params.y) * quant_params.x; }
35
+ half3 Dequantize(half3 i, half2 quant_params) { return (i - quant_params.y) * quant_params.x; }
36
+ half4 Dequantize(half4 i, half2 quant_params) { return (i - quant_params.y) * quant_params.x; }
37
+
38
+ int8_t Quantize(half f, half2 quant_params) { return int8_t(f * quant_params.x + quant_params.y); }
39
+ int8_t2 Quantize(half2 f, half2 quant_params) { return int8_t2(f * quant_params.x + quant_params.y); }
40
+ int8_t3 Quantize(half3 f, half2 quant_params) { return int8_t3(f * quant_params.x + quant_params.y); }
41
+ int8_t4 Quantize(half4 f, half2 quant_params) { return int8_t4(f * quant_params.x + quant_params.y); }
42
+
43
+ // Encode/Decode
44
+ // -----------------------------------------------------------------------------
45
+ uint8_t EncodeNearestDepthCoord(int32_t2 o)
46
  {
47
+ // o in {-2, -1, 0, +1, +2}^2
48
+ o = clamp(o, int32_t2(-2), int32_t2(2));
49
+ return uint8_t(((o.y + 2) << 3) | (o.x + 2)); // 0-24
50
  }
51
 
52
+ int32_t2 DecodeNearestDepthCoord(int32_t code)
 
53
  {
54
+ int32_t x = int32_t(code & 0x7) - 2; // bits 0-2
55
+ int32_t y = int32_t((code >> 3) & 0x7) - 2; // bits 3-5
56
+ return int32_t2(x, y);
57
  }
58
 
59
+ uint8_t EncodeNearestDepthCoordNibble(int32_t2 o)
 
60
  {
61
+ // The packed low-quality quad path only emits offsets inside the current
62
+ // 4x4 search footprint: {-1, 0, +1, +2}^2.
63
+ o = clamp(o, int32_t2(-1), int32_t2(2));
64
+ return uint8_t(((o.y + 1) << 2) | (o.x + 1)); // 0-15
65
  }
66
 
67
+ int32_t2 DecodeNearestDepthCoordNibble(int32_t code)
 
68
  {
69
+ int32_t x = int32_t(code & 0x3) - 1; // bits 0-1
70
+ int32_t y = int32_t((code >> 2) & 0x3) - 1; // bits 2-3
71
+ return int32_t2(x, y);
72
  }
73
 
74
+ uint8_t EncodeJitterOffset(int32_t2 offset)
 
 
 
 
 
 
 
 
75
  {
76
+ uint8_t col = uint8_t(offset.x + 1);
77
+ uint8_t row = uint8_t(offset.y + 1);
78
+ return uint8_t(row * 3 + col + 1); // reserve 0 for holes
79
  }
80
 
81
+ int32_t2 DecodeJitterOffset(uint8_t c8)
 
82
  {
83
+ uint8_t c = uint8_t(c8);
84
+ uint8_t mask = uint8_t(c != 0u);
85
+ uint8_t idx = (c - uint8_t(1)) * mask;
86
+ int32_t x = int32_t(idx % 3u) - int32_t(mask);
87
+ int32_t y = int32_t(idx / 3u) - int32_t(mask);
88
  return int32_t2(x, y);
89
  }
90
 
 
91
  // Image Operations
92
+ // -----------------------------------------------------------------------------
 
93
  half Luminance(half3 rgb)
94
  {
 
95
  return dot(rgb, half3(0.2126, 0.7152, 0.0722));
96
  }
97
 
 
98
  half3 Tonemap(half3 x)
99
  {
100
+ x = clamp(x, half3(0.HF), half3(MAX_FP16));
 
 
101
  return x * rcp(half3(1.HF) + max(max(x.r, x.g), x.b));
102
  }
103
 
 
104
  half3 InverseTonemap(half3 x)
105
  {
106
+ x = clamp(x, half3(0.HF), half3(1.HF - EPS));
 
 
107
  return x * rcp(half3(1.HF) - max(max(x.r, x.g), x.b));
108
  }
109
 
 
110
  half3 SafeColour(half3 x)
111
  {
112
  return clamp(x, half3(0.HF), half3(MAX_FP16));
113
  }
114
 
 
115
  #endif // NSS_COMMON
scenario/configs/960x540_1920x1080_high_fragment.json ADDED
@@ -0,0 +1,722 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "commands": [
3
+ {
4
+ "dispatch_compute": {
5
+ "shader_ref": "0_depth_scatter_init",
6
+ "rangeND": [
7
+ 60,
8
+ 34,
9
+ 1
10
+ ],
11
+ "implicit_barrier": false,
12
+ "bindings": [
13
+ {
14
+ "set": 0,
15
+ "id": 0,
16
+ "resource_ref": "out_depth_scatter",
17
+ "descriptor_type": "VK_DESCRIPTOR_TYPE_STORAGE_IMAGE"
18
+ }
19
+ ],
20
+ "push_data_ref": "push_data_0"
21
+ }
22
+ },
23
+ {
24
+ "dispatch_barrier": {
25
+ "image_barrier_refs": [
26
+ "barrier_depth_init_to_scatter"
27
+ ],
28
+ "tensor_barrier_refs": [],
29
+ "memory_barrier_refs": [],
30
+ "buffer_barrier_refs": []
31
+ }
32
+ },
33
+ {
34
+ "dispatch_compute": {
35
+ "shader_ref": "0_depth_scatter",
36
+ "rangeND": [
37
+ 60,
38
+ 34,
39
+ 1
40
+ ],
41
+ "implicit_barrier": false,
42
+ "bindings": [
43
+ {
44
+ "set": 0,
45
+ "id": 0,
46
+ "resource_ref": "in_motion"
47
+ },
48
+ {
49
+ "set": 0,
50
+ "id": 1,
51
+ "resource_ref": "in_depth"
52
+ },
53
+ {
54
+ "set": 1,
55
+ "id": 0,
56
+ "resource_ref": "out_depth_scatter",
57
+ "descriptor_type": "VK_DESCRIPTOR_TYPE_STORAGE_IMAGE"
58
+ }
59
+ ],
60
+ "push_data_ref": "push_data_0"
61
+ }
62
+ },
63
+ {
64
+ "dispatch_barrier": {
65
+ "image_barrier_refs": [
66
+ "barrier_depth_to_pre"
67
+ ],
68
+ "tensor_barrier_refs": [],
69
+ "memory_barrier_refs": [],
70
+ "buffer_barrier_refs": []
71
+ }
72
+ },
73
+ {
74
+ "dispatch_fragment": {
75
+ "vertex_shader_ref": "fullscreen_triangle_vert",
76
+ "fragment_shader_ref": "1_pre_process_frag",
77
+ "bindings": [
78
+ {
79
+ "set": 0,
80
+ "id": 0,
81
+ "resource_ref": "in_colour"
82
+ },
83
+ {
84
+ "set": 0,
85
+ "id": 1,
86
+ "resource_ref": "in_depth"
87
+ },
88
+ {
89
+ "set": 0,
90
+ "id": 2,
91
+ "resource_ref": "in_motion"
92
+ },
93
+ {
94
+ "set": 0,
95
+ "id": 3,
96
+ "resource_ref": "in_history"
97
+ },
98
+ {
99
+ "set": 0,
100
+ "id": 4,
101
+ "resource_ref": "in_temporal_tm1"
102
+ },
103
+ {
104
+ "set": 0,
105
+ "id": 5,
106
+ "resource_ref": "out_depth_scatter"
107
+ },
108
+ {
109
+ "set": 0,
110
+ "id": 6,
111
+ "resource_ref": "in_derivative_tm1"
112
+ },
113
+ {
114
+ "set": 1,
115
+ "id": 0,
116
+ "resource_ref": "out_input_tensor_buffer"
117
+ }
118
+ ],
119
+ "implicit_barrier": false,
120
+ "debug_name": "1_pre_process_frag",
121
+ "color_attachment_refs": [
122
+ "out_derivative",
123
+ "out_nearest_depth_offset"
124
+ ],
125
+ "render_extent": [
126
+ 960,
127
+ 544
128
+ ],
129
+ "push_data_ref": "push_data_1"
130
+ }
131
+ },
132
+ {
133
+ "dispatch_barrier": {
134
+ "image_barrier_refs": [],
135
+ "tensor_barrier_refs": [],
136
+ "memory_barrier_refs": [],
137
+ "buffer_barrier_refs": [
138
+ "barrier_pre_to_graph"
139
+ ]
140
+ }
141
+ },
142
+ {
143
+ "dispatch_graph": {
144
+ "graph_ref": "2_nss",
145
+ "implicit_barrier": false,
146
+ "bindings": [
147
+ {
148
+ "set": 0,
149
+ "id": 0,
150
+ "resource_ref": "out_input_tensor"
151
+ },
152
+ {
153
+ "set": 0,
154
+ "id": 1,
155
+ "resource_ref": "out_graph_0"
156
+ },
157
+ {
158
+ "set": 0,
159
+ "id": 2,
160
+ "resource_ref": "out_graph_1"
161
+ }
162
+ ]
163
+ }
164
+ },
165
+ {
166
+ "dispatch_barrier": {
167
+ "image_barrier_refs": [
168
+ "barrier_offset_to_post",
169
+ "barrier_temporal_to_post"
170
+ ],
171
+ "tensor_barrier_refs": [],
172
+ "memory_barrier_refs": [],
173
+ "buffer_barrier_refs": [
174
+ "barrier_graph0_buf_to_post"
175
+ ]
176
+ }
177
+ },
178
+ {
179
+ "dispatch_fragment": {
180
+ "vertex_shader_ref": "fullscreen_triangle_vert",
181
+ "fragment_shader_ref": "3_post_process_frag",
182
+ "bindings": [
183
+ {
184
+ "set": 0,
185
+ "id": 0,
186
+ "resource_ref": "in_colour"
187
+ },
188
+ {
189
+ "set": 0,
190
+ "id": 1,
191
+ "resource_ref": "in_history"
192
+ },
193
+ {
194
+ "set": 0,
195
+ "id": 2,
196
+ "resource_ref": "out_graph_0_buffer"
197
+ },
198
+ {
199
+ "set": 0,
200
+ "id": 3,
201
+ "resource_ref": "out_temporal"
202
+ },
203
+ {
204
+ "set": 0,
205
+ "id": 4,
206
+ "resource_ref": "in_motion"
207
+ },
208
+ {
209
+ "set": 0,
210
+ "id": 5,
211
+ "resource_ref": "out_nearest_depth_offset"
212
+ }
213
+ ],
214
+ "implicit_barrier": false,
215
+ "debug_name": "3_post_process_frag",
216
+ "color_attachment_refs": [
217
+ "out_colour"
218
+ ],
219
+ "render_extent": [
220
+ 1920,
221
+ 1080
222
+ ],
223
+ "push_data_ref": "push_data_3"
224
+ }
225
+ },
226
+ {
227
+ "mark_boundary": {
228
+ "resources": [
229
+ "out_colour",
230
+ "out_derivative",
231
+ "out_graph_1"
232
+ ]
233
+ }
234
+ }
235
+ ],
236
+ "resources": [
237
+ {
238
+ "image_barrier": {
239
+ "uid": "barrier_depth_init_to_scatter",
240
+ "src_access": "compute_shader_write",
241
+ "dst_access": "compute_shader_write",
242
+ "old_layout": "general",
243
+ "new_layout": "general",
244
+ "src_stage": [
245
+ "compute"
246
+ ],
247
+ "dst_stage": [
248
+ "compute"
249
+ ],
250
+ "image_resource": "out_depth_scatter"
251
+ }
252
+ },
253
+ {
254
+ "image_barrier": {
255
+ "uid": "barrier_depth_to_pre",
256
+ "src_access": "compute_shader_write",
257
+ "dst_access": "compute_shader_read",
258
+ "old_layout": "general",
259
+ "new_layout": "general",
260
+ "src_stage": [
261
+ "compute"
262
+ ],
263
+ "dst_stage": [
264
+ "graphics"
265
+ ],
266
+ "image_resource": "out_depth_scatter"
267
+ }
268
+ },
269
+ {
270
+ "buffer_barrier": {
271
+ "uid": "barrier_pre_to_graph",
272
+ "src_access": "compute_shader_write",
273
+ "dst_access": "graph_read",
274
+ "src_stage": [
275
+ "graphics"
276
+ ],
277
+ "dst_stage": [
278
+ "graph"
279
+ ],
280
+ "buffer_resource": "out_input_tensor_buffer",
281
+ "size": 6266880,
282
+ "offset": 0
283
+ }
284
+ },
285
+ {
286
+ "image_barrier": {
287
+ "uid": "barrier_offset_to_post",
288
+ "src_access": "compute_shader_write",
289
+ "dst_access": "compute_shader_read",
290
+ "old_layout": "general",
291
+ "new_layout": "general",
292
+ "src_stage": [
293
+ "graphics"
294
+ ],
295
+ "dst_stage": [
296
+ "graphics"
297
+ ],
298
+ "image_resource": "out_nearest_depth_offset"
299
+ }
300
+ },
301
+ {
302
+ "buffer_barrier": {
303
+ "uid": "barrier_graph0_buf_to_post",
304
+ "src_access": "graph_write",
305
+ "dst_access": "compute_shader_read",
306
+ "src_stage": [
307
+ "graph"
308
+ ],
309
+ "dst_stage": [
310
+ "graphics"
311
+ ],
312
+ "buffer_resource": "out_graph_0_buffer",
313
+ "size": 1175040,
314
+ "offset": 0
315
+ }
316
+ },
317
+ {
318
+ "image_barrier": {
319
+ "uid": "barrier_temporal_to_post",
320
+ "src_access": "graph_write",
321
+ "dst_access": "compute_shader_read",
322
+ "old_layout": "general",
323
+ "new_layout": "general",
324
+ "src_stage": [
325
+ "graph"
326
+ ],
327
+ "dst_stage": [
328
+ "graphics"
329
+ ],
330
+ "image_resource": "out_temporal"
331
+ }
332
+ },
333
+ {
334
+ "image": {
335
+ "uid": "out_depth_scatter",
336
+ "src": "./../assets/960x540_1920x1080/in_depth_scatter_init-480x270__960x540_1920x1080_high_fragment.dds",
337
+ "dst": "./out_depth_scatter.dds",
338
+ "dims": [
339
+ 1,
340
+ 480,
341
+ 270,
342
+ 1
343
+ ],
344
+ "format": "VK_FORMAT_R32_UINT",
345
+ "shader_access": "readwrite",
346
+ "mips": 1,
347
+ "tiling": "OPTIMAL"
348
+ }
349
+ },
350
+ {
351
+ "shader": {
352
+ "uid": "0_depth_scatter_init",
353
+ "src": "./../0_depth_scatter_init.comp",
354
+ "entry": "main",
355
+ "type": "GLSL",
356
+ "push_constants_size": 40,
357
+ "specialization_constants": [],
358
+ "build_options": "",
359
+ "include_dirs": [
360
+ "./.."
361
+ ]
362
+ }
363
+ },
364
+ {
365
+ "raw_data": {
366
+ "uid": "push_data_0",
367
+ "src": "./../assets/960x540_1920x1080/0_depth_scatter_push_consts__960x540_1920x1080_high_fragment.npy"
368
+ }
369
+ },
370
+ {
371
+ "image": {
372
+ "uid": "in_motion",
373
+ "src": "./../assets/960x540_1920x1080/in_motion.dds",
374
+ "dims": [
375
+ 1,
376
+ 960,
377
+ 540,
378
+ 1
379
+ ],
380
+ "format": "VK_FORMAT_R16G16_SFLOAT",
381
+ "shader_access": "readonly",
382
+ "mips": 1,
383
+ "tiling": "OPTIMAL"
384
+ }
385
+ },
386
+ {
387
+ "image": {
388
+ "uid": "in_depth",
389
+ "src": "./../assets/960x540_1920x1080/in_depth.dds",
390
+ "dims": [
391
+ 1,
392
+ 960,
393
+ 540,
394
+ 1
395
+ ],
396
+ "format": "VK_FORMAT_R32_SFLOAT",
397
+ "shader_access": "readonly",
398
+ "mips": 1,
399
+ "tiling": "OPTIMAL"
400
+ }
401
+ },
402
+ {
403
+ "shader": {
404
+ "uid": "0_depth_scatter",
405
+ "src": "./../0_depth_scatter.comp",
406
+ "entry": "main",
407
+ "type": "GLSL",
408
+ "push_constants_size": 40,
409
+ "specialization_constants": [],
410
+ "build_options": "",
411
+ "include_dirs": [
412
+ "./.."
413
+ ]
414
+ }
415
+ },
416
+ {
417
+ "image": {
418
+ "uid": "in_colour",
419
+ "src": "./../assets/960x540_1920x1080/in_colour.dds",
420
+ "dims": [
421
+ 1,
422
+ 960,
423
+ 540,
424
+ 1
425
+ ],
426
+ "format": "VK_FORMAT_B10G11R11_UFLOAT_PACK32",
427
+ "shader_access": "readonly",
428
+ "mips": 1,
429
+ "min_filter": "LINEAR",
430
+ "mag_filter": "LINEAR",
431
+ "mip_filter": "NEAREST",
432
+ "border_address_mode": "CLAMP_EDGE",
433
+ "tiling": "OPTIMAL"
434
+ }
435
+ },
436
+ {
437
+ "image": {
438
+ "uid": "in_history",
439
+ "src": "./../assets/960x540_1920x1080/in_history.dds",
440
+ "dims": [
441
+ 1,
442
+ 1920,
443
+ 1080,
444
+ 1
445
+ ],
446
+ "format": "VK_FORMAT_B10G11R11_UFLOAT_PACK32",
447
+ "shader_access": "readonly",
448
+ "mips": 1,
449
+ "min_filter": "LINEAR",
450
+ "mag_filter": "LINEAR",
451
+ "mip_filter": "NEAREST",
452
+ "border_address_mode": "CLAMP_EDGE",
453
+ "tiling": "OPTIMAL"
454
+ }
455
+ },
456
+ {
457
+ "image": {
458
+ "uid": "in_temporal_tm1",
459
+ "src": "./../assets/960x540_1920x1080/in_temporal_tm1-960x544__960x540_1920x1080_high_fragment.dds",
460
+ "dims": [
461
+ 1,
462
+ 960,
463
+ 544,
464
+ 1
465
+ ],
466
+ "format": "VK_FORMAT_R8G8B8A8_SNORM",
467
+ "shader_access": "readonly",
468
+ "mips": 1,
469
+ "min_filter": "LINEAR",
470
+ "mag_filter": "LINEAR",
471
+ "mip_filter": "NEAREST",
472
+ "border_address_mode": "CLAMP_BORDER",
473
+ "border_color": "FLOAT_CUSTOM_EXT",
474
+ "tiling": "LINEAR",
475
+ "custom_border_color": [
476
+ -1.0,
477
+ -1.0,
478
+ -1.0,
479
+ -1.0
480
+ ]
481
+ }
482
+ },
483
+ {
484
+ "image": {
485
+ "uid": "in_derivative_tm1",
486
+ "src": "./../assets/960x540_1920x1080/in_derivative_tm1-960x544__960x540_1920x1080_high_fragment.dds",
487
+ "dims": [
488
+ 1,
489
+ 960,
490
+ 544,
491
+ 1
492
+ ],
493
+ "format": "VK_FORMAT_R8G8B8A8_SNORM",
494
+ "shader_access": "readonly",
495
+ "mips": 1,
496
+ "min_filter": "LINEAR",
497
+ "mag_filter": "LINEAR",
498
+ "mip_filter": "NEAREST",
499
+ "border_address_mode": "CLAMP_BORDER",
500
+ "border_color": "FLOAT_CUSTOM_EXT",
501
+ "tiling": "OPTIMAL",
502
+ "custom_border_color": [
503
+ -1.0,
504
+ 0.0,
505
+ 0.0,
506
+ -1.0
507
+ ]
508
+ }
509
+ },
510
+ {
511
+ "buffer": {
512
+ "uid": "out_input_tensor_buffer",
513
+ "memory_group": {
514
+ "id": "mg_input_tensor"
515
+ },
516
+ "size": 6266880,
517
+ "shader_access": "readwrite"
518
+ }
519
+ },
520
+ {
521
+ "image": {
522
+ "uid": "out_derivative",
523
+ "dst": "./out_derivative.dds",
524
+ "dims": [
525
+ 1,
526
+ 960,
527
+ 544,
528
+ 1
529
+ ],
530
+ "format": "VK_FORMAT_R8G8B8A8_SNORM",
531
+ "shader_access": "writeonly",
532
+ "mips": 1,
533
+ "color_attachment": true,
534
+ "tiling": "OPTIMAL"
535
+ }
536
+ },
537
+ {
538
+ "image": {
539
+ "uid": "out_nearest_depth_offset",
540
+ "dst": "./out_nearest_depth_offset.dds",
541
+ "dims": [
542
+ 1,
543
+ 960,
544
+ 544,
545
+ 1
546
+ ],
547
+ "format": "VK_FORMAT_R8_UNORM",
548
+ "shader_access": "readwrite",
549
+ "mips": 1,
550
+ "color_attachment": true,
551
+ "tiling": "OPTIMAL"
552
+ }
553
+ },
554
+ {
555
+ "shader": {
556
+ "uid": "fullscreen_triangle_vert",
557
+ "src": "./../fullscreen_triangle.vert",
558
+ "entry": "main",
559
+ "type": "GLSL",
560
+ "push_constants_size": 0,
561
+ "specialization_constants": [],
562
+ "build_options": "",
563
+ "stage": "vertex",
564
+ "include_dirs": [
565
+ "./.."
566
+ ]
567
+ }
568
+ },
569
+ {
570
+ "shader": {
571
+ "uid": "1_pre_process_frag",
572
+ "src": "./../1_pre_process.frag",
573
+ "entry": "main",
574
+ "type": "GLSL",
575
+ "push_constants_size": 144,
576
+ "specialization_constants": [],
577
+ "build_options": "-DNSS_V1_FULL_RES_LUMA_DERIVATIVE=1 -DNSS_V1_HALF_RES_LUMA_DERIVATIVE=0",
578
+ "stage": "fragment",
579
+ "include_dirs": [
580
+ "./.."
581
+ ]
582
+ }
583
+ },
584
+ {
585
+ "raw_data": {
586
+ "uid": "push_data_1",
587
+ "src": "./../assets/960x540_1920x1080/1_pre_process_push_consts__960x540_1920x1080_high_fragment.npy"
588
+ }
589
+ },
590
+ {
591
+ "tensor": {
592
+ "uid": "out_input_tensor",
593
+ "dst": "./out_input_tensor.npy",
594
+ "memory_group": {
595
+ "id": "mg_input_tensor"
596
+ },
597
+ "dims": [
598
+ 1,
599
+ 544,
600
+ 960,
601
+ 12
602
+ ],
603
+ "format": "VK_FORMAT_R8_SINT",
604
+ "shader_access": "readwrite",
605
+ "tiling": "LINEAR"
606
+ }
607
+ },
608
+ {
609
+ "tensor": {
610
+ "uid": "out_graph_0",
611
+ "dst": "./out_graph_0.npy",
612
+ "memory_group": {
613
+ "id": "mg_out_kpn"
614
+ },
615
+ "dims": [
616
+ 1,
617
+ 136,
618
+ 240,
619
+ 36
620
+ ],
621
+ "format": "VK_FORMAT_R8_SINT",
622
+ "shader_access": "readwrite",
623
+ "tiling": "LINEAR"
624
+ }
625
+ },
626
+ {
627
+ "tensor": {
628
+ "uid": "out_graph_1",
629
+ "dst": "./out_graph_1.npy",
630
+ "memory_group": {
631
+ "id": "mg_out_temporal"
632
+ },
633
+ "dims": [
634
+ 1,
635
+ 544,
636
+ 960,
637
+ 4
638
+ ],
639
+ "format": "VK_FORMAT_R8_SINT",
640
+ "shader_access": "readwrite",
641
+ "tiling": "LINEAR"
642
+ }
643
+ },
644
+ {
645
+ "graph": {
646
+ "uid": "2_nss",
647
+ "src": "./../assets/960x540_1920x1080/2_nss-960x540-v1_0_1.vgf"
648
+ }
649
+ },
650
+ {
651
+ "buffer": {
652
+ "uid": "out_graph_0_buffer",
653
+ "memory_group": {
654
+ "id": "mg_out_kpn"
655
+ },
656
+ "size": 1175040,
657
+ "shader_access": "readonly"
658
+ }
659
+ },
660
+ {
661
+ "image": {
662
+ "uid": "out_temporal",
663
+ "memory_group": {
664
+ "id": "mg_out_temporal"
665
+ },
666
+ "dims": [
667
+ 1,
668
+ 960,
669
+ 544,
670
+ 1
671
+ ],
672
+ "format": "VK_FORMAT_R8G8B8A8_SNORM",
673
+ "shader_access": "readonly",
674
+ "mips": 1,
675
+ "min_filter": "LINEAR",
676
+ "mag_filter": "LINEAR",
677
+ "mip_filter": "NEAREST",
678
+ "border_address_mode": "CLAMP_BORDER",
679
+ "border_color": "FLOAT_TRANSPARENT_BLACK",
680
+ "tiling": "LINEAR"
681
+ }
682
+ },
683
+ {
684
+ "image": {
685
+ "uid": "out_colour",
686
+ "dst": "./out_colour.dds",
687
+ "dims": [
688
+ 1,
689
+ 1920,
690
+ 1080,
691
+ 1
692
+ ],
693
+ "format": "VK_FORMAT_B10G11R11_UFLOAT_PACK32",
694
+ "shader_access": "writeonly",
695
+ "mips": 1,
696
+ "color_attachment": true,
697
+ "tiling": "OPTIMAL"
698
+ }
699
+ },
700
+ {
701
+ "shader": {
702
+ "uid": "3_post_process_frag",
703
+ "src": "./../3_post_process.frag",
704
+ "entry": "main",
705
+ "type": "GLSL",
706
+ "push_constants_size": 120,
707
+ "specialization_constants": [],
708
+ "build_options": "-DNSS_V1_SHARP_THETA=1",
709
+ "stage": "fragment",
710
+ "include_dirs": [
711
+ "./.."
712
+ ]
713
+ }
714
+ },
715
+ {
716
+ "raw_data": {
717
+ "uid": "push_data_3",
718
+ "src": "./../assets/960x540_1920x1080/3_post_process_push_consts__960x540_1920x1080_high_fragment.npy"
719
+ }
720
+ }
721
+ ]
722
+ }
scenario/configs/960x540_1920x1080_low_fragment.json ADDED
@@ -0,0 +1,838 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "commands": [
3
+ {
4
+ "dispatch_compute": {
5
+ "shader_ref": "0_depth_scatter_init",
6
+ "rangeND": [
7
+ 30,
8
+ 17,
9
+ 1
10
+ ],
11
+ "implicit_barrier": false,
12
+ "bindings": [
13
+ {
14
+ "set": 0,
15
+ "id": 0,
16
+ "resource_ref": "out_depth_scatter",
17
+ "descriptor_type": "VK_DESCRIPTOR_TYPE_STORAGE_IMAGE"
18
+ }
19
+ ],
20
+ "push_data_ref": "push_data_0"
21
+ }
22
+ },
23
+ {
24
+ "dispatch_barrier": {
25
+ "image_barrier_refs": [
26
+ "barrier_depth_init_to_scatter"
27
+ ],
28
+ "tensor_barrier_refs": [],
29
+ "memory_barrier_refs": [],
30
+ "buffer_barrier_refs": []
31
+ }
32
+ },
33
+ {
34
+ "dispatch_compute": {
35
+ "shader_ref": "0_depth_scatter",
36
+ "rangeND": [
37
+ 30,
38
+ 17,
39
+ 1
40
+ ],
41
+ "implicit_barrier": false,
42
+ "bindings": [
43
+ {
44
+ "set": 0,
45
+ "id": 0,
46
+ "resource_ref": "in_motion"
47
+ },
48
+ {
49
+ "set": 0,
50
+ "id": 1,
51
+ "resource_ref": "in_depth"
52
+ },
53
+ {
54
+ "set": 1,
55
+ "id": 0,
56
+ "resource_ref": "out_depth_scatter",
57
+ "descriptor_type": "VK_DESCRIPTOR_TYPE_STORAGE_IMAGE"
58
+ }
59
+ ],
60
+ "push_data_ref": "push_data_0"
61
+ }
62
+ },
63
+ {
64
+ "dispatch_barrier": {
65
+ "image_barrier_refs": [
66
+ "barrier_depth_to_lq_disocclusion"
67
+ ],
68
+ "tensor_barrier_refs": [],
69
+ "memory_barrier_refs": [],
70
+ "buffer_barrier_refs": []
71
+ }
72
+ },
73
+ {
74
+ "dispatch_fragment": {
75
+ "vertex_shader_ref": "fullscreen_triangle_vert",
76
+ "fragment_shader_ref": "0_disocclusion_mask_lq",
77
+ "bindings": [
78
+ {
79
+ "set": 0,
80
+ "id": 0,
81
+ "resource_ref": "in_motion"
82
+ },
83
+ {
84
+ "set": 0,
85
+ "id": 1,
86
+ "resource_ref": "in_depth"
87
+ },
88
+ {
89
+ "set": 0,
90
+ "id": 2,
91
+ "resource_ref": "out_depth_scatter"
92
+ }
93
+ ],
94
+ "implicit_barrier": false,
95
+ "color_attachment_refs": [
96
+ "out_disocclusion_mask_lq"
97
+ ],
98
+ "debug_name": "0_disocclusion_mask_lq_frag",
99
+ "render_extent": [
100
+ 240,
101
+ 135
102
+ ],
103
+ "push_data_ref": "push_data_1"
104
+ }
105
+ },
106
+ {
107
+ "dispatch_barrier": {
108
+ "image_barrier_refs": [
109
+ "barrier_depth_to_pre",
110
+ "barrier_lq_disocclusion_to_pre"
111
+ ],
112
+ "tensor_barrier_refs": [],
113
+ "memory_barrier_refs": [],
114
+ "buffer_barrier_refs": []
115
+ }
116
+ },
117
+ {
118
+ "dispatch_fragment": {
119
+ "vertex_shader_ref": "fullscreen_triangle_vert",
120
+ "fragment_shader_ref": "1_pre_process_frag",
121
+ "bindings": [
122
+ {
123
+ "set": 0,
124
+ "id": 0,
125
+ "resource_ref": "in_colour"
126
+ },
127
+ {
128
+ "set": 0,
129
+ "id": 1,
130
+ "resource_ref": "in_depth"
131
+ },
132
+ {
133
+ "set": 0,
134
+ "id": 2,
135
+ "resource_ref": "in_motion"
136
+ },
137
+ {
138
+ "set": 0,
139
+ "id": 3,
140
+ "resource_ref": "in_history"
141
+ },
142
+ {
143
+ "set": 0,
144
+ "id": 4,
145
+ "resource_ref": "in_temporal_tm1"
146
+ },
147
+ {
148
+ "set": 0,
149
+ "id": 5,
150
+ "resource_ref": "out_depth_scatter"
151
+ },
152
+ {
153
+ "set": 0,
154
+ "id": 6,
155
+ "resource_ref": "in_derivative_tm1"
156
+ },
157
+ {
158
+ "set": 0,
159
+ "id": 7,
160
+ "resource_ref": "out_disocclusion_mask_lq"
161
+ },
162
+ {
163
+ "set": 1,
164
+ "id": 0,
165
+ "resource_ref": "out_input_tensor_buffer"
166
+ }
167
+ ],
168
+ "implicit_barrier": false,
169
+ "color_attachment_refs": [
170
+ "out_derivative",
171
+ "out_nearest_depth_offset"
172
+ ],
173
+ "debug_name": "1_pre_process_frag",
174
+ "render_extent": [
175
+ 480,
176
+ 272
177
+ ],
178
+ "push_data_ref": "push_data_1"
179
+ }
180
+ },
181
+ {
182
+ "dispatch_barrier": {
183
+ "image_barrier_refs": [],
184
+ "tensor_barrier_refs": [],
185
+ "memory_barrier_refs": [],
186
+ "buffer_barrier_refs": [
187
+ "barrier_pre_to_graph"
188
+ ]
189
+ }
190
+ },
191
+ {
192
+ "dispatch_graph": {
193
+ "graph_ref": "2_nss",
194
+ "implicit_barrier": false,
195
+ "bindings": [
196
+ {
197
+ "set": 0,
198
+ "id": 0,
199
+ "resource_ref": "out_input_tensor"
200
+ },
201
+ {
202
+ "set": 0,
203
+ "id": 1,
204
+ "resource_ref": "out_graph_0"
205
+ },
206
+ {
207
+ "set": 0,
208
+ "id": 2,
209
+ "resource_ref": "out_graph_1"
210
+ }
211
+ ]
212
+ }
213
+ },
214
+ {
215
+ "dispatch_barrier": {
216
+ "image_barrier_refs": [
217
+ "barrier_offset_to_post",
218
+ "barrier_temporal_to_post"
219
+ ],
220
+ "tensor_barrier_refs": [],
221
+ "memory_barrier_refs": [],
222
+ "buffer_barrier_refs": [
223
+ "barrier_graph0_buf_to_post"
224
+ ]
225
+ }
226
+ },
227
+ {
228
+ "dispatch_fragment": {
229
+ "vertex_shader_ref": "fullscreen_triangle_vert",
230
+ "fragment_shader_ref": "3_post_process_frag",
231
+ "bindings": [
232
+ {
233
+ "set": 0,
234
+ "id": 0,
235
+ "resource_ref": "in_colour"
236
+ },
237
+ {
238
+ "set": 0,
239
+ "id": 1,
240
+ "resource_ref": "in_history"
241
+ },
242
+ {
243
+ "set": 0,
244
+ "id": 2,
245
+ "resource_ref": "out_graph_0_buffer"
246
+ },
247
+ {
248
+ "set": 0,
249
+ "id": 3,
250
+ "resource_ref": "out_temporal"
251
+ },
252
+ {
253
+ "set": 0,
254
+ "id": 4,
255
+ "resource_ref": "in_motion"
256
+ },
257
+ {
258
+ "set": 0,
259
+ "id": 5,
260
+ "resource_ref": "out_nearest_depth_offset"
261
+ }
262
+ ],
263
+ "implicit_barrier": false,
264
+ "color_attachment_refs": [
265
+ "out_colour"
266
+ ],
267
+ "debug_name": "3_post_process_frag",
268
+ "render_extent": [
269
+ 1920,
270
+ 1080
271
+ ],
272
+ "push_data_ref": "push_data_3"
273
+ }
274
+ },
275
+ {
276
+ "mark_boundary": {
277
+ "resources": [
278
+ "out_colour",
279
+ "out_derivative",
280
+ "out_graph_1"
281
+ ]
282
+ }
283
+ }
284
+ ],
285
+ "resources": [
286
+ {
287
+ "image_barrier": {
288
+ "uid": "barrier_depth_init_to_scatter",
289
+ "src_access": "compute_shader_write",
290
+ "dst_access": "compute_shader_write",
291
+ "old_layout": "general",
292
+ "new_layout": "general",
293
+ "src_stage": [
294
+ "compute"
295
+ ],
296
+ "dst_stage": [
297
+ "compute"
298
+ ],
299
+ "image_resource": "out_depth_scatter"
300
+ }
301
+ },
302
+ {
303
+ "image_barrier": {
304
+ "uid": "barrier_depth_to_pre",
305
+ "src_access": "compute_shader_write",
306
+ "dst_access": "compute_shader_read",
307
+ "old_layout": "general",
308
+ "new_layout": "general",
309
+ "src_stage": [
310
+ "compute"
311
+ ],
312
+ "dst_stage": [
313
+ "graphics"
314
+ ],
315
+ "image_resource": "out_depth_scatter"
316
+ }
317
+ },
318
+ {
319
+ "image_barrier": {
320
+ "uid": "barrier_depth_to_lq_disocclusion",
321
+ "src_access": "compute_shader_write",
322
+ "dst_access": "compute_shader_read",
323
+ "old_layout": "general",
324
+ "new_layout": "general",
325
+ "src_stage": [
326
+ "compute"
327
+ ],
328
+ "dst_stage": [
329
+ "graphics"
330
+ ],
331
+ "image_resource": "out_depth_scatter"
332
+ }
333
+ },
334
+ {
335
+ "image_barrier": {
336
+ "uid": "barrier_lq_disocclusion_to_pre",
337
+ "src_access": "compute_shader_write",
338
+ "dst_access": "compute_shader_read",
339
+ "old_layout": "general",
340
+ "new_layout": "general",
341
+ "src_stage": [
342
+ "graphics"
343
+ ],
344
+ "dst_stage": [
345
+ "graphics"
346
+ ],
347
+ "image_resource": "out_disocclusion_mask_lq"
348
+ }
349
+ },
350
+ {
351
+ "buffer_barrier": {
352
+ "uid": "barrier_pre_to_graph",
353
+ "src_access": "compute_shader_write",
354
+ "dst_access": "graph_read",
355
+ "src_stage": [
356
+ "graphics"
357
+ ],
358
+ "dst_stage": [
359
+ "graph"
360
+ ],
361
+ "buffer_resource": "out_input_tensor_buffer",
362
+ "size": 1566720,
363
+ "offset": 0
364
+ }
365
+ },
366
+ {
367
+ "image_barrier": {
368
+ "uid": "barrier_offset_to_post",
369
+ "src_access": "compute_shader_write",
370
+ "dst_access": "compute_shader_read",
371
+ "old_layout": "general",
372
+ "new_layout": "general",
373
+ "src_stage": [
374
+ "graphics"
375
+ ],
376
+ "dst_stage": [
377
+ "graphics"
378
+ ],
379
+ "image_resource": "out_nearest_depth_offset"
380
+ }
381
+ },
382
+ {
383
+ "buffer_barrier": {
384
+ "uid": "barrier_graph0_buf_to_post",
385
+ "src_access": "graph_write",
386
+ "dst_access": "compute_shader_read",
387
+ "src_stage": [
388
+ "graph"
389
+ ],
390
+ "dst_stage": [
391
+ "graphics"
392
+ ],
393
+ "buffer_resource": "out_graph_0_buffer",
394
+ "size": 130560,
395
+ "offset": 0
396
+ }
397
+ },
398
+ {
399
+ "image_barrier": {
400
+ "uid": "barrier_temporal_to_post",
401
+ "src_access": "graph_write",
402
+ "dst_access": "compute_shader_read",
403
+ "old_layout": "general",
404
+ "new_layout": "general",
405
+ "src_stage": [
406
+ "graph"
407
+ ],
408
+ "dst_stage": [
409
+ "graphics"
410
+ ],
411
+ "image_resource": "out_temporal"
412
+ }
413
+ },
414
+ {
415
+ "image": {
416
+ "uid": "out_depth_scatter",
417
+ "src": "./../assets/960x540_1920x1080/in_depth_scatter_init-240x135__960x540_1920x1080_low_fragment.dds",
418
+ "dst": "./out_depth_scatter.dds",
419
+ "dims": [
420
+ 1,
421
+ 240,
422
+ 135,
423
+ 1
424
+ ],
425
+ "format": "VK_FORMAT_R32_UINT",
426
+ "shader_access": "readwrite",
427
+ "mips": 1,
428
+ "tiling": "OPTIMAL"
429
+ }
430
+ },
431
+ {
432
+ "shader": {
433
+ "uid": "0_depth_scatter_init",
434
+ "src": "./../0_depth_scatter_init.comp",
435
+ "entry": "main",
436
+ "type": "GLSL",
437
+ "push_constants_size": 40,
438
+ "specialization_constants": [],
439
+ "build_options": "",
440
+ "include_dirs": [
441
+ "./.."
442
+ ]
443
+ }
444
+ },
445
+ {
446
+ "raw_data": {
447
+ "uid": "push_data_0",
448
+ "src": "./../assets/960x540_1920x1080/0_depth_scatter_push_consts__960x540_1920x1080_low_fragment.npy"
449
+ }
450
+ },
451
+ {
452
+ "image": {
453
+ "uid": "in_motion",
454
+ "src": "./../assets/960x540_1920x1080/in_motion.dds",
455
+ "dims": [
456
+ 1,
457
+ 960,
458
+ 540,
459
+ 1
460
+ ],
461
+ "format": "VK_FORMAT_R16G16_SFLOAT",
462
+ "shader_access": "readonly",
463
+ "mips": 1,
464
+ "tiling": "OPTIMAL"
465
+ }
466
+ },
467
+ {
468
+ "image": {
469
+ "uid": "in_depth",
470
+ "src": "./../assets/960x540_1920x1080/in_depth.dds",
471
+ "dims": [
472
+ 1,
473
+ 960,
474
+ 540,
475
+ 1
476
+ ],
477
+ "format": "VK_FORMAT_R32_SFLOAT",
478
+ "shader_access": "readonly",
479
+ "mips": 1,
480
+ "tiling": "OPTIMAL"
481
+ }
482
+ },
483
+ {
484
+ "shader": {
485
+ "uid": "0_depth_scatter",
486
+ "src": "./../0_depth_scatter.comp",
487
+ "entry": "main",
488
+ "type": "GLSL",
489
+ "push_constants_size": 40,
490
+ "specialization_constants": [],
491
+ "build_options": "-DNSS_DEPTH_SCATTER_QUARTER_RES_INPUT=1",
492
+ "include_dirs": [
493
+ "./.."
494
+ ]
495
+ }
496
+ },
497
+ {
498
+ "image": {
499
+ "uid": "out_disocclusion_mask_lq",
500
+ "dst": "./out_disocclusion_mask_lq.dds",
501
+ "dims": [
502
+ 1,
503
+ 240,
504
+ 135,
505
+ 1
506
+ ],
507
+ "format": "VK_FORMAT_R8_UNORM",
508
+ "shader_access": "readwrite",
509
+ "mips": 1,
510
+ "color_attachment": true,
511
+ "min_filter": "LINEAR",
512
+ "mag_filter": "LINEAR",
513
+ "mip_filter": "NEAREST",
514
+ "tiling": "OPTIMAL"
515
+ }
516
+ },
517
+ {
518
+ "shader": {
519
+ "uid": "fullscreen_triangle_vert",
520
+ "src": "./../fullscreen_triangle.vert",
521
+ "entry": "main",
522
+ "type": "GLSL",
523
+ "push_constants_size": 0,
524
+ "specialization_constants": [],
525
+ "build_options": "",
526
+ "stage": "vertex",
527
+ "include_dirs": [
528
+ "./.."
529
+ ]
530
+ }
531
+ },
532
+ {
533
+ "shader": {
534
+ "uid": "0_disocclusion_mask_lq",
535
+ "src": "./../0_disocclusion_mask_lq.frag",
536
+ "entry": "main",
537
+ "type": "GLSL",
538
+ "push_constants_size": 144,
539
+ "specialization_constants": [],
540
+ "build_options": "",
541
+ "stage": "fragment",
542
+ "include_dirs": [
543
+ "./.."
544
+ ]
545
+ }
546
+ },
547
+ {
548
+ "raw_data": {
549
+ "uid": "push_data_1",
550
+ "src": "./../assets/960x540_1920x1080/1_pre_process_push_consts__960x540_1920x1080_low_fragment.npy"
551
+ }
552
+ },
553
+ {
554
+ "image": {
555
+ "uid": "in_colour",
556
+ "src": "./../assets/960x540_1920x1080/in_colour.dds",
557
+ "dims": [
558
+ 1,
559
+ 960,
560
+ 540,
561
+ 1
562
+ ],
563
+ "format": "VK_FORMAT_B10G11R11_UFLOAT_PACK32",
564
+ "shader_access": "readonly",
565
+ "mips": 1,
566
+ "min_filter": "LINEAR",
567
+ "mag_filter": "LINEAR",
568
+ "mip_filter": "NEAREST",
569
+ "border_address_mode": "CLAMP_EDGE",
570
+ "tiling": "OPTIMAL"
571
+ }
572
+ },
573
+ {
574
+ "image": {
575
+ "uid": "in_history",
576
+ "src": "./../assets/960x540_1920x1080/in_history.dds",
577
+ "dims": [
578
+ 1,
579
+ 1920,
580
+ 1080,
581
+ 1
582
+ ],
583
+ "format": "VK_FORMAT_B10G11R11_UFLOAT_PACK32",
584
+ "shader_access": "readonly",
585
+ "mips": 1,
586
+ "min_filter": "LINEAR",
587
+ "mag_filter": "LINEAR",
588
+ "mip_filter": "NEAREST",
589
+ "border_address_mode": "CLAMP_EDGE",
590
+ "tiling": "OPTIMAL"
591
+ }
592
+ },
593
+ {
594
+ "image": {
595
+ "uid": "in_temporal_tm1",
596
+ "src": "./../assets/960x540_1920x1080/in_temporal_tm1-480x272__960x540_1920x1080_low_fragment.dds",
597
+ "dims": [
598
+ 1,
599
+ 480,
600
+ 272,
601
+ 1
602
+ ],
603
+ "format": "VK_FORMAT_R8G8B8A8_SNORM",
604
+ "shader_access": "readonly",
605
+ "mips": 1,
606
+ "min_filter": "LINEAR",
607
+ "mag_filter": "LINEAR",
608
+ "mip_filter": "NEAREST",
609
+ "border_address_mode": "CLAMP_BORDER",
610
+ "border_color": "FLOAT_CUSTOM_EXT",
611
+ "tiling": "LINEAR",
612
+ "custom_border_color": [
613
+ -1.0,
614
+ -1.0,
615
+ -1.0,
616
+ -1.0
617
+ ]
618
+ }
619
+ },
620
+ {
621
+ "image": {
622
+ "uid": "in_derivative_tm1",
623
+ "src": "./../assets/960x540_1920x1080/in_derivative_tm1-480x272__960x540_1920x1080_low_fragment.dds",
624
+ "dims": [
625
+ 1,
626
+ 480,
627
+ 272,
628
+ 1
629
+ ],
630
+ "format": "VK_FORMAT_R8G8B8A8_SNORM",
631
+ "shader_access": "readonly",
632
+ "mips": 1,
633
+ "min_filter": "LINEAR",
634
+ "mag_filter": "LINEAR",
635
+ "mip_filter": "NEAREST",
636
+ "border_address_mode": "CLAMP_BORDER",
637
+ "border_color": "FLOAT_CUSTOM_EXT",
638
+ "tiling": "OPTIMAL",
639
+ "custom_border_color": [
640
+ -1.0,
641
+ 0.0,
642
+ 0.0,
643
+ -1.0
644
+ ]
645
+ }
646
+ },
647
+ {
648
+ "buffer": {
649
+ "uid": "out_input_tensor_buffer",
650
+ "memory_group": {
651
+ "id": "mg_input_tensor"
652
+ },
653
+ "size": 1566720,
654
+ "shader_access": "readwrite"
655
+ }
656
+ },
657
+ {
658
+ "image": {
659
+ "uid": "out_derivative",
660
+ "dst": "./out_derivative.dds",
661
+ "dims": [
662
+ 1,
663
+ 480,
664
+ 272,
665
+ 1
666
+ ],
667
+ "format": "VK_FORMAT_R8G8B8A8_SNORM",
668
+ "shader_access": "writeonly",
669
+ "mips": 1,
670
+ "color_attachment": true,
671
+ "tiling": "OPTIMAL"
672
+ }
673
+ },
674
+ {
675
+ "image": {
676
+ "uid": "out_nearest_depth_offset",
677
+ "dst": "./out_nearest_depth_offset.dds",
678
+ "dims": [
679
+ 1,
680
+ 480,
681
+ 272,
682
+ 1
683
+ ],
684
+ "format": "VK_FORMAT_R8G8_UNORM",
685
+ "shader_access": "readwrite",
686
+ "mips": 1,
687
+ "color_attachment": true,
688
+ "tiling": "OPTIMAL"
689
+ }
690
+ },
691
+ {
692
+ "shader": {
693
+ "uid": "1_pre_process_frag",
694
+ "src": "./../1_pre_process.frag",
695
+ "entry": "main",
696
+ "type": "GLSL",
697
+ "push_constants_size": 144,
698
+ "specialization_constants": [],
699
+ "build_options": "-DNSS_INPUT_LAYOUT=1 -DNSS_V1_FULL_RES_LUMA_DERIVATIVE=0 -DNSS_V1_HALF_RES_LUMA_DERIVATIVE=1",
700
+ "stage": "fragment",
701
+ "include_dirs": [
702
+ "./.."
703
+ ]
704
+ }
705
+ },
706
+ {
707
+ "tensor": {
708
+ "uid": "out_input_tensor",
709
+ "dst": "./out_input_tensor.npy",
710
+ "memory_group": {
711
+ "id": "mg_input_tensor"
712
+ },
713
+ "dims": [
714
+ 1,
715
+ 272,
716
+ 480,
717
+ 12
718
+ ],
719
+ "format": "VK_FORMAT_R8_SINT",
720
+ "shader_access": "readwrite",
721
+ "tiling": "LINEAR"
722
+ }
723
+ },
724
+ {
725
+ "tensor": {
726
+ "uid": "out_graph_0",
727
+ "dst": "./out_graph_0.npy",
728
+ "memory_group": {
729
+ "id": "mg_out_kpn"
730
+ },
731
+ "dims": [
732
+ 1,
733
+ 68,
734
+ 120,
735
+ 16
736
+ ],
737
+ "format": "VK_FORMAT_R8_SINT",
738
+ "shader_access": "readwrite",
739
+ "tiling": "LINEAR"
740
+ }
741
+ },
742
+ {
743
+ "tensor": {
744
+ "uid": "out_graph_1",
745
+ "dst": "./out_graph_1.npy",
746
+ "memory_group": {
747
+ "id": "mg_out_temporal"
748
+ },
749
+ "dims": [
750
+ 1,
751
+ 272,
752
+ 480,
753
+ 4
754
+ ],
755
+ "format": "VK_FORMAT_R8_SINT",
756
+ "shader_access": "readwrite",
757
+ "tiling": "LINEAR"
758
+ }
759
+ },
760
+ {
761
+ "graph": {
762
+ "uid": "2_nss",
763
+ "src": "./../assets/960x540_1920x1080/2_nss-480x270-kpn16-v1_0_1.vgf"
764
+ }
765
+ },
766
+ {
767
+ "buffer": {
768
+ "uid": "out_graph_0_buffer",
769
+ "memory_group": {
770
+ "id": "mg_out_kpn"
771
+ },
772
+ "size": 130560,
773
+ "shader_access": "readonly"
774
+ }
775
+ },
776
+ {
777
+ "image": {
778
+ "uid": "out_temporal",
779
+ "memory_group": {
780
+ "id": "mg_out_temporal"
781
+ },
782
+ "dims": [
783
+ 1,
784
+ 480,
785
+ 272,
786
+ 1
787
+ ],
788
+ "format": "VK_FORMAT_R8G8B8A8_SNORM",
789
+ "shader_access": "readonly",
790
+ "mips": 1,
791
+ "min_filter": "LINEAR",
792
+ "mag_filter": "LINEAR",
793
+ "mip_filter": "NEAREST",
794
+ "border_address_mode": "CLAMP_BORDER",
795
+ "border_color": "FLOAT_TRANSPARENT_BLACK",
796
+ "tiling": "LINEAR"
797
+ }
798
+ },
799
+ {
800
+ "image": {
801
+ "uid": "out_colour",
802
+ "dst": "./out_colour.dds",
803
+ "dims": [
804
+ 1,
805
+ 1920,
806
+ 1080,
807
+ 1
808
+ ],
809
+ "format": "VK_FORMAT_B10G11R11_UFLOAT_PACK32",
810
+ "shader_access": "writeonly",
811
+ "mips": 1,
812
+ "color_attachment": true,
813
+ "tiling": "OPTIMAL"
814
+ }
815
+ },
816
+ {
817
+ "shader": {
818
+ "uid": "3_post_process_frag",
819
+ "src": "./../3_post_process.frag",
820
+ "entry": "main",
821
+ "type": "GLSL",
822
+ "push_constants_size": 120,
823
+ "specialization_constants": [],
824
+ "build_options": "-DNSS_INPUT_LAYOUT=1 -DNSS_USE_HISTORY_CATMULL=0 -DNSS_V1_SHARP_THETA=1 -DNSS_FILTER_MODE=1",
825
+ "stage": "fragment",
826
+ "include_dirs": [
827
+ "./.."
828
+ ]
829
+ }
830
+ },
831
+ {
832
+ "raw_data": {
833
+ "uid": "push_data_3",
834
+ "src": "./../assets/960x540_1920x1080/3_post_process_push_consts__960x540_1920x1080_low_fragment.npy"
835
+ }
836
+ }
837
+ ]
838
+ }
scenario/configs/960x540_1920x1080_mid_fragment.json ADDED
@@ -0,0 +1,838 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "commands": [
3
+ {
4
+ "dispatch_compute": {
5
+ "shader_ref": "0_depth_scatter_init",
6
+ "rangeND": [
7
+ 30,
8
+ 17,
9
+ 1
10
+ ],
11
+ "implicit_barrier": false,
12
+ "bindings": [
13
+ {
14
+ "set": 0,
15
+ "id": 0,
16
+ "resource_ref": "out_depth_scatter",
17
+ "descriptor_type": "VK_DESCRIPTOR_TYPE_STORAGE_IMAGE"
18
+ }
19
+ ],
20
+ "push_data_ref": "push_data_0"
21
+ }
22
+ },
23
+ {
24
+ "dispatch_barrier": {
25
+ "image_barrier_refs": [
26
+ "barrier_depth_init_to_scatter"
27
+ ],
28
+ "tensor_barrier_refs": [],
29
+ "memory_barrier_refs": [],
30
+ "buffer_barrier_refs": []
31
+ }
32
+ },
33
+ {
34
+ "dispatch_compute": {
35
+ "shader_ref": "0_depth_scatter",
36
+ "rangeND": [
37
+ 30,
38
+ 17,
39
+ 1
40
+ ],
41
+ "implicit_barrier": false,
42
+ "bindings": [
43
+ {
44
+ "set": 0,
45
+ "id": 0,
46
+ "resource_ref": "in_motion"
47
+ },
48
+ {
49
+ "set": 0,
50
+ "id": 1,
51
+ "resource_ref": "in_depth"
52
+ },
53
+ {
54
+ "set": 1,
55
+ "id": 0,
56
+ "resource_ref": "out_depth_scatter",
57
+ "descriptor_type": "VK_DESCRIPTOR_TYPE_STORAGE_IMAGE"
58
+ }
59
+ ],
60
+ "push_data_ref": "push_data_0"
61
+ }
62
+ },
63
+ {
64
+ "dispatch_barrier": {
65
+ "image_barrier_refs": [
66
+ "barrier_depth_to_lq_disocclusion"
67
+ ],
68
+ "tensor_barrier_refs": [],
69
+ "memory_barrier_refs": [],
70
+ "buffer_barrier_refs": []
71
+ }
72
+ },
73
+ {
74
+ "dispatch_fragment": {
75
+ "vertex_shader_ref": "fullscreen_triangle_vert",
76
+ "fragment_shader_ref": "0_disocclusion_mask_lq",
77
+ "bindings": [
78
+ {
79
+ "set": 0,
80
+ "id": 0,
81
+ "resource_ref": "in_motion"
82
+ },
83
+ {
84
+ "set": 0,
85
+ "id": 1,
86
+ "resource_ref": "in_depth"
87
+ },
88
+ {
89
+ "set": 0,
90
+ "id": 2,
91
+ "resource_ref": "out_depth_scatter"
92
+ }
93
+ ],
94
+ "implicit_barrier": false,
95
+ "color_attachment_refs": [
96
+ "out_disocclusion_mask_lq"
97
+ ],
98
+ "debug_name": "0_disocclusion_mask_lq_frag",
99
+ "render_extent": [
100
+ 240,
101
+ 135
102
+ ],
103
+ "push_data_ref": "push_data_1"
104
+ }
105
+ },
106
+ {
107
+ "dispatch_barrier": {
108
+ "image_barrier_refs": [
109
+ "barrier_depth_to_pre",
110
+ "barrier_lq_disocclusion_to_pre"
111
+ ],
112
+ "tensor_barrier_refs": [],
113
+ "memory_barrier_refs": [],
114
+ "buffer_barrier_refs": []
115
+ }
116
+ },
117
+ {
118
+ "dispatch_fragment": {
119
+ "vertex_shader_ref": "fullscreen_triangle_vert",
120
+ "fragment_shader_ref": "1_pre_process_frag",
121
+ "bindings": [
122
+ {
123
+ "set": 0,
124
+ "id": 0,
125
+ "resource_ref": "in_colour"
126
+ },
127
+ {
128
+ "set": 0,
129
+ "id": 1,
130
+ "resource_ref": "in_depth"
131
+ },
132
+ {
133
+ "set": 0,
134
+ "id": 2,
135
+ "resource_ref": "in_motion"
136
+ },
137
+ {
138
+ "set": 0,
139
+ "id": 3,
140
+ "resource_ref": "in_history"
141
+ },
142
+ {
143
+ "set": 0,
144
+ "id": 4,
145
+ "resource_ref": "in_temporal_tm1"
146
+ },
147
+ {
148
+ "set": 0,
149
+ "id": 5,
150
+ "resource_ref": "out_depth_scatter"
151
+ },
152
+ {
153
+ "set": 0,
154
+ "id": 6,
155
+ "resource_ref": "in_derivative_tm1"
156
+ },
157
+ {
158
+ "set": 0,
159
+ "id": 7,
160
+ "resource_ref": "out_disocclusion_mask_lq"
161
+ },
162
+ {
163
+ "set": 1,
164
+ "id": 0,
165
+ "resource_ref": "out_input_tensor_buffer"
166
+ }
167
+ ],
168
+ "implicit_barrier": false,
169
+ "color_attachment_refs": [
170
+ "out_derivative",
171
+ "out_nearest_depth_offset"
172
+ ],
173
+ "debug_name": "1_pre_process_frag",
174
+ "render_extent": [
175
+ 480,
176
+ 272
177
+ ],
178
+ "push_data_ref": "push_data_1"
179
+ }
180
+ },
181
+ {
182
+ "dispatch_barrier": {
183
+ "image_barrier_refs": [],
184
+ "tensor_barrier_refs": [],
185
+ "memory_barrier_refs": [],
186
+ "buffer_barrier_refs": [
187
+ "barrier_pre_to_graph"
188
+ ]
189
+ }
190
+ },
191
+ {
192
+ "dispatch_graph": {
193
+ "graph_ref": "2_nss",
194
+ "implicit_barrier": false,
195
+ "bindings": [
196
+ {
197
+ "set": 0,
198
+ "id": 0,
199
+ "resource_ref": "out_input_tensor"
200
+ },
201
+ {
202
+ "set": 0,
203
+ "id": 1,
204
+ "resource_ref": "out_graph_0"
205
+ },
206
+ {
207
+ "set": 0,
208
+ "id": 2,
209
+ "resource_ref": "out_graph_1"
210
+ }
211
+ ]
212
+ }
213
+ },
214
+ {
215
+ "dispatch_barrier": {
216
+ "image_barrier_refs": [
217
+ "barrier_offset_to_post",
218
+ "barrier_temporal_to_post"
219
+ ],
220
+ "tensor_barrier_refs": [],
221
+ "memory_barrier_refs": [],
222
+ "buffer_barrier_refs": [
223
+ "barrier_graph0_buf_to_post"
224
+ ]
225
+ }
226
+ },
227
+ {
228
+ "dispatch_fragment": {
229
+ "vertex_shader_ref": "fullscreen_triangle_vert",
230
+ "fragment_shader_ref": "3_post_process_frag",
231
+ "bindings": [
232
+ {
233
+ "set": 0,
234
+ "id": 0,
235
+ "resource_ref": "in_colour"
236
+ },
237
+ {
238
+ "set": 0,
239
+ "id": 1,
240
+ "resource_ref": "in_history"
241
+ },
242
+ {
243
+ "set": 0,
244
+ "id": 2,
245
+ "resource_ref": "out_graph_0_buffer"
246
+ },
247
+ {
248
+ "set": 0,
249
+ "id": 3,
250
+ "resource_ref": "out_temporal"
251
+ },
252
+ {
253
+ "set": 0,
254
+ "id": 4,
255
+ "resource_ref": "in_motion"
256
+ },
257
+ {
258
+ "set": 0,
259
+ "id": 5,
260
+ "resource_ref": "out_nearest_depth_offset"
261
+ }
262
+ ],
263
+ "implicit_barrier": false,
264
+ "color_attachment_refs": [
265
+ "out_colour"
266
+ ],
267
+ "debug_name": "3_post_process_frag",
268
+ "render_extent": [
269
+ 1920,
270
+ 1080
271
+ ],
272
+ "push_data_ref": "push_data_3"
273
+ }
274
+ },
275
+ {
276
+ "mark_boundary": {
277
+ "resources": [
278
+ "out_colour",
279
+ "out_derivative",
280
+ "out_graph_1"
281
+ ]
282
+ }
283
+ }
284
+ ],
285
+ "resources": [
286
+ {
287
+ "image_barrier": {
288
+ "uid": "barrier_depth_init_to_scatter",
289
+ "src_access": "compute_shader_write",
290
+ "dst_access": "compute_shader_write",
291
+ "old_layout": "general",
292
+ "new_layout": "general",
293
+ "src_stage": [
294
+ "compute"
295
+ ],
296
+ "dst_stage": [
297
+ "compute"
298
+ ],
299
+ "image_resource": "out_depth_scatter"
300
+ }
301
+ },
302
+ {
303
+ "image_barrier": {
304
+ "uid": "barrier_depth_to_pre",
305
+ "src_access": "compute_shader_write",
306
+ "dst_access": "compute_shader_read",
307
+ "old_layout": "general",
308
+ "new_layout": "general",
309
+ "src_stage": [
310
+ "compute"
311
+ ],
312
+ "dst_stage": [
313
+ "graphics"
314
+ ],
315
+ "image_resource": "out_depth_scatter"
316
+ }
317
+ },
318
+ {
319
+ "image_barrier": {
320
+ "uid": "barrier_depth_to_lq_disocclusion",
321
+ "src_access": "compute_shader_write",
322
+ "dst_access": "compute_shader_read",
323
+ "old_layout": "general",
324
+ "new_layout": "general",
325
+ "src_stage": [
326
+ "compute"
327
+ ],
328
+ "dst_stage": [
329
+ "graphics"
330
+ ],
331
+ "image_resource": "out_depth_scatter"
332
+ }
333
+ },
334
+ {
335
+ "image_barrier": {
336
+ "uid": "barrier_lq_disocclusion_to_pre",
337
+ "src_access": "compute_shader_write",
338
+ "dst_access": "compute_shader_read",
339
+ "old_layout": "general",
340
+ "new_layout": "general",
341
+ "src_stage": [
342
+ "graphics"
343
+ ],
344
+ "dst_stage": [
345
+ "graphics"
346
+ ],
347
+ "image_resource": "out_disocclusion_mask_lq"
348
+ }
349
+ },
350
+ {
351
+ "buffer_barrier": {
352
+ "uid": "barrier_pre_to_graph",
353
+ "src_access": "compute_shader_write",
354
+ "dst_access": "graph_read",
355
+ "src_stage": [
356
+ "graphics"
357
+ ],
358
+ "dst_stage": [
359
+ "graph"
360
+ ],
361
+ "buffer_resource": "out_input_tensor_buffer",
362
+ "size": 1566720,
363
+ "offset": 0
364
+ }
365
+ },
366
+ {
367
+ "image_barrier": {
368
+ "uid": "barrier_offset_to_post",
369
+ "src_access": "compute_shader_write",
370
+ "dst_access": "compute_shader_read",
371
+ "old_layout": "general",
372
+ "new_layout": "general",
373
+ "src_stage": [
374
+ "graphics"
375
+ ],
376
+ "dst_stage": [
377
+ "graphics"
378
+ ],
379
+ "image_resource": "out_nearest_depth_offset"
380
+ }
381
+ },
382
+ {
383
+ "buffer_barrier": {
384
+ "uid": "barrier_graph0_buf_to_post",
385
+ "src_access": "graph_write",
386
+ "dst_access": "compute_shader_read",
387
+ "src_stage": [
388
+ "graph"
389
+ ],
390
+ "dst_stage": [
391
+ "graphics"
392
+ ],
393
+ "buffer_resource": "out_graph_0_buffer",
394
+ "size": 130560,
395
+ "offset": 0
396
+ }
397
+ },
398
+ {
399
+ "image_barrier": {
400
+ "uid": "barrier_temporal_to_post",
401
+ "src_access": "graph_write",
402
+ "dst_access": "compute_shader_read",
403
+ "old_layout": "general",
404
+ "new_layout": "general",
405
+ "src_stage": [
406
+ "graph"
407
+ ],
408
+ "dst_stage": [
409
+ "graphics"
410
+ ],
411
+ "image_resource": "out_temporal"
412
+ }
413
+ },
414
+ {
415
+ "image": {
416
+ "uid": "out_depth_scatter",
417
+ "src": "./../assets/960x540_1920x1080/in_depth_scatter_init-240x135__960x540_1920x1080_mid_fragment.dds",
418
+ "dst": "./out_depth_scatter.dds",
419
+ "dims": [
420
+ 1,
421
+ 240,
422
+ 135,
423
+ 1
424
+ ],
425
+ "format": "VK_FORMAT_R32_UINT",
426
+ "shader_access": "readwrite",
427
+ "mips": 1,
428
+ "tiling": "OPTIMAL"
429
+ }
430
+ },
431
+ {
432
+ "shader": {
433
+ "uid": "0_depth_scatter_init",
434
+ "src": "./../0_depth_scatter_init.comp",
435
+ "entry": "main",
436
+ "type": "GLSL",
437
+ "push_constants_size": 40,
438
+ "specialization_constants": [],
439
+ "build_options": "",
440
+ "include_dirs": [
441
+ "./.."
442
+ ]
443
+ }
444
+ },
445
+ {
446
+ "raw_data": {
447
+ "uid": "push_data_0",
448
+ "src": "./../assets/960x540_1920x1080/0_depth_scatter_push_consts__960x540_1920x1080_mid_fragment.npy"
449
+ }
450
+ },
451
+ {
452
+ "image": {
453
+ "uid": "in_motion",
454
+ "src": "./../assets/960x540_1920x1080/in_motion.dds",
455
+ "dims": [
456
+ 1,
457
+ 960,
458
+ 540,
459
+ 1
460
+ ],
461
+ "format": "VK_FORMAT_R16G16_SFLOAT",
462
+ "shader_access": "readonly",
463
+ "mips": 1,
464
+ "tiling": "OPTIMAL"
465
+ }
466
+ },
467
+ {
468
+ "image": {
469
+ "uid": "in_depth",
470
+ "src": "./../assets/960x540_1920x1080/in_depth.dds",
471
+ "dims": [
472
+ 1,
473
+ 960,
474
+ 540,
475
+ 1
476
+ ],
477
+ "format": "VK_FORMAT_R32_SFLOAT",
478
+ "shader_access": "readonly",
479
+ "mips": 1,
480
+ "tiling": "OPTIMAL"
481
+ }
482
+ },
483
+ {
484
+ "shader": {
485
+ "uid": "0_depth_scatter",
486
+ "src": "./../0_depth_scatter.comp",
487
+ "entry": "main",
488
+ "type": "GLSL",
489
+ "push_constants_size": 40,
490
+ "specialization_constants": [],
491
+ "build_options": "-DNSS_DEPTH_SCATTER_QUARTER_RES_INPUT=1",
492
+ "include_dirs": [
493
+ "./.."
494
+ ]
495
+ }
496
+ },
497
+ {
498
+ "image": {
499
+ "uid": "out_disocclusion_mask_lq",
500
+ "dst": "./out_disocclusion_mask_lq.dds",
501
+ "dims": [
502
+ 1,
503
+ 240,
504
+ 135,
505
+ 1
506
+ ],
507
+ "format": "VK_FORMAT_R8_UNORM",
508
+ "shader_access": "readwrite",
509
+ "mips": 1,
510
+ "color_attachment": true,
511
+ "min_filter": "LINEAR",
512
+ "mag_filter": "LINEAR",
513
+ "mip_filter": "NEAREST",
514
+ "tiling": "OPTIMAL"
515
+ }
516
+ },
517
+ {
518
+ "shader": {
519
+ "uid": "fullscreen_triangle_vert",
520
+ "src": "./../fullscreen_triangle.vert",
521
+ "entry": "main",
522
+ "type": "GLSL",
523
+ "push_constants_size": 0,
524
+ "specialization_constants": [],
525
+ "build_options": "",
526
+ "stage": "vertex",
527
+ "include_dirs": [
528
+ "./.."
529
+ ]
530
+ }
531
+ },
532
+ {
533
+ "shader": {
534
+ "uid": "0_disocclusion_mask_lq",
535
+ "src": "./../0_disocclusion_mask_lq.frag",
536
+ "entry": "main",
537
+ "type": "GLSL",
538
+ "push_constants_size": 144,
539
+ "specialization_constants": [],
540
+ "build_options": "",
541
+ "stage": "fragment",
542
+ "include_dirs": [
543
+ "./.."
544
+ ]
545
+ }
546
+ },
547
+ {
548
+ "raw_data": {
549
+ "uid": "push_data_1",
550
+ "src": "./../assets/960x540_1920x1080/1_pre_process_push_consts__960x540_1920x1080_mid_fragment.npy"
551
+ }
552
+ },
553
+ {
554
+ "image": {
555
+ "uid": "in_colour",
556
+ "src": "./../assets/960x540_1920x1080/in_colour.dds",
557
+ "dims": [
558
+ 1,
559
+ 960,
560
+ 540,
561
+ 1
562
+ ],
563
+ "format": "VK_FORMAT_B10G11R11_UFLOAT_PACK32",
564
+ "shader_access": "readonly",
565
+ "mips": 1,
566
+ "min_filter": "LINEAR",
567
+ "mag_filter": "LINEAR",
568
+ "mip_filter": "NEAREST",
569
+ "border_address_mode": "CLAMP_EDGE",
570
+ "tiling": "OPTIMAL"
571
+ }
572
+ },
573
+ {
574
+ "image": {
575
+ "uid": "in_history",
576
+ "src": "./../assets/960x540_1920x1080/in_history.dds",
577
+ "dims": [
578
+ 1,
579
+ 1920,
580
+ 1080,
581
+ 1
582
+ ],
583
+ "format": "VK_FORMAT_B10G11R11_UFLOAT_PACK32",
584
+ "shader_access": "readonly",
585
+ "mips": 1,
586
+ "min_filter": "LINEAR",
587
+ "mag_filter": "LINEAR",
588
+ "mip_filter": "NEAREST",
589
+ "border_address_mode": "CLAMP_EDGE",
590
+ "tiling": "OPTIMAL"
591
+ }
592
+ },
593
+ {
594
+ "image": {
595
+ "uid": "in_temporal_tm1",
596
+ "src": "./../assets/960x540_1920x1080/in_temporal_tm1-480x272__960x540_1920x1080_mid_fragment.dds",
597
+ "dims": [
598
+ 1,
599
+ 480,
600
+ 272,
601
+ 1
602
+ ],
603
+ "format": "VK_FORMAT_R8G8B8A8_SNORM",
604
+ "shader_access": "readonly",
605
+ "mips": 1,
606
+ "min_filter": "LINEAR",
607
+ "mag_filter": "LINEAR",
608
+ "mip_filter": "NEAREST",
609
+ "border_address_mode": "CLAMP_BORDER",
610
+ "border_color": "FLOAT_CUSTOM_EXT",
611
+ "tiling": "LINEAR",
612
+ "custom_border_color": [
613
+ -1.0,
614
+ -1.0,
615
+ -1.0,
616
+ -1.0
617
+ ]
618
+ }
619
+ },
620
+ {
621
+ "image": {
622
+ "uid": "in_derivative_tm1",
623
+ "src": "./../assets/960x540_1920x1080/in_derivative_tm1-480x272__960x540_1920x1080_mid_fragment.dds",
624
+ "dims": [
625
+ 1,
626
+ 480,
627
+ 272,
628
+ 1
629
+ ],
630
+ "format": "VK_FORMAT_R8G8B8A8_SNORM",
631
+ "shader_access": "readonly",
632
+ "mips": 1,
633
+ "min_filter": "LINEAR",
634
+ "mag_filter": "LINEAR",
635
+ "mip_filter": "NEAREST",
636
+ "border_address_mode": "CLAMP_BORDER",
637
+ "border_color": "FLOAT_CUSTOM_EXT",
638
+ "tiling": "OPTIMAL",
639
+ "custom_border_color": [
640
+ -1.0,
641
+ 0.0,
642
+ 0.0,
643
+ -1.0
644
+ ]
645
+ }
646
+ },
647
+ {
648
+ "buffer": {
649
+ "uid": "out_input_tensor_buffer",
650
+ "memory_group": {
651
+ "id": "mg_input_tensor"
652
+ },
653
+ "size": 1566720,
654
+ "shader_access": "readwrite"
655
+ }
656
+ },
657
+ {
658
+ "image": {
659
+ "uid": "out_derivative",
660
+ "dst": "./out_derivative.dds",
661
+ "dims": [
662
+ 1,
663
+ 480,
664
+ 272,
665
+ 1
666
+ ],
667
+ "format": "VK_FORMAT_R8G8B8A8_SNORM",
668
+ "shader_access": "writeonly",
669
+ "mips": 1,
670
+ "color_attachment": true,
671
+ "tiling": "OPTIMAL"
672
+ }
673
+ },
674
+ {
675
+ "image": {
676
+ "uid": "out_nearest_depth_offset",
677
+ "dst": "./out_nearest_depth_offset.dds",
678
+ "dims": [
679
+ 1,
680
+ 480,
681
+ 272,
682
+ 1
683
+ ],
684
+ "format": "VK_FORMAT_R8G8_UNORM",
685
+ "shader_access": "readwrite",
686
+ "mips": 1,
687
+ "color_attachment": true,
688
+ "tiling": "OPTIMAL"
689
+ }
690
+ },
691
+ {
692
+ "shader": {
693
+ "uid": "1_pre_process_frag",
694
+ "src": "./../1_pre_process.frag",
695
+ "entry": "main",
696
+ "type": "GLSL",
697
+ "push_constants_size": 144,
698
+ "specialization_constants": [],
699
+ "build_options": "-DNSS_INPUT_LAYOUT=1 -DNSS_V1_FULL_RES_LUMA_DERIVATIVE=0 -DNSS_V1_HALF_RES_LUMA_DERIVATIVE=1",
700
+ "stage": "fragment",
701
+ "include_dirs": [
702
+ "./.."
703
+ ]
704
+ }
705
+ },
706
+ {
707
+ "tensor": {
708
+ "uid": "out_input_tensor",
709
+ "dst": "./out_input_tensor.npy",
710
+ "memory_group": {
711
+ "id": "mg_input_tensor"
712
+ },
713
+ "dims": [
714
+ 1,
715
+ 272,
716
+ 480,
717
+ 12
718
+ ],
719
+ "format": "VK_FORMAT_R8_SINT",
720
+ "shader_access": "readwrite",
721
+ "tiling": "LINEAR"
722
+ }
723
+ },
724
+ {
725
+ "tensor": {
726
+ "uid": "out_graph_0",
727
+ "dst": "./out_graph_0.npy",
728
+ "memory_group": {
729
+ "id": "mg_out_kpn"
730
+ },
731
+ "dims": [
732
+ 1,
733
+ 68,
734
+ 120,
735
+ 16
736
+ ],
737
+ "format": "VK_FORMAT_R8_SINT",
738
+ "shader_access": "readwrite",
739
+ "tiling": "LINEAR"
740
+ }
741
+ },
742
+ {
743
+ "tensor": {
744
+ "uid": "out_graph_1",
745
+ "dst": "./out_graph_1.npy",
746
+ "memory_group": {
747
+ "id": "mg_out_temporal"
748
+ },
749
+ "dims": [
750
+ 1,
751
+ 272,
752
+ 480,
753
+ 4
754
+ ],
755
+ "format": "VK_FORMAT_R8_SINT",
756
+ "shader_access": "readwrite",
757
+ "tiling": "LINEAR"
758
+ }
759
+ },
760
+ {
761
+ "graph": {
762
+ "uid": "2_nss",
763
+ "src": "./../assets/960x540_1920x1080/2_nss-480x270-kpn16-v1_0_1.vgf"
764
+ }
765
+ },
766
+ {
767
+ "buffer": {
768
+ "uid": "out_graph_0_buffer",
769
+ "memory_group": {
770
+ "id": "mg_out_kpn"
771
+ },
772
+ "size": 130560,
773
+ "shader_access": "readonly"
774
+ }
775
+ },
776
+ {
777
+ "image": {
778
+ "uid": "out_temporal",
779
+ "memory_group": {
780
+ "id": "mg_out_temporal"
781
+ },
782
+ "dims": [
783
+ 1,
784
+ 480,
785
+ 272,
786
+ 1
787
+ ],
788
+ "format": "VK_FORMAT_R8G8B8A8_SNORM",
789
+ "shader_access": "readonly",
790
+ "mips": 1,
791
+ "min_filter": "LINEAR",
792
+ "mag_filter": "LINEAR",
793
+ "mip_filter": "NEAREST",
794
+ "border_address_mode": "CLAMP_BORDER",
795
+ "border_color": "FLOAT_TRANSPARENT_BLACK",
796
+ "tiling": "LINEAR"
797
+ }
798
+ },
799
+ {
800
+ "image": {
801
+ "uid": "out_colour",
802
+ "dst": "./out_colour.dds",
803
+ "dims": [
804
+ 1,
805
+ 1920,
806
+ 1080,
807
+ 1
808
+ ],
809
+ "format": "VK_FORMAT_B10G11R11_UFLOAT_PACK32",
810
+ "shader_access": "writeonly",
811
+ "mips": 1,
812
+ "color_attachment": true,
813
+ "tiling": "OPTIMAL"
814
+ }
815
+ },
816
+ {
817
+ "shader": {
818
+ "uid": "3_post_process_frag",
819
+ "src": "./../3_post_process.frag",
820
+ "entry": "main",
821
+ "type": "GLSL",
822
+ "push_constants_size": 120,
823
+ "specialization_constants": [],
824
+ "build_options": "-DNSS_INPUT_LAYOUT=1 -DNSS_V1_SHARP_THETA=1 -DNSS_FILTER_MODE=1",
825
+ "stage": "fragment",
826
+ "include_dirs": [
827
+ "./.."
828
+ ]
829
+ }
830
+ },
831
+ {
832
+ "raw_data": {
833
+ "uid": "push_data_3",
834
+ "src": "./../assets/960x540_1920x1080/3_post_process_push_consts__960x540_1920x1080_mid_fragment.npy"
835
+ }
836
+ }
837
+ ]
838
+ }
scenario/fullscreen_triangle.vert ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //
2
+ // -----------------------------------------------------------------------------
3
+ // The proprietary software and information contained in this file is
4
+ // confidential and may only be used by an authorized person under a valid
5
+ // licensing agreement from Arm Limited or its affiliates.
6
+ //
7
+ // Copyright (C) 2026 Arm Limited or its affiliates. All rights reserved.
8
+ //
9
+ // This entire notice must be reproduced on all copies of this file and
10
+ // copies of this file may only be made by an authorized person under a valid
11
+ // licensing agreement from Arm Limited or its affiliates.
12
+ // -----------------------------------------------------------------------------
13
+ //
14
+
15
+ #version 460
16
+
17
+ layout(location = 0) out vec2 vUV;
18
+
19
+ void main() {
20
+ // Fullscreen triangle without vertex buffers
21
+ vec2 pos = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
22
+ vUV = vec2(pos.x * 0.5, 1.0 - pos.y * 0.5);
23
+ gl_Position = vec4(pos * 2.0 - 1.0, 0.0, 1.0);
24
+ }
scenario/typedefs.h CHANGED
@@ -4,13 +4,14 @@
4
  // confidential and may only be used by an authorized person under a valid
5
  // licensing agreement from Arm Limited or its affiliates.
6
  //
7
- // Copyright (C) 2025. Arm Limited or its affiliates. All rights reserved.
8
  //
9
  // This entire notice must be reproduced on all copies of this file and
10
  // copies of this file may only be made by an authorized person under a valid
11
  // licensing agreement from Arm Limited or its affiliates.
12
  // -----------------------------------------------------------------------------
13
  //
 
14
  #ifndef NSS_TYPEDEFS
15
  #define NSS_TYPEDEFS
16
 
@@ -27,7 +28,7 @@
27
  #define float4 f32vec4
28
 
29
  // int8 types
30
- #define int8_t int8_t
31
  #define int8_t2 i8vec2
32
  #define int8_t3 i8vec3
33
  #define int8_t4 i8vec4
@@ -60,27 +61,27 @@
60
  #define lerp mix
61
 
62
  // --- RCP functions for float16 types ---
63
- half rcp(half x) { return half( 1.HF) / x; }
64
  half2 rcp(half2 x) { return half2(1.HF) / x; }
65
  half3 rcp(half3 x) { return half3(1.HF) / x; }
66
  half4 rcp(half4 x) { return half4(1.HF) / x; }
67
 
68
  // --- RCP functions for float32 types ---
69
- float rcp(float x) { return float( 1.0f) / x; }
70
  float2 rcp(float2 x) { return float2(1.0f) / x; }
71
  float3 rcp(float3 x) { return float3(1.0f) / x; }
72
  float4 rcp(float4 x) { return float4(1.0f) / x; }
73
 
74
  // --- Saturate functions for float16 types ---
75
- half saturate(half x) { return clamp(x, half( 0.HF), half( 1.HF)); }
76
- half2 saturate(half2 x) { return clamp(x, half2(0.HF), half2(1.HF)); }
77
- half3 saturate(half3 x) { return clamp(x, half3(0.HF), half3(1.HF)); }
78
- half4 saturate(half4 x) { return clamp(x, half4(0.HF), half4(1.HF)); }
79
 
80
  // --- Saturate functions for float32 types ---
81
- float saturate(float x) { return clamp(x, 0.f, 1.f); }
82
- float2 saturate(float2 x) { return clamp(x, float2(0.f), float2(1.f)); }
83
- float3 saturate(float3 x) { return clamp(x, float3(0.f), float3(1.f)); }
84
- float4 saturate(float4 x) { return clamp(x, float4(0.f), float4(1.f)); }
85
 
86
  #endif // NSS_TYPEDEFS
 
4
  // confidential and may only be used by an authorized person under a valid
5
  // licensing agreement from Arm Limited or its affiliates.
6
  //
7
+ // Copyright (C) 2026 Arm Limited or its affiliates. All rights reserved.
8
  //
9
  // This entire notice must be reproduced on all copies of this file and
10
  // copies of this file may only be made by an authorized person under a valid
11
  // licensing agreement from Arm Limited or its affiliates.
12
  // -----------------------------------------------------------------------------
13
  //
14
+
15
  #ifndef NSS_TYPEDEFS
16
  #define NSS_TYPEDEFS
17
 
 
28
  #define float4 f32vec4
29
 
30
  // int8 types
31
+ #define int8_t int8_t
32
  #define int8_t2 i8vec2
33
  #define int8_t3 i8vec3
34
  #define int8_t4 i8vec4
 
61
  #define lerp mix
62
 
63
  // --- RCP functions for float16 types ---
64
+ half rcp(half x) { return half(1.HF) / x; }
65
  half2 rcp(half2 x) { return half2(1.HF) / x; }
66
  half3 rcp(half3 x) { return half3(1.HF) / x; }
67
  half4 rcp(half4 x) { return half4(1.HF) / x; }
68
 
69
  // --- RCP functions for float32 types ---
70
+ float rcp(float x) { return float(1.0f) / x; }
71
  float2 rcp(float2 x) { return float2(1.0f) / x; }
72
  float3 rcp(float3 x) { return float3(1.0f) / x; }
73
  float4 rcp(float4 x) { return float4(1.0f) / x; }
74
 
75
  // --- Saturate functions for float16 types ---
76
+ half saturate(half x) { return clamp(x, half(0.HF), half(1.HF)); }
77
+ half2 saturate(half2 x) { return clamp(x, half2(0.HF), half2(1.HF)); }
78
+ half3 saturate(half3 x) { return clamp(x, half3(0.HF), half3(1.HF)); }
79
+ half4 saturate(half4 x) { return clamp(x, half4(0.HF), half4(1.HF)); }
80
 
81
  // --- Saturate functions for float32 types ---
82
+ float saturate(float x) { return clamp(x, 0.f, 1.f); }
83
+ float2 saturate(float2 x) { return clamp(x, float2(0.f), float2(1.f)); }
84
+ float3 saturate(float3 x) { return clamp(x, float3(0.f), float3(1.f)); }
85
+ float4 saturate(float4 x) { return clamp(x, float4(0.f), float4(1.f)); }
86
 
87
  #endif // NSS_TYPEDEFS
nss_v0.1.0_fp32.pt → v0_1/nss_v0.1.0_fp32.pt RENAMED
File without changes
nss_v0.1.1_int8.pt → v0_1/nss_v0.1.1_int8.pt RENAMED
File without changes
nss_v0.1.1_int8.vgf → v0_1/nss_v0.1.1_int8.vgf RENAMED
File without changes
nss_v0.1.1_int8_metadata.json → v0_1/nss_v0.1.1_int8_metadata.json RENAMED
File without changes