From b7442270d78cd3af4503948eba28952009aee28a Mon Sep 17 00:00:00 2001 From: Christoph Neuhauser Date: Fri, 1 Dec 2023 17:50:00 +0100 Subject: [PATCH] Fixed feature map generation. --- .github/workflows/build-brew.yml | 9 +- .github/workflows/build-vcpkg.yml | 13 +- Data/Shaders/VPT/Clouds.glsl | 29 +- Data/Shaders/VPT/DeltaTracking.glsl | 9 + Data/Shaders/VPT/VptHeader.glsl | 21 ++ src/Denoiser/Denoiser.hpp | 36 ++- src/PathTracer/VolumetricPathTracingPass.cpp | 304 ++++++++++++++++-- src/PathTracer/VolumetricPathTracingPass.hpp | 56 +++- src/PyTorch/Module.cpp | 27 +- src/PyTorch/Module.hpp | 2 + .../VolumetricPathTracingModuleRenderer.cpp | 16 +- .../VolumetricPathTracingModuleRenderer.hpp | 1 + vcpkg.json | 6 + 13 files changed, 474 insertions(+), 55 deletions(-) diff --git a/.github/workflows/build-brew.yml b/.github/workflows/build-brew.yml index bd3acec..801df00 100644 --- a/.github/workflows/build-brew.yml +++ b/.github/workflows/build-brew.yml @@ -50,7 +50,14 @@ jobs: fi brew install gcc elif [ "$RUNNER_OS" == "macOS" ]; then - brew install llvm libomp pkg-config + export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 + brew update + #rm /usr/local/bin/2to3 || true + #rm /usr/local/bin/idle3 || true + #rm /usr/local/bin/pydoc3 || true + #rm /usr/local/bin/python3 || true + #rm /usr/local/bin/python3-config || true + brew install --force --overwrite llvm libomp pkg-config else echo "$RUNNER_OS is not supported." exit 1 diff --git a/.github/workflows/build-vcpkg.yml b/.github/workflows/build-vcpkg.yml index 5dbc996..fedf39c 100644 --- a/.github/workflows/build-vcpkg.yml +++ b/.github/workflows/build-vcpkg.yml @@ -101,17 +101,24 @@ jobs: cd ~/VulkanSDK/$VULKAN_SDK_VERSION sudo ./install_vulkan.py || true sudo hdiutil unmount "${vulkan_dir}" - brew install llvm libomp pkg-config + export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 + brew update + #rm /usr/local/bin/2to3 || true + #rm /usr/local/bin/idle3 || true + #rm /usr/local/bin/pydoc3 || true + #rm /usr/local/bin/python3 || true + #rm /usr/local/bin/python3-config || true + brew install --force --overwrite llvm libomp pkg-config else echo "$RUNNER_OS is not supported." exit 1 fi - name: Setup vcpkg - uses: lukka/run-vcpkg@v10 + uses: lukka/run-vcpkg@v11 with: vcpkgGitCommitId: '4cac260c4b7331538d31886f57739fea0bffa27e' - #doNotCacheOnWorkflowFailure: true + doNotCacheOnWorkflowFailure: true - name: Create custom vcpkg triplet run: | diff --git a/Data/Shaders/VPT/Clouds.glsl b/Data/Shaders/VPT/Clouds.glsl index 6c4f7e3..6830f10 100644 --- a/Data/Shaders/VPT/Clouds.glsl +++ b/Data/Shaders/VPT/Clouds.glsl @@ -96,18 +96,21 @@ void pathTraceSample(int i, bool onlyFirstEvent, out ScatterEvent firstEvent){ #endif if (!onlyFirstEvent) { +#ifdef WRITE_CLOUDONLY_MAP // Accumulate cloudOnly vec4 cloudOnlyOld = frame == 0 ? vec4(0) : imageLoad(cloudOnlyImage, imageCoord); vec4 cloudOnly = firstEvent.hasValue ? vec4(result, 1) : vec4(0); cloudOnly = mix(cloudOnlyOld, cloudOnly, 1.0 / float(frame + 1)); imageStore(cloudOnlyImage, imageCoord, cloudOnly); +#endif +#ifdef WRITE_BACKGROUND_MAP // Accumulate background vec4 backgroundOld = frame == 0 ? vec4(0) : imageLoad(backgroundImage, imageCoord); vec4 background = firstEvent.hasValue ? vec4(sampleSkybox(w), 1) : vec4(result, 1); background = mix(backgroundOld, background, 1.0 / float(frame + 1)); imageStore(backgroundImage, imageCoord, background); - +#endif // Accumulate result vec3 resultOld = frame == 0 ? vec3(0) : imageLoad(accImage, imageCoord).xyz; @@ -116,44 +119,62 @@ void pathTraceSample(int i, bool onlyFirstEvent, out ScatterEvent firstEvent){ imageStore(resultImage, imageCoord, vec4(result, 1)); } +#ifdef WRITE_POSITION_MAP vec4 positionOld = frame == 0 ? vec4(0) : imageLoad(firstX, imageCoord); vec4 position = firstEvent.hasValue ? vec4(firstEvent.x, 1) : vec4(0); position = mix(positionOld, position, 1.0 / float(frame + 1)); imageStore(firstX, imageCoord, position); +#endif +#ifdef WRITE_DEPTH_MAP vec2 depthOld = frame == 0 ? vec2(0) : imageLoad(depthImage, imageCoord).xy; depthOld.y = depthOld.y * depthOld.y + depthOld.x * depthOld.x; vec2 depth = firstEvent.hasValue ? vec2(firstEvent.depth, firstEvent.depth * firstEvent.depth) : vec2(0); depth = mix(depthOld, depth, 1.0 / float(frame + 1)); imageStore(depthImage, imageCoord, vec4(depth.x, sqrt(max(0.,depth.y - depth.x * depth.x)),0,0)); +#endif +#ifdef WRITE_DENSITY_MAP vec2 densityOld = frame == 0 ? vec2(0) : imageLoad(densityImage, imageCoord).xy; densityOld.y = densityOld.y * densityOld.y + densityOld.x * densityOld.x; vec2 density = firstEvent.hasValue ? vec2(firstEvent.density * .001, firstEvent.density * firstEvent.density * .001 * .001) : vec2(0); density = mix(densityOld, density, 1.0 / float(frame + 1)); imageStore(densityImage, imageCoord, vec4(density.x, sqrt(max(0.,density.y - density.x * density.x)),0,0)); +#endif +#ifdef WRITE_REPROJ_UV_MAP vec2 oldReprojUV = frame == 0 ? vec2(-1,-1) : imageLoad(reprojUVImage, imageCoord).xy; vec4 prevClip = (parameters.previousViewProjMatrix * vec4(firstEvent.x, 1)); vec2 reprojUV = prevClip.xy / prevClip.w; reprojUV = reprojUV * .5 + .5; - reprojUV = firstEvent.hasValue? reprojUV : oldReprojUV; + reprojUV = firstEvent.hasValue ? reprojUV : oldReprojUV; imageStore(reprojUVImage, imageCoord, vec4(reprojUV, 0, 0)); +#endif // Saving the first scatter position and direction if (firstEvent.hasValue) { - vec3 diff = getCloudFiniteDifference(firstEvent.x); + //imageStore(firstX, imageCoord, vec4(firstEvent.x, firstEvent.pdf_x)); +#ifdef WRITE_NORMAL_MAP + vec3 diff = getCloudFiniteDifference(firstEvent.x); vec3 diffOld = frame == 0 ? vec3(0) : imageLoad(normalImage, imageCoord).xyz; diff = mix(diffOld, diff, 1.0 / float(frame + 1)); imageStore(normalImage, imageCoord, vec4(diff,1)); +#endif - //imageStore(firstX, imageCoord, vec4(firstEvent.x, firstEvent.pdf_x)); +#ifdef WRITE_FIRST_W_MAP imageStore(firstW, imageCoord, vec4(firstEvent.w, firstEvent.pdf_w)); +#endif } else { //imageStore(firstX, imageCoord, vec4(0)); + +#ifdef WRITE_NORMAL_MAP imageStore(normalImage, imageCoord, vec4(0)); +#endif + +#ifdef WRITE_FIRST_W_MAP imageStore(firstW, imageCoord, vec4(0)); +#endif } #ifdef COMPUTE_PRIMARY_RAY_ABSORPTION_MOMENTS diff --git a/Data/Shaders/VPT/DeltaTracking.glsl b/Data/Shaders/VPT/DeltaTracking.glsl index 4ef0052..24460cb 100644 --- a/Data/Shaders/VPT/DeltaTracking.glsl +++ b/Data/Shaders/VPT/DeltaTracking.glsl @@ -281,6 +281,15 @@ vec3 deltaTracking( } if (lastScalarSign != currentScalarSign) { + if (!firstEvent.hasValue) { + firstEvent.x = x; + firstEvent.pdf_x = 0; + firstEvent.w = vec3(0.); + firstEvent.pdf_w = 0; + firstEvent.hasValue = true; + firstEvent.density = parameters.extinction.x; + firstEvent.depth = tMax - d + t; + } refineIsoSurfaceHit(x1, x0, currentScalarSign); x = x1; vec3 color = getIsoSurfaceHit(x, w); diff --git a/Data/Shaders/VPT/VptHeader.glsl b/Data/Shaders/VPT/VptHeader.glsl index 7f3a981..8dd0aeb 100644 --- a/Data/Shaders/VPT/VptHeader.glsl +++ b/Data/Shaders/VPT/VptHeader.glsl @@ -89,9 +89,13 @@ layout (binding = 4) uniform FrameInfo { layout (binding = 5, rgba32f) uniform image2D accImage; +#ifdef WRITE_POSITION_MAP layout (binding = 6, rgba32f) uniform image2D firstX; +#endif +#ifdef WRITE_FIRST_W_MAP layout (binding = 7, rgba32f) uniform image2D firstW; +#endif #if !defined(USE_NANOVDB) && (defined(USE_RESIDUAL_RATIO_TRACKING) || defined(USE_DECOMPOSITION_TRACKING)) layout (binding = 8) uniform sampler3D superVoxelGridImage; @@ -111,12 +115,29 @@ layout (binding = 12, r32f) uniform image2DArray primaryRayAbsorptionMomentsImag layout (binding = 13, r32f) uniform image2DArray scatterRayAbsorptionMomentsImage; #endif +#ifdef WRITE_CLOUDONLY_MAP layout (binding = 14, rgba32f) uniform image2D cloudOnlyImage; +#endif + +#ifdef WRITE_DEPTH_MAP layout (binding = 15, rg32f) uniform image2D depthImage; +#endif + +#ifdef WRITE_DENSITY_MAP layout (binding = 16, rg32f) uniform image2D densityImage; +#endif + +#ifdef WRITE_BACKGROUND_MAP layout (binding = 17, rg32f) uniform image2D backgroundImage; +#endif + +#ifdef WRITE_REPROJ_UV_MAP layout (binding = 18, rg32f) uniform image2D reprojUVImage; +#endif + +#ifdef WRITE_NORMAL_MAP layout (binding = 19, rgba32f) uniform image2D normalImage; +#endif diff --git a/src/Denoiser/Denoiser.hpp b/src/Denoiser/Denoiser.hpp index d4bfcde..b172c7d 100644 --- a/src/Denoiser/Denoiser.hpp +++ b/src/Denoiser/Denoiser.hpp @@ -41,6 +41,7 @@ namespace sgl { class PropertyEditor; } + enum class DenoiserType { NONE, EAW, @@ -62,20 +63,45 @@ const char* const DENOISER_NAMES[] = { #endif }; + +// enum type, name, num channels, num channels padded +#define FEATURE_MAPS \ + FEATURE_MAP(COLOR, "Color", 4, 4) \ + FEATURE_MAP(ALBEDO, "Albedo", 4, 4) \ + FEATURE_MAP(FLOW, "Flow", 2, 2) \ + FEATURE_MAP(POSITION, "Position", 3, 4) \ + FEATURE_MAP(NORMAL, "Normal", 3, 4) \ + FEATURE_MAP(CLOUDONLY, "CloudOnly", 4, 4) \ + FEATURE_MAP(DEPTH, "Depth", 2, 2) \ + FEATURE_MAP(DENSITY, "Density", 2, 2) \ + FEATURE_MAP(BACKGROUND, "Background", 4, 4) \ + FEATURE_MAP(REPROJ_UV, "Reproj_UV", 2, 2) \ + FEATURE_MAP(UNUSED, "Unused", 1, 1) \ + enum class FeatureMapType { - COLOR, ALBEDO, FLOW, POSITION, NORMAL, CLOUDONLY, DEPTH, DENSITY, BACKGROUND, REPROJ_UV +#define FEATURE_MAP(enum_name, _1, _2, _3) enum_name, + FEATURE_MAPS +#undef FEATURE_MAP }; + const char* const FEATURE_MAP_NAMES[] = { - "Color", "Albedo", "Flow", "Position", "Normal", - "CloudOnly", "Depth", "Density", "Background", "Reproj_UV" +#define FEATURE_MAP(_1, string_name, _2, _3) string_name, + FEATURE_MAPS +#undef FEATURE_MAP }; + const uint32_t FEATURE_MAP_NUM_CHANNELS[] = { - 4, 4, 2, 3, 3, 4, 2, 2, 4, 2 +#define FEATURE_MAP(_1, _2, num_channels, _3) num_channels, + FEATURE_MAPS +#undef FEATURE_MAP }; const uint32_t FEATURE_MAP_NUM_CHANNELS_PADDED[] = { - 4, 4, 2, 4, 4, 4, 2, 2, 4, 2 +#define FEATURE_MAP(_1, _2, _3, num_channels_padded) num_channels_padded, + FEATURE_MAPS +#undef FEATURE_MAP }; + class Denoiser { public: virtual ~Denoiser() = default; diff --git a/src/PathTracer/VolumetricPathTracingPass.cpp b/src/PathTracer/VolumetricPathTracingPass.cpp index e133278..2db79f8 100644 --- a/src/PathTracer/VolumetricPathTracingPass.cpp +++ b/src/PathTracer/VolumetricPathTracingPass.cpp @@ -103,6 +103,7 @@ void VolumetricPathTracingPass::createDenoiser() { } if (resultImageTexture) { + checkRecreateFeatureMaps(); setDenoiserFeatureMaps(); if (denoiser) { denoiser->recreateSwapchain(lastViewportWidth, lastViewportHeight); @@ -133,7 +134,7 @@ void VolumetricPathTracingPass::setOutputImage(sgl::vk::ImageViewPtr& imageView) imageSettings.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; accImageTexture = std::make_shared(device, imageSettings, samplerSettings); - firstXTexture = std::make_shared(device, imageSettings, samplerSettings); + /*firstXTexture = std::make_shared(device, imageSettings, samplerSettings); firstWTexture = std::make_shared(device, imageSettings, samplerSettings); normalTexture = std::make_shared(device, imageSettings, samplerSettings); cloudOnlyTexture = std::make_shared(device, imageSettings, samplerSettings); @@ -143,18 +144,33 @@ void VolumetricPathTracingPass::setOutputImage(sgl::vk::ImageViewPtr& imageView) depthTexture = std::make_shared(device, imageSettings, samplerSettings); densityTexture = std::make_shared(device, imageSettings, samplerSettings); reprojUVTexture = std::make_shared(device, imageSettings, samplerSettings); + setDenoiserFeatureMaps();*/ blitResultRenderPass->setInputTexture(resultTexture); blitResultRenderPass->setOutputImage(imageView); blitPrimaryRayMomentTexturePass->setOutputImage(imageView); blitScatterRayMomentTexturePass->setOutputImage(imageView); - setDenoiserFeatureMaps(); frameInfo.frameCount = 0; setDataDirty(); } +void VolumetricPathTracingPass::recreateSwapchain(uint32_t width, uint32_t height) { + lastViewportWidth = width; + lastViewportHeight = height; + + recreateFeatureMaps(); + + blitResultRenderPass->recreateSwapchain(width, height); + blitScatterRayMomentTexturePass->recreateSwapchain(width, height); + blitPrimaryRayMomentTexturePass->recreateSwapchain(width, height); + + if (useDenoiser && denoiser) { + denoiser->recreateSwapchain(width, height); + } +} + void VolumetricPathTracingPass::setDenoiserFeatureMaps() { if (denoiser) { if (denoiser->getUseFeatureMap(FeatureMapType::COLOR)) { @@ -191,7 +207,167 @@ void VolumetricPathTracingPass::setDenoiserFeatureMaps() { } } -void VolumetricPathTracingPass::checkResetDenoiserFeatureMaps() { +void VolumetricPathTracingPass::recreateFeatureMaps() { + sgl::vk::ImageSamplerSettings samplerSettings; + sgl::vk::ImageSettings imageSettings; + imageSettings.width = lastViewportWidth; + imageSettings.height = lastViewportHeight; + + firstXTexture = {}; + if ((denoiser && denoiser->getUseFeatureMap(featureMapCorrespondence.getCorrespondenceDenoiser(FeatureMapTypeVpt::FIRST_X))) + || featureMapType == FeatureMapTypeVpt::FIRST_X || featureMapSet.find(FeatureMapTypeVpt::FIRST_X) != featureMapSet.end()) { + imageSettings.format = VK_FORMAT_R32G32B32A32_SFLOAT; + imageSettings.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + firstXTexture = std::make_shared(device, imageSettings, samplerSettings); + } + + firstWTexture = {}; + if ((denoiser && denoiser->getUseFeatureMap(featureMapCorrespondence.getCorrespondenceDenoiser(FeatureMapTypeVpt::FIRST_W))) + || featureMapType == FeatureMapTypeVpt::FIRST_W || featureMapSet.find(FeatureMapTypeVpt::FIRST_W) != featureMapSet.end()) { + imageSettings.format = VK_FORMAT_R32G32B32A32_SFLOAT; + imageSettings.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + firstWTexture = std::make_shared(device, imageSettings, samplerSettings); + } + + normalTexture = {}; + if ((denoiser && denoiser->getUseFeatureMap(featureMapCorrespondence.getCorrespondenceDenoiser(FeatureMapTypeVpt::NORMAL))) + || featureMapType == FeatureMapTypeVpt::NORMAL || featureMapSet.find(FeatureMapTypeVpt::NORMAL) != featureMapSet.end()) { + imageSettings.format = VK_FORMAT_R32G32B32A32_SFLOAT; + imageSettings.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + normalTexture = std::make_shared(device, imageSettings, samplerSettings); + } + + cloudOnlyTexture = {}; + if ((denoiser && denoiser->getUseFeatureMap(featureMapCorrespondence.getCorrespondenceDenoiser(FeatureMapTypeVpt::CLOUD_ONLY))) + || featureMapType == FeatureMapTypeVpt::CLOUD_ONLY || featureMapSet.find(FeatureMapTypeVpt::CLOUD_ONLY) != featureMapSet.end()) { + imageSettings.format = VK_FORMAT_R32G32B32A32_SFLOAT; + imageSettings.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + cloudOnlyTexture = std::make_shared(device, imageSettings, samplerSettings); + } + + backgroundTexture = {}; + if ((denoiser && denoiser->getUseFeatureMap(featureMapCorrespondence.getCorrespondenceDenoiser(FeatureMapTypeVpt::BACKGROUND))) + || featureMapType == FeatureMapTypeVpt::BACKGROUND || featureMapSet.find(FeatureMapTypeVpt::BACKGROUND) != featureMapSet.end()) { + imageSettings.format = VK_FORMAT_R32G32B32A32_SFLOAT; + imageSettings.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + backgroundTexture = std::make_shared(device, imageSettings, samplerSettings); + } + + depthTexture = {}; + if ((denoiser && denoiser->getUseFeatureMap(featureMapCorrespondence.getCorrespondenceDenoiser(FeatureMapTypeVpt::DEPTH))) + || featureMapType == FeatureMapTypeVpt::DEPTH || featureMapSet.find(FeatureMapTypeVpt::DEPTH) != featureMapSet.end()) { + imageSettings.format = VK_FORMAT_R32G32_SFLOAT; + imageSettings.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + depthTexture = std::make_shared(device, imageSettings, samplerSettings); + } + + densityTexture = {}; + if ((denoiser && denoiser->getUseFeatureMap(featureMapCorrespondence.getCorrespondenceDenoiser(FeatureMapTypeVpt::DENSITY))) + || featureMapType == FeatureMapTypeVpt::DENSITY || featureMapSet.find(FeatureMapTypeVpt::DENSITY) != featureMapSet.end()) { + imageSettings.format = VK_FORMAT_R32G32_SFLOAT; + imageSettings.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + densityTexture = std::make_shared(device, imageSettings, samplerSettings); + } + + reprojUVTexture = {}; + if ((denoiser && denoiser->getUseFeatureMap(featureMapCorrespondence.getCorrespondenceDenoiser(FeatureMapTypeVpt::REPROJ_UV))) + || featureMapType == FeatureMapTypeVpt::REPROJ_UV || featureMapSet.find(FeatureMapTypeVpt::REPROJ_UV) != featureMapSet.end()) { + imageSettings.format = VK_FORMAT_R32G32_SFLOAT; + imageSettings.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + reprojUVTexture = std::make_shared(device, imageSettings, samplerSettings); + } + + /*albedoTexture = {}; + if (denoiser && denoiser->getUseFeatureMap(FeatureMapType::ALBEDO)) { + imageSettings.format = VK_FORMAT_R32G32B32A32_SFLOAT; + imageSettings.usage = + VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT + | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + albedoTexture = std::make_shared(device, imageSettings, samplerSettings); + VkCommandBuffer commandBuffer = device->beginSingleTimeCommands(); + albedoTexture->getImage()->transitionImageLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, commandBuffer); + albedoTexture->getImageView()->clearColor(glm::vec4(1.0f, 1.0f, 1.0f, 1.0f), commandBuffer); + device->endSingleTimeCommands(commandBuffer); + } + + flowMapTexture = {}; + if (denoiser && denoiser->getUseFeatureMap(FeatureMapType::FLOW)) { + imageSettings.format = VK_FORMAT_R32G32_SFLOAT; + imageSettings.usage = + VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT + | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + flowMapTexture = std::make_shared(device, imageSettings, samplerSettings); + }*/ + + setDenoiserFeatureMaps(); +} + +void VolumetricPathTracingPass::checkRecreateFeatureMaps() { + bool useFirstXRenderer = firstXTexture.get() != nullptr; + bool useFirstWRenderer = firstWTexture.get() != nullptr; + bool useNormalRenderer = normalTexture.get() != nullptr; + bool useCloudOnlyRenderer = cloudOnlyTexture.get() != nullptr; + bool useBackgroundRenderer = backgroundTexture.get() != nullptr; + bool useDepthRenderer = depthTexture.get() != nullptr; + bool useDensityRenderer = densityTexture.get() != nullptr; + bool useReprojUVRenderer = reprojUVTexture.get() != nullptr; + //bool useAlbedoRenderer = albedoTexture.get() != nullptr; + //bool useFlowRenderer = flowMapTexture.get() != nullptr; + + bool shallRecreateFeatureMaps = false; + if (denoiser) { + if (useFirstXRenderer != (denoiser->getUseFeatureMap(featureMapCorrespondence.getCorrespondenceDenoiser(FeatureMapTypeVpt::FIRST_X)) + || featureMapType == FeatureMapTypeVpt::FIRST_X || featureMapSet.find(FeatureMapTypeVpt::FIRST_X) != featureMapSet.end()) + || useFirstWRenderer != (denoiser->getUseFeatureMap(featureMapCorrespondence.getCorrespondenceDenoiser(FeatureMapTypeVpt::FIRST_W)) + || featureMapType == FeatureMapTypeVpt::FIRST_W || featureMapSet.find(FeatureMapTypeVpt::FIRST_W) != featureMapSet.end()) + || useNormalRenderer != (denoiser->getUseFeatureMap(featureMapCorrespondence.getCorrespondenceDenoiser(FeatureMapTypeVpt::NORMAL)) + || featureMapType == FeatureMapTypeVpt::NORMAL || featureMapSet.find(FeatureMapTypeVpt::NORMAL) != featureMapSet.end()) + || useCloudOnlyRenderer != (denoiser->getUseFeatureMap(featureMapCorrespondence.getCorrespondenceDenoiser(FeatureMapTypeVpt::CLOUD_ONLY)) + || featureMapType == FeatureMapTypeVpt::CLOUD_ONLY || featureMapSet.find(FeatureMapTypeVpt::CLOUD_ONLY) != featureMapSet.end()) + || useBackgroundRenderer != (denoiser->getUseFeatureMap(featureMapCorrespondence.getCorrespondenceDenoiser(FeatureMapTypeVpt::BACKGROUND)) + || featureMapType == FeatureMapTypeVpt::BACKGROUND || featureMapSet.find(FeatureMapTypeVpt::BACKGROUND) != featureMapSet.end()) + || useDepthRenderer != (denoiser->getUseFeatureMap(featureMapCorrespondence.getCorrespondenceDenoiser(FeatureMapTypeVpt::DEPTH)) + || featureMapType == FeatureMapTypeVpt::DEPTH || featureMapSet.find(FeatureMapTypeVpt::DEPTH) != featureMapSet.end()) + || useDensityRenderer != (denoiser->getUseFeatureMap(featureMapCorrespondence.getCorrespondenceDenoiser(FeatureMapTypeVpt::DENSITY)) + || featureMapType == FeatureMapTypeVpt::DENSITY || featureMapSet.find(FeatureMapTypeVpt::DENSITY) != featureMapSet.end()) + || useReprojUVRenderer != (denoiser->getUseFeatureMap(featureMapCorrespondence.getCorrespondenceDenoiser(FeatureMapTypeVpt::REPROJ_UV)) + || featureMapType == FeatureMapTypeVpt::REPROJ_UV || featureMapSet.find(FeatureMapTypeVpt::REPROJ_UV) != featureMapSet.end())) { + shallRecreateFeatureMaps = true; + } + } else { + if (useFirstXRenderer || useFirstWRenderer || useNormalRenderer + || useCloudOnlyRenderer || useBackgroundRenderer || useDepthRenderer + || useDensityRenderer || useReprojUVRenderer) { + shallRecreateFeatureMaps = true; + } + } + + // Check if inputs should be accumulated. + // TODO + /*if (denoiser) { + if (accumulateInputs != denoiser->getWantsAccumulatedInput()) { + accumulateInputs = denoiser->getWantsAccumulatedInput(); + shallRecreateFeatureMaps = true; + } + useGlobalFrameNumber = denoiser->getWantsGlobalFrameNumber(); + } else { + if (!accumulateInputs) { + accumulateInputs = true; + shallRecreateFeatureMaps = true; + } + useGlobalFrameNumber = false; + }*/ + + if (shallRecreateFeatureMaps) { + setShaderDirty(); + device->waitIdle(); + recreateFeatureMaps(); + //onHasMovedParent(); + changedDenoiserSettings = false; + } +} + +/*void VolumetricPathTracingPass::checkResetDenoiserFeatureMaps() { bool shallResetFeatureMaps = false; if (denoiser) { for (int i = 0; i < IM_ARRAYSIZE(FEATURE_MAP_NAMES); i++) { @@ -205,20 +381,7 @@ void VolumetricPathTracingPass::checkResetDenoiserFeatureMaps() { setDenoiserFeatureMaps(); //changedDenoiserSettings = false; } -} - -void VolumetricPathTracingPass::recreateSwapchain(uint32_t width, uint32_t height) { - lastViewportWidth = width; - lastViewportHeight = height; - - blitResultRenderPass->recreateSwapchain(width, height); - blitScatterRayMomentTexturePass->recreateSwapchain(width, height); - blitPrimaryRayMomentTexturePass->recreateSwapchain(width, height); - - if (useDenoiser && denoiser) { - denoiser->recreateSwapchain(width, height); - } -} +}*/ void VolumetricPathTracingPass::setGridData() { nanoVdbBuffer = {}; @@ -511,6 +674,18 @@ void VolumetricPathTracingPass::setPhaseG(double phaseG){ void VolumetricPathTracingPass::setFeatureMapType(FeatureMapTypeVpt type) { this->featureMapType = type; + if (lastViewportWidth != 0 && lastViewportHeight != 0) { + checkRecreateFeatureMaps(); + } + loadShader(); +} + +void VolumetricPathTracingPass::setUseFeatureMaps(const std::unordered_set& _featureMapSet) { + this->featureMapSet = _featureMapSet; + if (lastViewportWidth != 0 && lastViewportHeight != 0) { + checkRecreateFeatureMaps(); + } + loadShader(); } @@ -682,6 +857,32 @@ void VolumetricPathTracingPass::loadShader() { if (useEmission && (emissionFieldTexture || emissionNanoVdbBuffer)) { customPreprocessorDefines.insert({ "USE_EMISSION", "" }); } + + if (firstXTexture) { + customPreprocessorDefines.insert(std::make_pair("WRITE_POSITION_MAP", "")); + } + if (firstWTexture) { + customPreprocessorDefines.insert(std::make_pair("WRITE_FIRST_W_MAP", "")); + } + if (normalTexture) { + customPreprocessorDefines.insert(std::make_pair("WRITE_NORMAL_MAP", "")); + } + if (cloudOnlyTexture) { + customPreprocessorDefines.insert(std::make_pair("WRITE_CLOUDONLY_MAP", "")); + } + if (depthTexture) { + customPreprocessorDefines.insert(std::make_pair("WRITE_DEPTH_MAP", "")); + } + if (densityTexture) { + customPreprocessorDefines.insert(std::make_pair("WRITE_DENSITY_MAP", "")); + } + if (backgroundTexture) { + customPreprocessorDefines.insert(std::make_pair("WRITE_BACKGROUND_MAP", "")); + } + if (reprojUVTexture) { + customPreprocessorDefines.insert(std::make_pair("WRITE_REPROJ_UV_MAP", "")); + } + if (blitPrimaryRayMomentTexturePass->getMomentType() != BlitMomentTexturePass::MomentType::NONE) { customPreprocessorDefines.insert({ "COMPUTE_PRIMARY_RAY_ABSORPTION_MOMENTS", "" }); customPreprocessorDefines.insert( @@ -778,14 +979,31 @@ void VolumetricPathTracingPass::createComputeData( computeData->setStaticBuffer(uniformBuffer, "Parameters"); computeData->setStaticBuffer(frameInfoBuffer, "FrameInfo"); computeData->setStaticImageView(accImageTexture->getImageView(), "accImage"); - computeData->setStaticImageView(firstXTexture->getImageView(), "firstX"); - computeData->setStaticImageView(firstWTexture->getImageView(), "firstW"); - computeData->setStaticImageView(normalTexture->getImageView(), "normalImage"); - computeData->setStaticImageView(cloudOnlyTexture->getImageView(), "cloudOnlyImage"); - computeData->setStaticImageView(depthTexture->getImageView(), "depthImage"); - computeData->setStaticImageView(densityTexture->getImageView(), "densityImage"); - computeData->setStaticImageView(backgroundTexture->getImageView(), "backgroundImage"); - computeData->setStaticImageView(reprojUVTexture->getImageView(), "reprojUVImage"); + + if (firstXTexture) { + computeData->setStaticImageView(firstXTexture->getImageView(), "firstX"); + } + if (firstWTexture) { + computeData->setStaticImageView(firstWTexture->getImageView(), "firstW"); + } + if (normalTexture) { + computeData->setStaticImageView(normalTexture->getImageView(), "normalImage"); + } + if (cloudOnlyTexture) { + computeData->setStaticImageView(cloudOnlyTexture->getImageView(), "cloudOnlyImage"); + } + if (depthTexture) { + computeData->setStaticImageView(depthTexture->getImageView(), "depthImage"); + } + if (densityTexture) { + computeData->setStaticImageView(densityTexture->getImageView(), "densityImage"); + } + if (backgroundTexture) { + computeData->setStaticImageView(backgroundTexture->getImageView(), "backgroundImage"); + } + if (reprojUVTexture) { + computeData->setStaticImageView(reprojUVTexture->getImageView(), "reprojUVImage"); + } if (useEnvironmentMapImage) { computeData->setStaticTexture(environmentMapTexture, "environmentMapTexture"); @@ -928,14 +1146,30 @@ void VolumetricPathTracingPass::_render() { densityFieldTexture->getImage(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); } renderer->transitionImageLayout(accImageTexture->getImage(), VK_IMAGE_LAYOUT_GENERAL); - renderer->transitionImageLayout(firstXTexture->getImage(), VK_IMAGE_LAYOUT_GENERAL); - renderer->transitionImageLayout(firstWTexture->getImage(), VK_IMAGE_LAYOUT_GENERAL); - renderer->transitionImageLayout(normalTexture->getImage(), VK_IMAGE_LAYOUT_GENERAL); - renderer->transitionImageLayout(cloudOnlyTexture->getImage(), VK_IMAGE_LAYOUT_GENERAL); - renderer->transitionImageLayout(backgroundTexture->getImage(), VK_IMAGE_LAYOUT_GENERAL); - renderer->transitionImageLayout(reprojUVTexture->getImage(), VK_IMAGE_LAYOUT_GENERAL); - renderer->transitionImageLayout(depthTexture->getImage(), VK_IMAGE_LAYOUT_GENERAL); - renderer->transitionImageLayout(densityTexture->getImage(), VK_IMAGE_LAYOUT_GENERAL); + if (firstXTexture) { + renderer->transitionImageLayout(firstXTexture->getImage(), VK_IMAGE_LAYOUT_GENERAL); + } + if (firstWTexture) { + renderer->transitionImageLayout(firstWTexture->getImage(), VK_IMAGE_LAYOUT_GENERAL); + } + if (normalTexture) { + renderer->transitionImageLayout(normalTexture->getImage(), VK_IMAGE_LAYOUT_GENERAL); + } + if (cloudOnlyTexture) { + renderer->transitionImageLayout(cloudOnlyTexture->getImage(), VK_IMAGE_LAYOUT_GENERAL); + } + if (backgroundTexture) { + renderer->transitionImageLayout(backgroundTexture->getImage(), VK_IMAGE_LAYOUT_GENERAL); + } + if (reprojUVTexture) { + renderer->transitionImageLayout(reprojUVTexture->getImage(), VK_IMAGE_LAYOUT_GENERAL); + } + if (depthTexture) { + renderer->transitionImageLayout(depthTexture->getImage(), VK_IMAGE_LAYOUT_GENERAL); + } + if (densityTexture) { + renderer->transitionImageLayout(densityTexture->getImage(), VK_IMAGE_LAYOUT_GENERAL); + } //renderer->transitionImageLayout( // blitPrimaryRayMomentTexturePass->getMomentTexture()->getImage(), VK_IMAGE_LAYOUT_GENERAL); //renderer->transitionImageLayout( @@ -1140,6 +1374,8 @@ bool VolumetricPathTracingPass::renderGuiPropertyEditorNodes(sgl::PropertyEditor if (propertyEditor.addCombo( "Feature Map", (int*)&featureMapType, VPT_FEATURE_MAP_NAMES, IM_ARRAYSIZE(VPT_FEATURE_MAP_NAMES))) { + checkRecreateFeatureMaps(); + loadShader(); optionChanged = true; //blitPrimaryRayMomentTexturePass->setVisualizeMomentTexture( // featureMapType == FeatureMapTypeVpt::PRIMARY_RAY_ABSORPTION_MOMENTS); @@ -1361,7 +1597,7 @@ bool VolumetricPathTracingPass::renderGuiPropertyEditorNodes(sgl::PropertyEditor reRender = denoiserReRender || reRender; changedDenoiserSettings = denoiserReRender || changedDenoiserSettings; if (denoiserReRender) { - checkResetDenoiserFeatureMaps(); + checkRecreateFeatureMaps(); } propertyEditor.endNode(); } diff --git a/src/PathTracer/VolumetricPathTracingPass.hpp b/src/PathTracer/VolumetricPathTracingPass.hpp index f7d27e5..ab2f7de 100644 --- a/src/PathTracer/VolumetricPathTracingPass.hpp +++ b/src/PathTracer/VolumetricPathTracingPass.hpp @@ -25,12 +25,16 @@ #ifndef CLOUDRENDERING_VOLUMETRICPATHTRACINGPASS_HPP #define CLOUDRENDERING_VOLUMETRICPATHTRACINGPASS_HPP +#include + #include #include + #include #include #include #include + #include "Denoiser/Denoiser.hpp" namespace sgl { @@ -59,9 +63,51 @@ const char* const VPT_FEATURE_MAP_NAMES[] = { "Primary Ray Absorption Moments", "Scatter Ray Absorption Moments" }; +struct FeatureMapCorrespondence { +public: + FeatureMapCorrespondence(const std::vector>& correspondences) { + for (const auto& correspondence : correspondences) { + denoiserToVpt.insert(correspondence); + vptToDenoiser.insert(std::make_pair(correspondence.second, correspondence.first)); + } + } + [[nodiscard]] FeatureMapTypeVpt getCorrespondenceVpt(FeatureMapType denoiserType) const { + auto it = denoiserToVpt.find(denoiserType); + if (it == denoiserToVpt.end()) { + return FeatureMapTypeVpt::RESULT; + } + return it->second; + } + [[nodiscard]] FeatureMapType getCorrespondenceDenoiser(FeatureMapTypeVpt vptType) const { + auto it = vptToDenoiser.find(vptType); + if (it == vptToDenoiser.end()) { + return FeatureMapType::COLOR; + } + return it->second; + } + +private: + std::map denoiserToVpt; + std::map vptToDenoiser; +}; + +const FeatureMapCorrespondence featureMapCorrespondence({ + {FeatureMapType::COLOR, FeatureMapTypeVpt::RESULT}, + {FeatureMapType::ALBEDO, FeatureMapTypeVpt::RESULT}, + {FeatureMapType::FLOW, FeatureMapTypeVpt::RESULT}, // TODO + {FeatureMapType::POSITION, FeatureMapTypeVpt::FIRST_X}, + {FeatureMapType::NORMAL, FeatureMapTypeVpt::NORMAL}, + {FeatureMapType::CLOUDONLY, FeatureMapTypeVpt::CLOUD_ONLY}, + {FeatureMapType::DEPTH, FeatureMapTypeVpt::DEPTH}, + {FeatureMapType::DENSITY, FeatureMapTypeVpt::DENSITY}, + {FeatureMapType::BACKGROUND, FeatureMapTypeVpt::BACKGROUND}, + {FeatureMapType::REPROJ_UV, FeatureMapTypeVpt::REPROJ_UV}, +}); + enum class VptMode { DELTA_TRACKING, SPECTRAL_DELTA_TRACKING, RATIO_TRACKING, DECOMPOSITION_TRACKING, RESIDUAL_RATIO_TRACKING, - NEXT_EVENT_TRACKING, NEXT_EVENT_TRACKING_SPECTRAL + NEXT_EVENT_TRACKING, NEXT_EVENT_TRACKING_SPECTRAL, + ISOSURFACE_RENDERING }; const char* const VPT_MODE_NAMES[] = { "Delta Tracking", "Delta Tracking (Spectral)", "Ratio Tracking", @@ -130,6 +176,7 @@ class VolumetricPathTracingPass : public sgl::vk::ComputePass { void setPhaseG(double phaseG); void setExtinctionBase(glm::vec3 extinctionBase); void setFeatureMapType(FeatureMapTypeVpt type); + void setUseFeatureMaps(const std::unordered_set& featureMapSet); void setPreviousViewProjMatrix(glm::mat4 previousViewProjMatrix); void setUseEmission(bool emission); @@ -170,6 +217,7 @@ class VolumetricPathTracingPass : public sgl::vk::ComputePass { CloudDataPtr cloudData; CloudDataPtr emissionData; FeatureMapTypeVpt featureMapType = FeatureMapTypeVpt::RESULT; + std::unordered_set featureMapSet; std::string emissionGridFilenameGui; void updateVptMode(); @@ -196,6 +244,8 @@ class VolumetricPathTracingPass : public sgl::vk::ComputePass { uint32_t lastViewportWidth = 0, lastViewportHeight = 0; + void recreateFeatureMaps(); + void checkRecreateFeatureMaps(); sgl::vk::ImageViewPtr resultImageView; sgl::vk::TexturePtr resultImageTexture; sgl::vk::TexturePtr resultTexture; @@ -207,8 +257,8 @@ class VolumetricPathTracingPass : public sgl::vk::ComputePass { sgl::vk::TexturePtr cloudOnlyTexture; sgl::vk::TexturePtr depthTexture; sgl::vk::TexturePtr densityTexture; - sgl::vk::TexturePtr backgroundTexture; - sgl::vk::TexturePtr reprojUVTexture; + sgl::vk::TexturePtr backgroundTexture; + sgl::vk::TexturePtr reprojUVTexture; std::string getCurrentEventName(); int targetNumSamples = 1024; diff --git a/src/PyTorch/Module.cpp b/src/PyTorch/Module.cpp index 28ffe5b..e146afe 100644 --- a/src/PyTorch/Module.cpp +++ b/src/PyTorch/Module.cpp @@ -72,7 +72,9 @@ TORCH_LIBRARY(vpt, m) { m.def("vpt::set_isosurface_type", setIsosurfaceType); m.def("vpt::set_surface_brdf", setSurfaceBrdf); m.def("vpt::set_seed_offset", setSeedOffset); + m.def("vpt::set_use_feature_maps", setUseFeatureMaps); m.def("vpt::get_feature_map", getFeatureMap); + m.def("vpt::get_feature_map_from_string", getFeatureMapFromString); m.def("vpt::set_phase_g", setPhaseG); m.def("vpt::set_view_projection_matrix_as_previous",setViewProjectionMatrixAsPrevious); m.def("vpt::set_use_emission", setUseEmission); @@ -120,8 +122,31 @@ torch::Tensor renderFrame(torch::Tensor inputTensor, int64_t frameCount) { return {}; } -torch::Tensor getFeatureMap(torch::Tensor inputTensor, int64_t featureMap) { +void setUseFeatureMaps(std::vector featureMapNames) { + std::unordered_set featureMaps; + for (const auto& featureMap : featureMapNames) { + for (int i = 0; i < IM_ARRAYSIZE(VPT_FEATURE_MAP_NAMES); i++) { + if (featureMap == VPT_FEATURE_MAP_NAMES[i]) { + featureMaps.insert(FeatureMapTypeVpt(i)); + break; + } + } + } + vptRenderer->setUseFeatureMaps(featureMaps); +} +torch::Tensor getFeatureMapFromString(torch::Tensor inputTensor, const std::string& featureMap) { + int featureMapIdx = 0; + for (int i = 0; i < IM_ARRAYSIZE(VPT_FEATURE_MAP_NAMES); i++) { + if (featureMap == VPT_FEATURE_MAP_NAMES[i]) { + featureMapIdx = i; + break; + } + } + return getFeatureMap(inputTensor, featureMapIdx); +} + +torch::Tensor getFeatureMap(torch::Tensor inputTensor, int64_t featureMap) { if (inputTensor.sizes().size() != 3) { std::cout << "err" << std::endl; diff --git a/src/PyTorch/Module.hpp b/src/PyTorch/Module.hpp index fb55955..700c389 100644 --- a/src/PyTorch/Module.hpp +++ b/src/PyTorch/Module.hpp @@ -82,6 +82,8 @@ MODULE_OP_API void rememberNextBounds(); MODULE_OP_API void forgetCurrentBounds(); MODULE_OP_API torch::Tensor renderFrame(torch::Tensor inputTensor, int64_t frameCount); +MODULE_OP_API void setUseFeatureMaps(std::vector featureMapNames); +MODULE_OP_API torch::Tensor getFeatureMapFromString(torch::Tensor inputTensor, const std::string& featureMap); MODULE_OP_API torch::Tensor getFeatureMap(torch::Tensor inputTensor, int64_t frameCount); class VolumetricPathTracingModuleRenderer; diff --git a/src/PyTorch/VolumetricPathTracingModuleRenderer.cpp b/src/PyTorch/VolumetricPathTracingModuleRenderer.cpp index 853d21c..fd7792d 100644 --- a/src/PyTorch/VolumetricPathTracingModuleRenderer.cpp +++ b/src/PyTorch/VolumetricPathTracingModuleRenderer.cpp @@ -142,6 +142,10 @@ void VolumetricPathTracingModuleRenderer::setExtinctionBase(glm::vec3 extinction vptPass->setExtinctionBase(extinctionBase); } +void VolumetricPathTracingModuleRenderer::setUseFeatureMaps(const std::unordered_set& featureMapSet) { + vptPass->setUseFeatureMaps(featureMapSet); +} + void VolumetricPathTracingModuleRenderer::setFeatureMapType(FeatureMapTypeVpt type) { vptPass->setFeatureMapType(type); } @@ -519,7 +523,6 @@ float* VolumetricPathTracingModuleRenderer::renderFrameCuda(uint32_t numFrames) #endif float* VolumetricPathTracingModuleRenderer::getFeatureMapCpu(FeatureMapTypeVpt featureMap) { - sgl::vk::TexturePtr texture = vptPass->getFeatureMapTexture(featureMap); renderer->beginCommandBuffer(); @@ -569,11 +572,14 @@ float* VolumetricPathTracingModuleRenderer::getFeatureMapCpu(FeatureMapTypeVpt f float* VolumetricPathTracingModuleRenderer::getFeatureMapCuda(FeatureMapTypeVpt featureMap) { - sgl::vk::TexturePtr texture = vptPass->getFeatureMapTexture(featureMap); cudaStream_t stream = at::cuda::getCurrentCUDAStream(); + // TODO + renderer->getDevice()->waitIdle(); + cudaStreamSynchronize(stream); + timelineValue++; sgl::vk::CommandBufferPtr commandBuffer = commandBuffers.at(0); @@ -620,8 +626,10 @@ float* VolumetricPathTracingModuleRenderer::getFeatureMapCuda(FeatureMapTypeVpt renderFinishedSemaphore->waitSemaphoreCuda(stream); #endif - //renderer->getDevice()->waitIdle(); - //cudaStreamSynchronize(stream); + // TODO + cudaStreamSynchronize(stream); + renderer->getDevice()->waitIdle(); + return (float*)outputImageBufferCu->getCudaDevicePtr(); } \ No newline at end of file diff --git a/src/PyTorch/VolumetricPathTracingModuleRenderer.hpp b/src/PyTorch/VolumetricPathTracingModuleRenderer.hpp index 092dcc8..ecddeb5 100644 --- a/src/PyTorch/VolumetricPathTracingModuleRenderer.hpp +++ b/src/PyTorch/VolumetricPathTracingModuleRenderer.hpp @@ -68,6 +68,7 @@ class VolumetricPathTracingModuleRenderer { void setExtinctionScale(double extinctionScale); void setExtinctionBase(glm::vec3 extinctionBase); void setPhaseG(double phaseG); + void setUseFeatureMaps(const std::unordered_set& featureMapSet); void setFeatureMapType(FeatureMapTypeVpt type); void setEmissionCap(double emissionCap); diff --git a/vcpkg.json b/vcpkg.json index b56acca..fcbee9e 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -10,6 +10,12 @@ "name": "boost-interprocess", "platform": "windows" }, + { + "name": "dbus", + "default-features": false, + "features": [], + "platform": "linux" + }, { "name": "sdl2", "features": [ "vulkan", "x11", "wayland" ],