Skip to content

Commit 9d477e3

Browse files
committed
Use atomicMax based mouse picking.
1 parent 4d7fae9 commit 9d477e3

20 files changed

+382
-526
lines changed

CMakeLists.txt

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,8 @@ target_sources(vk-gltf-viewer PRIVATE
162162
interface/math/Frustum.cppm
163163
interface/math/Plane.cppm
164164
interface/Renderer.cppm
165-
interface/shader_selector/mask_node_index_frag.cppm
166-
interface/shader_selector/mask_node_index_vert.cppm
165+
interface/shader_selector/mask_node_mouse_picking_frag.cppm
166+
interface/shader_selector/mask_node_mouse_picking_vert.cppm
167167
interface/shader_selector/mask_jump_flood_seed_frag.cppm
168168
interface/shader_selector/mask_jump_flood_seed_vert.cppm
169169
interface/shader_selector/mask_multi_node_mouse_picking_frag.cppm
@@ -183,7 +183,7 @@ target_sources(vk-gltf-viewer PRIVATE
183183
interface/vulkan/buffer/PrimitiveAttributes.cppm
184184
interface/vulkan/descriptor_set_layout/Asset.cppm
185185
interface/vulkan/descriptor_set_layout/ImageBasedLighting.cppm
186-
interface/vulkan/descriptor_set_layout/MultiNodeMousePicking.cppm
186+
interface/vulkan/descriptor_set_layout/MousePicking.cppm
187187
interface/vulkan/descriptor_set_layout/Skybox.cppm
188188
interface/vulkan/Frame.cppm
189189
interface/vulkan/FrameDeferredTask.cppm
@@ -196,21 +196,19 @@ target_sources(vk-gltf-viewer PRIVATE
196196
interface/vulkan/pipeline/InverseToneMappingRenderPipeline.cppm
197197
interface/vulkan/pipeline/JumpFloodComputePipeline.cppm
198198
interface/vulkan/pipeline/JumpFloodSeedRenderPipeline.cppm
199-
interface/vulkan/pipeline/MousePickingRenderPipeline.cppm
200199
interface/vulkan/pipeline/MultiNodeMousePickingRenderPipeline.cppm
201-
interface/vulkan/pipeline/NodeIndexRenderPipeline.cppm
200+
interface/vulkan/pipeline/NodeMousePickingRenderPipeline.cppm
202201
interface/vulkan/pipeline/OutlineRenderPipeline.cppm
203202
interface/vulkan/pipeline/PrepassPipelineConfig.cppm
204203
interface/vulkan/pipeline/PrimitiveRenderPipeline.cppm
205204
interface/vulkan/pipeline/SkyboxRenderPipeline.cppm
206205
interface/vulkan/pipeline/UnlitPrimitiveRenderPipeline.cppm
207206
interface/vulkan/pipeline/WeightedBlendedCompositionRenderPipeline.cppm
208-
interface/vulkan/pipeline_layout/MultiNodeMousePicking.cppm
207+
interface/vulkan/pipeline_layout/MousePicking.cppm
209208
interface/vulkan/pipeline_layout/Primitive.cppm
210209
interface/vulkan/pipeline_layout/PrimitiveNoShading.cppm
211210
interface/vulkan/render_pass/BloomApply.cppm
212211
interface/vulkan/render_pass/CubemapToneMapping.cppm
213-
interface/vulkan/render_pass/MousePicking.cppm
214212
interface/vulkan/render_pass/Scene.cppm
215213
interface/vulkan/sampler/BrdfLut.cppm
216214
interface/vulkan/sampler/Cubemap.cppm
@@ -297,10 +295,9 @@ target_link_shaders(vk-gltf-viewer PRIVATE
297295
shaders/jump_flood_seed.frag
298296
shaders/jump_flood_seed.vert
299297
shaders/jump_flood.comp
300-
shaders/mouse_picking.frag
301298
shaders/multi_node_mouse_picking.frag
302-
shaders/node_index.frag
303-
shaders/node_index.vert
299+
shaders/node_mouse_picking.frag
300+
shaders/node_mouse_picking.vert
304301
shaders/outline.frag
305302
shaders/screen_quad.vert
306303
shaders/skybox.frag
@@ -311,7 +308,7 @@ target_link_shader_variants(vk-gltf-viewer PRIVATE
311308
TARGET_ENV vulkan1.2
312309
FILES
313310
shaders/mask_jump_flood_seed.vert
314-
shaders/mask_node_index.vert
311+
shaders/mask_node_mouse_picking.vert
315312
MACRO_NAMES "HAS_BASE_COLOR_TEXTURE" "HAS_COLOR_0_ALPHA_ATTRIBUTE"
316313
MACRO_VALUES
317314
"0 0" "0 1"
@@ -323,7 +320,7 @@ target_link_shader_variants(vk-gltf-viewer PRIVATE
323320
FILES
324321
shaders/mask_jump_flood_seed.frag
325322
shaders/mask_multi_node_mouse_picking.frag
326-
shaders/mask_node_index.frag
323+
shaders/mask_node_mouse_picking.frag
327324
MACRO_NAMES "HAS_BASE_COLOR_TEXTURE" "HAS_COLOR_0_ALPHA_ATTRIBUTE"
328325
MACRO_VALUES
329326
"0 0" "0 1"

impl/vulkan/Frame.cpp

Lines changed: 73 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,8 @@ vk_gltf_viewer::vulkan::Frame::Frame(std::shared_ptr<const Renderer> _renderer,
108108
, swapchainImageAcquireSema { sharedData.gpu.device, vk::SemaphoreCreateInfo{} }
109109
, inFlightFence { sharedData.gpu.device, vk::FenceCreateInfo{} } {
110110
// Allocate descriptor sets.
111-
std::tie(mousePickingSet, multiNodeMousePickingSet, hoveringNodeJumpFloodSet, selectedNodeJumpFloodSet, hoveringNodeOutlineSet, selectedNodeOutlineSet, weightedBlendedCompositionSet, inverseToneMappingSet, bloomSet, bloomApplySet)
111+
std::tie(mousePickingSet, hoveringNodeJumpFloodSet, selectedNodeJumpFloodSet, hoveringNodeOutlineSet, selectedNodeOutlineSet, weightedBlendedCompositionSet, inverseToneMappingSet, bloomSet, bloomApplySet)
112112
= allocateDescriptorSets(*descriptorPool, std::tie(
113-
sharedData.mousePickingRenderPipeline.descriptorSetLayout,
114113
sharedData.multiNodeMousePickingDescriptorSetLayout,
115114
sharedData.jumpFloodComputePipeline.descriptorSetLayout,
116115
sharedData.jumpFloodComputePipeline.descriptorSetLayout,
@@ -149,9 +148,9 @@ vk_gltf_viewer::vulkan::Frame::ExecutionResult vk_gltf_viewer::vulkan::Frame::ge
149148
}
150149
},
151150
[&](const vk::Offset2D&) {
152-
const std::uint16_t hoveringNodeIndex = gltfAsset->mousePickingResultBuffer.asValue<const std::uint32_t>();
153-
if (hoveringNodeIndex != NO_INDEX) {
154-
result.mousePickingResult.emplace<std::size_t>(hoveringNodeIndex);
151+
const std::uint32_t packedNodeIndexAndDepth = gltfAsset->mousePickingResultBuffer.asValue<const std::uint32_t>();
152+
if (std::uint32_t nodeIndex = packedNodeIndexAndDepth & 0xFFFF; nodeIndex != NO_INDEX) {
153+
result.mousePickingResult.emplace<std::size_t>(nodeIndex);
155154
}
156155
},
157156
[](std::monostate) { }
@@ -228,15 +227,15 @@ void vk_gltf_viewer::vulkan::Frame::update(const ExecutionTask &task) {
228227
if (primitive.materialIndex) {
229228
const fastgltf::Material& material = gltfAsset->assetExtended->asset.materials[*primitive.materialIndex];
230229
if (material.alphaMode == fastgltf::AlphaMode::Mask) {
231-
result.pipeline = *sharedData.getMaskPrepassPipelines(primitive).nodeIndexRenderPipeline;
230+
result.pipeline = *sharedData.getMaskPrepassPipelines(primitive).nodeMousePickingRenderPipeline;
232231
}
233232
else {
234-
result.pipeline = *sharedData.getPrepassPipelines(primitive).nodeIndexRenderPipeline;
233+
result.pipeline = *sharedData.getPrepassPipelines(primitive).nodeMousePickingRenderPipeline;
235234
}
236235
result.cullMode = material.doubleSided ? vk::CullModeFlagBits::eNone : vk::CullModeFlagBits::eBack;
237236
}
238237
else {
239-
result.pipeline = *sharedData.getPrepassPipelines(primitive).nodeIndexRenderPipeline;
238+
result.pipeline = *sharedData.getPrepassPipelines(primitive).nodeMousePickingRenderPipeline;
240239
}
241240
return result;
242241
};
@@ -863,7 +862,6 @@ void vk_gltf_viewer::vulkan::Frame::setPassthruExtent(const vk::Extent2D &extent
863862
}
864863

865864
sharedData.gpu.device.updateDescriptorSets({
866-
mousePickingSet.getWriteOne<0>({ {}, *passthruResources->mousePickingAttachmentGroup.getColorAttachment(0).view, vk::ImageLayout::eShaderReadOnlyOptimal }),
867865
hoveringNodeJumpFloodSet.getWriteOne<0>({ {}, *passthruResources->hoveringNodeOutlineJumpFloodResources.imageView, vk::ImageLayout::eGeneral }),
868866
selectedNodeJumpFloodSet.getWriteOne<0>({ {}, *passthruResources->selectedNodeOutlineJumpFloodResources.imageView, vk::ImageLayout::eGeneral }),
869867
weightedBlendedCompositionSet.getWrite<0>(vku::unsafeProxy({
@@ -916,8 +914,7 @@ void vk_gltf_viewer::vulkan::Frame::updateAsset() {
916914

917915
// Update the descriptors that are unrelated to the asset textures.
918916
sharedData.gpu.device.updateDescriptorSets({
919-
mousePickingSet.getWriteOne<1>({ inner.mousePickingResultBuffer, 0, sizeof(std::uint32_t) }),
920-
multiNodeMousePickingSet.getWriteOne<0>({ inner.mousePickingResultBuffer, 0, vk::WholeSize }),
917+
mousePickingSet.getWriteOne<0>({ inner.mousePickingResultBuffer, 0, vk::WholeSize }),
921918
assetDescriptorSet.getWrite<0>(inner.assetExtended->primitiveBuffer.descriptorInfo),
922919
assetDescriptorSet.getWrite<1>(inner.nodeBuffer.descriptorInfo),
923920
assetDescriptorSet.getWrite<2>(inner.assetExtended->materialBuffer.descriptorInfo),
@@ -1023,15 +1020,6 @@ vk_gltf_viewer::vulkan::Frame::PassthruResources::PassthruResources(
10231020
vk::CommandBuffer graphicsCommandBuffer
10241021
) : extent { extent },
10251022
mousePickingAttachmentGroup { sharedData.gpu, extent },
1026-
mousePickingFramebuffer { sharedData.gpu.device, vk::FramebufferCreateInfo {
1027-
{},
1028-
*sharedData.mousePickingRenderPass,
1029-
vku::unsafeProxy({
1030-
*mousePickingAttachmentGroup.getColorAttachment(0).view,
1031-
*mousePickingAttachmentGroup.depthStencilAttachment->view,
1032-
}),
1033-
extent.width, extent.height, 1,
1034-
} },
10351023
hoveringNodeOutlineJumpFloodResources { sharedData.gpu, extent },
10361024
hoveringNodeJumpFloodSeedAttachmentGroup { sharedData.gpu, hoveringNodeOutlineJumpFloodResources.image },
10371025
selectedNodeOutlineJumpFloodResources { sharedData.gpu, extent },
@@ -1118,8 +1106,7 @@ vk_gltf_viewer::vulkan::Frame::PassthruResources::PassthruResources(
11181106

11191107
vk::raii::DescriptorPool vk_gltf_viewer::vulkan::Frame::createDescriptorPool() const {
11201108
const vku::PoolSizes poolSizes
1121-
= sharedData.mousePickingRenderPipeline.descriptorSetLayout.getPoolSize()
1122-
+ sharedData.multiNodeMousePickingDescriptorSetLayout.getPoolSize()
1109+
= sharedData.multiNodeMousePickingDescriptorSetLayout.getPoolSize()
11231110
+ 2 * getPoolSizes(sharedData.jumpFloodComputePipeline.descriptorSetLayout, sharedData.outlineRenderPipeline.descriptorSetLayout)
11241111
+ sharedData.weightedBlendedCompositionRenderPipeline.descriptorSetLayout.getPoolSize()
11251112
+ sharedData.inverseToneMappingRenderPipeline.descriptorSetLayout.getPoolSize()
@@ -1130,39 +1117,30 @@ vk::raii::DescriptorPool vk_gltf_viewer::vulkan::Frame::createDescriptorPool() c
11301117
}
11311118

11321119
void vk_gltf_viewer::vulkan::Frame::recordScenePrepassCommands(vk::CommandBuffer cb) const {
1133-
boost::container::static_vector<vk::ImageMemoryBarrier, 3> memoryBarriers;
1134-
1135-
// If glTF Scene have to be rendered, prepare attachment layout transition for node index and depth rendering.
1136-
if (renderingNodes) {
1137-
memoryBarriers.push_back({
1138-
{}, vk::AccessFlagBits::eColorAttachmentWrite,
1139-
{}, vk::ImageLayout::eColorAttachmentOptimal,
1140-
vk::QueueFamilyIgnored, vk::QueueFamilyIgnored,
1141-
passthruResources->mousePickingAttachmentGroup.getColorAttachment(0).image, vku::fullSubresourceRange(),
1142-
});
1143-
}
1144-
1145-
// If hovering node's outline have to be rendered, prepare attachment layout transition for jump flood seeding.
1146-
const auto getJumpFloodSeedImageMemoryBarrier = [](vk::Image image) -> vk::ImageMemoryBarrier {
1120+
// If hovering/selected node's outline have to be rendered, prepare attachment layout transition for jump flood seeding.
1121+
constexpr auto getJumpFloodSeedImageMemoryBarrier = [](vk::Image image) -> vk::ImageMemoryBarrier {
11471122
return {
11481123
{}, vk::AccessFlagBits::eColorAttachmentWrite,
11491124
{}, vk::ImageLayout::eColorAttachmentOptimal,
11501125
vk::QueueFamilyIgnored, vk::QueueFamilyIgnored,
11511126
image, { vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1 } /* ping image */,
11521127
};
11531128
};
1129+
1130+
boost::container::static_vector<vk::ImageMemoryBarrier, 2> memoryBarriers;
11541131
if (selectedNodes) {
11551132
memoryBarriers.push_back(getJumpFloodSeedImageMemoryBarrier(passthruResources->selectedNodeOutlineJumpFloodResources.image));
11561133
}
1157-
// Same holds for hovering nodes' outline.
11581134
if (hoveringNode) {
11591135
memoryBarriers.push_back(getJumpFloodSeedImageMemoryBarrier(passthruResources->hoveringNodeOutlineJumpFloodResources.image));
11601136
}
11611137

1162-
// Attachment layout transitions.
1163-
cb.pipelineBarrier(
1164-
vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eColorAttachmentOutput,
1165-
{}, {}, {}, memoryBarriers);
1138+
if (!memoryBarriers.empty()) {
1139+
// Attachment layout transitions.
1140+
cb.pipelineBarrier(
1141+
vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eColorAttachmentOutput,
1142+
{}, {}, {}, memoryBarriers);
1143+
}
11661144

11671145
struct ResourceBindingState {
11681146
vk::Pipeline pipeline{};
@@ -1236,8 +1214,7 @@ void vk_gltf_viewer::vulkan::Frame::recordScenePrepassCommands(vk::CommandBuffer
12361214
// Mouse picking.
12371215
const bool makeMousePickingResultBufferAvailableToHost = renderingNodes && visit(multilambda {
12381216
[&](const vk::Offset2D &offset) {
1239-
// Clear the first [0, 4] region of mousePickingResultBuffer as NO_INDEX.
1240-
cb.fillBuffer(gltfAsset->mousePickingResultBuffer, 0, sizeof(std::uint32_t), NO_INDEX);
1217+
cb.updateBuffer<std::uint32_t>(gltfAsset->mousePickingResultBuffer, 0, NO_INDEX);
12411218

12421219
if (renderingNodes->startMousePickingRenderPass) {
12431220
cb.pipelineBarrier(
@@ -1246,27 +1223,59 @@ void vk_gltf_viewer::vulkan::Frame::recordScenePrepassCommands(vk::CommandBuffer
12461223

12471224
cb.setScissor(0, vk::Rect2D { offset, { 1, 1 } });
12481225

1249-
cb.beginRenderPass(vk::RenderPassBeginInfo {
1250-
*sharedData.mousePickingRenderPass,
1251-
*passthruResources->mousePickingFramebuffer,
1252-
{ { 0, 0 }, passthruResources->extent },
1253-
vku::unsafeProxy<vk::ClearValue>({
1254-
vk::ClearColorValue { static_cast<std::uint32_t>(NO_INDEX), 0U, 0U, 0U },
1255-
vk::ClearDepthStencilValue { 0.f, 0U },
1256-
}),
1257-
}, vk::SubpassContents::eInline);
1226+
auto drawPrimitives = [&, resourceBindingState = ResourceBindingState{}](const auto &indirectDrawCommandBuffers) mutable {
1227+
for (const auto &[criteria, indirectDrawCommandBuffer] : indirectDrawCommandBuffers) {
1228+
if (resourceBindingState.pipeline != criteria.pipeline) {
1229+
cb.bindPipeline(vk::PipelineBindPoint::eGraphics, resourceBindingState.pipeline = criteria.pipeline);
1230+
}
12581231

1259-
// Subpass 1: draw node index to the 1x1 pixel (which lies at the right below the cursor).
1260-
drawPrimitives(renderingNodes->mousePickingIndirectDrawCommandBuffers);
1232+
if (!resourceBindingState.descriptorSetBound) {
1233+
cb.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, *sharedData.mousePickingPipelineLayout,
1234+
0, { assetDescriptorSet, mousePickingSet }, {});
1235+
resourceBindingState.descriptorSetBound = true;
1236+
}
12611237

1262-
cb.nextSubpass(vk::SubpassContents::eInline);
1238+
if (!resourceBindingState.pushConstantBound) {
1239+
cb.pushConstants<pl::MousePicking::PushConstant>(*sharedData.mousePickingPipelineLayout, vk::ShaderStageFlagBits::eVertex,
1240+
0, pl::MousePicking::PushConstant {
1241+
.projectionView = projectionViewMatrix,
1242+
});
1243+
resourceBindingState.pushConstantBound = true;
1244+
}
1245+
1246+
if (resourceBindingState.primitiveTopology != criteria.primitiveTopology) {
1247+
cb.setPrimitiveTopologyEXT(resourceBindingState.primitiveTopology.emplace(criteria.primitiveTopology));
1248+
}
12631249

1264-
// Subpass 2: read it and copy to the mousePickingResultBuffer.
1265-
cb.bindPipeline(vk::PipelineBindPoint::eGraphics, *sharedData.mousePickingRenderPipeline.pipeline);
1266-
cb.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, *sharedData.mousePickingRenderPipeline.pipelineLayout, 0, mousePickingSet, {});
1267-
cb.draw(3, 1, 0, 0);
1250+
if (resourceBindingState.cullMode != criteria.cullMode) {
1251+
cb.setCullModeEXT(resourceBindingState.cullMode.emplace(criteria.cullMode));
1252+
}
1253+
1254+
if (criteria.indexType && resourceBindingState.indexType != *criteria.indexType) {
1255+
resourceBindingState.indexType.emplace(*criteria.indexType);
1256+
cb.bindIndexBuffer(
1257+
gltfAsset->assetExtended->combinedIndexBuffer,
1258+
gltfAsset->assetExtended->combinedIndexBuffer.getIndexOffsetAndSize(*resourceBindingState.indexType).first,
1259+
*resourceBindingState.indexType);
1260+
}
1261+
indirectDrawCommandBuffer.recordDrawCommand(cb, sharedData.gpu.supportDrawIndirectCount);
1262+
}
1263+
};
12681264

1269-
cb.endRenderPass();
1265+
cb.beginRenderingKHR(vk::RenderingInfo {
1266+
{},
1267+
{ offset, { 1, 1 } },
1268+
1,
1269+
0,
1270+
vk::ArrayProxyNoTemporaries<const vk::RenderingAttachmentInfo>{},
1271+
vku::unsafeAddress(vk::RenderingAttachmentInfo {
1272+
*passthruResources->mousePickingAttachmentGroup.depthStencilAttachment->view, vk::ImageLayout::eDepthAttachmentOptimal,
1273+
{}, {}, {},
1274+
vk::AttachmentLoadOp::eClear, vk::AttachmentStoreOp::eDontCare, vk::ClearDepthStencilValue { 0.f, 0U },
1275+
}),
1276+
});
1277+
drawPrimitives(renderingNodes->mousePickingIndirectDrawCommandBuffers);
1278+
cb.endRenderingKHR();
12701279

12711280
return true;
12721281
}
@@ -1298,14 +1307,14 @@ void vk_gltf_viewer::vulkan::Frame::recordScenePrepassCommands(vk::CommandBuffer
12981307
}
12991308

13001309
if (!resourceBindingState.descriptorSetBound) {
1301-
cb.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, *sharedData.multiNodeMousePickingPipelineLayout,
1302-
0, { assetDescriptorSet, multiNodeMousePickingSet }, {});
1310+
cb.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, *sharedData.mousePickingPipelineLayout,
1311+
0, { assetDescriptorSet, mousePickingSet }, {});
13031312
resourceBindingState.descriptorSetBound = true;
13041313
}
13051314

13061315
if (!resourceBindingState.pushConstantBound) {
1307-
cb.pushConstants<pl::MultiNodeMousePicking::PushConstant>(*sharedData.multiNodeMousePickingPipelineLayout, vk::ShaderStageFlagBits::eVertex,
1308-
0, pl::MultiNodeMousePicking::PushConstant {
1316+
cb.pushConstants<pl::MousePicking::PushConstant>(*sharedData.mousePickingPipelineLayout, vk::ShaderStageFlagBits::eVertex,
1317+
0, pl::MousePicking::PushConstant {
13091318
.projectionView = projectionViewMatrix,
13101319
});
13111320
resourceBindingState.pushConstantBound = true;

0 commit comments

Comments
 (0)