Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • vulkan2021/vkcv-framework
1 result
Select Git revision
Show changes
Showing
with 1597 additions and 533 deletions
#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_GOOGLE_include_directive : enable
#include "common.inc"
layout(location = 0) in vec3 inPosition;
layout(location = 1) in vec3 inNormal;
layout(location = 0) out vec3 passNormal;
layout(location = 1) out uint dummyOutput;
layout(std430, binding = 0) readonly buffer matrixBuffer
{
ObjectMatrices objectMatrices[];
};
layout( push_constant ) uniform constants{
uint matrixIndex;
uint padding; // pad to same size as mesh shader constants
};
void main() {
gl_Position = objectMatrices[matrixIndex].mvp * vec4(inPosition, 1.0);
passNormal = inNormal;
dummyOutput = padding * 0; // padding must be used, else compiler shrinks constant size
}
\ No newline at end of file
#include <iostream>
#include <vkcv/Core.hpp>
#include <GLFW/glfw3.h>
#include <vkcv/camera/CameraManager.hpp>
#include <chrono>
#include <vkcv/shader/GLSLCompiler.hpp>
#include <vkcv/gui/GUI.hpp>
#include <vkcv/asset/asset_loader.hpp>
#include <vkcv/meshlet/Meshlet.hpp>
#include <vkcv/meshlet/Tipsify.hpp>
#include <vkcv/meshlet/Forsyth.hpp>
struct Plane {
glm::vec3 pointOnPlane;
float padding0;
glm::vec3 normal;
float padding1;
};
struct CameraPlanes {
Plane planes[6];
};
CameraPlanes computeCameraPlanes(const vkcv::camera::Camera& camera) {
const float fov = camera.getFov();
const glm::vec3 pos = camera.getPosition();
const float ratio = camera.getRatio();
const glm::vec3 forward = glm::normalize(camera.getFront());
float near;
float far;
camera.getNearFar(near, far);
glm::vec3 up = glm::vec3(0, -1, 0);
glm::vec3 right = glm::normalize(glm::cross(forward, up));
up = glm::cross(forward, right);
const glm::vec3 nearCenter = pos + forward * near;
const glm::vec3 farCenter = pos + forward * far;
const float tanFovHalf = glm::tan(fov / 2);
const glm::vec3 nearUpCenter = nearCenter + up * tanFovHalf * near;
const glm::vec3 nearDownCenter = nearCenter - up * tanFovHalf * near;
const glm::vec3 nearRightCenter = nearCenter + right * tanFovHalf * near * ratio;
const glm::vec3 nearLeftCenter = nearCenter - right * tanFovHalf * near * ratio;
const glm::vec3 farUpCenter = farCenter + up * tanFovHalf * far;
const glm::vec3 farDownCenter = farCenter - up * tanFovHalf * far;
const glm::vec3 farRightCenter = farCenter + right * tanFovHalf * far * ratio;
const glm::vec3 farLeftCenter = farCenter - right * tanFovHalf * far * ratio;
CameraPlanes cameraPlanes;
// near
cameraPlanes.planes[0].pointOnPlane = nearCenter;
cameraPlanes.planes[0].normal = -forward;
// far
cameraPlanes.planes[1].pointOnPlane = farCenter;
cameraPlanes.planes[1].normal = forward;
// top
cameraPlanes.planes[2].pointOnPlane = nearUpCenter;
cameraPlanes.planes[2].normal = glm::normalize(glm::cross(farUpCenter - nearUpCenter, right));
// bot
cameraPlanes.planes[3].pointOnPlane = nearDownCenter;
cameraPlanes.planes[3].normal = glm::normalize(glm::cross(right, farDownCenter - nearDownCenter));
// right
cameraPlanes.planes[4].pointOnPlane = nearRightCenter;
cameraPlanes.planes[4].normal = glm::normalize(glm::cross(up, farRightCenter - nearRightCenter));
// left
cameraPlanes.planes[5].pointOnPlane = nearLeftCenter;
cameraPlanes.planes[5].normal = glm::normalize(glm::cross(farLeftCenter - nearLeftCenter, up));
return cameraPlanes;
}
int main(int argc, const char** argv) {
const char* applicationName = "Mesh shader";
const int windowWidth = 1280;
const int windowHeight = 720;
vkcv::Window window = vkcv::Window::create(
applicationName,
windowWidth,
windowHeight,
false
);
vkcv::Core core = vkcv::Core::create(
window,
applicationName,
VK_MAKE_VERSION(0, 0, 1),
{ vk::QueueFlagBits::eTransfer,vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eCompute },
{},
{ "VK_KHR_swapchain", VK_NV_MESH_SHADER_EXTENSION_NAME }
);
vkcv::gui::GUI gui (core, window);
vkcv::asset::Scene mesh;
const char* path = argc > 1 ? argv[1] : "resources/Bunny/Bunny.glb";
vkcv::asset::loadScene(path, mesh);
assert(!mesh.vertexGroups.empty());
auto vertexBuffer = core.createBuffer<uint8_t>(
vkcv::BufferType::VERTEX,
mesh.vertexGroups[0].vertexBuffer.data.size(),
vkcv::BufferMemoryType::DEVICE_LOCAL
);
vertexBuffer.fill(mesh.vertexGroups[0].vertexBuffer.data);
auto indexBuffer = core.createBuffer<uint8_t>(
vkcv::BufferType::INDEX,
mesh.vertexGroups[0].indexBuffer.data.size(),
vkcv::BufferMemoryType::DEVICE_LOCAL
);
indexBuffer.fill(mesh.vertexGroups[0].indexBuffer.data);
// format data for mesh shader
auto& attributes = mesh.vertexGroups[0].vertexBuffer.attributes;
std::sort(attributes.begin(), attributes.end(), [](const vkcv::asset::VertexAttribute& x, const vkcv::asset::VertexAttribute& y) {
return static_cast<uint32_t>(x.type) < static_cast<uint32_t>(y.type);
});
const std::vector<vkcv::VertexBufferBinding> vertexBufferBindings = {
vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[0].offset), vertexBuffer.getVulkanHandle()),
vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[1].offset), vertexBuffer.getVulkanHandle()),
vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[2].offset), vertexBuffer.getVulkanHandle()) };
const auto& bunny = mesh.vertexGroups[0];
std::vector<vkcv::meshlet::Vertex> interleavedVertices = vkcv::meshlet::convertToVertices(bunny.vertexBuffer.data, bunny.numVertices, attributes[0], attributes[1]);
// mesh shader buffers
const auto& assetLoaderIndexBuffer = mesh.vertexGroups[0].indexBuffer;
std::vector<uint32_t> indexBuffer32Bit = vkcv::meshlet::assetLoaderIndicesTo32BitIndices(assetLoaderIndexBuffer.data, assetLoaderIndexBuffer.type);
vkcv::meshlet::VertexCacheReorderResult tipsifyResult = vkcv::meshlet::tipsifyMesh(indexBuffer32Bit, interleavedVertices.size());
vkcv::meshlet::VertexCacheReorderResult forsythResult = vkcv::meshlet::forsythReorder(indexBuffer32Bit, interleavedVertices.size());
const auto meshShaderModelData = createMeshShaderModelData(interleavedVertices, forsythResult.indexBuffer, forsythResult.skippedIndices);
auto meshShaderVertexBuffer = core.createBuffer<vkcv::meshlet::Vertex>(
vkcv::BufferType::STORAGE,
meshShaderModelData.vertices.size());
meshShaderVertexBuffer.fill(meshShaderModelData.vertices);
auto meshShaderIndexBuffer = core.createBuffer<uint32_t>(
vkcv::BufferType::STORAGE,
meshShaderModelData.localIndices.size());
meshShaderIndexBuffer.fill(meshShaderModelData.localIndices);
auto meshletBuffer = core.createBuffer<vkcv::meshlet::Meshlet>(
vkcv::BufferType::STORAGE,
meshShaderModelData.meshlets.size(),
vkcv::BufferMemoryType::DEVICE_LOCAL
);
meshletBuffer.fill(meshShaderModelData.meshlets);
// attachments
const vkcv::AttachmentDescription present_color_attachment(
vkcv::AttachmentOperation::STORE,
vkcv::AttachmentOperation::CLEAR,
core.getSwapchain().getFormat());
const vkcv::AttachmentDescription depth_attachment(
vkcv::AttachmentOperation::STORE,
vkcv::AttachmentOperation::CLEAR,
vk::Format::eD32Sfloat
);
vkcv::PassConfig bunnyPassDefinition({ present_color_attachment, depth_attachment });
vkcv::PassHandle renderPass = core.createPass(bunnyPassDefinition);
if (!renderPass)
{
std::cout << "Error. Could not create renderpass. Exiting." << std::endl;
return EXIT_FAILURE;
}
vkcv::ShaderProgram bunnyShaderProgram{};
vkcv::shader::GLSLCompiler compiler;
compiler.compile(vkcv::ShaderStage::VERTEX, std::filesystem::path("resources/shaders/shader.vert"),
[&bunnyShaderProgram](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
bunnyShaderProgram.addShader(shaderStage, path);
});
compiler.compile(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("resources/shaders/shader.frag"),
[&bunnyShaderProgram](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
bunnyShaderProgram.addShader(shaderStage, path);
});
const std::vector<vkcv::VertexAttachment> vertexAttachments = bunnyShaderProgram.getVertexAttachments();
std::vector<vkcv::VertexBinding> bindings;
for (size_t i = 0; i < vertexAttachments.size(); i++) {
bindings.push_back(vkcv::VertexBinding(i, { vertexAttachments[i] }));
}
const vkcv::VertexLayout bunnyLayout (bindings);
vkcv::DescriptorSetHandle vertexShaderDescriptorSet = core.createDescriptorSet(bunnyShaderProgram.getReflectedDescriptors()[0]);
const vkcv::PipelineConfig bunnyPipelineDefinition {
bunnyShaderProgram,
(uint32_t)windowWidth,
(uint32_t)windowHeight,
renderPass,
{ bunnyLayout },
{ core.getDescriptorSet(vertexShaderDescriptorSet).layout },
false
};
struct ObjectMatrices {
glm::mat4 model;
glm::mat4 mvp;
};
const size_t objectCount = 1;
vkcv::Buffer<ObjectMatrices> matrixBuffer = core.createBuffer<ObjectMatrices>(vkcv::BufferType::STORAGE, objectCount);
vkcv::DescriptorWrites vertexShaderDescriptorWrites;
vertexShaderDescriptorWrites.storageBufferWrites = { vkcv::BufferDescriptorWrite(0, matrixBuffer.getHandle()) };
core.writeDescriptorSet(vertexShaderDescriptorSet, vertexShaderDescriptorWrites);
vkcv::PipelineHandle bunnyPipeline = core.createGraphicsPipeline(bunnyPipelineDefinition);
if (!bunnyPipeline)
{
std::cout << "Error. Could not create graphics pipeline. Exiting." << std::endl;
return EXIT_FAILURE;
}
// mesh shader
vkcv::ShaderProgram meshShaderProgram;
compiler.compile(vkcv::ShaderStage::TASK, std::filesystem::path("resources/shaders/shader.task"),
[&meshShaderProgram](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
meshShaderProgram.addShader(shaderStage, path);
});
compiler.compile(vkcv::ShaderStage::MESH, std::filesystem::path("resources/shaders/shader.mesh"),
[&meshShaderProgram](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
meshShaderProgram.addShader(shaderStage, path);
});
compiler.compile(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("resources/shaders/shader.frag"),
[&meshShaderProgram](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
meshShaderProgram.addShader(shaderStage, path);
});
uint32_t setID = 0;
vkcv::DescriptorSetHandle meshShaderDescriptorSet = core.createDescriptorSet( meshShaderProgram.getReflectedDescriptors()[setID]);
const vkcv::VertexLayout meshShaderLayout(bindings);
const vkcv::PipelineConfig meshShaderPipelineDefinition{
meshShaderProgram,
(uint32_t)windowWidth,
(uint32_t)windowHeight,
renderPass,
{meshShaderLayout},
{core.getDescriptorSet(meshShaderDescriptorSet).layout},
false
};
vkcv::PipelineHandle meshShaderPipeline = core.createGraphicsPipeline(meshShaderPipelineDefinition);
if (!meshShaderPipeline)
{
std::cout << "Error. Could not create mesh shader pipeline. Exiting." << std::endl;
return EXIT_FAILURE;
}
vkcv::Buffer<CameraPlanes> cameraPlaneBuffer = core.createBuffer<CameraPlanes>(vkcv::BufferType::UNIFORM, 1);
vkcv::DescriptorWrites meshShaderWrites;
meshShaderWrites.storageBufferWrites = {
vkcv::BufferDescriptorWrite(0, meshShaderVertexBuffer.getHandle()),
vkcv::BufferDescriptorWrite(1, meshShaderIndexBuffer.getHandle()),
vkcv::BufferDescriptorWrite(2, meshletBuffer.getHandle()),
vkcv::BufferDescriptorWrite(4, matrixBuffer.getHandle()),
vkcv::BufferDescriptorWrite(5, meshletBuffer.getHandle()),
};
meshShaderWrites.uniformBufferWrites = {
vkcv::BufferDescriptorWrite(3, cameraPlaneBuffer.getHandle()),
};
core.writeDescriptorSet( meshShaderDescriptorSet, meshShaderWrites);
vkcv::ImageHandle depthBuffer = core.createImage(vk::Format::eD32Sfloat, windowWidth, windowHeight, 1, false).getHandle();
auto start = std::chrono::system_clock::now();
vkcv::ImageHandle swapchainImageHandle = vkcv::ImageHandle::createSwapchainImageHandle();
const vkcv::Mesh renderMesh(vertexBufferBindings, indexBuffer.getVulkanHandle(), mesh.vertexGroups[0].numIndices, vkcv::IndexBitCount::Bit32);
const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle();
vkcv::camera::CameraManager cameraManager(window);
uint32_t camIndex0 = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT);
cameraManager.getCamera(camIndex0).setPosition(glm::vec3(0, 0, -2));
bool useMeshShader = true;
bool updateFrustumPlanes = true;
while (window.isWindowOpen())
{
vkcv::Window::pollEvents();
uint32_t swapchainWidth, swapchainHeight; // No resizing = No problem
if (!core.beginFrame(swapchainWidth, swapchainHeight)) {
continue;
}
auto end = std::chrono::system_clock::now();
auto deltatime = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
start = end;
cameraManager.update(0.000001 * static_cast<double>(deltatime.count()));
const vkcv::camera::Camera& camera = cameraManager.getActiveCamera();
ObjectMatrices objectMatrices;
objectMatrices.model = *reinterpret_cast<glm::mat4*>(&mesh.meshes.front().modelMatrix);
objectMatrices.mvp = camera.getMVP() * objectMatrices.model;
matrixBuffer.fill({ objectMatrices });
struct PushConstants {
uint32_t matrixIndex;
uint32_t meshletCount;
};
PushConstants pushConstants{ 0, static_cast<uint32_t>(meshShaderModelData.meshlets.size()) };
if (updateFrustumPlanes) {
const CameraPlanes cameraPlanes = computeCameraPlanes(camera);
cameraPlaneBuffer.fill({ cameraPlanes });
}
const std::vector<vkcv::ImageHandle> renderTargets = { swapchainInput, depthBuffer };
auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics);
vkcv::PushConstants pushConstantData(sizeof(pushConstants));
pushConstantData.appendDrawcall(pushConstants);
if (useMeshShader) {
vkcv::DescriptorSetUsage descriptorUsage(0, core.getDescriptorSet(meshShaderDescriptorSet).vulkanHandle);
const uint32_t taskCount = (meshShaderModelData.meshlets.size() + 31) / 32;
core.recordMeshShaderDrawcalls(
cmdStream,
renderPass,
meshShaderPipeline,
pushConstantData,
{ vkcv::MeshShaderDrawcall({descriptorUsage}, taskCount)},
{ renderTargets });
}
else {
vkcv::DescriptorSetUsage descriptorUsage(0, core.getDescriptorSet(vertexShaderDescriptorSet).vulkanHandle);
core.recordDrawcallsToCmdStream(
cmdStream,
renderPass,
bunnyPipeline,
pushConstantData,
{ vkcv::DrawcallInfo(renderMesh, { descriptorUsage }) },
{ renderTargets });
}
core.prepareSwapchainImageForPresent(cmdStream);
core.submitCommandStream(cmdStream);
gui.beginGUI();
ImGui::Begin("Settings");
ImGui::Checkbox("Use mesh shader", &useMeshShader);
ImGui::Checkbox("Update frustum culling", &updateFrustumPlanes);
ImGui::End();
gui.endGUI();
core.endFrame();
}
return 0;
}
...@@ -104,7 +104,7 @@ void BloomAndFlares::execDownsamplePipe(const vkcv::CommandStreamHandle &cmdStre ...@@ -104,7 +104,7 @@ void BloomAndFlares::execDownsamplePipe(const vkcv::CommandStreamHandle &cmdStre
m_DownsamplePipe, m_DownsamplePipe,
initialDispatchCount, initialDispatchCount,
{vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_DownsampleDescSets[0]).vulkanHandle)}, {vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_DownsampleDescSets[0]).vulkanHandle)},
vkcv::PushConstantData(nullptr, 0)); vkcv::PushConstants(0));
// downsample dispatches of blur buffer's mip maps // downsample dispatches of blur buffer's mip maps
float mipDispatchCountX = dispatchCountX; float mipDispatchCountX = dispatchCountX;
...@@ -139,7 +139,7 @@ void BloomAndFlares::execDownsamplePipe(const vkcv::CommandStreamHandle &cmdStre ...@@ -139,7 +139,7 @@ void BloomAndFlares::execDownsamplePipe(const vkcv::CommandStreamHandle &cmdStre
m_DownsamplePipe, m_DownsamplePipe,
mipDispatchCount, mipDispatchCount,
{vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_DownsampleDescSets[mipLevel]).vulkanHandle)}, {vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_DownsampleDescSets[mipLevel]).vulkanHandle)},
vkcv::PushConstantData(nullptr, 0)); vkcv::PushConstants(0));
// image barrier between mips // image barrier between mips
p_Core->recordImageMemoryBarrier(cmdStream, m_Blur.getHandle()); p_Core->recordImageMemoryBarrier(cmdStream, m_Blur.getHandle());
...@@ -184,7 +184,7 @@ void BloomAndFlares::execUpsamplePipe(const vkcv::CommandStreamHandle &cmdStream ...@@ -184,7 +184,7 @@ void BloomAndFlares::execUpsamplePipe(const vkcv::CommandStreamHandle &cmdStream
m_UpsamplePipe, m_UpsamplePipe,
upsampleDispatchCount, upsampleDispatchCount,
{vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_UpsampleDescSets[mipLevel]).vulkanHandle)}, {vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_UpsampleDescSets[mipLevel]).vulkanHandle)},
vkcv::PushConstantData(nullptr, 0) vkcv::PushConstants(0)
); );
// image barrier between mips // image barrier between mips
p_Core->recordImageMemoryBarrier(cmdStream, m_Blur.getHandle()); p_Core->recordImageMemoryBarrier(cmdStream, m_Blur.getHandle());
...@@ -216,7 +216,7 @@ void BloomAndFlares::execLensFeaturePipe(const vkcv::CommandStreamHandle &cmdStr ...@@ -216,7 +216,7 @@ void BloomAndFlares::execLensFeaturePipe(const vkcv::CommandStreamHandle &cmdStr
m_LensFlarePipe, m_LensFlarePipe,
lensFeatureDispatchCount, lensFeatureDispatchCount,
{vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_LensFlareDescSet).vulkanHandle)}, {vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_LensFlareDescSet).vulkanHandle)},
vkcv::PushConstantData(nullptr, 0)); vkcv::PushConstants(0));
} }
void BloomAndFlares::execCompositePipe(const vkcv::CommandStreamHandle &cmdStream, void BloomAndFlares::execCompositePipe(const vkcv::CommandStreamHandle &cmdStream,
...@@ -249,7 +249,7 @@ void BloomAndFlares::execCompositePipe(const vkcv::CommandStreamHandle &cmdStrea ...@@ -249,7 +249,7 @@ void BloomAndFlares::execCompositePipe(const vkcv::CommandStreamHandle &cmdStrea
m_CompositePipe, m_CompositePipe,
compositeDispatchCount, compositeDispatchCount,
{vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_CompositeDescSet).vulkanHandle)}, {vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_CompositeDescSet).vulkanHandle)},
vkcv::PushConstantData(nullptr, 0)); vkcv::PushConstants(0));
} }
void BloomAndFlares::execWholePipeline(const vkcv::CommandStreamHandle &cmdStream, void BloomAndFlares::execWholePipeline(const vkcv::CommandStreamHandle &cmdStream,
...@@ -263,6 +263,10 @@ void BloomAndFlares::execWholePipeline(const vkcv::CommandStreamHandle &cmdStrea ...@@ -263,6 +263,10 @@ void BloomAndFlares::execWholePipeline(const vkcv::CommandStreamHandle &cmdStrea
void BloomAndFlares::updateImageDimensions(uint32_t width, uint32_t height) void BloomAndFlares::updateImageDimensions(uint32_t width, uint32_t height)
{ {
if ((width == m_Width) && (height == m_Height)) {
return;
}
m_Width = width; m_Width = width;
m_Height = height; m_Height = height;
......
...@@ -3,16 +3,17 @@ ...@@ -3,16 +3,17 @@
Particle::Particle(glm::vec3 position, glm::vec3 velocity, float lifeTime) Particle::Particle(glm::vec3 position, glm::vec3 velocity, float lifeTime)
: m_position(position), : m_position(position),
m_velocity(velocity), m_lifeTime(lifeTime),
m_lifeTime(lifeTime), m_velocity(velocity),
m_reset_velocity(velocity) m_mass(1.0f),
m_reset_velocity(velocity)
{} {}
const glm::vec3& Particle::getPosition()const{ const glm::vec3& Particle::getPosition()const{
return m_position; return m_position;
} }
const bool Particle::isAlive()const{ bool Particle::isAlive()const{
return m_lifeTime > 0.f; return m_lifeTime > 0.f;
} }
......
...@@ -17,7 +17,7 @@ public: ...@@ -17,7 +17,7 @@ public:
void update( const float delta ); void update( const float delta );
const bool isAlive()const; bool isAlive()const;
void setLifeTime( const float lifeTime ); void setLifeTime( const float lifeTime );
...@@ -28,7 +28,7 @@ private: ...@@ -28,7 +28,7 @@ private:
glm::vec3 m_position; glm::vec3 m_position;
float m_lifeTime; float m_lifeTime;
glm::vec3 m_velocity; glm::vec3 m_velocity;
float mass = 1.f; float m_mass;
glm::vec3 m_reset_velocity; glm::vec3 m_reset_velocity;
float padding_3 = 0.f; float padding_3;
}; };
...@@ -58,12 +58,28 @@ int main(int argc, const char **argv) { ...@@ -58,12 +58,28 @@ int main(int argc, const char **argv) {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
// use space or use water // use space or use water or gravity
bool useSpace = true; std::string shaderPathCompute = "shaders/shader_space.comp";
std::string shaderPathFragment = "shaders/shader_space.frag";
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--space") == 0) {
shaderPathCompute = "shaders/shader_space.comp";
shaderPathFragment = "shaders/shader_space.frag";
} else
if (strcmp(argv[i], "--water") == 0) {
shaderPathCompute = "shaders/shader_water.comp";
shaderPathFragment = "shaders/shader_water.frag";
} else
if (strcmp(argv[i], "--gravity") == 0) {
shaderPathCompute = "shaders/shader_gravity.comp";
shaderPathFragment = "shaders/shader_space.frag";
}
}
vkcv::shader::GLSLCompiler compiler; vkcv::shader::GLSLCompiler compiler;
vkcv::ShaderProgram computeShaderProgram{}; vkcv::ShaderProgram computeShaderProgram{};
compiler.compile(vkcv::ShaderStage::COMPUTE, useSpace ? "shaders/shader_space.comp" : "shaders/shader_water.comp", [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { compiler.compile(vkcv::ShaderStage::COMPUTE, shaderPathCompute, [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
computeShaderProgram.addShader(shaderStage, path); computeShaderProgram.addShader(shaderStage, path);
}); });
...@@ -81,7 +97,7 @@ int main(int argc, const char **argv) { ...@@ -81,7 +97,7 @@ int main(int argc, const char **argv) {
compiler.compile(vkcv::ShaderStage::VERTEX, "shaders/shader.vert", [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { compiler.compile(vkcv::ShaderStage::VERTEX, "shaders/shader.vert", [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
particleShaderProgram.addShader(shaderStage, path); particleShaderProgram.addShader(shaderStage, path);
}); });
compiler.compile(vkcv::ShaderStage::FRAGMENT, useSpace ? "shaders/shader_space.frag" : "shaders/shader_water.frag", [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { compiler.compile(vkcv::ShaderStage::FRAGMENT, shaderPathFragment, [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
particleShaderProgram.addShader(shaderStage, path); particleShaderProgram.addShader(shaderStage, path);
}); });
...@@ -147,13 +163,13 @@ int main(int argc, const char **argv) { ...@@ -147,13 +163,13 @@ int main(int argc, const char **argv) {
particleBuffer.fill(particleSystem.getParticles()); particleBuffer.fill(particleSystem.getParticles());
vkcv::DescriptorWrites setWrites; vkcv::DescriptorWrites setWrites;
setWrites.uniformBufferWrites = {vkcv::UniformBufferDescriptorWrite(0,color.getHandle()), setWrites.uniformBufferWrites = {vkcv::BufferDescriptorWrite(0,color.getHandle()),
vkcv::UniformBufferDescriptorWrite(1,position.getHandle())}; vkcv::BufferDescriptorWrite(1,position.getHandle())};
setWrites.storageBufferWrites = { vkcv::StorageBufferDescriptorWrite(2,particleBuffer.getHandle())}; setWrites.storageBufferWrites = { vkcv::BufferDescriptorWrite(2,particleBuffer.getHandle())};
core.writeDescriptorSet(descriptorSet, setWrites); core.writeDescriptorSet(descriptorSet, setWrites);
vkcv::DescriptorWrites computeWrites; vkcv::DescriptorWrites computeWrites;
computeWrites.storageBufferWrites = { vkcv::StorageBufferDescriptorWrite(0,particleBuffer.getHandle())}; computeWrites.storageBufferWrites = { vkcv::BufferDescriptorWrite(0,particleBuffer.getHandle())};
core.writeDescriptorSet(computeDescriptorSet, computeWrites); core.writeDescriptorSet(computeDescriptorSet, computeWrites);
if (!particlePipeline || !computePipeline) if (!particlePipeline || !computePipeline)
...@@ -167,38 +183,16 @@ int main(int argc, const char **argv) { ...@@ -167,38 +183,16 @@ int main(int argc, const char **argv) {
const vkcv::Mesh renderMesh({vertexBufferBindings}, particleIndexBuffer.getVulkanHandle(), const vkcv::Mesh renderMesh({vertexBufferBindings}, particleIndexBuffer.getVulkanHandle(),
particleIndexBuffer.getCount()); particleIndexBuffer.getCount());
vkcv::DescriptorSetUsage descriptorUsage(0, core.getDescriptorSet(descriptorSet).vulkanHandle); vkcv::DescriptorSetUsage descriptorUsage(0, core.getDescriptorSet(descriptorSet).vulkanHandle);
//vkcv::DrawcallInfo drawcalls(renderMesh, {vkcv::DescriptorSetUsage(0, core.getDescriptorSet(descriptorSet).vulkanHandle)});
glm::vec2 pos = glm::vec2(0.f); auto pos = glm::vec2(0.f);
glm::vec3 spawnPosition = glm::vec3(0.f); auto spawnPosition = glm::vec3(0.f);
glm::vec4 tempPosition = glm::vec4(0.f);
window.e_mouseMove.add([&](double offsetX, double offsetY) { window.e_mouseMove.add([&](double offsetX, double offsetY) {
pos = glm::vec2(static_cast<float>(offsetX), static_cast<float>(offsetY)); pos = glm::vec2(static_cast<float>(offsetX), static_cast<float>(offsetY));
// std::cout << offsetX << " , " << offsetY << std::endl;
// borders are assumed to be 0.5
//pos = glm::vec2((pos.x -0.5f * static_cast<float>(window.getWidth()))/static_cast<float>(window.getWidth()), (pos.y -0.5f * static_cast<float>(window.getHeight()))/static_cast<float>(window.getHeight()));
//borders are assumed to be 1
pos.x = (-2 * pos.x + static_cast<float>(window.getWidth())) / static_cast<float>(window.getWidth()); pos.x = (-2 * pos.x + static_cast<float>(window.getWidth())) / static_cast<float>(window.getWidth());
pos.y = (-2 * pos.y + static_cast<float>(window.getHeight())) / static_cast<float>(window.getHeight()); pos.y = (-2 * pos.y + static_cast<float>(window.getHeight())) / static_cast<float>(window.getHeight());
glm::vec4 row1 = glm::row(cameraManager.getCamera(0).getView(), 0);
glm::vec4 row2 = glm::row(cameraManager.getCamera(0).getView(), 1);
glm::vec4 row3 = glm::row(cameraManager.getCamera(0).getView(), 2);
glm::vec4 camera_pos = glm::column(cameraManager.getCamera(0).getView(), 3);
// std::cout << "row1: " << row1.x << ", " << row1.y << ", " << row1.z << std::endl;
// std::cout << "row2: " << row2.x << ", " << row2.y << ", " << row2.z << std::endl;
// std::cout << "row3: " << row3.x << ", " << row3.y << ", " << row3.z << std::endl;
// std::cout << "camerapos: " << camera_pos.x << ", " << camera_pos.y << ", " << camera_pos.z << std::endl;
// std::cout << "camerapos: " << camera_pos.x << ", " << camera_pos.y << ", " << camera_pos.z << std::endl;
//glm::vec4 view_axis = glm::row(cameraManager.getCamera().getView(), 2);
// std::cout << "view_axis: " << view_axis.x << ", " << view_axis.y << ", " << view_axis.z << std::endl;
//std::cout << "Front: " << cameraManager.getCamera().getFront().x << ", " << cameraManager.getCamera().getFront().z << ", " << cameraManager.getCamera().getFront().z << std::endl;
glm::mat4 viewmat = cameraManager.getCamera(0).getView();
spawnPosition = glm::vec3(pos.x, pos.y, 0.f); spawnPosition = glm::vec3(pos.x, pos.y, 0.f);
tempPosition = glm::vec4(spawnPosition, 1.0f);
spawnPosition = glm::vec3(tempPosition.x, tempPosition.y, tempPosition.z);
particleSystem.setRespawnPos(glm::vec3(-spawnPosition.x, spawnPosition.y, spawnPosition.z)); particleSystem.setRespawnPos(glm::vec3(-spawnPosition.x, spawnPosition.y, spawnPosition.z));
// std::cout << "respawn pos: " << spawnPosition.x << ", " << spawnPosition.y << ", " << spawnPosition.z << std::endl;
}); });
std::vector<glm::mat4> modelMatrices; std::vector<glm::mat4> modelMatrices;
...@@ -242,7 +236,7 @@ int main(int argc, const char **argv) { ...@@ -242,7 +236,7 @@ int main(int argc, const char **argv) {
std::uniform_real_distribution<float> rdm = std::uniform_real_distribution<float>(0.95f, 1.05f); std::uniform_real_distribution<float> rdm = std::uniform_real_distribution<float>(0.95f, 1.05f);
std::default_random_engine rdmEngine; std::default_random_engine rdmEngine;
while (window.isWindowOpen()) { while (window.isWindowOpen()) {
window.pollEvents(); vkcv::Window::pollEvents();
uint32_t swapchainWidth, swapchainHeight; uint32_t swapchainWidth, swapchainHeight;
if (!core.beginFrame(swapchainWidth, swapchainHeight)) { if (!core.beginFrame(swapchainWidth, swapchainHeight)) {
...@@ -255,35 +249,42 @@ int main(int argc, const char **argv) { ...@@ -255,35 +249,42 @@ int main(int argc, const char **argv) {
auto end = std::chrono::system_clock::now(); auto end = std::chrono::system_clock::now();
float deltatime = 0.000001 * static_cast<float>( std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() ); float deltatime = 0.000001 * static_cast<float>( std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() );
start = end; start = end;
// particleSystem.updateParticles(deltatime);
cameraManager.update(deltatime); cameraManager.update(deltatime);
// split view and projection to allow for easy billboarding in shader // split view and projection to allow for easy billboarding in shader
glm::mat4 renderingMatrices[2]; struct {
renderingMatrices[0] = cameraManager.getActiveCamera().getView(); glm::mat4 view;
renderingMatrices[1] = cameraManager.getActiveCamera().getProjection(); glm::mat4 projection;
} renderingMatrices;
renderingMatrices.view = cameraManager.getActiveCamera().getView();
renderingMatrices.projection = cameraManager.getActiveCamera().getProjection();
auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics); auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics);
float random = rdm(rdmEngine); float random = rdm(rdmEngine);
glm::vec2 pushData = glm::vec2(deltatime, random); glm::vec2 pushData = glm::vec2(deltatime, random);
vkcv::PushConstantData pushConstantDataCompute( &pushData, sizeof(glm::vec2)); vkcv::PushConstants pushConstantsCompute (sizeof(glm::vec2));
pushConstantsCompute.appendDrawcall(pushData);
uint32_t computeDispatchCount[3] = {static_cast<uint32_t> (std::ceil(particleSystem.getParticles().size()/256.f)),1,1}; uint32_t computeDispatchCount[3] = {static_cast<uint32_t> (std::ceil(particleSystem.getParticles().size()/256.f)),1,1};
core.recordComputeDispatchToCmdStream(cmdStream, core.recordComputeDispatchToCmdStream(cmdStream,
computePipeline, computePipeline,
computeDispatchCount, computeDispatchCount,
{vkcv::DescriptorSetUsage(0,core.getDescriptorSet(computeDescriptorSet).vulkanHandle)}, {vkcv::DescriptorSetUsage(0,core.getDescriptorSet(computeDescriptorSet).vulkanHandle)},
pushConstantDataCompute); pushConstantsCompute);
core.recordBufferMemoryBarrier(cmdStream, particleBuffer.getHandle()); core.recordBufferMemoryBarrier(cmdStream, particleBuffer.getHandle());
vkcv::PushConstantData pushConstantDataDraw((void *) &renderingMatrices[0], 2 * sizeof(glm::mat4)); vkcv::PushConstants pushConstantsDraw (sizeof(renderingMatrices));
pushConstantsDraw.appendDrawcall(renderingMatrices);
core.recordDrawcallsToCmdStream( core.recordDrawcallsToCmdStream(
cmdStream, cmdStream,
particlePass, particlePass,
particlePipeline, particlePipeline,
pushConstantDataDraw, pushConstantsDraw,
{drawcalls}, {drawcalls},
{ colorBuffer }); { colorBuffer });
...@@ -309,7 +310,7 @@ int main(int argc, const char **argv) { ...@@ -309,7 +310,7 @@ int main(int argc, const char **argv) {
tonemappingPipe, tonemappingPipe,
tonemappingDispatchCount, tonemappingDispatchCount,
{vkcv::DescriptorSetUsage(0, core.getDescriptorSet(tonemappingDescriptor).vulkanHandle) }, {vkcv::DescriptorSetUsage(0, core.getDescriptorSet(tonemappingDescriptor).vulkanHandle) },
vkcv::PushConstantData(nullptr, 0)); vkcv::PushConstants(0));
core.prepareSwapchainImageForPresent(cmdStream); core.prepareSwapchainImageForPresent(cmdStream);
core.submitCommandStream(cmdStream); core.submitCommandStream(cmdStream);
......
...@@ -30,7 +30,7 @@ if(MSVC) ...@@ -30,7 +30,7 @@ if(MSVC)
endif() endif()
# including headers of dependencies and the VkCV framework # including headers of dependencies and the VkCV framework
target_include_directories(voxelization SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_asset_loader_include} ${vkcv_camera_include} ${vkcv_shader_compiler_include} ${vkcv_gui_include}) target_include_directories(voxelization SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_asset_loader_include} ${vkcv_camera_include} ${vkcv_shader_compiler_include} ${vkcv_gui_include} ${vkcv_upscaling_include})
# linking with libraries from all dependencies and the VkCV framework # linking with libraries from all dependencies and the VkCV framework
target_link_libraries(voxelization vkcv ${vkcv_libraries} vkcv_asset_loader ${vkcv_asset_loader_libraries} vkcv_camera vkcv_shader_compiler vkcv_gui) target_link_libraries(voxelization vkcv ${vkcv_libraries} vkcv_asset_loader ${vkcv_asset_loader_libraries} vkcv_camera vkcv_shader_compiler vkcv_gui vkcv_upscaling)
#version 440
#extension GL_GOOGLE_include_directive : enable
#include "luma.inc"
layout(set=0, binding=0) uniform texture2D inTexture;
layout(set=0, binding=1) uniform sampler textureSampler;
layout(set=0, binding=2, rgba8) uniform image2D outImage;
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
layout( push_constant ) uniform constants{
float time;
};
// from: https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/
vec3 ACESFilm(vec3 x)
{
float a = 2.51f;
float b = 0.03f;
float c = 2.43f;
float d = 0.59f;
float e = 0.14f;
return clamp((x*(a*x+b))/(x*(c*x+d)+e), 0, 1);
}
// From Dave Hoskins: https://www.shadertoy.com/view/4djSRW.
float hash(vec3 p3){
p3 = fract(p3 * 0.1031);
p3 += dot(p3,p3.yzx + 19.19);
return fract((p3.x + p3.y) * p3.z);
}
// From iq: https://www.shadertoy.com/view/4sfGzS.
float noise(vec3 x){
vec3 i = floor(x);
vec3 f = fract(x);
f = f*f*(3.0-2.0*f);
return mix(mix(mix(hash(i+vec3(0, 0, 0)),
hash(i+vec3(1, 0, 0)),f.x),
mix(hash(i+vec3(0, 1, 0)),
hash(i+vec3(1, 1, 0)),f.x),f.y),
mix(mix(hash(i+vec3(0, 0, 1)),
hash(i+vec3(1, 0, 1)),f.x),
mix(hash(i+vec3(0, 1, 1)),
hash(i+vec3(1, 1, 1)),f.x),f.y),f.z);
}
// From: https://www.shadertoy.com/view/3sGSWVF
// Slightly high-passed continuous value-noise.
float grainSource(vec3 x, float strength, float pitch){
float center = noise(x);
float v1 = center - noise(vec3( 1, 0, 0)/pitch + x) + 0.5;
float v2 = center - noise(vec3( 0, 1, 0)/pitch + x) + 0.5;
float v3 = center - noise(vec3(-1, 0, 0)/pitch + x) + 0.5;
float v4 = center - noise(vec3( 0,-1, 0)/pitch + x) + 0.5;
float total = (v1 + v2 + v3 + v4) / 4.0;
return mix(1, 0.5 + total, strength);
}
vec3 applyGrain(ivec2 uv, vec3 c){
float grainLift = 0.6;
float grainStrength = 0.4;
float grainTimeFactor = 0.1;
float timeColorOffset = 1.2;
vec3 grain = vec3(
grainSource(vec3(uv, floor(grainTimeFactor*time)), grainStrength, grainLift),
grainSource(vec3(uv, floor(grainTimeFactor*time + timeColorOffset)), grainStrength, grainLift),
grainSource(vec3(uv, floor(grainTimeFactor*time - timeColorOffset)), grainStrength, grainLift));
return c * grain;
}
vec2 computeDistortedUV(vec2 uv, float aspectRatio){
uv = uv * 2 - 1;
float r2 = dot(uv, uv);
float k1 = 0.02f;
float maxR2 = dot(vec2(1), vec2(1));
float maxFactor = maxR2 * k1;
// correction only needed for pincushion distortion
maxFactor = min(maxFactor, 0);
uv /= 1 + r2*k1;
// correction to avoid going out of [-1, 1] range when using barrel distortion
uv *= 1 + maxFactor;
return uv * 0.5 + 0.5;
}
float computeLocalContrast(vec2 uv){
float lumaMin = 100;
float lumaMax = 0;
vec2 pixelSize = vec2(1) / textureSize(sampler2D(inTexture, textureSampler), 0);
for(int x = -1; x <= 1; x++){
for(int y = -1; y <= 1; y++){
vec3 c = texture(sampler2D(inTexture, textureSampler), uv + vec2(x, y) * pixelSize).rgb;
float luma = computeLuma(c);
lumaMin = min(lumaMin, luma);
lumaMax = max(lumaMax, luma);
}
}
return lumaMax - lumaMin;
}
vec3 computeChromaticAberrationScale(vec2 uv){
float localContrast = computeLocalContrast(uv);
vec3 colorScales = vec3(-1, 0, 1);
float aberrationScale = 0.004;
vec3 maxScaleFactors = colorScales * aberrationScale;
float factor = clamp(localContrast, 0, 1);
return mix(vec3(0), maxScaleFactors, factor);
}
vec3 sampleColorChromaticAberration(vec2 uv){
vec2 toCenter = (vec2(0.5) - uv);
vec3 scaleFactors = computeChromaticAberrationScale(uv);
float r = texture(sampler2D(inTexture, textureSampler), uv + toCenter * scaleFactors.r).r;
float g = texture(sampler2D(inTexture, textureSampler), uv + toCenter * scaleFactors.g).g;
float b = texture(sampler2D(inTexture, textureSampler), uv + toCenter * scaleFactors.b).b;
return vec3(r, g, b);
}
void main(){
if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(outImage)))){
return;
}
ivec2 textureRes = textureSize(sampler2D(inTexture, textureSampler), 0);
ivec2 coord = ivec2(gl_GlobalInvocationID.xy);
vec2 uv = vec2(coord) / textureRes;
float aspectRatio = float(textureRes.x) / textureRes.y;
uv = computeDistortedUV(uv, aspectRatio);
vec3 tonemapped = sampleColorChromaticAberration(uv);
tonemapped = applyGrain(coord, tonemapped);
vec3 gammaCorrected = pow(tonemapped, vec3(1.f / 2.2f));
imageStore(outImage, coord, vec4(gammaCorrected, 0.f));
}
\ No newline at end of file
#version 440 #version 440
#extension GL_GOOGLE_include_directive : enable #extension GL_GOOGLE_include_directive : enable
#include "luma.inc"
layout(set=0, binding=0) uniform texture2D inTexture; layout(set=0, binding=0) uniform texture2D inTexture;
layout(set=0, binding=1) uniform sampler textureSampler; layout(set=0, binding=1) uniform sampler textureSampler;
layout(set=0, binding=2, rgba8) uniform image2D outImage; layout(set=0, binding=2, rgba8) uniform image2D outImage;
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
layout( push_constant ) uniform constants{
float time;
};
// from: https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/ // from: https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/
vec3 ACESFilm(vec3 x) vec3 ACESFilm(vec3 x)
{ {
...@@ -24,112 +18,6 @@ vec3 ACESFilm(vec3 x) ...@@ -24,112 +18,6 @@ vec3 ACESFilm(vec3 x)
return clamp((x*(a*x+b))/(x*(c*x+d)+e), 0, 1); return clamp((x*(a*x+b))/(x*(c*x+d)+e), 0, 1);
} }
// From Dave Hoskins: https://www.shadertoy.com/view/4djSRW.
float hash(vec3 p3){
p3 = fract(p3 * 0.1031);
p3 += dot(p3,p3.yzx + 19.19);
return fract((p3.x + p3.y) * p3.z);
}
// From iq: https://www.shadertoy.com/view/4sfGzS.
float noise(vec3 x){
vec3 i = floor(x);
vec3 f = fract(x);
f = f*f*(3.0-2.0*f);
return mix(mix(mix(hash(i+vec3(0, 0, 0)),
hash(i+vec3(1, 0, 0)),f.x),
mix(hash(i+vec3(0, 1, 0)),
hash(i+vec3(1, 1, 0)),f.x),f.y),
mix(mix(hash(i+vec3(0, 0, 1)),
hash(i+vec3(1, 0, 1)),f.x),
mix(hash(i+vec3(0, 1, 1)),
hash(i+vec3(1, 1, 1)),f.x),f.y),f.z);
}
// From: https://www.shadertoy.com/view/3sGSWVF
// Slightly high-passed continuous value-noise.
float grainSource(vec3 x, float strength, float pitch){
float center = noise(x);
float v1 = center - noise(vec3( 1, 0, 0)/pitch + x) + 0.5;
float v2 = center - noise(vec3( 0, 1, 0)/pitch + x) + 0.5;
float v3 = center - noise(vec3(-1, 0, 0)/pitch + x) + 0.5;
float v4 = center - noise(vec3( 0,-1, 0)/pitch + x) + 0.5;
float total = (v1 + v2 + v3 + v4) / 4.0;
return mix(1, 0.5 + total, strength);
}
vec3 applyGrain(ivec2 uv, vec3 c){
float grainLift = 0.6;
float grainStrength = 0.4;
float grainTimeFactor = 0.1;
float timeColorOffset = 1.2;
vec3 grain = vec3(
grainSource(vec3(uv, floor(grainTimeFactor*time)), grainStrength, grainLift),
grainSource(vec3(uv, floor(grainTimeFactor*time + timeColorOffset)), grainStrength, grainLift),
grainSource(vec3(uv, floor(grainTimeFactor*time - timeColorOffset)), grainStrength, grainLift));
return c * grain;
}
vec2 computeDistortedUV(vec2 uv, float aspectRatio){
uv = uv * 2 - 1;
float r2 = dot(uv, uv);
float k1 = 0.02f;
float maxR2 = dot(vec2(1), vec2(1));
float maxFactor = maxR2 * k1;
// correction only needed for pincushion distortion
maxFactor = min(maxFactor, 0);
uv /= 1 + r2*k1;
// correction to avoid going out of [-1, 1] range when using barrel distortion
uv *= 1 + maxFactor;
return uv * 0.5 + 0.5;
}
float computeLocalContrast(vec2 uv){
float lumaMin = 100;
float lumaMax = 0;
vec2 pixelSize = vec2(1) / textureSize(sampler2D(inTexture, textureSampler), 0);
for(int x = -1; x <= 1; x++){
for(int y = -1; y <= 1; y++){
vec3 c = texture(sampler2D(inTexture, textureSampler), uv + vec2(x, y) * pixelSize).rgb;
float luma = computeLuma(c);
lumaMin = min(lumaMin, luma);
lumaMax = max(lumaMax, luma);
}
}
return lumaMax - lumaMin;
}
vec3 computeChromaticAberrationScale(vec2 uv){
float localContrast = computeLocalContrast(uv);
vec3 colorScales = vec3(-1, 0, 1);
float aberrationScale = 0.004;
vec3 maxScaleFactors = colorScales * aberrationScale;
float factor = clamp(localContrast, 0, 1);
return mix(vec3(0), maxScaleFactors, factor);
}
vec3 sampleColorChromaticAberration(vec2 uv){
vec2 toCenter = (vec2(0.5) - uv);
vec3 scaleFactors = computeChromaticAberrationScale(uv);
float r = texture(sampler2D(inTexture, textureSampler), uv + toCenter * scaleFactors.r).r;
float g = texture(sampler2D(inTexture, textureSampler), uv + toCenter * scaleFactors.g).g;
float b = texture(sampler2D(inTexture, textureSampler), uv + toCenter * scaleFactors.b).b;
return vec3(r, g, b);
}
void main(){ void main(){
if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(outImage)))){ if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(outImage)))){
...@@ -138,12 +26,9 @@ void main(){ ...@@ -138,12 +26,9 @@ void main(){
ivec2 textureRes = textureSize(sampler2D(inTexture, textureSampler), 0); ivec2 textureRes = textureSize(sampler2D(inTexture, textureSampler), 0);
ivec2 coord = ivec2(gl_GlobalInvocationID.xy); ivec2 coord = ivec2(gl_GlobalInvocationID.xy);
vec2 uv = vec2(coord) / textureRes; vec2 uv = vec2(coord) / textureRes;
float aspectRatio = float(textureRes.x) / textureRes.y;
uv = computeDistortedUV(uv, aspectRatio); vec3 linearColor = texture(sampler2D(inTexture, textureSampler), uv).rgb;
vec3 linearColor = sampleColorChromaticAberration(uv);
vec3 tonemapped = ACESFilm(linearColor); vec3 tonemapped = ACESFilm(linearColor);
tonemapped = applyGrain(coord, tonemapped);
imageStore(outImage, coord, vec4(tonemapped, 0.f));
vec3 gammaCorrected = pow(tonemapped, vec3(1.f / 2.2f));
imageStore(outImage, coord, vec4(gammaCorrected, 0.f));
} }
\ No newline at end of file
...@@ -128,7 +128,7 @@ void BloomAndFlares::execDownsamplePipe(const vkcv::CommandStreamHandle &cmdStre ...@@ -128,7 +128,7 @@ void BloomAndFlares::execDownsamplePipe(const vkcv::CommandStreamHandle &cmdStre
m_DownsamplePipe, m_DownsamplePipe,
initialDispatchCount, initialDispatchCount,
{vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_DownsampleDescSets[0]).vulkanHandle)}, {vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_DownsampleDescSets[0]).vulkanHandle)},
vkcv::PushConstantData(nullptr, 0)); vkcv::PushConstants(0));
// downsample dispatches of blur buffer's mip maps // downsample dispatches of blur buffer's mip maps
float mipDispatchCountX = dispatchCountX; float mipDispatchCountX = dispatchCountX;
...@@ -163,7 +163,7 @@ void BloomAndFlares::execDownsamplePipe(const vkcv::CommandStreamHandle &cmdStre ...@@ -163,7 +163,7 @@ void BloomAndFlares::execDownsamplePipe(const vkcv::CommandStreamHandle &cmdStre
m_DownsamplePipe, m_DownsamplePipe,
mipDispatchCount, mipDispatchCount,
{vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_DownsampleDescSets[mipLevel]).vulkanHandle)}, {vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_DownsampleDescSets[mipLevel]).vulkanHandle)},
vkcv::PushConstantData(nullptr, 0)); vkcv::PushConstants(0));
// image barrier between mips // image barrier between mips
p_Core->recordImageMemoryBarrier(cmdStream, m_Blur.getHandle()); p_Core->recordImageMemoryBarrier(cmdStream, m_Blur.getHandle());
...@@ -208,7 +208,7 @@ void BloomAndFlares::execUpsamplePipe(const vkcv::CommandStreamHandle &cmdStream ...@@ -208,7 +208,7 @@ void BloomAndFlares::execUpsamplePipe(const vkcv::CommandStreamHandle &cmdStream
m_UpsamplePipe, m_UpsamplePipe,
upsampleDispatchCount, upsampleDispatchCount,
{vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_UpsampleDescSets[mipLevel]).vulkanHandle)}, {vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_UpsampleDescSets[mipLevel]).vulkanHandle)},
vkcv::PushConstantData(nullptr, 0) vkcv::PushConstants(0)
); );
// image barrier between mips // image barrier between mips
p_Core->recordImageMemoryBarrier(cmdStream, m_Blur.getHandle()); p_Core->recordImageMemoryBarrier(cmdStream, m_Blur.getHandle());
...@@ -243,7 +243,7 @@ void BloomAndFlares::execLensFeaturePipe(const vkcv::CommandStreamHandle &cmdStr ...@@ -243,7 +243,7 @@ void BloomAndFlares::execLensFeaturePipe(const vkcv::CommandStreamHandle &cmdStr
m_LensFlarePipe, m_LensFlarePipe,
lensFeatureDispatchCount, lensFeatureDispatchCount,
{vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_LensFlareDescSet).vulkanHandle)}, {vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_LensFlareDescSet).vulkanHandle)},
vkcv::PushConstantData(nullptr, 0)); vkcv::PushConstants(0));
// upsample dispatch // upsample dispatch
p_Core->prepareImageForStorage(cmdStream, m_LensFeatures.getHandle()); p_Core->prepareImageForStorage(cmdStream, m_LensFeatures.getHandle());
...@@ -276,7 +276,7 @@ void BloomAndFlares::execLensFeaturePipe(const vkcv::CommandStreamHandle &cmdStr ...@@ -276,7 +276,7 @@ void BloomAndFlares::execLensFeaturePipe(const vkcv::CommandStreamHandle &cmdStr
m_UpsamplePipe, m_UpsamplePipe,
upsampleDispatchCount, upsampleDispatchCount,
{ vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_UpsampleLensFlareDescSets[i]).vulkanHandle) }, { vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_UpsampleLensFlareDescSets[i]).vulkanHandle) },
vkcv::PushConstantData(nullptr, 0) vkcv::PushConstants(0)
); );
// image barrier between mips // image barrier between mips
p_Core->recordImageMemoryBarrier(cmdStream, m_LensFeatures.getHandle()); p_Core->recordImageMemoryBarrier(cmdStream, m_LensFeatures.getHandle());
...@@ -309,6 +309,9 @@ void BloomAndFlares::execCompositePipe(const vkcv::CommandStreamHandle &cmdStrea ...@@ -309,6 +309,9 @@ void BloomAndFlares::execCompositePipe(const vkcv::CommandStreamHandle &cmdStrea
static_cast<uint32_t>(glm::ceil(dispatchCountY)), static_cast<uint32_t>(glm::ceil(dispatchCountY)),
1 1
}; };
vkcv::PushConstants pushConstants (sizeof(cameraForward));
pushConstants.appendDrawcall(cameraForward);
// bloom composite dispatch // bloom composite dispatch
p_Core->recordComputeDispatchToCmdStream( p_Core->recordComputeDispatchToCmdStream(
...@@ -316,7 +319,7 @@ void BloomAndFlares::execCompositePipe(const vkcv::CommandStreamHandle &cmdStrea ...@@ -316,7 +319,7 @@ void BloomAndFlares::execCompositePipe(const vkcv::CommandStreamHandle &cmdStrea
m_CompositePipe, m_CompositePipe,
compositeDispatchCount, compositeDispatchCount,
{vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_CompositeDescSet).vulkanHandle)}, {vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_CompositeDescSet).vulkanHandle)},
vkcv::PushConstantData((void*)&cameraForward, sizeof(cameraForward))); pushConstants);
} }
void BloomAndFlares::execWholePipeline(const vkcv::CommandStreamHandle &cmdStream, const vkcv::ImageHandle &colorAttachment, void BloomAndFlares::execWholePipeline(const vkcv::CommandStreamHandle &cmdStream, const vkcv::ImageHandle &colorAttachment,
......
...@@ -248,12 +248,13 @@ void ShadowMapping::recordShadowMapRendering( ...@@ -248,12 +248,13 @@ void ShadowMapping::recordShadowMapRendering(
voxelVolumeOffset, voxelVolumeOffset,
voxelVolumeExtent); voxelVolumeExtent);
m_lightInfoBuffer.fill({ lightInfo }); m_lightInfoBuffer.fill({ lightInfo });
std::vector<glm::mat4> mvpLight; vkcv::PushConstants shadowPushConstants (sizeof(glm::mat4));
for (const auto& m : modelMatrices) { for (const auto& m : modelMatrices) {
mvpLight.push_back(lightInfo.lightMatrix * m); shadowPushConstants.appendDrawcall(lightInfo.lightMatrix * m);
} }
const vkcv::PushConstantData shadowPushConstantData((void*)mvpLight.data(), sizeof(glm::mat4));
std::vector<vkcv::DrawcallInfo> drawcalls; std::vector<vkcv::DrawcallInfo> drawcalls;
for (const auto& mesh : meshes) { for (const auto& mesh : meshes) {
...@@ -264,7 +265,7 @@ void ShadowMapping::recordShadowMapRendering( ...@@ -264,7 +265,7 @@ void ShadowMapping::recordShadowMapRendering(
cmdStream, cmdStream,
m_shadowMapPass, m_shadowMapPass,
m_shadowMapPipe, m_shadowMapPipe,
shadowPushConstantData, shadowPushConstants,
drawcalls, drawcalls,
{ m_shadowMapDepth.getHandle() }); { m_shadowMapDepth.getHandle() });
m_corePtr->prepareImageForSampling(cmdStream, m_shadowMapDepth.getHandle()); m_corePtr->prepareImageForSampling(cmdStream, m_shadowMapDepth.getHandle());
...@@ -276,6 +277,9 @@ void ShadowMapping::recordShadowMapRendering( ...@@ -276,6 +277,9 @@ void ShadowMapping::recordShadowMapRendering(
dispatchCount[2] = 1; dispatchCount[2] = 1;
const uint32_t msaaSampleCount = msaaToSampleCount(msaa); const uint32_t msaaSampleCount = msaaToSampleCount(msaa);
vkcv::PushConstants msaaPushConstants (sizeof(msaaSampleCount));
msaaPushConstants.appendDrawcall(msaaSampleCount);
m_corePtr->prepareImageForStorage(cmdStream, m_shadowMap.getHandle()); m_corePtr->prepareImageForStorage(cmdStream, m_shadowMap.getHandle());
m_corePtr->recordComputeDispatchToCmdStream( m_corePtr->recordComputeDispatchToCmdStream(
...@@ -283,7 +287,7 @@ void ShadowMapping::recordShadowMapRendering( ...@@ -283,7 +287,7 @@ void ShadowMapping::recordShadowMapRendering(
m_depthToMomentsPipe, m_depthToMomentsPipe,
dispatchCount, dispatchCount,
{ vkcv::DescriptorSetUsage(0, m_corePtr->getDescriptorSet(m_depthToMomentsDescriptorSet).vulkanHandle) }, { vkcv::DescriptorSetUsage(0, m_corePtr->getDescriptorSet(m_depthToMomentsDescriptorSet).vulkanHandle) },
vkcv::PushConstantData((void*)&msaaSampleCount, sizeof(msaaSampleCount))); msaaPushConstants);
m_corePtr->prepareImageForSampling(cmdStream, m_shadowMap.getHandle()); m_corePtr->prepareImageForSampling(cmdStream, m_shadowMap.getHandle());
// blur X // blur X
...@@ -293,7 +297,7 @@ void ShadowMapping::recordShadowMapRendering( ...@@ -293,7 +297,7 @@ void ShadowMapping::recordShadowMapRendering(
m_shadowBlurXPipe, m_shadowBlurXPipe,
dispatchCount, dispatchCount,
{ vkcv::DescriptorSetUsage(0, m_corePtr->getDescriptorSet(m_shadowBlurXDescriptorSet).vulkanHandle) }, { vkcv::DescriptorSetUsage(0, m_corePtr->getDescriptorSet(m_shadowBlurXDescriptorSet).vulkanHandle) },
vkcv::PushConstantData(nullptr, 0)); vkcv::PushConstants(0));
m_corePtr->prepareImageForSampling(cmdStream, m_shadowMapIntermediate.getHandle()); m_corePtr->prepareImageForSampling(cmdStream, m_shadowMapIntermediate.getHandle());
// blur Y // blur Y
...@@ -303,7 +307,7 @@ void ShadowMapping::recordShadowMapRendering( ...@@ -303,7 +307,7 @@ void ShadowMapping::recordShadowMapRendering(
m_shadowBlurYPipe, m_shadowBlurYPipe,
dispatchCount, dispatchCount,
{ vkcv::DescriptorSetUsage(0, m_corePtr->getDescriptorSet(m_shadowBlurYDescriptorSet).vulkanHandle) }, { vkcv::DescriptorSetUsage(0, m_corePtr->getDescriptorSet(m_shadowBlurYDescriptorSet).vulkanHandle) },
vkcv::PushConstantData(nullptr, 0)); vkcv::PushConstants(0));
m_shadowMap.recordMipChainGeneration(cmdStream); m_shadowMap.recordMipChainGeneration(cmdStream);
m_corePtr->prepareImageForSampling(cmdStream, m_shadowMap.getHandle()); m_corePtr->prepareImageForSampling(cmdStream, m_shadowMap.getHandle());
} }
......
...@@ -119,10 +119,10 @@ Voxelization::Voxelization( ...@@ -119,10 +119,10 @@ Voxelization::Voxelization(
m_voxelizationPipe = m_corePtr->createGraphicsPipeline(voxelizationPipeConfig); m_voxelizationPipe = m_corePtr->createGraphicsPipeline(voxelizationPipeConfig);
vkcv::DescriptorWrites voxelizationDescriptorWrites; vkcv::DescriptorWrites voxelizationDescriptorWrites;
voxelizationDescriptorWrites.storageBufferWrites = { vkcv::StorageBufferDescriptorWrite(0, m_voxelBuffer.getHandle()) }; voxelizationDescriptorWrites.storageBufferWrites = { vkcv::BufferDescriptorWrite(0, m_voxelBuffer.getHandle()) };
voxelizationDescriptorWrites.uniformBufferWrites = { voxelizationDescriptorWrites.uniformBufferWrites = {
vkcv::UniformBufferDescriptorWrite(1, m_voxelInfoBuffer.getHandle()), vkcv::BufferDescriptorWrite(1, m_voxelInfoBuffer.getHandle()),
vkcv::UniformBufferDescriptorWrite(3, lightInfoBuffer) vkcv::BufferDescriptorWrite(3, lightInfoBuffer)
}; };
voxelizationDescriptorWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(4, shadowMap) }; voxelizationDescriptorWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(4, shadowMap) };
voxelizationDescriptorWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(5, shadowSampler) }; voxelizationDescriptorWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(5, shadowSampler) };
...@@ -180,7 +180,7 @@ Voxelization::Voxelization( ...@@ -180,7 +180,7 @@ Voxelization::Voxelization(
{ m_corePtr->getDescriptorSet(m_voxelResetDescriptorSet).layout }); { m_corePtr->getDescriptorSet(m_voxelResetDescriptorSet).layout });
vkcv::DescriptorWrites resetVoxelWrites; vkcv::DescriptorWrites resetVoxelWrites;
resetVoxelWrites.storageBufferWrites = { vkcv::StorageBufferDescriptorWrite(0, m_voxelBuffer.getHandle()) }; resetVoxelWrites.storageBufferWrites = { vkcv::BufferDescriptorWrite(0, m_voxelBuffer.getHandle()) };
m_corePtr->writeDescriptorSet(m_voxelResetDescriptorSet, resetVoxelWrites); m_corePtr->writeDescriptorSet(m_voxelResetDescriptorSet, resetVoxelWrites);
// buffer to image // buffer to image
...@@ -192,7 +192,7 @@ Voxelization::Voxelization( ...@@ -192,7 +192,7 @@ Voxelization::Voxelization(
{ m_corePtr->getDescriptorSet(m_bufferToImageDescriptorSet).layout }); { m_corePtr->getDescriptorSet(m_bufferToImageDescriptorSet).layout });
vkcv::DescriptorWrites bufferToImageDescriptorWrites; vkcv::DescriptorWrites bufferToImageDescriptorWrites;
bufferToImageDescriptorWrites.storageBufferWrites = { vkcv::StorageBufferDescriptorWrite(0, m_voxelBuffer.getHandle()) }; bufferToImageDescriptorWrites.storageBufferWrites = { vkcv::BufferDescriptorWrite(0, m_voxelBuffer.getHandle()) };
bufferToImageDescriptorWrites.storageImageWrites = { vkcv::StorageImageDescriptorWrite(1, m_voxelImageIntermediate.getHandle()) }; bufferToImageDescriptorWrites.storageImageWrites = { vkcv::StorageImageDescriptorWrite(1, m_voxelImageIntermediate.getHandle()) };
m_corePtr->writeDescriptorSet(m_bufferToImageDescriptorSet, bufferToImageDescriptorWrites); m_corePtr->writeDescriptorSet(m_bufferToImageDescriptorSet, bufferToImageDescriptorWrites);
...@@ -205,11 +205,11 @@ Voxelization::Voxelization( ...@@ -205,11 +205,11 @@ Voxelization::Voxelization(
{ m_corePtr->getDescriptorSet(m_secondaryBounceDescriptorSet).layout }); { m_corePtr->getDescriptorSet(m_secondaryBounceDescriptorSet).layout });
vkcv::DescriptorWrites secondaryBounceDescriptorWrites; vkcv::DescriptorWrites secondaryBounceDescriptorWrites;
secondaryBounceDescriptorWrites.storageBufferWrites = { vkcv::StorageBufferDescriptorWrite(0, m_voxelBuffer.getHandle()) }; secondaryBounceDescriptorWrites.storageBufferWrites = { vkcv::BufferDescriptorWrite(0, m_voxelBuffer.getHandle()) };
secondaryBounceDescriptorWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(1, m_voxelImageIntermediate.getHandle()) }; secondaryBounceDescriptorWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(1, m_voxelImageIntermediate.getHandle()) };
secondaryBounceDescriptorWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(2, voxelSampler) }; secondaryBounceDescriptorWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(2, voxelSampler) };
secondaryBounceDescriptorWrites.storageImageWrites = { vkcv::StorageImageDescriptorWrite(3, m_voxelImage.getHandle()) }; secondaryBounceDescriptorWrites.storageImageWrites = { vkcv::StorageImageDescriptorWrite(3, m_voxelImage.getHandle()) };
secondaryBounceDescriptorWrites.uniformBufferWrites = { vkcv::UniformBufferDescriptorWrite(4, m_voxelInfoBuffer.getHandle()) }; secondaryBounceDescriptorWrites.uniformBufferWrites = { vkcv::BufferDescriptorWrite(4, m_voxelInfoBuffer.getHandle()) };
m_corePtr->writeDescriptorSet(m_secondaryBounceDescriptorSet, secondaryBounceDescriptorWrites); m_corePtr->writeDescriptorSet(m_secondaryBounceDescriptorSet, secondaryBounceDescriptorWrites);
} }
...@@ -232,34 +232,36 @@ void Voxelization::voxelizeMeshes( ...@@ -232,34 +232,36 @@ void Voxelization::voxelizeMeshes(
const glm::mat4 voxelizationView = glm::translate(glm::mat4(1.f), -m_voxelInfo.offset); const glm::mat4 voxelizationView = glm::translate(glm::mat4(1.f), -m_voxelInfo.offset);
const glm::mat4 voxelizationViewProjection = voxelizationProjection * voxelizationView; const glm::mat4 voxelizationViewProjection = voxelizationProjection * voxelizationView;
std::vector<std::array<glm::mat4, 2>> voxelizationMatrices; vkcv::PushConstants voxelizationPushConstants (2 * sizeof(glm::mat4));
for (const auto& m : modelMatrices) { for (const auto& m : modelMatrices) {
voxelizationMatrices.push_back({ voxelizationViewProjection * m, m }); voxelizationPushConstants.appendDrawcall(std::array<glm::mat4, 2>{ voxelizationViewProjection * m, m });
} }
const vkcv::PushConstantData voxelizationPushConstantData((void*)voxelizationMatrices.data(), 2 * sizeof(glm::mat4));
// reset voxels // reset voxels
const uint32_t resetVoxelGroupSize = 64; const uint32_t resetVoxelGroupSize = 64;
uint32_t resetVoxelDispatchCount[3]; uint32_t resetVoxelDispatchCount[3];
resetVoxelDispatchCount[0] = glm::ceil(voxelCount / float(resetVoxelGroupSize)); resetVoxelDispatchCount[0] = glm::ceil(voxelCount / float(resetVoxelGroupSize));
resetVoxelDispatchCount[1] = 1; resetVoxelDispatchCount[1] = 1;
resetVoxelDispatchCount[2] = 1; resetVoxelDispatchCount[2] = 1;
vkcv::PushConstants voxelCountPushConstants (sizeof(voxelCount));
voxelCountPushConstants.appendDrawcall(voxelCount);
m_corePtr->recordComputeDispatchToCmdStream( m_corePtr->recordComputeDispatchToCmdStream(
cmdStream, cmdStream,
m_voxelResetPipe, m_voxelResetPipe,
resetVoxelDispatchCount, resetVoxelDispatchCount,
{ vkcv::DescriptorSetUsage(0, m_corePtr->getDescriptorSet(m_voxelResetDescriptorSet).vulkanHandle) }, { vkcv::DescriptorSetUsage(0, m_corePtr->getDescriptorSet(m_voxelResetDescriptorSet).vulkanHandle) },
vkcv::PushConstantData(&voxelCount, sizeof(voxelCount))); voxelCountPushConstants);
m_corePtr->recordBufferMemoryBarrier(cmdStream, m_voxelBuffer.getHandle()); m_corePtr->recordBufferMemoryBarrier(cmdStream, m_voxelBuffer.getHandle());
// voxelization // voxelization
std::vector<vkcv::DrawcallInfo> drawcalls; std::vector<vkcv::DrawcallInfo> drawcalls;
for (int i = 0; i < meshes.size(); i++) { for (size_t i = 0; i < meshes.size(); i++) {
drawcalls.push_back(vkcv::DrawcallInfo( drawcalls.push_back(vkcv::DrawcallInfo(
meshes[i], meshes[i],
{ {
vkcv::DescriptorSetUsage(0, m_corePtr->getDescriptorSet(m_voxelizationDescriptorSet).vulkanHandle), vkcv::DescriptorSetUsage(0, m_corePtr->getDescriptorSet(m_voxelizationDescriptorSet).vulkanHandle),
vkcv::DescriptorSetUsage(1, m_corePtr->getDescriptorSet(perMeshDescriptorSets[i]).vulkanHandle) vkcv::DescriptorSetUsage(1, m_corePtr->getDescriptorSet(perMeshDescriptorSets[i]).vulkanHandle)
...@@ -271,7 +273,7 @@ void Voxelization::voxelizeMeshes( ...@@ -271,7 +273,7 @@ void Voxelization::voxelizeMeshes(
cmdStream, cmdStream,
m_voxelizationPass, m_voxelizationPass,
m_voxelizationPipe, m_voxelizationPipe,
voxelizationPushConstantData, voxelizationPushConstants,
drawcalls, drawcalls,
{ m_dummyRenderTarget.getHandle() }); { m_dummyRenderTarget.getHandle() });
...@@ -287,7 +289,7 @@ void Voxelization::voxelizeMeshes( ...@@ -287,7 +289,7 @@ void Voxelization::voxelizeMeshes(
m_bufferToImagePipe, m_bufferToImagePipe,
bufferToImageDispatchCount, bufferToImageDispatchCount,
{ vkcv::DescriptorSetUsage(0, m_corePtr->getDescriptorSet(m_bufferToImageDescriptorSet).vulkanHandle) }, { vkcv::DescriptorSetUsage(0, m_corePtr->getDescriptorSet(m_bufferToImageDescriptorSet).vulkanHandle) },
vkcv::PushConstantData(nullptr, 0)); vkcv::PushConstants(0));
m_corePtr->recordImageMemoryBarrier(cmdStream, m_voxelImageIntermediate.getHandle()); m_corePtr->recordImageMemoryBarrier(cmdStream, m_voxelImageIntermediate.getHandle());
...@@ -303,7 +305,7 @@ void Voxelization::voxelizeMeshes( ...@@ -303,7 +305,7 @@ void Voxelization::voxelizeMeshes(
m_secondaryBouncePipe, m_secondaryBouncePipe,
bufferToImageDispatchCount, bufferToImageDispatchCount,
{ vkcv::DescriptorSetUsage(0, m_corePtr->getDescriptorSet(m_secondaryBounceDescriptorSet).vulkanHandle) }, { vkcv::DescriptorSetUsage(0, m_corePtr->getDescriptorSet(m_secondaryBounceDescriptorSet).vulkanHandle) },
vkcv::PushConstantData(nullptr, 0)); vkcv::PushConstants(0));
m_voxelImage.recordMipChainGeneration(cmdStream); m_voxelImage.recordMipChainGeneration(cmdStream);
m_corePtr->recordImageMemoryBarrier(cmdStream, m_voxelImage.getHandle()); m_corePtr->recordImageMemoryBarrier(cmdStream, m_voxelImage.getHandle());
...@@ -319,7 +321,8 @@ void Voxelization::renderVoxelVisualisation( ...@@ -319,7 +321,8 @@ void Voxelization::renderVoxelVisualisation(
const std::vector<vkcv::ImageHandle>& renderTargets, const std::vector<vkcv::ImageHandle>& renderTargets,
uint32_t mipLevel) { uint32_t mipLevel) {
const vkcv::PushConstantData voxelVisualisationPushConstantData((void*)&viewProjectin, sizeof(glm::mat4)); vkcv::PushConstants voxelVisualisationPushConstants (sizeof(glm::mat4));
voxelVisualisationPushConstants.appendDrawcall(viewProjectin);
mipLevel = std::clamp(mipLevel, (uint32_t)0, m_voxelImage.getMipCount()-1); mipLevel = std::clamp(mipLevel, (uint32_t)0, m_voxelImage.getMipCount()-1);
...@@ -328,7 +331,7 @@ void Voxelization::renderVoxelVisualisation( ...@@ -328,7 +331,7 @@ void Voxelization::renderVoxelVisualisation(
voxelVisualisationDescriptorWrite.storageImageWrites = voxelVisualisationDescriptorWrite.storageImageWrites =
{ vkcv::StorageImageDescriptorWrite(0, m_voxelImage.getHandle(), mipLevel) }; { vkcv::StorageImageDescriptorWrite(0, m_voxelImage.getHandle(), mipLevel) };
voxelVisualisationDescriptorWrite.uniformBufferWrites = voxelVisualisationDescriptorWrite.uniformBufferWrites =
{ vkcv::UniformBufferDescriptorWrite(1, m_voxelInfoBuffer.getHandle()) }; { vkcv::BufferDescriptorWrite(1, m_voxelInfoBuffer.getHandle()) };
m_corePtr->writeDescriptorSet(m_visualisationDescriptorSet, voxelVisualisationDescriptorWrite); m_corePtr->writeDescriptorSet(m_visualisationDescriptorSet, voxelVisualisationDescriptorWrite);
uint32_t drawVoxelCount = voxelCount / exp2(mipLevel); uint32_t drawVoxelCount = voxelCount / exp2(mipLevel);
...@@ -342,7 +345,7 @@ void Voxelization::renderVoxelVisualisation( ...@@ -342,7 +345,7 @@ void Voxelization::renderVoxelVisualisation(
cmdStream, cmdStream,
m_visualisationPass, m_visualisationPass,
m_visualisationPipe, m_visualisationPipe,
voxelVisualisationPushConstantData, voxelVisualisationPushConstants,
{ drawcall }, { drawcall },
renderTargets); renderTargets);
} }
......
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
#include "vkcv/gui/GUI.hpp" #include "vkcv/gui/GUI.hpp"
#include "ShadowMapping.hpp" #include "ShadowMapping.hpp"
#include "BloomAndFlares.hpp" #include "BloomAndFlares.hpp"
#include <vkcv/upscaling/FSRUpscaling.hpp>
#include <vkcv/upscaling/BilinearUpscaling.hpp>
int main(int argc, const char** argv) { int main(int argc, const char** argv) {
const char* applicationName = "Voxelization"; const char* applicationName = "Voxelization";
...@@ -27,11 +29,11 @@ int main(int argc, const char** argv) { ...@@ -27,11 +29,11 @@ int main(int argc, const char** argv) {
true true
); );
bool isFullscreen = false; bool isFullscreen = false;
int windowedWidthBackup = windowWidth; uint32_t windowedWidthBackup = windowWidth;
int windowedHeightBackup = windowHeight; uint32_t windowedHeightBackup = windowHeight;
int windowedPosXBackup; int windowedPosXBackup;
int windowedPosYBackup; int windowedPosYBackup;
glfwGetWindowPos(window.getWindow(), &windowedPosXBackup, &windowedPosYBackup); glfwGetWindowPos(window.getWindow(), &windowedPosXBackup, &windowedPosYBackup);
window.e_key.add([&](int key, int scancode, int action, int mods) { window.e_key.add([&](int key, int scancode, int action, int mods) {
...@@ -85,7 +87,7 @@ int main(int argc, const char** argv) { ...@@ -85,7 +87,7 @@ int main(int argc, const char** argv) {
VK_MAKE_VERSION(0, 0, 1), VK_MAKE_VERSION(0, 0, 1),
{ vk::QueueFlagBits::eTransfer,vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eCompute }, { vk::QueueFlagBits::eTransfer,vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eCompute },
{}, {},
{ "VK_KHR_swapchain" } { "VK_KHR_swapchain", "VK_KHR_shader_float16_int8", "VK_KHR_16bit_storage" }
); );
vkcv::asset::Scene mesh; vkcv::asset::Scene mesh;
...@@ -111,7 +113,7 @@ int main(int argc, const char** argv) { ...@@ -111,7 +113,7 @@ int main(int argc, const char** argv) {
std::vector<std::vector<vkcv::VertexBufferBinding>> vertexBufferBindings; std::vector<std::vector<vkcv::VertexBufferBinding>> vertexBufferBindings;
std::vector<vkcv::asset::VertexAttribute> vAttributes; std::vector<vkcv::asset::VertexAttribute> vAttributes;
for (int i = 0; i < scene.vertexGroups.size(); i++) { for (size_t i = 0; i < scene.vertexGroups.size(); i++) {
vBuffers.push_back(scene.vertexGroups[i].vertexBuffer.data); vBuffers.push_back(scene.vertexGroups[i].vertexBuffer.data);
iBuffers.push_back(scene.vertexGroups[i].indexBuffer.data); iBuffers.push_back(scene.vertexGroups[i].indexBuffer.data);
...@@ -393,6 +395,9 @@ int main(int argc, const char** argv) { ...@@ -393,6 +395,9 @@ int main(int argc, const char** argv) {
else { else {
resolvedColorBuffer = colorBuffer; resolvedColorBuffer = colorBuffer;
} }
vkcv::ImageHandle swapBuffer = core.createImage(colorBufferFormat, windowWidth, windowHeight, 1, false, true).getHandle();
vkcv::ImageHandle swapBuffer2 = core.createImage(colorBufferFormat, windowWidth, windowHeight, 1, false, true).getHandle();
const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle();
...@@ -421,6 +426,18 @@ int main(int argc, const char** argv) { ...@@ -421,6 +426,18 @@ int main(int argc, const char** argv) {
vkcv::PipelineHandle tonemappingPipeline = core.createComputePipeline( vkcv::PipelineHandle tonemappingPipeline = core.createComputePipeline(
tonemappingProgram, tonemappingProgram,
{ core.getDescriptorSet(tonemappingDescriptorSet).layout }); { core.getDescriptorSet(tonemappingDescriptorSet).layout });
// tonemapping compute shader
vkcv::ShaderProgram postEffectsProgram;
compiler.compile(vkcv::ShaderStage::COMPUTE, "resources/shaders/postEffects.comp",
[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
postEffectsProgram.addShader(shaderStage, path);
});
vkcv::DescriptorSetHandle postEffectsDescriptorSet = core.createDescriptorSet(
postEffectsProgram.getReflectedDescriptors()[0]);
vkcv::PipelineHandle postEffectsPipeline = core.createComputePipeline(
postEffectsProgram,
{ core.getDescriptorSet(postEffectsDescriptorSet).layout });
// resolve compute shader // resolve compute shader
vkcv::ShaderProgram resolveProgram; vkcv::ShaderProgram resolveProgram;
...@@ -438,7 +455,8 @@ int main(int argc, const char** argv) { ...@@ -438,7 +455,8 @@ int main(int argc, const char** argv) {
vkcv::SamplerFilterType::NEAREST, vkcv::SamplerFilterType::NEAREST,
vkcv::SamplerFilterType::NEAREST, vkcv::SamplerFilterType::NEAREST,
vkcv::SamplerMipmapMode::NEAREST, vkcv::SamplerMipmapMode::NEAREST,
vkcv::SamplerAddressMode::CLAMP_TO_EDGE); vkcv::SamplerAddressMode::CLAMP_TO_EDGE
);
// model matrices per mesh // model matrices per mesh
std::vector<glm::mat4> modelMatrices; std::vector<glm::mat4> modelMatrices;
...@@ -452,14 +470,14 @@ int main(int argc, const char** argv) { ...@@ -452,14 +470,14 @@ int main(int argc, const char** argv) {
// prepare meshes // prepare meshes
std::vector<vkcv::Mesh> meshes; std::vector<vkcv::Mesh> meshes;
for (int i = 0; i < scene.vertexGroups.size(); i++) { for (size_t i = 0; i < scene.vertexGroups.size(); i++) {
vkcv::Mesh mesh(vertexBufferBindings[i], indexBuffers[i].getVulkanHandle(), scene.vertexGroups[i].numIndices); vkcv::Mesh mesh(vertexBufferBindings[i], indexBuffers[i].getVulkanHandle(), scene.vertexGroups[i].numIndices);
meshes.push_back(mesh); meshes.push_back(mesh);
} }
std::vector<vkcv::DrawcallInfo> drawcalls; std::vector<vkcv::DrawcallInfo> drawcalls;
std::vector<vkcv::DrawcallInfo> prepassDrawcalls; std::vector<vkcv::DrawcallInfo> prepassDrawcalls;
for (int i = 0; i < meshes.size(); i++) { for (size_t i = 0; i < meshes.size(); i++) {
drawcalls.push_back(vkcv::DrawcallInfo(meshes[i], { drawcalls.push_back(vkcv::DrawcallInfo(meshes[i], {
vkcv::DescriptorSetUsage(0, core.getDescriptorSet(forwardShadingDescriptorSet).vulkanHandle), vkcv::DescriptorSetUsage(0, core.getDescriptorSet(forwardShadingDescriptorSet).vulkanHandle),
...@@ -473,7 +491,8 @@ int main(int argc, const char** argv) { ...@@ -473,7 +491,8 @@ int main(int argc, const char** argv) {
vkcv::SamplerFilterType::LINEAR, vkcv::SamplerFilterType::LINEAR,
vkcv::SamplerFilterType::LINEAR, vkcv::SamplerFilterType::LINEAR,
vkcv::SamplerMipmapMode::LINEAR, vkcv::SamplerMipmapMode::LINEAR,
vkcv::SamplerAddressMode::CLAMP_TO_EDGE); vkcv::SamplerAddressMode::CLAMP_TO_EDGE
);
ShadowMapping shadowMapping(&core, vertexLayout); ShadowMapping shadowMapping(&core, vertexLayout);
...@@ -511,10 +530,10 @@ int main(int argc, const char** argv) { ...@@ -511,10 +530,10 @@ int main(int argc, const char** argv) {
// write forward pass descriptor set // write forward pass descriptor set
vkcv::DescriptorWrites forwardDescriptorWrites; vkcv::DescriptorWrites forwardDescriptorWrites;
forwardDescriptorWrites.uniformBufferWrites = { forwardDescriptorWrites.uniformBufferWrites = {
vkcv::UniformBufferDescriptorWrite(0, shadowMapping.getLightInfoBuffer()), vkcv::BufferDescriptorWrite(0, shadowMapping.getLightInfoBuffer()),
vkcv::UniformBufferDescriptorWrite(3, cameraPosBuffer.getHandle()), vkcv::BufferDescriptorWrite(3, cameraPosBuffer.getHandle()),
vkcv::UniformBufferDescriptorWrite(6, voxelization.getVoxelInfoBufferHandle()), vkcv::BufferDescriptorWrite(6, voxelization.getVoxelInfoBufferHandle()),
vkcv::UniformBufferDescriptorWrite(7, volumetricSettingsBuffer.getHandle())}; vkcv::BufferDescriptorWrite(7, volumetricSettingsBuffer.getHandle())};
forwardDescriptorWrites.sampledImageWrites = { forwardDescriptorWrites.sampledImageWrites = {
vkcv::SampledImageDescriptorWrite(1, shadowMapping.getShadowMap()), vkcv::SampledImageDescriptorWrite(1, shadowMapping.getShadowMap()),
vkcv::SampledImageDescriptorWrite(4, voxelization.getVoxelImageHandle()) }; vkcv::SampledImageDescriptorWrite(4, voxelization.getVoxelImageHandle()) };
...@@ -523,6 +542,27 @@ int main(int argc, const char** argv) { ...@@ -523,6 +542,27 @@ int main(int argc, const char** argv) {
vkcv::SamplerDescriptorWrite(5, voxelSampler) }; vkcv::SamplerDescriptorWrite(5, voxelSampler) };
core.writeDescriptorSet(forwardShadingDescriptorSet, forwardDescriptorWrites); core.writeDescriptorSet(forwardShadingDescriptorSet, forwardDescriptorWrites);
vkcv::upscaling::FSRUpscaling upscaling (core);
uint32_t fsrWidth = windowWidth, fsrHeight = windowHeight;
vkcv::upscaling::FSRQualityMode fsrMode = vkcv::upscaling::FSRQualityMode::NONE;
int fsrModeIndex = static_cast<int>(fsrMode);
const std::vector<const char*> fsrModeNames = {
"None",
"Ultra Quality",
"Quality",
"Balanced",
"Performance"
};
bool fsrMipLoadBiasFlag = true;
bool fsrMipLoadBiasFlagBackup = fsrMipLoadBiasFlag;
vkcv::upscaling::BilinearUpscaling upscaling1 (core);
bool bilinearUpscaling = false;
vkcv::gui::GUI gui(core, window); vkcv::gui::GUI gui(core, window);
glm::vec2 lightAnglesDegree = glm::vec2(90.f, 0.f); glm::vec2 lightAnglesDegree = glm::vec2(90.f, 0.f);
...@@ -550,22 +590,72 @@ int main(int argc, const char** argv) { ...@@ -550,22 +590,72 @@ int main(int argc, const char** argv) {
if (!core.beginFrame(swapchainWidth, swapchainHeight)) { if (!core.beginFrame(swapchainWidth, swapchainHeight)) {
continue; continue;
} }
if ((swapchainWidth != windowWidth) || ((swapchainHeight != windowHeight))) { uint32_t width, height;
depthBuffer = core.createImage(depthBufferFormat, swapchainWidth, swapchainHeight, 1, false, false, false, msaa).getHandle(); vkcv::upscaling::getFSRResolution(
colorBuffer = core.createImage(colorBufferFormat, swapchainWidth, swapchainHeight, 1, false, colorBufferRequiresStorage, true, msaa).getHandle(); fsrMode,
swapchainWidth, swapchainHeight,
width, height
);
if ((width != fsrWidth) || ((height != fsrHeight)) || (fsrMipLoadBiasFlagBackup != fsrMipLoadBiasFlag)) {
fsrWidth = width;
fsrHeight = height;
fsrMipLoadBiasFlagBackup = fsrMipLoadBiasFlag;
colorSampler = core.createSampler(
vkcv::SamplerFilterType::LINEAR,
vkcv::SamplerFilterType::LINEAR,
vkcv::SamplerMipmapMode::LINEAR,
vkcv::SamplerAddressMode::REPEAT,
fsrMipLoadBiasFlag? vkcv::upscaling::getFSRLodBias(fsrMode) : 0.0f
);
for (size_t i = 0; i < scene.materials.size(); i++) {
vkcv::DescriptorWrites setWrites;
setWrites.samplerWrites = {
vkcv::SamplerDescriptorWrite(1, colorSampler),
};
core.writeDescriptorSet(materialDescriptorSets[i], setWrites);
}
depthBuffer = core.createImage(
depthBufferFormat,
fsrWidth, fsrHeight, 1,
false, false, false,
msaa
).getHandle();
colorBuffer = core.createImage(
colorBufferFormat,
fsrWidth, fsrHeight, 1,
false, colorBufferRequiresStorage, true,
msaa
).getHandle();
if (usingMsaa) { if (usingMsaa) {
resolvedColorBuffer = core.createImage(colorBufferFormat, swapchainWidth, swapchainHeight, 1, false, true, true).getHandle(); resolvedColorBuffer = core.createImage(
} colorBufferFormat,
else { fsrWidth, fsrHeight, 1,
false, true, true
).getHandle();
} else {
resolvedColorBuffer = colorBuffer; resolvedColorBuffer = colorBuffer;
} }
windowWidth = swapchainWidth; swapBuffer = core.createImage(
windowHeight = swapchainHeight; colorBufferFormat,
fsrWidth, fsrHeight, 1,
bloomFlares.updateImageDimensions(windowWidth, windowHeight); false, true
).getHandle();
swapBuffer2 = core.createImage(
colorBufferFormat,
swapchainWidth, swapchainHeight, 1,
false, true
).getHandle();
bloomFlares.updateImageDimensions(swapchainWidth, swapchainHeight);
} }
auto end = std::chrono::system_clock::now(); auto end = std::chrono::system_clock::now();
...@@ -575,9 +665,17 @@ int main(int argc, const char** argv) { ...@@ -575,9 +665,17 @@ int main(int argc, const char** argv) {
vkcv::DescriptorWrites tonemappingDescriptorWrites; vkcv::DescriptorWrites tonemappingDescriptorWrites;
tonemappingDescriptorWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(0, resolvedColorBuffer) }; tonemappingDescriptorWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(0, resolvedColorBuffer) };
tonemappingDescriptorWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(1, colorSampler) }; tonemappingDescriptorWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(1, colorSampler) };
tonemappingDescriptorWrites.storageImageWrites = { vkcv::StorageImageDescriptorWrite(2, swapchainInput) }; tonemappingDescriptorWrites.storageImageWrites = { vkcv::StorageImageDescriptorWrite(2, swapBuffer) };
core.writeDescriptorSet(tonemappingDescriptorSet, tonemappingDescriptorWrites); core.writeDescriptorSet(tonemappingDescriptorSet, tonemappingDescriptorWrites);
// update descriptor sets which use swapchain image
vkcv::DescriptorWrites postEffectsDescriptorWrites;
postEffectsDescriptorWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(0, swapBuffer2) };
postEffectsDescriptorWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(1, colorSampler) };
postEffectsDescriptorWrites.storageImageWrites = { vkcv::StorageImageDescriptorWrite(2, swapchainInput) };
core.writeDescriptorSet(postEffectsDescriptorSet, postEffectsDescriptorWrites);
// update resolve descriptor, color images could be changed // update resolve descriptor, color images could be changed
vkcv::DescriptorWrites resolveDescriptorWrites; vkcv::DescriptorWrites resolveDescriptorWrites;
...@@ -618,29 +716,32 @@ int main(int argc, const char** argv) { ...@@ -618,29 +716,32 @@ int main(int argc, const char** argv) {
// depth prepass // depth prepass
const glm::mat4 viewProjectionCamera = cameraManager.getActiveCamera().getMVP(); const glm::mat4 viewProjectionCamera = cameraManager.getActiveCamera().getMVP();
vkcv::PushConstants prepassPushConstants (sizeof(glm::mat4));
std::vector<glm::mat4> prepassMatrices; std::vector<glm::mat4> prepassMatrices;
for (const auto& m : modelMatrices) { for (const auto& m : modelMatrices) {
prepassMatrices.push_back(viewProjectionCamera * m); prepassPushConstants.appendDrawcall(viewProjectionCamera * m);
} }
const vkcv::PushConstantData prepassPushConstantData((void*)prepassMatrices.data(), sizeof(glm::mat4));
const std::vector<vkcv::ImageHandle> prepassRenderTargets = { depthBuffer }; const std::vector<vkcv::ImageHandle> prepassRenderTargets = { depthBuffer };
core.recordDrawcallsToCmdStream( core.recordDrawcallsToCmdStream(
cmdStream, cmdStream,
prepassPass, prepassPass,
prepassPipeline, prepassPipeline,
prepassPushConstantData, prepassPushConstants,
prepassDrawcalls, prepassDrawcalls,
prepassRenderTargets); prepassRenderTargets);
core.recordImageMemoryBarrier(cmdStream, depthBuffer); core.recordImageMemoryBarrier(cmdStream, depthBuffer);
vkcv::PushConstants pushConstants (2 * sizeof(glm::mat4));
// main pass // main pass
std::vector<std::array<glm::mat4, 2>> mainPassMatrices;
for (const auto& m : modelMatrices) { for (const auto& m : modelMatrices) {
mainPassMatrices.push_back({ viewProjectionCamera * m, m }); pushConstants.appendDrawcall(std::array<glm::mat4, 2>{ viewProjectionCamera * m, m });
} }
VolumetricSettings volumeSettings; VolumetricSettings volumeSettings;
...@@ -648,37 +749,46 @@ int main(int argc, const char** argv) { ...@@ -648,37 +749,46 @@ int main(int argc, const char** argv) {
volumeSettings.absorptionCoefficient = absorptionColor * absorptionDensity; volumeSettings.absorptionCoefficient = absorptionColor * absorptionDensity;
volumeSettings.ambientLight = volumetricAmbient; volumeSettings.ambientLight = volumetricAmbient;
volumetricSettingsBuffer.fill({ volumeSettings }); volumetricSettingsBuffer.fill({ volumeSettings });
const vkcv::PushConstantData pushConstantData((void*)mainPassMatrices.data(), 2 * sizeof(glm::mat4));
const std::vector<vkcv::ImageHandle> renderTargets = { colorBuffer, depthBuffer }; const std::vector<vkcv::ImageHandle> renderTargets = { colorBuffer, depthBuffer };
core.recordDrawcallsToCmdStream( core.recordDrawcallsToCmdStream(
cmdStream, cmdStream,
forwardPass, forwardPass,
forwardPipeline, forwardPipeline,
pushConstantData, pushConstants,
drawcalls, drawcalls,
renderTargets); renderTargets);
if (renderVoxelVis) { if (renderVoxelVis) {
voxelization.renderVoxelVisualisation(cmdStream, viewProjectionCamera, renderTargets, voxelVisualisationMip); voxelization.renderVoxelVisualisation(cmdStream, viewProjectionCamera, renderTargets, voxelVisualisationMip);
} }
vkcv::PushConstants skySettingsPushConstants (sizeof(skySettings));
skySettingsPushConstants.appendDrawcall(skySettings);
// sky // sky
core.recordDrawcallsToCmdStream( core.recordDrawcallsToCmdStream(
cmdStream, cmdStream,
skyPass, skyPass,
skyPipe, skyPipe,
vkcv::PushConstantData((void*)&skySettings, sizeof(skySettings)), skySettingsPushConstants,
{ vkcv::DrawcallInfo(vkcv::Mesh({}, nullptr, 3), {}) }, { vkcv::DrawcallInfo(vkcv::Mesh({}, nullptr, 3), {}) },
renderTargets); renderTargets);
const uint32_t fullscreenLocalGroupSize = 8; const uint32_t fullscreenLocalGroupSize = 8;
const uint32_t fulsscreenDispatchCount[3] = {
static_cast<uint32_t>(glm::ceil(windowWidth / static_cast<float>(fullscreenLocalGroupSize))), uint32_t fulsscreenDispatchCount [3];
static_cast<uint32_t>(glm::ceil(windowHeight / static_cast<float>(fullscreenLocalGroupSize))),
1 fulsscreenDispatchCount[0] = static_cast<uint32_t>(
}; glm::ceil(fsrWidth / static_cast<float>(fullscreenLocalGroupSize))
);
fulsscreenDispatchCount[1] = static_cast<uint32_t>(
glm::ceil(fsrHeight / static_cast<float>(fullscreenLocalGroupSize))
);
fulsscreenDispatchCount[2] = 1;
if (usingMsaa) { if (usingMsaa) {
if (msaaCustomResolve) { if (msaaCustomResolve) {
...@@ -692,7 +802,7 @@ int main(int argc, const char** argv) { ...@@ -692,7 +802,7 @@ int main(int argc, const char** argv) {
resolvePipeline, resolvePipeline,
fulsscreenDispatchCount, fulsscreenDispatchCount,
{ vkcv::DescriptorSetUsage(0, core.getDescriptorSet(resolveDescriptorSet).vulkanHandle) }, { vkcv::DescriptorSetUsage(0, core.getDescriptorSet(resolveDescriptorSet).vulkanHandle) },
vkcv::PushConstantData(nullptr, 0)); vkcv::PushConstants(0));
core.recordImageMemoryBarrier(cmdStream, resolvedColorBuffer); core.recordImageMemoryBarrier(cmdStream, resolvedColorBuffer);
} }
...@@ -701,21 +811,58 @@ int main(int argc, const char** argv) { ...@@ -701,21 +811,58 @@ int main(int argc, const char** argv) {
} }
} }
bloomFlares.execWholePipeline(cmdStream, resolvedColorBuffer, windowWidth, windowHeight, bloomFlares.execWholePipeline(cmdStream, resolvedColorBuffer, fsrWidth, fsrHeight,
glm::normalize(cameraManager.getActiveCamera().getFront())); glm::normalize(cameraManager.getActiveCamera().getFront())
);
core.prepareImageForStorage(cmdStream, swapchainInput); core.prepareImageForStorage(cmdStream, swapBuffer);
core.prepareImageForSampling(cmdStream, resolvedColorBuffer); core.prepareImageForSampling(cmdStream, resolvedColorBuffer);
auto timeSinceStart = std::chrono::duration_cast<std::chrono::microseconds>(end - appStartTime);
float timeF = static_cast<float>(timeSinceStart.count()) * 0.01;
core.recordComputeDispatchToCmdStream( core.recordComputeDispatchToCmdStream(
cmdStream, cmdStream,
tonemappingPipeline, tonemappingPipeline,
fulsscreenDispatchCount, fulsscreenDispatchCount,
{ vkcv::DescriptorSetUsage(0, core.getDescriptorSet(tonemappingDescriptorSet).vulkanHandle) }, { vkcv::DescriptorSetUsage(0, core.getDescriptorSet(
vkcv::PushConstantData(&timeF, sizeof(timeF))); tonemappingDescriptorSet
).vulkanHandle) },
vkcv::PushConstants(0)
);
core.prepareImageForStorage(cmdStream, swapBuffer2);
core.prepareImageForSampling(cmdStream, swapBuffer);
if (bilinearUpscaling) {
upscaling1.recordUpscaling(cmdStream, swapBuffer, swapBuffer2);
} else {
upscaling.recordUpscaling(cmdStream, swapBuffer, swapBuffer2);
}
core.prepareImageForStorage(cmdStream, swapchainInput);
core.prepareImageForSampling(cmdStream, swapBuffer2);
auto timeSinceStart = std::chrono::duration_cast<std::chrono::microseconds>(end - appStartTime);
float timeF = static_cast<float>(timeSinceStart.count()) * 0.01f;
vkcv::PushConstants timePushConstants (sizeof(timeF));
timePushConstants.appendDrawcall(timeF);
fulsscreenDispatchCount[0] = static_cast<uint32_t>(
glm::ceil(swapchainWidth / static_cast<float>(fullscreenLocalGroupSize))
);
fulsscreenDispatchCount[1] = static_cast<uint32_t>(
glm::ceil(swapchainHeight / static_cast<float>(fullscreenLocalGroupSize))
);
core.recordComputeDispatchToCmdStream(
cmdStream,
postEffectsPipeline,
fulsscreenDispatchCount,
{ vkcv::DescriptorSetUsage(0, core.getDescriptorSet(
postEffectsDescriptorSet
).vulkanHandle) },
timePushConstants
);
// present and end // present and end
core.prepareSwapchainImageForPresent(cmdStream); core.prepareSwapchainImageForPresent(cmdStream);
...@@ -743,12 +890,25 @@ int main(int argc, const char** argv) { ...@@ -743,12 +890,25 @@ int main(int argc, const char** argv) {
ImGui::DragFloat("Voxelization extent", &voxelizationExtent, 1.f, 0.f); ImGui::DragFloat("Voxelization extent", &voxelizationExtent, 1.f, 0.f);
voxelizationExtent = std::max(voxelizationExtent, 1.f); voxelizationExtent = std::max(voxelizationExtent, 1.f);
voxelVisualisationMip = std::max(voxelVisualisationMip, 0); voxelVisualisationMip = std::max(voxelVisualisationMip, 0);
ImGui::ColorEdit3("Scattering color", &scatteringColor.x); ImGui::ColorEdit3("Scattering color", &scatteringColor.x);
ImGui::DragFloat("Scattering density", &scatteringDensity, 0.0001); ImGui::DragFloat("Scattering density", &scatteringDensity, 0.0001);
ImGui::ColorEdit3("Absorption color", &absorptionColor.x); ImGui::ColorEdit3("Absorption color", &absorptionColor.x);
ImGui::DragFloat("Absorption density", &absorptionDensity, 0.0001); ImGui::DragFloat("Absorption density", &absorptionDensity, 0.0001);
ImGui::DragFloat("Volumetric ambient", &volumetricAmbient, 0.002); ImGui::DragFloat("Volumetric ambient", &volumetricAmbient, 0.002);
float fsrSharpness = upscaling.getSharpness();
ImGui::Combo("FSR Quality Mode", &fsrModeIndex, fsrModeNames.data(), fsrModeNames.size());
ImGui::DragFloat("FSR Sharpness", &fsrSharpness, 0.001, 0.0f, 1.0f);
ImGui::Checkbox("FSR Mip Lod Bias", &fsrMipLoadBiasFlag);
ImGui::Checkbox("Bilinear Upscaling", &bilinearUpscaling);
if ((fsrModeIndex >= 0) && (fsrModeIndex <= 4)) {
fsrMode = static_cast<vkcv::upscaling::FSRQualityMode>(fsrModeIndex);
}
upscaling.setSharpness(fsrSharpness);
if (ImGui::Button("Reload forward pass")) { if (ImGui::Button("Reload forward pass")) {
......
...@@ -19,7 +19,7 @@ namespace vkcv { ...@@ -19,7 +19,7 @@ namespace vkcv {
return; return;
} }
m_stagingBuffer = createBuffer(BufferType::STAGING, 1024 * 1024, BufferMemoryType::HOST_VISIBLE); m_stagingBuffer = createBuffer(BufferType::STAGING, 1024 * 1024, BufferMemoryType::HOST_VISIBLE, false);
} }
BufferManager::~BufferManager() noexcept { BufferManager::~BufferManager() noexcept {
...@@ -28,33 +28,7 @@ namespace vkcv { ...@@ -28,33 +28,7 @@ namespace vkcv {
} }
} }
/** BufferHandle BufferManager::createBuffer(BufferType type, size_t size, BufferMemoryType memoryType, bool supportIndirect) {
* @brief searches memory type index for buffer allocation, combines requirements of buffer and application
* @param physicalMemoryProperties Memory Properties of physical device
* @param typeBits Bit field for suitable memory types
* @param requirements Property flags that are required
* @return memory type index for Buffer
*/
uint32_t searchBufferMemoryType(const vk::PhysicalDeviceMemoryProperties& physicalMemoryProperties, uint32_t typeBits, vk::MemoryPropertyFlags requirements) {
const uint32_t memoryCount = physicalMemoryProperties.memoryTypeCount;
for (uint32_t memoryIndex = 0; memoryIndex < memoryCount; ++memoryIndex) {
const uint32_t memoryTypeBits = (1 << memoryIndex);
const bool isRequiredMemoryType = typeBits & memoryTypeBits;
const vk::MemoryPropertyFlags properties =
physicalMemoryProperties.memoryTypes[memoryIndex].propertyFlags;
const bool hasRequiredProperties =
(properties & requirements) == requirements;
if (isRequiredMemoryType && hasRequiredProperties)
return static_cast<int32_t>(memoryIndex);
}
// failed to find memory type
return -1;
}
BufferHandle BufferManager::createBuffer(BufferType type, size_t size, BufferMemoryType memoryType) {
vk::BufferCreateFlags createFlags; vk::BufferCreateFlags createFlags;
vk::BufferUsageFlags usageFlags; vk::BufferUsageFlags usageFlags;
...@@ -75,51 +49,62 @@ namespace vkcv { ...@@ -75,51 +49,62 @@ namespace vkcv {
usageFlags = vk::BufferUsageFlagBits::eIndexBuffer; usageFlags = vk::BufferUsageFlagBits::eIndexBuffer;
break; break;
default: default:
// TODO: maybe an issue vkcv_log(LogLevel::WARNING, "Unknown buffer type");
break; break;
} }
if (memoryType == BufferMemoryType::DEVICE_LOCAL) { if (memoryType == BufferMemoryType::DEVICE_LOCAL) {
usageFlags |= vk::BufferUsageFlagBits::eTransferDst; usageFlags |= vk::BufferUsageFlagBits::eTransferDst;
} }
if (supportIndirect)
usageFlags |= vk::BufferUsageFlagBits::eIndirectBuffer;
const vk::Device& device = m_core->getContext().getDevice(); const vma::Allocator& allocator = m_core->getContext().getAllocator();
vk::Buffer buffer = device.createBuffer(
vk::BufferCreateInfo(createFlags, size, usageFlags)
);
const vk::MemoryRequirements requirements = device.getBufferMemoryRequirements(buffer);
const vk::PhysicalDevice& physicalDevice = m_core->getContext().getPhysicalDevice();
vk::MemoryPropertyFlags memoryTypeFlags; vk::MemoryPropertyFlags memoryTypeFlags;
vma::MemoryUsage memoryUsage;
bool mappable = false; bool mappable = false;
switch (memoryType) { switch (memoryType) {
case BufferMemoryType::DEVICE_LOCAL: case BufferMemoryType::DEVICE_LOCAL:
memoryTypeFlags = vk::MemoryPropertyFlagBits::eDeviceLocal; memoryTypeFlags = vk::MemoryPropertyFlagBits::eDeviceLocal;
memoryUsage = vma::MemoryUsage::eGpuOnly;
mappable = false;
break; break;
case BufferMemoryType::HOST_VISIBLE: case BufferMemoryType::HOST_VISIBLE:
memoryTypeFlags = vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent; memoryTypeFlags = vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent;
memoryUsage = vma::MemoryUsage::eCpuOnly;
mappable = true; mappable = true;
break; break;
default: default:
// TODO: maybe an issue vkcv_log(LogLevel::WARNING, "Unknown buffer memory type");
memoryUsage = vma::MemoryUsage::eUnknown;
mappable = false;
break; break;
} }
const uint32_t memoryTypeIndex = searchBufferMemoryType( if (type == BufferType::STAGING) {
physicalDevice.getMemoryProperties(), memoryUsage = vma::MemoryUsage::eCpuToGpu;
requirements.memoryTypeBits, }
memoryTypeFlags
);
vk::DeviceMemory memory = device.allocateMemory(vk::MemoryAllocateInfo(requirements.size, memoryTypeIndex)); auto bufferAllocation = allocator.createBuffer(
vk::BufferCreateInfo(createFlags, size, usageFlags),
vma::AllocationCreateInfo(
vma::AllocationCreateFlags(),
memoryUsage,
memoryTypeFlags,
memoryTypeFlags,
0,
vma::Pool(),
nullptr
)
);
device.bindBufferMemory(buffer, memory, 0); vk::Buffer buffer = bufferAllocation.first;
vma::Allocation allocation = bufferAllocation.second;
const uint64_t id = m_buffers.size(); const uint64_t id = m_buffers.size();
m_buffers.push_back({ buffer, memory, size, nullptr, mappable }); m_buffers.push_back({ buffer, allocation, size, mappable });
return BufferHandle(id, [&](uint64_t id) { destroyBufferById(id); }); return BufferHandle(id, [&](uint64_t id) { destroyBufferById(id); });
} }
...@@ -130,7 +115,7 @@ namespace vkcv { ...@@ -130,7 +115,7 @@ namespace vkcv {
vk::Buffer buffer; vk::Buffer buffer;
vk::Buffer stagingBuffer; vk::Buffer stagingBuffer;
vk::DeviceMemory stagingMemory; vma::Allocation stagingAllocation;
size_t stagingLimit; size_t stagingLimit;
size_t stagingPosition; size_t stagingPosition;
...@@ -150,11 +135,11 @@ namespace vkcv { ...@@ -150,11 +135,11 @@ namespace vkcv {
const size_t remaining = info.size - info.stagingPosition; const size_t remaining = info.size - info.stagingPosition;
const size_t mapped_size = std::min(remaining, info.stagingLimit); const size_t mapped_size = std::min(remaining, info.stagingLimit);
const vk::Device& device = core->getContext().getDevice(); const vma::Allocator& allocator = core->getContext().getAllocator();
void* mapped = device.mapMemory(info.stagingMemory, 0, mapped_size); void* mapped = allocator.mapMemory(info.stagingAllocation);
memcpy(mapped, reinterpret_cast<const char*>(info.data) + info.stagingPosition, mapped_size); memcpy(mapped, reinterpret_cast<const char*>(info.data) + info.stagingPosition, mapped_size);
device.unmapMemory(info.stagingMemory); allocator.unmapMemory(info.stagingAllocation);
SubmitInfo submitInfo; SubmitInfo submitInfo;
submitInfo.queueType = QueueType::Transfer; submitInfo.queueType = QueueType::Transfer;
...@@ -216,7 +201,13 @@ namespace vkcv { ...@@ -216,7 +201,13 @@ namespace vkcv {
auto& buffer = m_buffers[id]; auto& buffer = m_buffers[id];
return buffer.m_memory; const vma::Allocator& allocator = m_core->getContext().getAllocator();
auto info = allocator.getAllocationInfo(
buffer.m_allocation
);
return info.deviceMemory;
} }
void BufferManager::fillBuffer(const BufferHandle& handle, const void *data, size_t size, size_t offset) { void BufferManager::fillBuffer(const BufferHandle& handle, const void *data, size_t size, size_t offset) {
...@@ -232,11 +223,7 @@ namespace vkcv { ...@@ -232,11 +223,7 @@ namespace vkcv {
auto& buffer = m_buffers[id]; auto& buffer = m_buffers[id];
if (buffer.m_mapped) { const vma::Allocator& allocator = m_core->getContext().getAllocator();
return;
}
const vk::Device& device = m_core->getContext().getDevice();
if (offset > buffer.m_size) { if (offset > buffer.m_size) {
return; return;
...@@ -245,9 +232,9 @@ namespace vkcv { ...@@ -245,9 +232,9 @@ namespace vkcv {
const size_t max_size = std::min(size, buffer.m_size - offset); const size_t max_size = std::min(size, buffer.m_size - offset);
if (buffer.m_mappable) { if (buffer.m_mappable) {
void* mapped = device.mapMemory(buffer.m_memory, offset, max_size); void* mapped = allocator.mapMemory(buffer.m_allocation);
memcpy(mapped, data, max_size); memcpy(reinterpret_cast<char*>(mapped) + offset, data, max_size);
device.unmapMemory(buffer.m_memory); allocator.unmapMemory(buffer.m_allocation);
} else { } else {
auto& stagingBuffer = m_buffers[ m_stagingBuffer.getId() ]; auto& stagingBuffer = m_buffers[ m_stagingBuffer.getId() ];
...@@ -258,11 +245,9 @@ namespace vkcv { ...@@ -258,11 +245,9 @@ namespace vkcv {
info.buffer = buffer.m_handle; info.buffer = buffer.m_handle;
info.stagingBuffer = stagingBuffer.m_handle; info.stagingBuffer = stagingBuffer.m_handle;
info.stagingMemory = stagingBuffer.m_memory; info.stagingAllocation = stagingBuffer.m_allocation;
const vk::MemoryRequirements stagingRequirements = device.getBufferMemoryRequirements(stagingBuffer.m_handle); info.stagingLimit = stagingBuffer.m_size;
info.stagingLimit = stagingRequirements.size;
info.stagingPosition = 0; info.stagingPosition = 0;
copyFromStagingBuffer(m_core, info); copyFromStagingBuffer(m_core, info);
...@@ -282,19 +267,13 @@ namespace vkcv { ...@@ -282,19 +267,13 @@ namespace vkcv {
auto& buffer = m_buffers[id]; auto& buffer = m_buffers[id];
if (buffer.m_mapped) { const vma::Allocator& allocator = m_core->getContext().getAllocator();
return nullptr;
}
const vk::Device& device = m_core->getContext().getDevice();
if (offset > buffer.m_size) { if (offset > buffer.m_size) {
return nullptr; return nullptr;
} }
const size_t max_size = std::min(size, buffer.m_size - offset); return reinterpret_cast<char*>(allocator.mapMemory(buffer.m_allocation)) + offset;
buffer.m_mapped = device.mapMemory(buffer.m_memory, offset, max_size);
return buffer.m_mapped;
} }
void BufferManager::unmapBuffer(const BufferHandle& handle) { void BufferManager::unmapBuffer(const BufferHandle& handle) {
...@@ -306,14 +285,9 @@ namespace vkcv { ...@@ -306,14 +285,9 @@ namespace vkcv {
auto& buffer = m_buffers[id]; auto& buffer = m_buffers[id];
if (buffer.m_mapped == nullptr) { const vma::Allocator& allocator = m_core->getContext().getAllocator();
return;
}
const vk::Device& device = m_core->getContext().getDevice();
device.unmapMemory(buffer.m_memory); allocator.unmapMemory(buffer.m_allocation);
buffer.m_mapped = nullptr;
} }
void BufferManager::destroyBufferById(uint64_t id) { void BufferManager::destroyBufferById(uint64_t id) {
...@@ -323,16 +297,13 @@ namespace vkcv { ...@@ -323,16 +297,13 @@ namespace vkcv {
auto& buffer = m_buffers[id]; auto& buffer = m_buffers[id];
const vk::Device& device = m_core->getContext().getDevice(); const vma::Allocator& allocator = m_core->getContext().getAllocator();
if (buffer.m_memory) {
device.freeMemory(buffer.m_memory);
buffer.m_memory = nullptr;
}
if (buffer.m_handle) { if (buffer.m_handle) {
device.destroyBuffer(buffer.m_handle); allocator.destroyBuffer(buffer.m_handle, buffer.m_allocation);
buffer.m_handle = nullptr; buffer.m_handle = nullptr;
buffer.m_allocation = nullptr;
} }
} }
......
...@@ -32,11 +32,10 @@ namespace vkcv { ...@@ -32,11 +32,10 @@ namespace vkcv {
// find unused stream // find unused stream
int unusedStreamIndex = -1; int unusedStreamIndex = -1;
for (int i = 0; i < m_commandStreams.size(); i++) { for (size_t i = 0; i < m_commandStreams.size(); i++) {
if (m_commandStreams[i].cmdBuffer) { if (m_commandStreams[i].cmdBuffer) {
// still in use // still in use
} } else {
else {
unusedStreamIndex = i; unusedStreamIndex = i;
break; break;
} }
......
...@@ -9,11 +9,13 @@ namespace vkcv ...@@ -9,11 +9,13 @@ namespace vkcv
m_Instance(other.m_Instance), m_Instance(other.m_Instance),
m_PhysicalDevice(other.m_PhysicalDevice), m_PhysicalDevice(other.m_PhysicalDevice),
m_Device(other.m_Device), m_Device(other.m_Device),
m_QueueManager(other.m_QueueManager) m_QueueManager(other.m_QueueManager),
m_Allocator(other.m_Allocator)
{ {
other.m_Instance = nullptr; other.m_Instance = nullptr;
other.m_PhysicalDevice = nullptr; other.m_PhysicalDevice = nullptr;
other.m_Device = nullptr; other.m_Device = nullptr;
other.m_Allocator = nullptr;
} }
Context & Context::operator=(Context &&other) noexcept Context & Context::operator=(Context &&other) noexcept
...@@ -22,10 +24,12 @@ namespace vkcv ...@@ -22,10 +24,12 @@ namespace vkcv
m_PhysicalDevice = other.m_PhysicalDevice; m_PhysicalDevice = other.m_PhysicalDevice;
m_Device = other.m_Device; m_Device = other.m_Device;
m_QueueManager = other.m_QueueManager; m_QueueManager = other.m_QueueManager;
m_Allocator = other.m_Allocator;
other.m_Instance = nullptr; other.m_Instance = nullptr;
other.m_PhysicalDevice = nullptr; other.m_PhysicalDevice = nullptr;
other.m_Device = nullptr; other.m_Device = nullptr;
other.m_Allocator = nullptr;
return *this; return *this;
} }
...@@ -33,15 +37,18 @@ namespace vkcv ...@@ -33,15 +37,18 @@ namespace vkcv
Context::Context(vk::Instance instance, Context::Context(vk::Instance instance,
vk::PhysicalDevice physicalDevice, vk::PhysicalDevice physicalDevice,
vk::Device device, vk::Device device,
QueueManager&& queueManager) noexcept : QueueManager&& queueManager,
m_Instance{instance}, vma::Allocator&& allocator) noexcept :
m_PhysicalDevice{physicalDevice}, m_Instance(instance),
m_Device{device}, m_PhysicalDevice(physicalDevice),
m_QueueManager{queueManager} m_Device(device),
m_QueueManager(queueManager),
m_Allocator(allocator)
{} {}
Context::~Context() noexcept Context::~Context() noexcept
{ {
m_Allocator.destroy();
m_Device.destroy(); m_Device.destroy();
m_Instance.destroy(); m_Instance.destroy();
} }
...@@ -64,6 +71,10 @@ namespace vkcv ...@@ -64,6 +71,10 @@ namespace vkcv
const QueueManager& Context::getQueueManager() const { const QueueManager& Context::getQueueManager() const {
return m_QueueManager; return m_QueueManager;
} }
const vma::Allocator& Context::getAllocator() const {
return m_Allocator;
}
/** /**
* @brief The physical device is evaluated by three categories: * @brief The physical device is evaluated by three categories:
...@@ -140,7 +151,7 @@ namespace vkcv ...@@ -140,7 +151,7 @@ namespace vkcv
* @param check The elements to be checked * @param check The elements to be checked
* @return True, if all elements in "check" are supported * @return True, if all elements in "check" are supported
*/ */
bool checkSupport(std::vector<const char*>& supported, std::vector<const char*>& check) bool checkSupport(const std::vector<const char*>& supported, const std::vector<const char*>& check)
{ {
for (auto checkElem : check) { for (auto checkElem : check) {
bool found = false; bool found = false;
...@@ -169,11 +180,20 @@ namespace vkcv ...@@ -169,11 +180,20 @@ namespace vkcv
return extensions; return extensions;
} }
bool isPresentInCharPtrVector(const std::vector<const char*>& v, const char* term){
for (const auto& entry : v) {
if (strcmp(entry, term) != 0) {
return true;
}
}
return false;
}
Context Context::create(const char *applicationName, Context Context::create(const char *applicationName,
uint32_t applicationVersion, uint32_t applicationVersion,
std::vector<vk::QueueFlagBits> queueFlags, const std::vector<vk::QueueFlagBits>& queueFlags,
std::vector<const char *> instanceExtensions, const std::vector<const char *>& instanceExtensions,
std::vector<const char *> deviceExtensions) { const std::vector<const char *>& deviceExtensions) {
// check for layer support // check for layer support
const std::vector<vk::LayerProperties>& layerProperties = vk::enumerateInstanceLayerProperties(); const std::vector<vk::LayerProperties>& layerProperties = vk::enumerateInstanceLayerProperties();
...@@ -212,7 +232,7 @@ namespace vkcv ...@@ -212,7 +232,7 @@ namespace vkcv
// for GLFW: get all required extensions // for GLFW: get all required extensions
std::vector<const char*> requiredExtensions = getRequiredExtensions(); std::vector<const char*> requiredExtensions = getRequiredExtensions();
instanceExtensions.insert(instanceExtensions.end(), requiredExtensions.begin(), requiredExtensions.end()); requiredExtensions.insert(requiredExtensions.end(), instanceExtensions.begin(), instanceExtensions.end());
const vk::ApplicationInfo applicationInfo( const vk::ApplicationInfo applicationInfo(
applicationName, applicationName,
...@@ -227,8 +247,8 @@ namespace vkcv ...@@ -227,8 +247,8 @@ namespace vkcv
&applicationInfo, &applicationInfo,
0, 0,
nullptr, nullptr,
static_cast<uint32_t>(instanceExtensions.size()), static_cast<uint32_t>(requiredExtensions.size()),
instanceExtensions.data() requiredExtensions.data()
); );
#ifndef NDEBUG #ifndef NDEBUG
...@@ -275,13 +295,39 @@ namespace vkcv ...@@ -275,13 +295,39 @@ namespace vkcv
deviceCreateInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size()); deviceCreateInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
deviceCreateInfo.ppEnabledLayerNames = validationLayers.data(); deviceCreateInfo.ppEnabledLayerNames = validationLayers.data();
#endif #endif
const bool shaderFloat16 = checkSupport(deviceExtensions, { "VK_KHR_shader_float16_int8" });
const bool storage16bit = checkSupport(deviceExtensions, { "VK_KHR_16bit_storage" });
// FIXME: check if device feature is supported // FIXME: check if device feature is supported
vk::PhysicalDeviceFeatures deviceFeatures; vk::PhysicalDeviceShaderFloat16Int8Features deviceShaderFloat16Int8Features;
deviceFeatures.fragmentStoresAndAtomics = true; deviceShaderFloat16Int8Features.shaderFloat16 = shaderFloat16;
deviceFeatures.geometryShader = true;
deviceFeatures.depthClamp = true; vk::PhysicalDevice16BitStorageFeatures device16BitStorageFeatures;
deviceCreateInfo.pEnabledFeatures = &deviceFeatures; device16BitStorageFeatures.storageBuffer16BitAccess = storage16bit;
vk::PhysicalDeviceFeatures2 deviceFeatures2;
deviceFeatures2.features.fragmentStoresAndAtomics = true;
deviceFeatures2.features.geometryShader = true;
deviceFeatures2.features.depthClamp = true;
deviceFeatures2.features.shaderInt16 = true;
const bool usingMeshShaders = isPresentInCharPtrVector(deviceExtensions, VK_NV_MESH_SHADER_EXTENSION_NAME);
vk::PhysicalDeviceMeshShaderFeaturesNV meshShadingFeatures;
if (usingMeshShaders) {
meshShadingFeatures.taskShader = true;
meshShadingFeatures.meshShader = true;
deviceFeatures2.setPNext(&meshShadingFeatures);
}
if (shaderFloat16) {
deviceFeatures2.setPNext(&deviceShaderFloat16Int8Features);
}
if (storage16bit) {
deviceShaderFloat16Int8Features.setPNext(&device16BitStorageFeatures);
}
deviceCreateInfo.setPNext(&deviceFeatures2);
// Ablauf // Ablauf
// qCreateInfos erstellen --> braucht das Device // qCreateInfos erstellen --> braucht das Device
...@@ -289,10 +335,50 @@ namespace vkcv ...@@ -289,10 +335,50 @@ namespace vkcv
// jetzt koennen wir mit dem device die queues erstellen // jetzt koennen wir mit dem device die queues erstellen
vk::Device device = physicalDevice.createDevice(deviceCreateInfo); vk::Device device = physicalDevice.createDevice(deviceCreateInfo);
if (usingMeshShaders)
{
InitMeshShaderDrawFunctions(device);
}
QueueManager queueManager = QueueManager::create(device, queuePairsGraphics, queuePairsCompute, queuePairsTransfer); QueueManager queueManager = QueueManager::create(
device,
queuePairsGraphics,
queuePairsCompute,
queuePairsTransfer
);
return Context(instance, physicalDevice, device, std::move(queueManager)); const vma::AllocatorCreateInfo allocatorCreateInfo (
vma::AllocatorCreateFlags(),
physicalDevice,
device,
0,
nullptr,
nullptr,
0,
nullptr,
nullptr,
nullptr,
instance,
/* Uses default version when set to 0 (currently VK_VERSION_1_0):
*
* The reason for this is that the allocator restricts the allowed version
* to be at maximum VK_VERSION_1_1 which is already less than
* VK_HEADER_VERSION_COMPLETE at most platforms.
* */
0
);
vma::Allocator allocator = vma::createAllocator(allocatorCreateInfo);
return Context(
instance,
physicalDevice,
device,
std::move(queueManager),
std::move(allocator)
);
} }
} }
...@@ -53,9 +53,9 @@ namespace vkcv ...@@ -53,9 +53,9 @@ namespace vkcv
Core Core::create(Window &window, Core Core::create(Window &window,
const char *applicationName, const char *applicationName,
uint32_t applicationVersion, uint32_t applicationVersion,
std::vector<vk::QueueFlagBits> queueFlags, const std::vector<vk::QueueFlagBits>& queueFlags,
std::vector<const char *> instanceExtensions, const std::vector<const char *>& instanceExtensions,
std::vector<const char *> deviceExtensions) const std::vector<const char *>& deviceExtensions)
{ {
Context context = Context::create( Context context = Context::create(
applicationName, applicationVersion, applicationName, applicationVersion,
...@@ -71,7 +71,6 @@ namespace vkcv ...@@ -71,7 +71,6 @@ namespace vkcv
const auto& queueManager = context.getQueueManager(); const auto& queueManager = context.getQueueManager();
const int graphicQueueFamilyIndex = queueManager.getGraphicsQueues()[0].familyIndex;
const std::unordered_set<int> queueFamilySet = generateQueueFamilyIndexSet(queueManager); const std::unordered_set<int> queueFamilySet = generateQueueFamilyIndexSet(queueManager);
const auto commandResources = createCommandResources(context.getDevice(), queueFamilySet); const auto commandResources = createCommandResources(context.getDevice(), queueFamilySet);
const auto defaultSyncResources = createSyncResources(context.getDevice()); const auto defaultSyncResources = createSyncResources(context.getDevice());
...@@ -91,8 +90,8 @@ namespace vkcv ...@@ -91,8 +90,8 @@ namespace vkcv
Core::Core(Context &&context, Window &window, const Swapchain& swapChain, std::vector<vk::ImageView> swapchainImageViews, Core::Core(Context &&context, Window &window, const Swapchain& swapChain, std::vector<vk::ImageView> swapchainImageViews,
const CommandResources& commandResources, const SyncResources& syncResources) noexcept : const CommandResources& commandResources, const SyncResources& syncResources) noexcept :
m_Context(std::move(context)), m_Context(std::move(context)),
m_swapchain(swapChain),
m_window(window), m_window(window),
m_swapchain(swapChain),
m_PassManager{std::make_unique<PassManager>(m_Context.m_Device)}, m_PassManager{std::make_unique<PassManager>(m_Context.m_Device)},
m_PipelineManager{std::make_unique<PipelineManager>(m_Context.m_Device)}, m_PipelineManager{std::make_unique<PipelineManager>(m_Context.m_Device)},
m_DescriptorManager(std::make_unique<DescriptorManager>(m_Context.m_Device)), m_DescriptorManager(std::make_unique<DescriptorManager>(m_Context.m_Device)),
...@@ -119,7 +118,8 @@ namespace vkcv ...@@ -119,7 +118,8 @@ namespace vkcv
swapchainImageViews, swapchainImageViews,
swapChain.getExtent().width, swapChain.getExtent().width,
swapChain.getExtent().height, swapChain.getExtent().height,
swapChain.getFormat()); swapChain.getFormat()
);
} }
Core::~Core() noexcept { Core::~Core() noexcept {
...@@ -163,9 +163,9 @@ namespace vkcv ...@@ -163,9 +163,9 @@ namespace vkcv
nullptr, nullptr,
&imageIndex, {} &imageIndex, {}
); );
} catch (vk::OutOfDateKHRError e) { } catch (const vk::OutOfDateKHRError& e) {
result = vk::Result::eErrorOutOfDateKHR; result = vk::Result::eErrorOutOfDateKHR;
} catch (vk::DeviceLostError e) { } catch (const vk::DeviceLostError& e) {
result = vk::Result::eErrorDeviceLost; result = vk::Result::eErrorDeviceLost;
} }
...@@ -228,133 +228,246 @@ namespace vkcv ...@@ -228,133 +228,246 @@ namespace vkcv
return (m_currentSwapchainImageIndex != std::numeric_limits<uint32_t>::max()); return (m_currentSwapchainImageIndex != std::numeric_limits<uint32_t>::max());
} }
void Core::recordDrawcallsToCmdStream( std::array<uint32_t, 2> getWidthHeightFromRenderTargets(
const CommandStreamHandle cmdStreamHandle, const std::vector<ImageHandle>& renderTargets,
const PassHandle renderpassHandle, const Swapchain& swapchain,
const PipelineHandle pipelineHandle, const ImageManager& imageManager) {
const PushConstantData &pushConstantData,
const std::vector<DrawcallInfo> &drawcalls,
const std::vector<ImageHandle> &renderTargets) {
if (m_currentSwapchainImageIndex == std::numeric_limits<uint32_t>::max()) { std::array<uint32_t, 2> widthHeight;
return;
}
uint32_t width;
uint32_t height;
if (renderTargets.size() > 0) { if (renderTargets.size() > 0) {
const vkcv::ImageHandle firstImage = renderTargets[0]; const vkcv::ImageHandle firstImage = renderTargets[0];
if (firstImage.isSwapchainImage()) { if (firstImage.isSwapchainImage()) {
const auto& swapchainExtent = m_swapchain.getExtent(); const auto& swapchainExtent = swapchain.getExtent();
width = swapchainExtent.width; widthHeight[0] = swapchainExtent.width;
height = swapchainExtent.height; widthHeight[1] = swapchainExtent.height;
} }
else { else {
width = m_ImageManager->getImageWidth(firstImage); widthHeight[0] = imageManager.getImageWidth(firstImage);
height = m_ImageManager->getImageHeight(firstImage); widthHeight[1] = imageManager.getImageHeight(firstImage);
} }
} }
else { else {
width = 1; widthHeight[0] = 1;
height = 1; widthHeight[1] = 1;
} }
// TODO: validate that width/height match for all attachments // TODO: validate that width/height match for all attachments
return widthHeight;
}
const vk::RenderPass renderpass = m_PassManager->getVkPass(renderpassHandle); vk::Framebuffer createFramebuffer(
const PassConfig passConfig = m_PassManager->getPassConfig(renderpassHandle); const std::vector<ImageHandle>& renderTargets,
const ImageManager& imageManager,
const vk::Pipeline pipeline = m_PipelineManager->getVkPipeline(pipelineHandle); const Swapchain& swapchain,
const vk::PipelineLayout pipelineLayout = m_PipelineManager->getVkPipelineLayout(pipelineHandle); vk::RenderPass renderpass,
const vk::Rect2D renderArea(vk::Offset2D(0, 0), vk::Extent2D(width, height)); vk::Device device) {
std::vector<vk::ImageView> attachmentsViews; std::vector<vk::ImageView> attachmentsViews;
for (const ImageHandle handle : renderTargets) { for (const ImageHandle handle : renderTargets) {
vk::ImageView targetHandle; vk::ImageView targetHandle = imageManager.getVulkanImageView(handle);
const auto cmdBuffer = m_CommandStreamManager->getStreamCommandBuffer(cmdStreamHandle); attachmentsViews.push_back(targetHandle);
}
const std::array<uint32_t, 2> widthHeight = getWidthHeightFromRenderTargets(renderTargets, swapchain, imageManager);
const vk::FramebufferCreateInfo createInfo(
{},
renderpass,
static_cast<uint32_t>(attachmentsViews.size()),
attachmentsViews.data(),
widthHeight[0],
widthHeight[1],
1);
return device.createFramebuffer(createInfo);
}
targetHandle = m_ImageManager->getVulkanImageView(handle); void transitionRendertargetsToAttachmentLayout(
const bool isDepthImage = isDepthFormat(m_ImageManager->getImageFormat(handle)); const std::vector<ImageHandle>& renderTargets,
const vk::ImageLayout targetLayout = ImageManager& imageManager,
const vk::CommandBuffer cmdBuffer) {
for (const ImageHandle handle : renderTargets) {
vk::ImageView targetHandle = imageManager.getVulkanImageView(handle);
const bool isDepthImage = isDepthFormat(imageManager.getImageFormat(handle));
const vk::ImageLayout targetLayout =
isDepthImage ? vk::ImageLayout::eDepthStencilAttachmentOptimal : vk::ImageLayout::eColorAttachmentOptimal; isDepthImage ? vk::ImageLayout::eDepthStencilAttachmentOptimal : vk::ImageLayout::eColorAttachmentOptimal;
m_ImageManager->recordImageLayoutTransition(handle, targetLayout, cmdBuffer); imageManager.recordImageLayoutTransition(handle, targetLayout, cmdBuffer);
attachmentsViews.push_back(targetHandle);
} }
}
const vk::FramebufferCreateInfo createInfo(
{}, std::vector<vk::ClearValue> createAttachmentClearValues(const std::vector<AttachmentDescription>& attachments) {
renderpass, std::vector<vk::ClearValue> clearValues;
static_cast<uint32_t>(attachmentsViews.size()), for (const auto& attachment : attachments) {
attachmentsViews.data(), if (attachment.load_operation == AttachmentOperation::CLEAR) {
width, float clear = 0.0f;
height,
1 if (isDepthFormat(attachment.format)) {
clear = 1.0f;
}
clearValues.emplace_back(std::array<float, 4>{
clear,
clear,
clear,
1.f
});
}
}
return clearValues;
}
void recordDynamicViewport(vk::CommandBuffer cmdBuffer, uint32_t width, uint32_t height) {
vk::Viewport dynamicViewport(
0.0f, 0.0f,
static_cast<float>(width), static_cast<float>(height),
0.0f, 1.0f
); );
vk::Framebuffer framebuffer = m_Context.m_Device.createFramebuffer(createInfo); vk::Rect2D dynamicScissor({ 0, 0 }, { width, height });
if (!framebuffer) { cmdBuffer.setViewport(0, 1, &dynamicViewport);
cmdBuffer.setScissor(0, 1, &dynamicScissor);
}
void Core::recordDrawcallsToCmdStream(
const CommandStreamHandle cmdStreamHandle,
const PassHandle renderpassHandle,
const PipelineHandle pipelineHandle,
const PushConstants &pushConstantData,
const std::vector<DrawcallInfo> &drawcalls,
const std::vector<ImageHandle> &renderTargets) {
if (m_currentSwapchainImageIndex == std::numeric_limits<uint32_t>::max()) {
return;
}
const std::array<uint32_t, 2> widthHeight = getWidthHeightFromRenderTargets(renderTargets, m_swapchain, *m_ImageManager);
const auto width = widthHeight[0];
const auto height = widthHeight[1];
const vk::RenderPass renderpass = m_PassManager->getVkPass(renderpassHandle);
const PassConfig passConfig = m_PassManager->getPassConfig(renderpassHandle);
const vk::Pipeline pipeline = m_PipelineManager->getVkPipeline(pipelineHandle);
const vk::PipelineLayout pipelineLayout = m_PipelineManager->getVkPipelineLayout(pipelineHandle);
const vk::Rect2D renderArea(vk::Offset2D(0, 0), vk::Extent2D(width, height));
vk::CommandBuffer cmdBuffer = m_CommandStreamManager->getStreamCommandBuffer(cmdStreamHandle);
transitionRendertargetsToAttachmentLayout(renderTargets, *m_ImageManager, cmdBuffer);
const vk::Framebuffer framebuffer = createFramebuffer(renderTargets, *m_ImageManager, m_swapchain, renderpass, m_Context.m_Device);
if (!framebuffer) {
vkcv_log(LogLevel::ERROR, "Failed to create temporary framebuffer"); vkcv_log(LogLevel::ERROR, "Failed to create temporary framebuffer");
return; return;
} }
vk::Viewport dynamicViewport( SubmitInfo submitInfo;
0.0f, 0.0f, submitInfo.queueType = QueueType::Graphics;
static_cast<float>(width), static_cast<float>(height), submitInfo.signalSemaphores = { m_SyncResources.renderFinished };
0.0f, 1.0f
); auto submitFunction = [&](const vk::CommandBuffer& cmdBuffer) {
const std::vector<vk::ClearValue> clearValues = createAttachmentClearValues(passConfig.attachments);
const vk::RenderPassBeginInfo beginInfo(renderpass, framebuffer, renderArea, clearValues.size(), clearValues.data());
cmdBuffer.beginRenderPass(beginInfo, {}, {});
cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline, {});
const PipelineConfig &pipeConfig = m_PipelineManager->getPipelineConfig(pipelineHandle);
if(pipeConfig.m_UseDynamicViewport)
{
recordDynamicViewport(cmdBuffer, width, height);
}
for (int i = 0; i < drawcalls.size(); i++) {
recordDrawcall(drawcalls[i], cmdBuffer, pipelineLayout, pushConstantData, i);
}
vk::Rect2D dynamicScissor({0, 0}, {width, height}); vk::Rect2D dynamicScissor({0, 0}, {width, height});
cmdBuffer.endRenderPass();
};
auto finishFunction = [framebuffer, this]()
{
m_Context.m_Device.destroy(framebuffer);
};
auto &bufferManager = m_BufferManager; recordCommandsToStream(cmdStreamHandle, submitFunction, finishFunction);
}
void Core::recordMeshShaderDrawcalls(
const CommandStreamHandle cmdStreamHandle,
const PassHandle renderpassHandle,
const PipelineHandle pipelineHandle,
const PushConstants& pushConstantData,
const std::vector<MeshShaderDrawcall>& drawcalls,
const std::vector<ImageHandle>& renderTargets) {
if (m_currentSwapchainImageIndex == std::numeric_limits<uint32_t>::max()) {
return;
}
const std::array<uint32_t, 2> widthHeight = getWidthHeightFromRenderTargets(renderTargets, m_swapchain, *m_ImageManager);
const auto width = widthHeight[0];
const auto height = widthHeight[1];
const vk::RenderPass renderpass = m_PassManager->getVkPass(renderpassHandle);
const PassConfig passConfig = m_PassManager->getPassConfig(renderpassHandle);
const vk::Pipeline pipeline = m_PipelineManager->getVkPipeline(pipelineHandle);
const vk::PipelineLayout pipelineLayout = m_PipelineManager->getVkPipelineLayout(pipelineHandle);
const vk::Rect2D renderArea(vk::Offset2D(0, 0), vk::Extent2D(width, height));
vk::CommandBuffer cmdBuffer = m_CommandStreamManager->getStreamCommandBuffer(cmdStreamHandle);
transitionRendertargetsToAttachmentLayout(renderTargets, *m_ImageManager, cmdBuffer);
const vk::Framebuffer framebuffer = createFramebuffer(renderTargets, *m_ImageManager, m_swapchain, renderpass, m_Context.m_Device);
if (!framebuffer) {
vkcv_log(LogLevel::ERROR, "Failed to create temporary framebuffer");
return;
}
SubmitInfo submitInfo; SubmitInfo submitInfo;
submitInfo.queueType = QueueType::Graphics; submitInfo.queueType = QueueType::Graphics;
submitInfo.signalSemaphores = { m_SyncResources.renderFinished }; submitInfo.signalSemaphores = { m_SyncResources.renderFinished };
auto submitFunction = [&](const vk::CommandBuffer& cmdBuffer) { auto submitFunction = [&](const vk::CommandBuffer& cmdBuffer) {
std::vector<vk::ClearValue> clearValues;
const std::vector<vk::ClearValue> clearValues = createAttachmentClearValues(passConfig.attachments);
for (const auto& attachment : passConfig.attachments) {
if (attachment.load_operation == AttachmentOperation::CLEAR) { const vk::RenderPassBeginInfo beginInfo(renderpass, framebuffer, renderArea, clearValues.size(), clearValues.data());
float clear = 0.0f; cmdBuffer.beginRenderPass(beginInfo, {}, {});
if (isDepthFormat(attachment.format)) { cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline, {});
clear = 1.0f;
} const PipelineConfig& pipeConfig = m_PipelineManager->getPipelineConfig(pipelineHandle);
if (pipeConfig.m_UseDynamicViewport)
clearValues.emplace_back(std::array<float, 4>{ {
clear, recordDynamicViewport(cmdBuffer, width, height);
clear, }
clear,
1.f for (int i = 0; i < drawcalls.size(); i++) {
}); const uint32_t pushConstantOffset = i * pushConstantData.getSizePerDrawcall();
} recordMeshShaderDrawcall(
} cmdBuffer,
pipelineLayout,
const vk::RenderPassBeginInfo beginInfo(renderpass, framebuffer, renderArea, clearValues.size(), clearValues.data()); pushConstantData,
const vk::SubpassContents subpassContents = {}; pushConstantOffset,
cmdBuffer.beginRenderPass(beginInfo, subpassContents, {}); drawcalls[i],
0);
cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline, {}); }
const PipelineConfig &pipeConfig = m_PipelineManager->getPipelineConfig(pipelineHandle); cmdBuffer.endRenderPass();
if(pipeConfig.m_UseDynamicViewport) };
{
cmdBuffer.setViewport(0, 1, &dynamicViewport); auto finishFunction = [framebuffer, this]()
cmdBuffer.setScissor(0, 1, &dynamicScissor); {
} m_Context.m_Device.destroy(framebuffer);
};
for (int i = 0; i < drawcalls.size(); i++) {
recordDrawcall(drawcalls[i], cmdBuffer, pipelineLayout, pushConstantData, i);
}
cmdBuffer.endRenderPass();
};
auto finishFunction = [framebuffer, this]()
{
m_Context.m_Device.destroy(framebuffer);
};
recordCommandsToStream(cmdStreamHandle, submitFunction, finishFunction); recordCommandsToStream(cmdStreamHandle, submitFunction, finishFunction);
} }
...@@ -364,7 +477,7 @@ namespace vkcv ...@@ -364,7 +477,7 @@ namespace vkcv
PipelineHandle computePipeline, PipelineHandle computePipeline,
const uint32_t dispatchCount[3], const uint32_t dispatchCount[3],
const std::vector<DescriptorSetUsage>& descriptorSetUsages, const std::vector<DescriptorSetUsage>& descriptorSetUsages,
const PushConstantData& pushConstantData) { const PushConstants& pushConstants) {
auto submitFunction = [&](const vk::CommandBuffer& cmdBuffer) { auto submitFunction = [&](const vk::CommandBuffer& cmdBuffer) {
...@@ -377,15 +490,16 @@ namespace vkcv ...@@ -377,15 +490,16 @@ namespace vkcv
pipelineLayout, pipelineLayout,
usage.setLocation, usage.setLocation,
{ usage.vulkanHandle }, { usage.vulkanHandle },
{}); usage.dynamicOffsets
);
} }
if (pushConstantData.sizePerDrawcall > 0) { if (pushConstants.getSizePerDrawcall() > 0) {
cmdBuffer.pushConstants( cmdBuffer.pushConstants(
pipelineLayout, pipelineLayout,
vk::ShaderStageFlagBits::eCompute, vk::ShaderStageFlagBits::eCompute,
0, 0,
pushConstantData.sizePerDrawcall, pushConstants.getSizePerDrawcall(),
pushConstantData.data); pushConstants.getData());
} }
cmdBuffer.dispatch(dispatchCount[0], dispatchCount[1], dispatchCount[2]); cmdBuffer.dispatch(dispatchCount[0], dispatchCount[1], dispatchCount[2]);
}; };
...@@ -393,6 +507,42 @@ namespace vkcv ...@@ -393,6 +507,42 @@ namespace vkcv
recordCommandsToStream(cmdStreamHandle, submitFunction, nullptr); recordCommandsToStream(cmdStreamHandle, submitFunction, nullptr);
} }
void Core::recordComputeIndirectDispatchToCmdStream(
const CommandStreamHandle cmdStream,
const PipelineHandle computePipeline,
const vkcv::BufferHandle buffer,
const size_t bufferArgOffset,
const std::vector<DescriptorSetUsage>& descriptorSetUsages,
const PushConstants& pushConstants) {
auto submitFunction = [&](const vk::CommandBuffer& cmdBuffer) {
const auto pipelineLayout = m_PipelineManager->getVkPipelineLayout(computePipeline);
cmdBuffer.bindPipeline(vk::PipelineBindPoint::eCompute, m_PipelineManager->getVkPipeline(computePipeline));
for (const auto& usage : descriptorSetUsages) {
cmdBuffer.bindDescriptorSets(
vk::PipelineBindPoint::eCompute,
pipelineLayout,
usage.setLocation,
{ usage.vulkanHandle },
usage.dynamicOffsets
);
}
if (pushConstants.getSizePerDrawcall() > 0) {
cmdBuffer.pushConstants(
pipelineLayout,
vk::ShaderStageFlagBits::eCompute,
0,
pushConstants.getSizePerDrawcall(),
pushConstants.getData());
}
cmdBuffer.dispatchIndirect(m_BufferManager->getBuffer(buffer), bufferArgOffset);
};
recordCommandsToStream(cmdStream, submitFunction, nullptr);
}
void Core::endFrame() { void Core::endFrame() {
if (m_currentSwapchainImageIndex == std::numeric_limits<uint32_t>::max()) { if (m_currentSwapchainImageIndex == std::numeric_limits<uint32_t>::max()) {
return; return;
...@@ -417,9 +567,9 @@ namespace vkcv ...@@ -417,9 +567,9 @@ namespace vkcv
try { try {
result = queueManager.getPresentQueue().handle.presentKHR(presentInfo); result = queueManager.getPresentQueue().handle.presentKHR(presentInfo);
} catch (vk::OutOfDateKHRError e) { } catch (const vk::OutOfDateKHRError& e) {
result = vk::Result::eErrorOutOfDateKHR; result = vk::Result::eErrorOutOfDateKHR;
} catch (vk::DeviceLostError e) { } catch (const vk::DeviceLostError& e) {
result = vk::Result::eErrorDeviceLost; result = vk::Result::eErrorDeviceLost;
} }
...@@ -463,8 +613,6 @@ namespace vkcv ...@@ -463,8 +613,6 @@ namespace vkcv
} }
CommandStreamHandle Core::createCommandStream(QueueType queueType) { CommandStreamHandle Core::createCommandStream(QueueType queueType) {
const vk::Device& device = m_Context.getDevice();
const vkcv::Queue queue = getQueueForSubmit(queueType, m_Context.getQueueManager()); const vkcv::Queue queue = getQueueForSubmit(queueType, m_Context.getQueueManager());
const vk::CommandPool cmdPool = chooseCmdPool(queue, m_CommandResources); const vk::CommandPool cmdPool = chooseCmdPool(queue, m_CommandResources);
...@@ -482,7 +630,7 @@ namespace vkcv ...@@ -482,7 +630,7 @@ namespace vkcv
} }
} }
void Core::submitCommandStream(const CommandStreamHandle handle) { void Core::submitCommandStream(const CommandStreamHandle& handle) {
std::vector<vk::Semaphore> waitSemaphores; std::vector<vk::Semaphore> waitSemaphores;
// FIXME: add proper user controllable sync // FIXME: add proper user controllable sync
std::vector<vk::Semaphore> signalSemaphores = { m_SyncResources.renderFinished }; std::vector<vk::Semaphore> signalSemaphores = { m_SyncResources.renderFinished };
...@@ -490,8 +638,9 @@ namespace vkcv ...@@ -490,8 +638,9 @@ namespace vkcv
} }
SamplerHandle Core::createSampler(SamplerFilterType magFilter, SamplerFilterType minFilter, SamplerHandle Core::createSampler(SamplerFilterType magFilter, SamplerFilterType minFilter,
SamplerMipmapMode mipmapMode, SamplerAddressMode addressMode) { SamplerMipmapMode mipmapMode, SamplerAddressMode addressMode,
return m_SamplerManager->createSampler(magFilter, minFilter, mipmapMode, addressMode); float mipLodBias) {
return m_SamplerManager->createSampler(magFilter, minFilter, mipmapMode, addressMode, mipLodBias);
} }
Image Core::createImage( Image Core::createImage(
...@@ -522,14 +671,18 @@ namespace vkcv ...@@ -522,14 +671,18 @@ namespace vkcv
multisampling); multisampling);
} }
const uint32_t Core::getImageWidth(ImageHandle imageHandle) uint32_t Core::getImageWidth(const ImageHandle& image)
{ {
return m_ImageManager->getImageWidth(imageHandle); return m_ImageManager->getImageWidth(image);
} }
const uint32_t Core::getImageHeight(ImageHandle imageHandle) uint32_t Core::getImageHeight(const ImageHandle& image)
{ {
return m_ImageManager->getImageHeight(imageHandle); return m_ImageManager->getImageHeight(image);
}
vk::Format Core::getImageFormat(const ImageHandle& image) {
return m_ImageManager->getImageFormat(image);
} }
DescriptorSetHandle Core::createDescriptorSet(const std::vector<DescriptorBinding>& bindings) DescriptorSetHandle Core::createDescriptorSet(const std::vector<DescriptorBinding>& bindings)
...@@ -550,38 +703,38 @@ namespace vkcv ...@@ -550,38 +703,38 @@ namespace vkcv
return m_DescriptorManager->getDescriptorSet(handle); return m_DescriptorManager->getDescriptorSet(handle);
} }
void Core::prepareSwapchainImageForPresent(const CommandStreamHandle cmdStream) { void Core::prepareSwapchainImageForPresent(const CommandStreamHandle& cmdStream) {
auto swapchainHandle = ImageHandle::createSwapchainImageHandle(); auto swapchainHandle = ImageHandle::createSwapchainImageHandle();
recordCommandsToStream(cmdStream, [swapchainHandle, this](const vk::CommandBuffer cmdBuffer) { recordCommandsToStream(cmdStream, [swapchainHandle, this](const vk::CommandBuffer cmdBuffer) {
m_ImageManager->recordImageLayoutTransition(swapchainHandle, vk::ImageLayout::ePresentSrcKHR, cmdBuffer); m_ImageManager->recordImageLayoutTransition(swapchainHandle, vk::ImageLayout::ePresentSrcKHR, cmdBuffer);
}, nullptr); }, nullptr);
} }
void Core::prepareImageForSampling(const CommandStreamHandle cmdStream, const ImageHandle image) { void Core::prepareImageForSampling(const CommandStreamHandle& cmdStream, const ImageHandle& image) {
recordCommandsToStream(cmdStream, [image, this](const vk::CommandBuffer cmdBuffer) { recordCommandsToStream(cmdStream, [image, this](const vk::CommandBuffer cmdBuffer) {
m_ImageManager->recordImageLayoutTransition(image, vk::ImageLayout::eShaderReadOnlyOptimal, cmdBuffer); m_ImageManager->recordImageLayoutTransition(image, vk::ImageLayout::eShaderReadOnlyOptimal, cmdBuffer);
}, nullptr); }, nullptr);
} }
void Core::prepareImageForStorage(const CommandStreamHandle cmdStream, const ImageHandle image) { void Core::prepareImageForStorage(const CommandStreamHandle& cmdStream, const ImageHandle& image) {
recordCommandsToStream(cmdStream, [image, this](const vk::CommandBuffer cmdBuffer) { recordCommandsToStream(cmdStream, [image, this](const vk::CommandBuffer cmdBuffer) {
m_ImageManager->recordImageLayoutTransition(image, vk::ImageLayout::eGeneral, cmdBuffer); m_ImageManager->recordImageLayoutTransition(image, vk::ImageLayout::eGeneral, cmdBuffer);
}, nullptr); }, nullptr);
} }
void Core::recordImageMemoryBarrier(const CommandStreamHandle cmdStream, const ImageHandle image) { void Core::recordImageMemoryBarrier(const CommandStreamHandle& cmdStream, const ImageHandle& image) {
recordCommandsToStream(cmdStream, [image, this](const vk::CommandBuffer cmdBuffer) { recordCommandsToStream(cmdStream, [image, this](const vk::CommandBuffer cmdBuffer) {
m_ImageManager->recordImageMemoryBarrier(image, cmdBuffer); m_ImageManager->recordImageMemoryBarrier(image, cmdBuffer);
}, nullptr); }, nullptr);
} }
void Core::recordBufferMemoryBarrier(const CommandStreamHandle cmdStream, const BufferHandle buffer) { void Core::recordBufferMemoryBarrier(const CommandStreamHandle& cmdStream, const BufferHandle& buffer) {
recordCommandsToStream(cmdStream, [buffer, this](const vk::CommandBuffer cmdBuffer) { recordCommandsToStream(cmdStream, [buffer, this](const vk::CommandBuffer cmdBuffer) {
m_BufferManager->recordBufferMemoryBarrier(buffer, cmdBuffer); m_BufferManager->recordBufferMemoryBarrier(buffer, cmdBuffer);
}, nullptr); }, nullptr);
} }
void Core::resolveMSAAImage(CommandStreamHandle cmdStream, ImageHandle src, ImageHandle dst) { void Core::resolveMSAAImage(const CommandStreamHandle& cmdStream, const ImageHandle& src, const ImageHandle& dst) {
recordCommandsToStream(cmdStream, [src, dst, this](const vk::CommandBuffer cmdBuffer) { recordCommandsToStream(cmdStream, [src, dst, this](const vk::CommandBuffer cmdBuffer) {
m_ImageManager->recordMSAAResolve(cmdBuffer, src, dst); m_ImageManager->recordMSAAResolve(cmdBuffer, src, dst);
}, nullptr); }, nullptr);
...@@ -590,5 +743,86 @@ namespace vkcv ...@@ -590,5 +743,86 @@ namespace vkcv
vk::ImageView Core::getSwapchainImageView() const { vk::ImageView Core::getSwapchainImageView() const {
return m_ImageManager->getVulkanImageView(vkcv::ImageHandle::createSwapchainImageHandle()); return m_ImageManager->getVulkanImageView(vkcv::ImageHandle::createSwapchainImageHandle());
} }
void Core::recordMemoryBarrier(const CommandStreamHandle& cmdStream) {
recordCommandsToStream(cmdStream, [](const vk::CommandBuffer cmdBuffer) {
vk::MemoryBarrier barrier (
vk::AccessFlagBits::eMemoryWrite | vk::AccessFlagBits::eMemoryRead,
vk::AccessFlagBits::eMemoryWrite | vk::AccessFlagBits::eMemoryRead
);
cmdBuffer.pipelineBarrier(
vk::PipelineStageFlagBits::eAllCommands,
vk::PipelineStageFlagBits::eAllCommands,
vk::DependencyFlags(),
1, &barrier,
0, nullptr,
0, nullptr
);
}, nullptr);
}
void Core::recordBlitImage(const CommandStreamHandle& cmdStream, const ImageHandle& src, const ImageHandle& dst,
SamplerFilterType filterType) {
recordCommandsToStream(cmdStream, [&](const vk::CommandBuffer cmdBuffer) {
m_ImageManager->recordImageLayoutTransition(
src, vk::ImageLayout::eTransferSrcOptimal, cmdBuffer
);
m_ImageManager->recordImageLayoutTransition(
dst, vk::ImageLayout::eTransferDstOptimal, cmdBuffer
);
const std::array<vk::Offset3D, 2> srcOffsets = {
vk::Offset3D(0, 0, 0),
vk::Offset3D(
m_ImageManager->getImageWidth(src),
m_ImageManager->getImageHeight(src),
1
)
};
const std::array<vk::Offset3D, 2> dstOffsets = {
vk::Offset3D(0, 0, 0),
vk::Offset3D(
m_ImageManager->getImageWidth(dst),
m_ImageManager->getImageHeight(dst),
1
)
};
const bool srcDepth = isDepthFormat(m_ImageManager->getImageFormat(src));
const bool dstDepth = isDepthFormat(m_ImageManager->getImageFormat(dst));
const vk::ImageBlit blit = vk::ImageBlit(
vk::ImageSubresourceLayers(
srcDepth?
vk::ImageAspectFlagBits::eDepth :
vk::ImageAspectFlagBits::eColor,
0, 0, 1
),
srcOffsets,
vk::ImageSubresourceLayers(
dstDepth?
vk::ImageAspectFlagBits::eDepth :
vk::ImageAspectFlagBits::eColor,
0, 0, 1
),
dstOffsets
);
cmdBuffer.blitImage(
m_ImageManager->getVulkanImage(src),
vk::ImageLayout::eTransferSrcOptimal,
m_ImageManager->getVulkanImage(dst),
vk::ImageLayout::eTransferDstOptimal,
1,
&blit,
filterType == SamplerFilterType::LINEAR?
vk::Filter::eLinear :
vk::Filter::eNearest
);
}, nullptr);
}
} }
...@@ -11,12 +11,17 @@ namespace vkcv ...@@ -11,12 +11,17 @@ namespace vkcv
* Allocate the set size for the descriptor pools, namely 1000 units of each descriptor type below. * Allocate the set size for the descriptor pools, namely 1000 units of each descriptor type below.
* Finally, create an initial pool. * Finally, create an initial pool.
*/ */
m_PoolSizes = { vk::DescriptorPoolSize(vk::DescriptorType::eSampler, 1000), m_PoolSizes = {
vk::DescriptorPoolSize(vk::DescriptorType::eSampledImage, 1000), vk::DescriptorPoolSize(vk::DescriptorType::eSampler, 1000),
vk::DescriptorPoolSize(vk::DescriptorType::eUniformBuffer, 1000), vk::DescriptorPoolSize(vk::DescriptorType::eSampledImage, 1000),
vk::DescriptorPoolSize(vk::DescriptorType::eStorageBuffer, 1000) }; vk::DescriptorPoolSize(vk::DescriptorType::eUniformBuffer, 1000),
vk::DescriptorPoolSize(vk::DescriptorType::eStorageBuffer, 1000),
vk::DescriptorPoolSize(vk::DescriptorType::eUniformBufferDynamic, 1000),
vk::DescriptorPoolSize(vk::DescriptorType::eStorageBufferDynamic, 1000)
};
m_PoolInfo = vk::DescriptorPoolCreateInfo({}, m_PoolInfo = vk::DescriptorPoolCreateInfo(
vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet,
1000, 1000,
static_cast<uint32_t>(m_PoolSizes.size()), static_cast<uint32_t>(m_PoolSizes.size()),
m_PoolSizes.data()); m_PoolSizes.data());
...@@ -29,9 +34,13 @@ namespace vkcv ...@@ -29,9 +34,13 @@ namespace vkcv
for (uint64_t id = 0; id < m_DescriptorSets.size(); id++) { for (uint64_t id = 0; id < m_DescriptorSets.size(); id++) {
destroyDescriptorSetById(id); destroyDescriptorSetById(id);
} }
m_DescriptorSets.clear(); m_DescriptorSets.clear();
for (const auto &pool : m_Pools) { for (const auto &pool : m_Pools) {
m_Device.destroy(pool); if (pool) {
m_Device.destroy(pool);
}
} }
} }
...@@ -40,12 +49,12 @@ namespace vkcv ...@@ -40,12 +49,12 @@ namespace vkcv
std::vector<vk::DescriptorSetLayoutBinding> setBindings = {}; std::vector<vk::DescriptorSetLayoutBinding> setBindings = {};
//create each set's binding //create each set's binding
for (uint32_t i = 0; i < bindings.size(); i++) { for (auto binding : bindings) {
vk::DescriptorSetLayoutBinding descriptorSetLayoutBinding( vk::DescriptorSetLayoutBinding descriptorSetLayoutBinding(
bindings[i].bindingID, binding.bindingID,
convertDescriptorTypeFlag(bindings[i].descriptorType), convertDescriptorTypeFlag(binding.descriptorType),
bindings[i].descriptorCount, binding.descriptorCount,
convertShaderStageFlag(bindings[i].shaderStage)); convertShaderStageFlag(binding.shaderStage));
setBindings.push_back(descriptorSetLayoutBinding); setBindings.push_back(descriptorSetLayoutBinding);
} }
...@@ -53,8 +62,7 @@ namespace vkcv ...@@ -53,8 +62,7 @@ namespace vkcv
//create the descriptor set's layout from the bindings gathered above //create the descriptor set's layout from the bindings gathered above
vk::DescriptorSetLayoutCreateInfo layoutInfo({}, setBindings); vk::DescriptorSetLayoutCreateInfo layoutInfo({}, setBindings);
if(m_Device.createDescriptorSetLayout(&layoutInfo, nullptr, &set.layout) != vk::Result::eSuccess) if (m_Device.createDescriptorSetLayout(&layoutInfo, nullptr, &set.layout) != vk::Result::eSuccess) {
{
vkcv_log(LogLevel::ERROR, "Failed to create descriptor set layout"); vkcv_log(LogLevel::ERROR, "Failed to create descriptor set layout");
return DescriptorSetHandle(); return DescriptorSetHandle();
}; };
...@@ -70,6 +78,7 @@ namespace vkcv ...@@ -70,6 +78,7 @@ namespace vkcv
allocInfo.setDescriptorPool(m_Pools.back()); allocInfo.setDescriptorPool(m_Pools.back());
result = m_Device.allocateDescriptorSets(&allocInfo, &set.vulkanHandle); result = m_Device.allocateDescriptorSets(&allocInfo, &set.vulkanHandle);
} }
if (result != vk::Result::eSuccess) { if (result != vk::Result::eSuccess) {
vkcv_log(LogLevel::ERROR, "Failed to create descriptor set (%s)", vkcv_log(LogLevel::ERROR, "Failed to create descriptor set (%s)",
vk::to_string(result).c_str()); vk::to_string(result).c_str());
...@@ -78,6 +87,8 @@ namespace vkcv ...@@ -78,6 +87,8 @@ namespace vkcv
return DescriptorSetHandle(); return DescriptorSetHandle();
} }
}; };
set.poolIndex = (m_Pools.size() - 1);
const uint64_t id = m_DescriptorSets.size(); const uint64_t id = m_DescriptorSets.size();
...@@ -98,7 +109,6 @@ namespace vkcv ...@@ -98,7 +109,6 @@ namespace vkcv
const ImageManager &imageManager, const ImageManager &imageManager,
const BufferManager &bufferManager, const BufferManager &bufferManager,
const SamplerManager &samplerManager) { const SamplerManager &samplerManager) {
vk::DescriptorSet set = m_DescriptorSets[handle.getId()].vulkanHandle; vk::DescriptorSet set = m_DescriptorSets[handle.getId()].vulkanHandle;
std::vector<vk::DescriptorImageInfo> imageInfos; std::vector<vk::DescriptorImageInfo> imageInfos;
...@@ -146,10 +156,15 @@ namespace vkcv ...@@ -146,10 +156,15 @@ namespace vkcv
} }
for (const auto& write : writes.uniformBufferWrites) { for (const auto& write : writes.uniformBufferWrites) {
const size_t size = bufferManager.getBufferSize(write.buffer);
const uint32_t offset = std::clamp<uint32_t>(write.offset, 0, size);
const vk::DescriptorBufferInfo bufferInfo( const vk::DescriptorBufferInfo bufferInfo(
bufferManager.getBuffer(write.buffer), bufferManager.getBuffer(write.buffer),
static_cast<uint32_t>(0), offset,
bufferManager.getBufferSize(write.buffer) write.size == 0? size : std::min<uint32_t>(
write.size, size - offset
)
); );
bufferInfos.push_back(bufferInfo); bufferInfos.push_back(bufferInfo);
...@@ -158,6 +173,8 @@ namespace vkcv ...@@ -158,6 +173,8 @@ namespace vkcv
0, 0,
bufferInfos.size(), bufferInfos.size(),
write.binding, write.binding,
write.dynamic?
vk::DescriptorType::eUniformBufferDynamic :
vk::DescriptorType::eUniformBuffer vk::DescriptorType::eUniformBuffer
}; };
...@@ -165,10 +182,15 @@ namespace vkcv ...@@ -165,10 +182,15 @@ namespace vkcv
} }
for (const auto& write : writes.storageBufferWrites) { for (const auto& write : writes.storageBufferWrites) {
const size_t size = bufferManager.getBufferSize(write.buffer);
const uint32_t offset = std::clamp<uint32_t>(write.offset, 0, size);
const vk::DescriptorBufferInfo bufferInfo( const vk::DescriptorBufferInfo bufferInfo(
bufferManager.getBuffer(write.buffer), bufferManager.getBuffer(write.buffer),
static_cast<uint32_t>(0), offset,
bufferManager.getBufferSize(write.buffer) write.size == 0? size : std::min<uint32_t>(
write.size, size - offset
)
); );
bufferInfos.push_back(bufferInfo); bufferInfos.push_back(bufferInfo);
...@@ -177,6 +199,8 @@ namespace vkcv ...@@ -177,6 +199,8 @@ namespace vkcv
0, 0,
bufferInfos.size(), bufferInfos.size(),
write.binding, write.binding,
write.dynamic?
vk::DescriptorType::eStorageBufferDynamic :
vk::DescriptorType::eStorageBuffer vk::DescriptorType::eStorageBuffer
}; };
...@@ -232,8 +256,12 @@ namespace vkcv ...@@ -232,8 +256,12 @@ namespace vkcv
{ {
case DescriptorType::UNIFORM_BUFFER: case DescriptorType::UNIFORM_BUFFER:
return vk::DescriptorType::eUniformBuffer; return vk::DescriptorType::eUniformBuffer;
case DescriptorType::UNIFORM_BUFFER_DYNAMIC:
return vk::DescriptorType::eUniformBufferDynamic;
case DescriptorType::STORAGE_BUFFER: case DescriptorType::STORAGE_BUFFER:
return vk::DescriptorType::eStorageBuffer; return vk::DescriptorType::eStorageBuffer;
case DescriptorType::STORAGE_BUFFER_DYNAMIC:
return vk::DescriptorType::eStorageBufferDynamic;
case DescriptorType::SAMPLER: case DescriptorType::SAMPLER:
return vk::DescriptorType::eSampler; return vk::DescriptorType::eSampler;
case DescriptorType::IMAGE_SAMPLED: case DescriptorType::IMAGE_SAMPLED:
...@@ -277,17 +305,22 @@ namespace vkcv ...@@ -277,17 +305,22 @@ namespace vkcv
m_Device.destroyDescriptorSetLayout(set.layout); m_Device.destroyDescriptorSetLayout(set.layout);
set.layout = nullptr; set.layout = nullptr;
} }
// FIXME: descriptor set itself not destroyed
if (set.vulkanHandle) {
m_Device.freeDescriptorSets(m_Pools[set.poolIndex], 1, &(set.vulkanHandle));
set.vulkanHandle = nullptr;
}
} }
vk::DescriptorPool DescriptorManager::allocateDescriptorPool() { vk::DescriptorPool DescriptorManager::allocateDescriptorPool() {
vk::DescriptorPool pool; vk::DescriptorPool pool;
if (m_Device.createDescriptorPool(&m_PoolInfo, nullptr, &pool) != vk::Result::eSuccess) if (m_Device.createDescriptorPool(&m_PoolInfo, nullptr, &pool) != vk::Result::eSuccess) {
{
vkcv_log(LogLevel::WARNING, "Failed to allocate descriptor pool"); vkcv_log(LogLevel::WARNING, "Failed to allocate descriptor pool");
pool = nullptr; pool = nullptr;
}; } else {
m_Pools.push_back(pool); m_Pools.push_back(pool);
}
return pool; return pool;
} }
......
#include <vkcv/DrawcallRecording.hpp> #include <vkcv/DrawcallRecording.hpp>
#include <vkcv/Logger.hpp>
namespace vkcv { namespace vkcv {
vk::IndexType getIndexType(IndexBitCount indexByteCount){
switch (indexByteCount) {
case IndexBitCount::Bit16: return vk::IndexType::eUint16;
case IndexBitCount::Bit32: return vk::IndexType::eUint32;
default:
vkcv_log(LogLevel::ERROR, "unknown Enum");
return vk::IndexType::eUint16;
}
}
void recordDrawcall( void recordDrawcall(
const DrawcallInfo &drawcall, const DrawcallInfo &drawcall,
vk::CommandBuffer cmdBuffer, vk::CommandBuffer cmdBuffer,
vk::PipelineLayout pipelineLayout, vk::PipelineLayout pipelineLayout,
const PushConstantData &pushConstantData, const PushConstants &pushConstants,
const size_t drawcallIndex) { const size_t drawcallIndex) {
for (uint32_t i = 0; i < drawcall.mesh.vertexBufferBindings.size(); i++) { for (uint32_t i = 0; i < drawcall.mesh.vertexBufferBindings.size(); i++) {
...@@ -23,25 +34,69 @@ namespace vkcv { ...@@ -23,25 +34,69 @@ namespace vkcv {
nullptr); nullptr);
} }
const size_t drawcallPushConstantOffset = drawcallIndex * pushConstantData.sizePerDrawcall; if (pushConstants.getSizePerDrawcall() > 0) {
// char* cast because void* does not support pointer arithmetic
const void* drawcallPushConstantData = drawcallPushConstantOffset + (char*)pushConstantData.data;
if (pushConstantData.data && pushConstantData.sizePerDrawcall > 0) {
cmdBuffer.pushConstants( cmdBuffer.pushConstants(
pipelineLayout, pipelineLayout,
vk::ShaderStageFlagBits::eAll, vk::ShaderStageFlagBits::eAll,
0, 0,
pushConstantData.sizePerDrawcall, pushConstants.getSizePerDrawcall(),
drawcallPushConstantData); pushConstants.getDrawcallData(drawcallIndex));
} }
if (drawcall.mesh.indexBuffer) { if (drawcall.mesh.indexBuffer) {
cmdBuffer.bindIndexBuffer(drawcall.mesh.indexBuffer, 0, vk::IndexType::eUint16); //FIXME: choose proper size cmdBuffer.bindIndexBuffer(drawcall.mesh.indexBuffer, 0, getIndexType(drawcall.mesh.indexBitCount));
cmdBuffer.drawIndexed(drawcall.mesh.indexCount, drawcall.instanceCount, 0, 0, {}); cmdBuffer.drawIndexed(drawcall.mesh.indexCount, drawcall.instanceCount, 0, 0, {});
} }
else { else {
cmdBuffer.draw(drawcall.mesh.indexCount, 1, 0, 0, {}); cmdBuffer.draw(drawcall.mesh.indexCount, drawcall.instanceCount, 0, 0, {});
}
}
struct MeshShaderFunctions
{
PFN_vkCmdDrawMeshTasksNV cmdDrawMeshTasks = nullptr;
PFN_vkCmdDrawMeshTasksIndirectNV cmdDrawMeshTasksIndirect = nullptr;
PFN_vkCmdDrawMeshTasksIndirectCountNV cmdDrawMeshTasksIndirectCount = nullptr;
} MeshShaderFunctions;
void InitMeshShaderDrawFunctions(vk::Device device)
{
MeshShaderFunctions.cmdDrawMeshTasks = PFN_vkCmdDrawMeshTasksNV(device.getProcAddr("vkCmdDrawMeshTasksNV"));
MeshShaderFunctions.cmdDrawMeshTasksIndirect = PFN_vkCmdDrawMeshTasksIndirectNV(device.getProcAddr("vkCmdDrawMeshTasksIndirectNV"));
MeshShaderFunctions.cmdDrawMeshTasksIndirectCount = PFN_vkCmdDrawMeshTasksIndirectCountNV (device.getProcAddr( "vkCmdDrawMeshTasksIndirectCountNV"));
}
void recordMeshShaderDrawcall(
vk::CommandBuffer cmdBuffer,
vk::PipelineLayout pipelineLayout,
const PushConstants& pushConstantData,
const uint32_t pushConstantOffset,
const MeshShaderDrawcall& drawcall,
const uint32_t firstTask) {
for (const auto& descriptorUsage : drawcall.descriptorSets) {
cmdBuffer.bindDescriptorSets(
vk::PipelineBindPoint::eGraphics,
pipelineLayout,
descriptorUsage.setLocation,
descriptorUsage.vulkanHandle,
nullptr);
}
// char* cast because void* does not support pointer arithmetic
const void* drawcallPushConstantData = pushConstantOffset + (char*)pushConstantData.getData();
if (pushConstantData.getData()) {
cmdBuffer.pushConstants(
pipelineLayout,
vk::ShaderStageFlagBits::eAll,
0,
pushConstantData.getSizePerDrawcall(),
drawcallPushConstantData);
} }
MeshShaderFunctions.cmdDrawMeshTasks(VkCommandBuffer(cmdBuffer), drawcall.taskCount, firstTask);
} }
} }
#include "vkcv/File.hpp"
#include <stdlib.h>
#ifdef _WIN32
#include <io.h>
#else
#include <unistd.h>
#endif
#include "vkcv/Logger.hpp"
namespace vkcv {
std::filesystem::path generateTemporaryFilePath() {
std::filesystem::path tmp = generateTemporaryDirectoryPath();
if (std::filesystem::is_directory(tmp)) {
return std::filesystem::path(tmp.string() + "W"); // add W for Wambo
} else {
return tmp;
}
}
std::filesystem::path generateTemporaryDirectoryPath() {
std::error_code code;
auto tmp = std::filesystem::temp_directory_path(code);
if (tmp.empty()) {
tmp = std::filesystem::current_path();
}
char name [16] = "vkcv_tmp_XXXXXX";
#ifdef _WIN32
int err = _mktemp_s(name, 16);
if (err != 0) {
vkcv_log(LogLevel::ERROR, "Temporary file path could not be generated");
return "";
}
#else
int fd = mkstemp(name); // creates a file locally
if (fd == -1) {
vkcv_log(LogLevel::ERROR, "Temporary file path could not be generated");
return "";
}
close(fd);
remove(name); // removes the local file again
#endif
return tmp / name;
}
}