Skip to content

Commit a7b5e1e

Browse files
committed
Use optional Vulkan12Features::shaderBufferInt64Atomics feature for better mouse picking precision.
1 parent d60f6e1 commit a7b5e1e

File tree

9 files changed

+83
-16
lines changed

9 files changed

+83
-16
lines changed

CMakeLists.txt

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -296,14 +296,21 @@ target_link_shaders(vk-gltf-viewer PRIVATE
296296
shaders/jump_flood_seed.vert
297297
shaders/jump_flood.comp
298298
shaders/multi_node_mouse_picking.frag
299-
shaders/node_mouse_picking.frag
300299
shaders/node_mouse_picking.vert
301300
shaders/outline.frag
302301
shaders/screen_quad.vert
303302
shaders/skybox.frag
304303
shaders/skybox.vert
305304
)
306305

306+
target_link_shader_variants(vk-gltf-viewer PRIVATE
307+
TARGET_ENV vulkan1.2
308+
MACRO_DEFS "SEPARATE_IMAGE_SAMPLER=$<PLATFORM_ID:Darwin>"
309+
FILES
310+
shaders/node_mouse_picking.frag
311+
MACRO_NAMES "KHR_SHADER_ATOMIC_INT64"
312+
MACRO_VALUES 0 1
313+
)
307314
target_link_shader_variants(vk-gltf-viewer PRIVATE
308315
TARGET_ENV vulkan1.2
309316
FILES
@@ -314,13 +321,22 @@ target_link_shader_variants(vk-gltf-viewer PRIVATE
314321
"0 0" "0 1"
315322
"1 0" "1 1"
316323
)
324+
target_link_shader_variants(vk-gltf-viewer PRIVATE
325+
TARGET_ENV vulkan1.2
326+
MACRO_DEFS "SEPARATE_IMAGE_SAMPLER=$<PLATFORM_ID:Darwin>"
327+
FILES
328+
shaders/mask_node_mouse_picking.frag
329+
MACRO_NAMES "HAS_BASE_COLOR_TEXTURE" "HAS_COLOR_0_ALPHA_ATTRIBUTE" "KHR_SHADER_ATOMIC_INT64"
330+
MACRO_VALUES
331+
"0 0 0" "0 0 1" "0 1 0" "0 1 1"
332+
"1 0 0" "1 0 1" "1 1 0" "1 1 1"
333+
)
317334
target_link_shader_variants(vk-gltf-viewer PRIVATE
318335
TARGET_ENV vulkan1.2
319336
MACRO_DEFS "SEPARATE_IMAGE_SAMPLER=$<PLATFORM_ID:Darwin>"
320337
FILES
321338
shaders/mask_jump_flood_seed.frag
322339
shaders/mask_multi_node_mouse_picking.frag
323-
shaders/mask_node_mouse_picking.frag
324340
MACRO_NAMES "HAS_BASE_COLOR_TEXTURE" "HAS_COLOR_0_ALPHA_ATTRIBUTE"
325341
MACRO_VALUES
326342
"0 0" "0 1"

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ The extensions and feature used in this application are quite common in the mode
121121
- `timelineSemaphore`
122122
- `shaderInt8`
123123
- (optional) `drawIndirectCount` (If not presented, GPU frustum culling will be unavailable and fallback to the CPU frustum culling.)
124+
- (optional) `shaderBufferInt64Atomics` (better mouse picking precision)
124125
- `VkPhysicalDeviceDynamicRenderingFeatures`
125126
- `VkPhysicalDeviceSynchronization2Features`
126127
- `VkPhysicalDeviceExtendedDynamicStateFeaturesEXT`

impl/vulkan/Frame.cpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ vk_gltf_viewer::vulkan::Frame::GltfAsset::GltfAsset(const SharedData &sharedData
6969
sharedData.gpu.allocator,
7070
vk::BufferCreateInfo {
7171
{},
72-
sizeof(std::uint32_t) * math::divCeil<std::uint32_t>(assetExtended->asset.nodes.size(), 32U),
72+
std::max(sizeof(std::uint64_t), sizeof(std::uint32_t) * math::divCeil<std::uint32_t>(assetExtended->asset.nodes.size(), 32U)),
7373
vk::BufferUsageFlagBits::eTransferDst | vk::BufferUsageFlagBits::eStorageBuffer,
7474
},
7575
vma::AllocationCreateInfo {
@@ -148,8 +148,15 @@ vk_gltf_viewer::vulkan::Frame::ExecutionResult vk_gltf_viewer::vulkan::Frame::ge
148148
}
149149
},
150150
[&](const vk::Offset2D&) {
151-
const std::uint32_t packedNodeIndexAndDepth = gltfAsset->mousePickingResultBuffer.asValue<const std::uint32_t>();
152-
if (std::uint32_t nodeIndex = packedNodeIndexAndDepth & 0xFFFF; nodeIndex != NO_INDEX) {
151+
std::uint32_t nodeIndex;
152+
if (sharedData.gpu.supportShaderBufferInt64Atomics) {
153+
nodeIndex = gltfAsset->mousePickingResultBuffer.asValue<const std::uint64_t>() & 0xFFFF;
154+
}
155+
else {
156+
nodeIndex = gltfAsset->mousePickingResultBuffer.asValue<const std::uint32_t>() & 0xFFFF;
157+
}
158+
159+
if (nodeIndex != NO_INDEX) {
153160
result.mousePickingResult.emplace<std::size_t>(nodeIndex);
154161
}
155162
},
@@ -1218,7 +1225,12 @@ void vk_gltf_viewer::vulkan::Frame::recordScenePrepassCommands(vk::CommandBuffer
12181225
// Mouse picking.
12191226
const bool makeMousePickingResultBufferAvailableToHost = renderingNodes && visit(multilambda {
12201227
[&](const vk::Offset2D &offset) {
1221-
cb.updateBuffer<std::uint32_t>(gltfAsset->mousePickingResultBuffer, 0, NO_INDEX);
1228+
if (sharedData.gpu.supportShaderBufferInt64Atomics) {
1229+
cb.updateBuffer<std::uint64_t>(gltfAsset->mousePickingResultBuffer, 0, NO_INDEX);
1230+
}
1231+
else {
1232+
cb.updateBuffer<std::uint32_t>(gltfAsset->mousePickingResultBuffer, 0, NO_INDEX);
1233+
}
12221234

12231235
if (renderingNodes->startMousePickingRenderPass) {
12241236
cb.pipelineBarrier(

impl/vulkan/Gpu.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ vk::raii::Device vk_gltf_viewer::vulkan::Gpu::createDevice() {
235235
vk::PhysicalDeviceVulkan12Features,
236236
vk::PhysicalDeviceIndexTypeUint8FeaturesKHR>();
237237

238+
supportShaderBufferInt64Atomics = vulkan12Features.shaderBufferInt64Atomics;
238239
supportDrawIndirectCount = vulkan12Features.drawIndirectCount;
239240
#if __APPLE__
240241
// MoltenVK supports VK_KHR_index_type_uint8 from v1.3.0 by dynamically generating 16-bit indices from 8-bit indices
@@ -270,7 +271,10 @@ vk::raii::Device vk_gltf_viewer::vulkan::Gpu::createDevice() {
270271
{},
271272
extensions,
272273
},
273-
vk::PhysicalDeviceFeatures2 { requiredFeatures },
274+
vk::PhysicalDeviceFeatures2 {
275+
vk::PhysicalDeviceFeatures { requiredFeatures }
276+
.setShaderInt64(supportShaderBufferInt64Atomics),
277+
},
274278
vk::PhysicalDeviceVulkan11Features{}
275279
.setShaderDrawParameters(true)
276280
.setStorageBuffer16BitAccess(true)
@@ -288,7 +292,8 @@ vk::raii::Device vk_gltf_viewer::vulkan::Gpu::createDevice() {
288292
.setScalarBlockLayout(true)
289293
.setTimelineSemaphore(true)
290294
.setShaderInt8(true)
291-
.setDrawIndirectCount(supportDrawIndirectCount),
295+
.setDrawIndirectCount(supportDrawIndirectCount)
296+
.setShaderBufferInt64Atomics(supportShaderBufferInt64Atomics),
292297
vk::PhysicalDeviceDynamicRenderingFeatures { true },
293298
vk::PhysicalDeviceSynchronization2Features { true },
294299
vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT { true },

interface/shader_selector/mask_node_mouse_picking_frag.cppm

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,19 @@ import vk_gltf_viewer.shader.mask_node_mouse_picking_frag;
77

88
namespace vk_gltf_viewer::shader_selector {
99
export
10-
[[nodiscard]] std::span<const unsigned int> mask_node_mouse_picking_frag(int HAS_BASE_COLOR_TEXTURE, int HAS_COLOR_0_ALPHA_ATTRIBUTE);
10+
[[nodiscard]] std::span<const unsigned int> mask_node_mouse_picking_frag(int HAS_BASE_COLOR_TEXTURE, int HAS_COLOR_0_ALPHA_ATTRIBUTE, int KHR_SHADER_ATOMIC_INT64);
1111
}
1212

1313
#if !defined(__GNUC__) || defined(__clang__)
1414
module :private;
1515
#endif
1616

17-
std::span<const unsigned int> vk_gltf_viewer::shader_selector::mask_node_mouse_picking_frag(int HAS_BASE_COLOR_TEXTURE, int HAS_COLOR_0_ALPHA_ATTRIBUTE) {
17+
std::span<const unsigned int> vk_gltf_viewer::shader_selector::mask_node_mouse_picking_frag(int HAS_BASE_COLOR_TEXTURE, int HAS_COLOR_0_ALPHA_ATTRIBUTE, int KHR_SHADER_ATOMIC_INT64) {
1818
return std::visit(
1919
[](auto... Is) -> std::span<const unsigned int> {
2020
return shader::mask_node_mouse_picking_frag<Is...>;
2121
},
2222
iota_map<2>::get_variant(HAS_BASE_COLOR_TEXTURE),
23-
iota_map<2>::get_variant(HAS_COLOR_0_ALPHA_ATTRIBUTE));
23+
iota_map<2>::get_variant(HAS_COLOR_0_ALPHA_ATTRIBUTE),
24+
iota_map<2>::get_variant(KHR_SHADER_ATOMIC_INT64));
2425
}

interface/vulkan/Gpu.cppm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ namespace vk_gltf_viewer::vulkan {
5959

6060
bool isUmaDevice;
6161
bool supportSwapchainMutableFormat;
62+
bool supportShaderBufferInt64Atomics;
6263
bool supportDrawIndirectCount;
6364
bool supportUint8Index;
6465
bool supportAttachmentFeedbackLoopLayout;

interface/vulkan/pipeline/NodeMousePickingRenderPipeline.cppm

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ namespace vk_gltf_viewer::vulkan::inline pipeline {
5050

5151
[[nodiscard]] static std::array<int, 2> getVertexShaderVariants(const PrepassPipelineConfig<true> &config) noexcept;
5252
[[nodiscard]] static VertexShaderSpecialization getVertexShaderSpecialization(const PrepassPipelineConfig<true> &config) noexcept;
53-
[[nodiscard]] static std::array<int, 2> getFragmentShaderVariants(const PrepassPipelineConfig<true> &config) noexcept;
53+
[[nodiscard]] static std::array<int, 3> getFragmentShaderVariants(const PrepassPipelineConfig<true> &config, bool supportShaderBufferInt64Atomics) noexcept;
5454
[[nodiscard]] static FragmentShaderSpecialization getFragmentShaderSpecialization(const PrepassPipelineConfig<true> &config) noexcept;
5555
};
5656
}
@@ -88,7 +88,12 @@ vk_gltf_viewer::vulkan::pipeline::NodeMousePickingRenderPipeline<false>::NodeMou
8888
vku::unsafeProxy(getVertexShaderSpecialization(config)),
8989
}),
9090
},
91-
vku::Shader { shader::node_mouse_picking_frag, vk::ShaderStageFlagBits::eFragment }).get(),
91+
vku::Shader {
92+
gpu.supportShaderBufferInt64Atomics
93+
? std::span<const std::uint32_t> { shader::node_mouse_picking_frag<1> }
94+
: std::span<const std::uint32_t> { shader::node_mouse_picking_frag<0> },
95+
vk::ShaderStageFlagBits::eFragment,
96+
}).get(),
9297
// See doc about Gpu::Workaround::attachmentLessRenderPass.
9398
*pipelineLayout, 0, gpu.workaround.attachmentLessRenderPass)
9499
.setPInputAssemblyState(vku::unsafeAddress(vk::PipelineInputAssemblyStateCreateInfo {
@@ -157,7 +162,7 @@ vk_gltf_viewer::vulkan::pipeline::NodeMousePickingRenderPipeline<true>::NodeMous
157162
}),
158163
},
159164
vku::Shader {
160-
std::apply(LIFT(shader_selector::mask_node_mouse_picking_frag), getFragmentShaderVariants(config)),
165+
std::apply(LIFT(shader_selector::mask_node_mouse_picking_frag), getFragmentShaderVariants(config, gpu.supportShaderBufferInt64Atomics)),
161166
vk::ShaderStageFlagBits::eFragment,
162167
vku::unsafeAddress(vk::SpecializationInfo {
163168
SpecializationMap<FragmentShaderSpecialization>::value,
@@ -215,12 +220,14 @@ auto vk_gltf_viewer::vulkan::pipeline::NodeMousePickingRenderPipeline<true>::get
215220
return result;
216221
}
217222

218-
std::array<int, 2> vk_gltf_viewer::vulkan::pipeline::NodeMousePickingRenderPipeline<true>::getFragmentShaderVariants(
219-
const PrepassPipelineConfig<true> &config
223+
std::array<int, 3> vk_gltf_viewer::vulkan::pipeline::NodeMousePickingRenderPipeline<true>::getFragmentShaderVariants(
224+
const PrepassPipelineConfig<true> &config,
225+
bool supportShaderBufferInt64Atomics
220226
) noexcept {
221227
return {
222228
config.baseColorTexcoordComponentTypeAndNormalized.has_value(),
223229
config.color0AlphaComponentType.has_value(),
230+
supportShaderBufferInt64Atomics,
224231
};
225232
}
226233

shaders/mask_node_mouse_picking.frag

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
#extension GL_EXT_nonuniform_qualifier : require
44
#extension GL_EXT_shader_16bit_storage : require
55
#extension GL_EXT_shader_8bit_storage : require
6+
#if KHR_SHADER_ATOMIC_INT64 == 1
7+
#extension GL_EXT_shader_atomic_int64 : require
8+
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
9+
#endif
610

711
#define FRAGMENT_SHADER
812
#include "indexing.glsl"
@@ -36,7 +40,11 @@ layout (set = 0, binding = 3) uniform sampler2D textures[];
3640
#endif
3741

3842
layout (set = 1, binding = 0) buffer MousePickingResultBuffer {
43+
#if KHR_SHADER_ATOMIC_INT64 == 1
44+
uint64_t packedNodeIndexAndDepth;
45+
#else
3946
uint packedNodeIndexAndDepth;
47+
#endif
4048
};
4149

4250
void main(){
@@ -57,5 +65,9 @@ void main(){
5765
#endif
5866
if (baseColorAlpha < MATERIAL.alphaCutoff) discard;
5967

68+
#if KHR_SHADER_ATOMIC_INT64 == 1
69+
atomicMax(packedNodeIndexAndDepth, packUint2x32(uvec2(inNodeIndex, floatBitsToUint(gl_FragCoord.z))));
70+
#else
6071
atomicMax(packedNodeIndexAndDepth, (uint(gl_FragCoord.z * 65535) << 16) | inNodeIndex);
72+
#endif
6173
}

shaders/node_mouse_picking.frag

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,23 @@
11
#version 450
2+
#if KHR_SHADER_ATOMIC_INT64 == 1
3+
#extension GL_EXT_shader_atomic_int64 : require
4+
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
5+
#endif
26

37
layout (location = 0) flat in uint inNodeIndex;
48

59
layout (set = 1, binding = 0) buffer MousePickingResultBuffer {
10+
#if KHR_SHADER_ATOMIC_INT64 == 1
11+
uint64_t packedNodeIndexAndDepth;
12+
#else
613
uint packedNodeIndexAndDepth;
14+
#endif
715
};
816

917
void main(){
18+
#if KHR_SHADER_ATOMIC_INT64 == 1
19+
atomicMax(packedNodeIndexAndDepth, packUint2x32(uvec2(inNodeIndex, floatBitsToUint(gl_FragCoord.z))));
20+
#else
1021
atomicMax(packedNodeIndexAndDepth, (uint(gl_FragCoord.z * 65535) << 16) | inNodeIndex);
22+
#endif
1123
}

0 commit comments

Comments
 (0)