Skip to content
Snippets Groups Projects

Resolve "Indirect Dispatch"

Merged Ghost User requested to merge 106-indirect-dispatch into develop
2 files
+ 8
1
Compare changes
  • Side-by-side
  • Inline
Files
2
  • e537a34e
    [#106] Switch motion vector visualisation sampler from linear to nearest · e537a34e
    Alexander Gauggel authored
+ 369
0
#include "App.hpp"
#include "AppConfig.hpp"
#include <chrono>
#include <vkcv/gui/GUI.hpp>
#include <functional>
App::App() :
m_applicationName("Indirect Dispatch"),
m_windowWidth(AppConfig::defaultWindowWidth),
m_windowHeight(AppConfig::defaultWindowHeight),
m_window(vkcv::Window::create(
m_applicationName,
m_windowWidth,
m_windowHeight,
true)),
m_core(vkcv::Core::create(
m_window,
m_applicationName,
VK_MAKE_VERSION(0, 0, 1),
{ vk::QueueFlagBits::eGraphics ,vk::QueueFlagBits::eCompute , vk::QueueFlagBits::eTransfer },
{},
{ "VK_KHR_swapchain" })),
m_cameraManager(m_window){}
bool App::initialize() {
if (!loadMeshPass(m_core, &m_meshPass))
return false;
if (!loadSkyPass(m_core, &m_skyPass))
return false;
if (!loadPrePass(m_core, &m_prePass))
return false;
if (!loadSkyPrePass(m_core, &m_skyPrePass))
return false;
if (!loadComputePass(m_core, "resources/shaders/gammaCorrection.comp", &m_gammaCorrectionPass))
return false;
if (!loadMesh(m_core, "resources/models/cube.gltf", &m_cubeMesh))
return false;
if (!loadMesh(m_core, "resources/models/ground.gltf", &m_groundMesh))
return false;
if(!loadImage(m_core, "resources/models/grid.png", &m_gridTexture))
return false;
if (!m_motionBlur.initialize(&m_core, m_windowWidth, m_windowHeight))
return false;
m_linearSampler = m_core.createSampler(
vkcv::SamplerFilterType::LINEAR,
vkcv::SamplerFilterType::LINEAR,
vkcv::SamplerMipmapMode::LINEAR,
vkcv::SamplerAddressMode::CLAMP_TO_EDGE);
m_renderTargets = createRenderTargets(m_core, m_windowWidth, m_windowHeight);
const int cameraIndex = m_cameraManager.addCamera(vkcv::camera::ControllerType::PILOT);
m_cameraManager.getCamera(cameraIndex).setPosition(glm::vec3(0, 1, -3));
m_cameraManager.getCamera(cameraIndex).setNearFar(0.1f, 30.f);
vkcv::DescriptorWrites meshPassDescriptorWrites;
meshPassDescriptorWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(0, m_gridTexture) };
meshPassDescriptorWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(1, m_linearSampler) };
m_core.writeDescriptorSet(m_meshPass.descriptorSet, meshPassDescriptorWrites);
return true;
}
void App::run() {
auto frameStartTime = std::chrono::system_clock::now();
const auto appStartTime = std::chrono::system_clock::now();
const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle();
const vkcv::DrawcallInfo skyDrawcall(m_cubeMesh.mesh, {}, 1);
vkcv::gui::GUI gui(m_core, m_window);
eMotionVectorVisualisationMode motionVectorVisualisationMode = eMotionVectorVisualisationMode::None;
eMotionBlurMode motionBlurMode = eMotionBlurMode::Default;
bool freezeFrame = false;
float motionBlurTileOffsetLength = 3;
float objectVerticalSpeed = 5;
float objectAmplitude = 0;
float objectMeanHeight = 1;
float objectRotationSpeedX = 5;
float objectRotationSpeedY = 5;
int cameraShutterSpeedInverse = 24;
float motionVectorVisualisationRange = 0.008;
float motionBlurFastPathThreshold = 1;
glm::mat4 viewProjection = m_cameraManager.getActiveCamera().getMVP();
glm::mat4 viewProjectionPrevious = m_cameraManager.getActiveCamera().getMVP();
struct Object {
MeshResources meshResources;
glm::mat4 modelMatrix = glm::mat4(1.f);
glm::mat4 mvp = glm::mat4(1.f);
glm::mat4 mvpPrevious = glm::mat4(1.f);
std::function<void(float, Object&)> modelMatrixUpdate;
};
std::vector<Object> sceneObjects;
Object ground;
ground.meshResources = m_groundMesh;
sceneObjects.push_back(ground);
Object sphere;
sphere.meshResources = m_cubeMesh;
sphere.modelMatrixUpdate = [&](float time, Object& obj) {
const float currentHeight = objectMeanHeight + objectAmplitude * glm::sin(time * objectVerticalSpeed);
const glm::mat4 translation = glm::translate(glm::mat4(1), glm::vec3(0, currentHeight, 0));
const glm::mat4 rotationX = glm::rotate(glm::mat4(1), objectRotationSpeedX * time, glm::vec3(1, 0, 0));
const glm::mat4 rotationY = glm::rotate(glm::mat4(1), objectRotationSpeedY * time, glm::vec3(0, 1, 0));
obj.modelMatrix = translation * rotationX * rotationY;
};
sceneObjects.push_back(sphere);
bool spaceWasPressed = false;
m_window.e_key.add([&](int key, int scancode, int action, int mods) {
if (key == GLFW_KEY_SPACE) {
if (action == GLFW_PRESS) {
if (!spaceWasPressed) {
freezeFrame = !freezeFrame;
}
spaceWasPressed = true;
}
else if (action == GLFW_RELEASE) {
spaceWasPressed = false;
}
}
});
auto frameEndTime = std::chrono::system_clock::now();
while (m_window.isWindowOpen()) {
vkcv::Window::pollEvents();
if (!freezeFrame) {
frameStartTime = frameEndTime;
viewProjectionPrevious = viewProjection;
for (Object& obj : sceneObjects) {
obj.mvpPrevious = obj.mvp;
}
}
if (m_window.getHeight() == 0 || m_window.getWidth() == 0)
continue;
uint32_t swapchainWidth, swapchainHeight;
if (!m_core.beginFrame(swapchainWidth, swapchainHeight))
continue;
const bool hasResolutionChanged = (swapchainWidth != m_windowWidth) || (swapchainHeight != m_windowHeight);
if (hasResolutionChanged) {
m_windowWidth = swapchainWidth;
m_windowHeight = swapchainHeight;
m_renderTargets = createRenderTargets(m_core, m_windowWidth, m_windowHeight);
m_motionBlur.setResolution(m_windowWidth, m_windowHeight);
}
if(!freezeFrame)
frameEndTime = std::chrono::system_clock::now();
const float microsecondToSecond = 0.000001;
const float fDeltaTimeSeconds = microsecondToSecond * std::chrono::duration_cast<std::chrono::microseconds>(frameEndTime - frameStartTime).count();
m_cameraManager.update(fDeltaTimeSeconds);
const auto time = frameEndTime - appStartTime;
const float fCurrentTime = std::chrono::duration_cast<std::chrono::milliseconds>(time).count() * 0.001f;
// update matrices
if (!freezeFrame) {
viewProjection = m_cameraManager.getActiveCamera().getMVP();
for (Object& obj : sceneObjects) {
if (obj.modelMatrixUpdate) {
obj.modelMatrixUpdate(fCurrentTime, obj);
}
obj.mvp = viewProjection * obj.modelMatrix;
}
}
const vkcv::CommandStreamHandle cmdStream = m_core.createCommandStream(vkcv::QueueType::Graphics);
// prepass
vkcv::PushConstants prepassPushConstants(sizeof(glm::mat4) * 2);
for (const Object& obj : sceneObjects) {
glm::mat4 prepassMatrices[2] = { obj.mvp, obj.mvpPrevious };
prepassPushConstants.appendDrawcall(prepassMatrices);
}
const std::vector<vkcv::ImageHandle> prepassRenderTargets = {
m_renderTargets.motionBuffer,
m_renderTargets.depthBuffer };
std::vector<vkcv::DrawcallInfo> prepassSceneDrawcalls;
for (const Object& obj : sceneObjects) {
prepassSceneDrawcalls.push_back(vkcv::DrawcallInfo(obj.meshResources.mesh, {}));
}
m_core.recordDrawcallsToCmdStream(
cmdStream,
m_prePass.renderPass,
m_prePass.pipeline,
prepassPushConstants,
prepassSceneDrawcalls,
prepassRenderTargets);
// sky prepass
glm::mat4 skyPrepassMatrices[2] = {
viewProjection,
viewProjectionPrevious };
vkcv::PushConstants skyPrepassPushConstants(sizeof(glm::mat4) * 2);
skyPrepassPushConstants.appendDrawcall(skyPrepassMatrices);
m_core.recordDrawcallsToCmdStream(
cmdStream,
m_skyPrePass.renderPass,
m_skyPrePass.pipeline,
skyPrepassPushConstants,
{ skyDrawcall },
prepassRenderTargets);
// main pass
const std::vector<vkcv::ImageHandle> renderTargets = {
m_renderTargets.colorBuffer,
m_renderTargets.depthBuffer };
vkcv::PushConstants meshPushConstants(2 * sizeof(glm::mat4));
for (const Object& obj : sceneObjects) {
glm::mat4 matrices[2] = { obj.mvp, obj.modelMatrix };
meshPushConstants.appendDrawcall(matrices);
}
std::vector<vkcv::DrawcallInfo> forwardSceneDrawcalls;
for (const Object& obj : sceneObjects) {
forwardSceneDrawcalls.push_back(vkcv::DrawcallInfo(
obj.meshResources.mesh,
{ vkcv::DescriptorSetUsage(0, m_core.getDescriptorSet(m_meshPass.descriptorSet).vulkanHandle) }));
}
m_core.recordDrawcallsToCmdStream(
cmdStream,
m_meshPass.renderPass,
m_meshPass.pipeline,
meshPushConstants,
forwardSceneDrawcalls,
renderTargets);
// sky
vkcv::PushConstants skyPushConstants(sizeof(glm::mat4));
skyPushConstants.appendDrawcall(viewProjection);
m_core.recordDrawcallsToCmdStream(
cmdStream,
m_skyPass.renderPass,
m_skyPass.pipeline,
skyPushConstants,
{ skyDrawcall },
renderTargets);
// motion blur
vkcv::ImageHandle motionBlurOutput;
if (motionVectorVisualisationMode == eMotionVectorVisualisationMode::None) {
float cameraNear;
float cameraFar;
m_cameraManager.getActiveCamera().getNearFar(cameraNear, cameraFar);
motionBlurOutput = m_motionBlur.render(
cmdStream,
m_renderTargets.motionBuffer,
m_renderTargets.colorBuffer,
m_renderTargets.depthBuffer,
motionBlurMode,
cameraNear,
cameraFar,
fDeltaTimeSeconds,
cameraShutterSpeedInverse,
motionBlurTileOffsetLength,
motionBlurFastPathThreshold);
}
else {
motionBlurOutput = m_motionBlur.renderMotionVectorVisualisation(
cmdStream,
m_renderTargets.motionBuffer,
motionVectorVisualisationMode,
motionVectorVisualisationRange);
}
// gamma correction
vkcv::DescriptorWrites gammaCorrectionDescriptorWrites;
gammaCorrectionDescriptorWrites.sampledImageWrites = {
vkcv::SampledImageDescriptorWrite(0, motionBlurOutput) };
gammaCorrectionDescriptorWrites.samplerWrites = {
vkcv::SamplerDescriptorWrite(1, m_linearSampler) };
gammaCorrectionDescriptorWrites.storageImageWrites = {
vkcv::StorageImageDescriptorWrite(2, swapchainInput) };
m_core.writeDescriptorSet(m_gammaCorrectionPass.descriptorSet, gammaCorrectionDescriptorWrites);
m_core.prepareImageForSampling(cmdStream, motionBlurOutput);
m_core.prepareImageForStorage (cmdStream, swapchainInput);
const uint32_t fullScreenImageDispatch[3] = {
static_cast<uint32_t>((m_windowWidth + 7) / 8),
static_cast<uint32_t>((m_windowHeight + 7) / 8),
static_cast<uint32_t>(1) };
m_core.recordComputeDispatchToCmdStream(
cmdStream,
m_gammaCorrectionPass.pipeline,
fullScreenImageDispatch,
{ vkcv::DescriptorSetUsage(0, m_core.getDescriptorSet(m_gammaCorrectionPass.descriptorSet).vulkanHandle) },
vkcv::PushConstants(0));
m_core.prepareSwapchainImageForPresent(cmdStream);
m_core.submitCommandStream(cmdStream);
gui.beginGUI();
ImGui::Begin("Settings");
ImGui::Checkbox("Freeze frame", &freezeFrame);
ImGui::InputFloat("Motion tile offset length", &motionBlurTileOffsetLength);
ImGui::InputFloat("Motion blur fast path threshold", &motionBlurFastPathThreshold);
ImGui::Combo(
"Motion blur mode",
reinterpret_cast<int*>(&motionBlurMode),
MotionBlurModeLabels,
static_cast<int>(eMotionBlurMode::OptionCount));
ImGui::Combo(
"Debug view",
reinterpret_cast<int*>(&motionVectorVisualisationMode),
MotionVectorVisualisationModeLabels,
static_cast<int>(eMotionVectorVisualisationMode::OptionCount));
if (motionVectorVisualisationMode != eMotionVectorVisualisationMode::None)
ImGui::InputFloat("Motion vector visualisation range", &motionVectorVisualisationRange);
ImGui::InputInt("Camera shutter speed inverse", &cameraShutterSpeedInverse);
ImGui::InputFloat("Object movement speed", &objectVerticalSpeed);
ImGui::InputFloat("Object movement amplitude", &objectAmplitude);
ImGui::InputFloat("Object mean height", &objectMeanHeight);
ImGui::InputFloat("Object rotation speed X", &objectRotationSpeedX);
ImGui::InputFloat("Object rotation speed Y", &objectRotationSpeedY);
ImGui::End();
gui.endGUI();
m_core.endFrame();
}
}
\ No newline at end of file
Loading