mirror of
https://github.com/Awakenchan/LanternEngine.git
synced 2026-11-10 09:21:42 -10:00
Problem: the previous commit made the volumetric sunlight fog skip the game's default white lighting record and fade between colors. That fixed the flicker in game, but there was no way to get the original behaviour back, for example to compare the two or if the new color looks wrong somewhere. What changed (volumetric_light.comp, vk_volumetric_light.cpp, EngineSwitches.cs): - New switch "Steady sunlight color" under Engine > Graphics, on by default. It sets the environment variable BB_VOLUMETRIC_STEADY, which is on unless its value starts with 0 (the same rule as LANTERN_JOB_SLOTS). It is not in lantern.ini, the Looks or the effect list, and it never greys out. - On: exactly the behaviour of the previous commit. - Off: the tint pass no longer skips the white default record, so it competes like any other record, and the color is set at once with no fade. This is the color the fog had before the previous commit, including the flip to white and back. - The tint pass's push constants grow from 12 to 16 bytes (a new skip flag) and the shader reads it. - The first volumetric log line is followed by one line saying whether the steady color is on or off. Effect: nothing changes unless the switch is turned off. Not run in game. Tests: volumetric-tint-test (new off-mode cases: the white record wins, the color changes at once with blend 1), effect-pipelines-test (tint push constant size now 16; 15 built, 0 validation messages), point-volumetric-test and settings-test pass. The graphics library compiles. Both launchers build and LooksChecks passes, including new checks that the switch is in Graphics, on by default, and not used by any Look knob or effect row. LocalizationChecks fails on "Seamless co-op" missing from zh-CN, which main also lacks and this change does not touch.
214 lines
9.7 KiB
C++
214 lines
9.7 KiB
C++
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
#include <array>
|
|
#include <cassert>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <initializer_list>
|
|
#include <span>
|
|
#include <vector>
|
|
#define VULKAN_HPP_NO_CONSTRUCTORS
|
|
#define VULKAN_HPP_NO_EXCEPTIONS
|
|
#define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1
|
|
#include <vulkan/vulkan.hpp>
|
|
#include "video_core/host_shaders/contact_shadow_comp.h"
|
|
#include "video_core/host_shaders/gtao_frag.h"
|
|
#include "video_core/host_shaders/native_motion_blur_frag.h"
|
|
#include "video_core/host_shaders/point_shadow_comp.h"
|
|
#include "video_core/host_shaders/point_volumetric_comp.h"
|
|
#include "video_core/host_shaders/ssgi_composite_comp.h"
|
|
#include "video_core/host_shaders/ssgi_denoise_comp.h"
|
|
#include "video_core/host_shaders/ssgi_gather_comp.h"
|
|
#include "video_core/host_shaders/ssgi_prep_comp.h"
|
|
#include "video_core/host_shaders/ssr_frag.h"
|
|
#include "video_core/host_shaders/ssr_temporal_copy_comp.h"
|
|
#include "video_core/host_shaders/ssr_temporal_resolve_comp.h"
|
|
#include "video_core/host_shaders/ssr_trace_comp.h"
|
|
#include "video_core/host_shaders/volumetric_light_composite_comp.h"
|
|
#include "video_core/host_shaders/volumetric_light_filter_comp.h"
|
|
#include "video_core/host_shaders/volumetric_light_integrate_comp.h"
|
|
#include "video_core/host_shaders/volumetric_light_repair_comp.h"
|
|
#include "video_core/host_shaders/volumetric_light_tint_comp.h"
|
|
|
|
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
|
|
|
using u32 = uint32_t;
|
|
|
|
namespace {
|
|
u32 messages = 0;
|
|
|
|
VKAPI_ATTR VkBool32 VKAPI_CALL Message(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
|
|
VkDebugUtilsMessageTypeFlagsEXT,
|
|
const VkDebugUtilsMessengerCallbackDataEXT* data, void*) {
|
|
if (severity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) {
|
|
++messages;
|
|
std::printf("%s\n", data->pMessage);
|
|
}
|
|
return VK_FALSE;
|
|
}
|
|
|
|
struct Pass {
|
|
const char* name;
|
|
std::span<const u32> code;
|
|
std::vector<vk::DescriptorType> types;
|
|
u32 push;
|
|
};
|
|
}
|
|
|
|
int main() {
|
|
static vk::detail::DynamicLoader loader;
|
|
VULKAN_HPP_DEFAULT_DISPATCHER.init(
|
|
loader.getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr"));
|
|
const vk::ApplicationInfo app{.pApplicationName = "effect-pipelines-test",
|
|
.apiVersion = VK_API_VERSION_1_3};
|
|
const char* debug_utils = VK_EXT_DEBUG_UTILS_EXTENSION_NAME;
|
|
auto instance = vk::createInstanceUnique({.pApplicationInfo = &app,
|
|
.enabledExtensionCount = 1,
|
|
.ppEnabledExtensionNames = &debug_utils})
|
|
.value;
|
|
VULKAN_HPP_DEFAULT_DISPATCHER.init(*instance);
|
|
auto messenger =
|
|
instance
|
|
->createDebugUtilsMessengerEXTUnique(
|
|
{.messageSeverity = vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning |
|
|
vk::DebugUtilsMessageSeverityFlagBitsEXT::eError,
|
|
.messageType = vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation |
|
|
vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral,
|
|
.pfnUserCallback =
|
|
reinterpret_cast<vk::PFN_DebugUtilsMessengerCallbackEXT>(Message)})
|
|
.value;
|
|
const auto gpus = instance->enumeratePhysicalDevices().value;
|
|
assert(!gpus.empty());
|
|
const auto physical = gpus[0];
|
|
std::printf("device: %s\n", physical.getProperties().deviceName.data());
|
|
const auto supported = physical.getFeatures();
|
|
const float priority = 1;
|
|
const vk::DeviceQueueCreateInfo queue{.queueFamilyIndex = 0,
|
|
.queueCount = 1,
|
|
.pQueuePriorities = &priority};
|
|
const char* extension = VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME;
|
|
const vk::PhysicalDeviceFeatures features{
|
|
.shaderStorageImageExtendedFormats = supported.shaderStorageImageExtendedFormats};
|
|
vk::PhysicalDeviceVulkan12Features v12{.scalarBlockLayout = true,
|
|
.uniformBufferStandardLayout = true};
|
|
auto owned = physical
|
|
.createDeviceUnique({.pNext = &v12,
|
|
.queueCreateInfoCount = 1,
|
|
.pQueueCreateInfos = &queue,
|
|
.enabledExtensionCount = 1,
|
|
.ppEnabledExtensionNames = &extension,
|
|
.pEnabledFeatures = &features})
|
|
.value;
|
|
const auto device = *owned;
|
|
VULKAN_HPP_DEFAULT_DISPATCHER.init(device);
|
|
|
|
using enum vk::DescriptorType;
|
|
const std::vector<Pass> passes = {
|
|
{"ssgi prep", SSGI_PREP_COMP, {eSampledImage, eStorageImage, eSampledImage}, 128},
|
|
{"ssgi gather",
|
|
SSGI_GATHER_COMP,
|
|
{eSampledImage, eSampledImage, eSampledImage, eStorageImage, eSampledImage},
|
|
128},
|
|
{"ssgi denoise", SSGI_DENOISE_COMP, {eSampledImage, eSampledImage, eStorageImage}, 128},
|
|
{"ssgi composite",
|
|
SSGI_COMPOSITE_COMP,
|
|
{eSampledImage, eSampledImage, eStorageImage, eSampledImage, eSampledImage},
|
|
128},
|
|
{"ssr resolve",
|
|
SSR_TEMPORAL_RESOLVE_COMP,
|
|
{eSampledImage, eSampledImage, eSampledImage, eStorageImage},
|
|
128},
|
|
{"ssr copy", SSR_TEMPORAL_COPY_COMP, {eSampledImage, eStorageImage}, 128},
|
|
{"ssr trace",
|
|
SSR_TRACE_COMP,
|
|
{eUniformBuffer, eCombinedImageSampler, eCombinedImageSampler, eCombinedImageSampler,
|
|
eStorageImage},
|
|
16},
|
|
{"contact shadows",
|
|
CONTACT_SHADOW_COMP,
|
|
{eStorageBuffer, eCombinedImageSampler, eStorageImage, eCombinedImageSampler,
|
|
eStorageBuffer},
|
|
68},
|
|
{"point shadows",
|
|
POINT_SHADOW_COMP,
|
|
{eStorageBuffer, eCombinedImageSampler, eStorageImage, eStorageImage, eStorageImage,
|
|
eStorageImage},
|
|
64},
|
|
{"volumetric integrate",
|
|
VOLUMETRIC_LIGHT_INTEGRATE_COMP,
|
|
{eStorageBuffer, eStorageBuffer, eCombinedImageSampler, eCombinedImageSampler,
|
|
eStorageImage, eStorageImage},
|
|
32},
|
|
{"volumetric repair",
|
|
VOLUMETRIC_LIGHT_REPAIR_COMP,
|
|
{eStorageBuffer, eStorageBuffer, eCombinedImageSampler, eCombinedImageSampler,
|
|
eStorageImage, eStorageImage, eStorageImage},
|
|
32},
|
|
{"volumetric tint",
|
|
VOLUMETRIC_LIGHT_TINT_COMP,
|
|
{eStorageBuffer, eStorageBuffer},
|
|
16},
|
|
{"volumetric filter",
|
|
VOLUMETRIC_LIGHT_FILTER_COMP,
|
|
{eCombinedImageSampler, eStorageImage},
|
|
4},
|
|
{"volumetric composite",
|
|
VOLUMETRIC_LIGHT_COMPOSITE_COMP,
|
|
{eCombinedImageSampler, eCombinedImageSampler, eStorageImage, eStorageBuffer,
|
|
eCombinedImageSampler, eCombinedImageSampler},
|
|
4},
|
|
{"point volumetric",
|
|
POINT_VOLUMETRIC_COMP,
|
|
{eStorageBuffer, eStorageBuffer, eCombinedImageSampler, eStorageImage},
|
|
8},
|
|
};
|
|
u32 built = 0;
|
|
for (const Pass& pass : passes) {
|
|
std::vector<vk::DescriptorSetLayoutBinding> bindings;
|
|
for (const auto type : pass.types) {
|
|
bindings.push_back({.binding = u32(bindings.size()),
|
|
.descriptorType = type,
|
|
.descriptorCount = 1,
|
|
.stageFlags = vk::ShaderStageFlagBits::eCompute});
|
|
}
|
|
auto set = device
|
|
.createDescriptorSetLayoutUnique(
|
|
{.flags = vk::DescriptorSetLayoutCreateFlagBits::ePushDescriptorKHR,
|
|
.bindingCount = u32(bindings.size()),
|
|
.pBindings = bindings.data()})
|
|
.value;
|
|
const vk::PushConstantRange push{.stageFlags = vk::ShaderStageFlagBits::eCompute,
|
|
.offset = 0,
|
|
.size = pass.push};
|
|
auto layout = device
|
|
.createPipelineLayoutUnique({.setLayoutCount = 1,
|
|
.pSetLayouts = &*set,
|
|
.pushConstantRangeCount = 1,
|
|
.pPushConstantRanges = &push})
|
|
.value;
|
|
auto module = device
|
|
.createShaderModuleUnique({.codeSize = pass.code.size_bytes(),
|
|
.pCode = pass.code.data()})
|
|
.value;
|
|
auto pipeline = device.createComputePipelineUnique(
|
|
{}, vk::ComputePipelineCreateInfo{.flags = vk::PipelineCreateFlagBits::eDispatchBase,
|
|
.stage = {.stage = vk::ShaderStageFlagBits::eCompute,
|
|
.module = *module,
|
|
.pName = "main"},
|
|
.layout = *layout});
|
|
if (pipeline.result != vk::Result::eSuccess) {
|
|
std::printf("%s: %s\n", pass.name, vk::to_string(pipeline.result).c_str());
|
|
return 1;
|
|
}
|
|
++built;
|
|
}
|
|
for (const auto code : {std::span<const u32>(GTAO_FRAG), std::span<const u32>(SSR_FRAG),
|
|
std::span<const u32>(NATIVE_MOTION_BLUR_FRAG)}) {
|
|
auto module = device.createShaderModuleUnique(
|
|
{.codeSize = code.size_bytes(), .pCode = code.data()});
|
|
assert(module.result == vk::Result::eSuccess);
|
|
}
|
|
std::printf("effect pipelines: %u built, %u validation messages\n", built, messages);
|
|
return messages == 0 ? 0 : 1;
|
|
}
|