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

Target

Select target project
  • vulkan2021/vkcv-framework
1 result
Show changes
Showing
with 1064 additions and 400 deletions
......@@ -30,7 +30,7 @@ if(MSVC)
endif()
# 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
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
#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)
{
......@@ -24,112 +18,6 @@ vec3 ACESFilm(vec3 x)
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)))){
......@@ -138,12 +26,9 @@ void main(){
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 linearColor = sampleColorChromaticAberration(uv);
vec3 linearColor = texture(sampler2D(inTexture, textureSampler), uv).rgb;
vec3 tonemapped = ACESFilm(linearColor);
tonemapped = applyGrain(coord, tonemapped);
vec3 gammaCorrected = pow(tonemapped, vec3(1.f / 2.2f));
imageStore(outImage, coord, vec4(gammaCorrected, 0.f));
imageStore(outImage, coord, vec4(tonemapped, 0.f));
}
\ No newline at end of file
......@@ -119,10 +119,10 @@ Voxelization::Voxelization(
m_voxelizationPipe = m_corePtr->createGraphicsPipeline(voxelizationPipeConfig);
vkcv::DescriptorWrites voxelizationDescriptorWrites;
voxelizationDescriptorWrites.storageBufferWrites = { vkcv::StorageBufferDescriptorWrite(0, m_voxelBuffer.getHandle()) };
voxelizationDescriptorWrites.storageBufferWrites = { vkcv::BufferDescriptorWrite(0, m_voxelBuffer.getHandle()) };
voxelizationDescriptorWrites.uniformBufferWrites = {
vkcv::UniformBufferDescriptorWrite(1, m_voxelInfoBuffer.getHandle()),
vkcv::UniformBufferDescriptorWrite(3, lightInfoBuffer)
vkcv::BufferDescriptorWrite(1, m_voxelInfoBuffer.getHandle()),
vkcv::BufferDescriptorWrite(3, lightInfoBuffer)
};
voxelizationDescriptorWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(4, shadowMap) };
voxelizationDescriptorWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(5, shadowSampler) };
......@@ -180,7 +180,7 @@ Voxelization::Voxelization(
{ m_corePtr->getDescriptorSet(m_voxelResetDescriptorSet).layout });
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);
// buffer to image
......@@ -192,7 +192,7 @@ Voxelization::Voxelization(
{ m_corePtr->getDescriptorSet(m_bufferToImageDescriptorSet).layout });
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()) };
m_corePtr->writeDescriptorSet(m_bufferToImageDescriptorSet, bufferToImageDescriptorWrites);
......@@ -205,11 +205,11 @@ Voxelization::Voxelization(
{ m_corePtr->getDescriptorSet(m_secondaryBounceDescriptorSet).layout });
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.samplerWrites = { vkcv::SamplerDescriptorWrite(2, voxelSampler) };
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);
}
......@@ -331,7 +331,7 @@ void Voxelization::renderVoxelVisualisation(
voxelVisualisationDescriptorWrite.storageImageWrites =
{ vkcv::StorageImageDescriptorWrite(0, m_voxelImage.getHandle(), mipLevel) };
voxelVisualisationDescriptorWrite.uniformBufferWrites =
{ vkcv::UniformBufferDescriptorWrite(1, m_voxelInfoBuffer.getHandle()) };
{ vkcv::BufferDescriptorWrite(1, m_voxelInfoBuffer.getHandle()) };
m_corePtr->writeDescriptorSet(m_visualisationDescriptorSet, voxelVisualisationDescriptorWrite);
uint32_t drawVoxelCount = voxelCount / exp2(mipLevel);
......
......@@ -11,6 +11,8 @@
#include "vkcv/gui/GUI.hpp"
#include "ShadowMapping.hpp"
#include "BloomAndFlares.hpp"
#include <vkcv/upscaling/FSRUpscaling.hpp>
#include <vkcv/upscaling/BilinearUpscaling.hpp>
int main(int argc, const char** argv) {
const char* applicationName = "Voxelization";
......@@ -27,11 +29,11 @@ int main(int argc, const char** argv) {
true
);
bool isFullscreen = false;
int windowedWidthBackup = windowWidth;
int windowedHeightBackup = windowHeight;
int windowedPosXBackup;
int windowedPosYBackup;
bool isFullscreen = false;
uint32_t windowedWidthBackup = windowWidth;
uint32_t windowedHeightBackup = windowHeight;
int windowedPosXBackup;
int windowedPosYBackup;
glfwGetWindowPos(window.getWindow(), &windowedPosXBackup, &windowedPosYBackup);
window.e_key.add([&](int key, int scancode, int action, int mods) {
......@@ -85,7 +87,7 @@ int main(int argc, const char** argv) {
VK_MAKE_VERSION(0, 0, 1),
{ 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;
......@@ -393,6 +395,9 @@ int main(int argc, const char** argv) {
else {
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();
......@@ -421,6 +426,18 @@ int main(int argc, const char** argv) {
vkcv::PipelineHandle tonemappingPipeline = core.createComputePipeline(
tonemappingProgram,
{ 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
vkcv::ShaderProgram resolveProgram;
......@@ -438,7 +455,8 @@ int main(int argc, const char** argv) {
vkcv::SamplerFilterType::NEAREST,
vkcv::SamplerFilterType::NEAREST,
vkcv::SamplerMipmapMode::NEAREST,
vkcv::SamplerAddressMode::CLAMP_TO_EDGE);
vkcv::SamplerAddressMode::CLAMP_TO_EDGE
);
// model matrices per mesh
std::vector<glm::mat4> modelMatrices;
......@@ -473,7 +491,8 @@ int main(int argc, const char** argv) {
vkcv::SamplerFilterType::LINEAR,
vkcv::SamplerFilterType::LINEAR,
vkcv::SamplerMipmapMode::LINEAR,
vkcv::SamplerAddressMode::CLAMP_TO_EDGE);
vkcv::SamplerAddressMode::CLAMP_TO_EDGE
);
ShadowMapping shadowMapping(&core, vertexLayout);
......@@ -511,10 +530,10 @@ int main(int argc, const char** argv) {
// write forward pass descriptor set
vkcv::DescriptorWrites forwardDescriptorWrites;
forwardDescriptorWrites.uniformBufferWrites = {
vkcv::UniformBufferDescriptorWrite(0, shadowMapping.getLightInfoBuffer()),
vkcv::UniformBufferDescriptorWrite(3, cameraPosBuffer.getHandle()),
vkcv::UniformBufferDescriptorWrite(6, voxelization.getVoxelInfoBufferHandle()),
vkcv::UniformBufferDescriptorWrite(7, volumetricSettingsBuffer.getHandle())};
vkcv::BufferDescriptorWrite(0, shadowMapping.getLightInfoBuffer()),
vkcv::BufferDescriptorWrite(3, cameraPosBuffer.getHandle()),
vkcv::BufferDescriptorWrite(6, voxelization.getVoxelInfoBufferHandle()),
vkcv::BufferDescriptorWrite(7, volumetricSettingsBuffer.getHandle())};
forwardDescriptorWrites.sampledImageWrites = {
vkcv::SampledImageDescriptorWrite(1, shadowMapping.getShadowMap()),
vkcv::SampledImageDescriptorWrite(4, voxelization.getVoxelImageHandle()) };
......@@ -523,6 +542,27 @@ int main(int argc, const char** argv) {
vkcv::SamplerDescriptorWrite(5, voxelSampler) };
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);
glm::vec2 lightAnglesDegree = glm::vec2(90.f, 0.f);
......@@ -550,22 +590,72 @@ int main(int argc, const char** argv) {
if (!core.beginFrame(swapchainWidth, swapchainHeight)) {
continue;
}
if ((swapchainWidth != windowWidth) || ((swapchainHeight != windowHeight))) {
depthBuffer = core.createImage(depthBufferFormat, swapchainWidth, swapchainHeight, 1, false, false, false, msaa).getHandle();
colorBuffer = core.createImage(colorBufferFormat, swapchainWidth, swapchainHeight, 1, false, colorBufferRequiresStorage, true, msaa).getHandle();
uint32_t width, height;
vkcv::upscaling::getFSRResolution(
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) {
resolvedColorBuffer = core.createImage(colorBufferFormat, swapchainWidth, swapchainHeight, 1, false, true, true).getHandle();
}
else {
resolvedColorBuffer = core.createImage(
colorBufferFormat,
fsrWidth, fsrHeight, 1,
false, true, true
).getHandle();
} else {
resolvedColorBuffer = colorBuffer;
}
windowWidth = swapchainWidth;
windowHeight = swapchainHeight;
bloomFlares.updateImageDimensions(windowWidth, windowHeight);
swapBuffer = core.createImage(
colorBufferFormat,
fsrWidth, fsrHeight, 1,
false, true
).getHandle();
swapBuffer2 = core.createImage(
colorBufferFormat,
swapchainWidth, swapchainHeight, 1,
false, true
).getHandle();
bloomFlares.updateImageDimensions(swapchainWidth, swapchainHeight);
}
auto end = std::chrono::system_clock::now();
......@@ -575,9 +665,17 @@ int main(int argc, const char** argv) {
vkcv::DescriptorWrites tonemappingDescriptorWrites;
tonemappingDescriptorWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(0, resolvedColorBuffer) };
tonemappingDescriptorWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(1, colorSampler) };
tonemappingDescriptorWrites.storageImageWrites = { vkcv::StorageImageDescriptorWrite(2, swapchainInput) };
tonemappingDescriptorWrites.storageImageWrites = { vkcv::StorageImageDescriptorWrite(2, swapBuffer) };
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
vkcv::DescriptorWrites resolveDescriptorWrites;
......@@ -679,11 +777,18 @@ int main(int argc, const char** argv) {
renderTargets);
const uint32_t fullscreenLocalGroupSize = 8;
const uint32_t fulsscreenDispatchCount[3] = {
static_cast<uint32_t>(glm::ceil(windowWidth / static_cast<float>(fullscreenLocalGroupSize))),
static_cast<uint32_t>(glm::ceil(windowHeight / static_cast<float>(fullscreenLocalGroupSize))),
1
};
uint32_t fulsscreenDispatchCount [3];
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 (msaaCustomResolve) {
......@@ -706,24 +811,58 @@ int main(int argc, const char** argv) {
}
}
bloomFlares.execWholePipeline(cmdStream, resolvedColorBuffer, windowWidth, windowHeight,
glm::normalize(cameraManager.getActiveCamera().getFront()));
bloomFlares.execWholePipeline(cmdStream, resolvedColorBuffer, fsrWidth, fsrHeight,
glm::normalize(cameraManager.getActiveCamera().getFront())
);
core.prepareImageForStorage(cmdStream, swapchainInput);
core.prepareImageForStorage(cmdStream, swapBuffer);
core.prepareImageForSampling(cmdStream, resolvedColorBuffer);
auto timeSinceStart = std::chrono::duration_cast<std::chrono::microseconds>(end - appStartTime);
float timeF = static_cast<float>(timeSinceStart.count()) * 0.01;
vkcv::PushConstants timePushConstants (sizeof(timeF));
timePushConstants.appendDrawcall(timeF);
core.recordComputeDispatchToCmdStream(
cmdStream,
tonemappingPipeline,
fulsscreenDispatchCount,
{ vkcv::DescriptorSetUsage(0, core.getDescriptorSet(tonemappingDescriptorSet).vulkanHandle) },
timePushConstants);
{ vkcv::DescriptorSetUsage(0, core.getDescriptorSet(
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
core.prepareSwapchainImageForPresent(cmdStream);
......@@ -751,12 +890,25 @@ int main(int argc, const char** argv) {
ImGui::DragFloat("Voxelization extent", &voxelizationExtent, 1.f, 0.f);
voxelizationExtent = std::max(voxelizationExtent, 1.f);
voxelVisualisationMip = std::max(voxelVisualisationMip, 0);
ImGui::ColorEdit3("Scattering color", &scatteringColor.x);
ImGui::DragFloat("Scattering density", &scatteringDensity, 0.0001);
ImGui::ColorEdit3("Absorption color", &absorptionColor.x);
ImGui::DragFloat("Absorption density", &absorptionDensity, 0.0001);
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")) {
......
......@@ -151,7 +151,7 @@ namespace vkcv
* @param check The elements to be checked
* @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) {
bool found = false;
......@@ -180,11 +180,20 @@ namespace vkcv
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,
uint32_t applicationVersion,
std::vector<vk::QueueFlagBits> queueFlags,
std::vector<const char *> instanceExtensions,
std::vector<const char *> deviceExtensions) {
const std::vector<vk::QueueFlagBits>& queueFlags,
const std::vector<const char *>& instanceExtensions,
const std::vector<const char *>& deviceExtensions) {
// check for layer support
const std::vector<vk::LayerProperties>& layerProperties = vk::enumerateInstanceLayerProperties();
......@@ -223,7 +232,7 @@ namespace vkcv
// for GLFW: get all required extensions
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(
applicationName,
......@@ -238,8 +247,8 @@ namespace vkcv
&applicationInfo,
0,
nullptr,
static_cast<uint32_t>(instanceExtensions.size()),
instanceExtensions.data()
static_cast<uint32_t>(requiredExtensions.size()),
requiredExtensions.data()
);
#ifndef NDEBUG
......@@ -286,13 +295,39 @@ namespace vkcv
deviceCreateInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
deviceCreateInfo.ppEnabledLayerNames = validationLayers.data();
#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
vk::PhysicalDeviceFeatures deviceFeatures;
deviceFeatures.fragmentStoresAndAtomics = true;
deviceFeatures.geometryShader = true;
deviceFeatures.depthClamp = true;
deviceCreateInfo.pEnabledFeatures = &deviceFeatures;
vk::PhysicalDeviceShaderFloat16Int8Features deviceShaderFloat16Int8Features;
deviceShaderFloat16Int8Features.shaderFloat16 = shaderFloat16;
vk::PhysicalDevice16BitStorageFeatures device16BitStorageFeatures;
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
// qCreateInfos erstellen --> braucht das Device
......@@ -300,6 +335,11 @@ namespace vkcv
// jetzt koennen wir mit dem device die queues erstellen
vk::Device device = physicalDevice.createDevice(deviceCreateInfo);
if (usingMeshShaders)
{
InitMeshShaderDrawFunctions(device);
}
QueueManager queueManager = QueueManager::create(
device,
......
This diff is collapsed.
......@@ -11,10 +11,14 @@ namespace vkcv
* Allocate the set size for the descriptor pools, namely 1000 units of each descriptor type below.
* Finally, create an initial pool.
*/
m_PoolSizes = { vk::DescriptorPoolSize(vk::DescriptorType::eSampler, 1000),
vk::DescriptorPoolSize(vk::DescriptorType::eSampledImage, 1000),
vk::DescriptorPoolSize(vk::DescriptorType::eUniformBuffer, 1000),
vk::DescriptorPoolSize(vk::DescriptorType::eStorageBuffer, 1000) };
m_PoolSizes = {
vk::DescriptorPoolSize(vk::DescriptorType::eSampler, 1000),
vk::DescriptorPoolSize(vk::DescriptorType::eSampledImage, 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(
vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet,
......@@ -105,7 +109,6 @@ namespace vkcv
const ImageManager &imageManager,
const BufferManager &bufferManager,
const SamplerManager &samplerManager) {
vk::DescriptorSet set = m_DescriptorSets[handle.getId()].vulkanHandle;
std::vector<vk::DescriptorImageInfo> imageInfos;
......@@ -153,10 +156,15 @@ namespace vkcv
}
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(
bufferManager.getBuffer(write.buffer),
static_cast<uint32_t>(0),
bufferManager.getBufferSize(write.buffer)
offset,
write.size == 0? size : std::min<uint32_t>(
write.size, size - offset
)
);
bufferInfos.push_back(bufferInfo);
......@@ -165,6 +173,8 @@ namespace vkcv
0,
bufferInfos.size(),
write.binding,
write.dynamic?
vk::DescriptorType::eUniformBufferDynamic :
vk::DescriptorType::eUniformBuffer
};
......@@ -172,10 +182,15 @@ namespace vkcv
}
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(
bufferManager.getBuffer(write.buffer),
static_cast<uint32_t>(0),
bufferManager.getBufferSize(write.buffer)
offset,
write.size == 0? size : std::min<uint32_t>(
write.size, size - offset
)
);
bufferInfos.push_back(bufferInfo);
......@@ -184,6 +199,8 @@ namespace vkcv
0,
bufferInfos.size(),
write.binding,
write.dynamic?
vk::DescriptorType::eStorageBufferDynamic :
vk::DescriptorType::eStorageBuffer
};
......@@ -239,8 +256,12 @@ namespace vkcv
{
case DescriptorType::UNIFORM_BUFFER:
return vk::DescriptorType::eUniformBuffer;
case DescriptorType::UNIFORM_BUFFER_DYNAMIC:
return vk::DescriptorType::eUniformBufferDynamic;
case DescriptorType::STORAGE_BUFFER:
return vk::DescriptorType::eStorageBuffer;
case DescriptorType::STORAGE_BUFFER_DYNAMIC:
return vk::DescriptorType::eStorageBufferDynamic;
case DescriptorType::SAMPLER:
return vk::DescriptorType::eSampler;
case DescriptorType::IMAGE_SAMPLED:
......
#include <vkcv/DrawcallRecording.hpp>
#include <vkcv/Logger.hpp>
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(
const DrawcallInfo &drawcall,
vk::CommandBuffer cmdBuffer,
......@@ -33,11 +44,59 @@ namespace vkcv {
}
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, {});
}
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;
}
}
......@@ -13,6 +13,8 @@
#include "vkcv/ImageConfig.hpp"
namespace vkcv {
bool isDepthImageFormat(vk::Format format);
class ImageManager
{
......
......@@ -44,95 +44,190 @@ namespace vkcv
vk::PrimitiveTopology primitiveTopologyToVulkanPrimitiveTopology(const PrimitiveTopology topology) {
switch (topology) {
case(PrimitiveTopology::PointList): return vk::PrimitiveTopology::ePointList;
case(PrimitiveTopology::LineList): return vk::PrimitiveTopology::eLineList;
case(PrimitiveTopology::TriangleList): return vk::PrimitiveTopology::eTriangleList;
default: std::cout << "Error: Unknown primitive topology type" << std::endl; return vk::PrimitiveTopology::eTriangleList;
case(PrimitiveTopology::PointList): return vk::PrimitiveTopology::ePointList;
case(PrimitiveTopology::LineList): return vk::PrimitiveTopology::eLineList;
case(PrimitiveTopology::TriangleList): return vk::PrimitiveTopology::eTriangleList;
default: std::cout << "Error: Unknown primitive topology type" << std::endl; return vk::PrimitiveTopology::eTriangleList;
}
}
vk::CompareOp depthTestToVkCompareOp(DepthTest depthTest) {
switch (depthTest) {
case(DepthTest::None): return vk::CompareOp::eAlways;
case(DepthTest::Less): return vk::CompareOp::eLess;
case(DepthTest::LessEqual): return vk::CompareOp::eLessOrEqual;
case(DepthTest::Greater): return vk::CompareOp::eGreater;
case(DepthTest::GreatherEqual): return vk::CompareOp::eGreaterOrEqual;
case(DepthTest::Equal): return vk::CompareOp::eEqual;
default: vkcv_log(vkcv::LogLevel::ERROR, "Unknown depth test enum"); return vk::CompareOp::eAlways;
case(DepthTest::None): return vk::CompareOp::eAlways;
case(DepthTest::Less): return vk::CompareOp::eLess;
case(DepthTest::LessEqual): return vk::CompareOp::eLessOrEqual;
case(DepthTest::Greater): return vk::CompareOp::eGreater;
case(DepthTest::GreatherEqual): return vk::CompareOp::eGreaterOrEqual;
case(DepthTest::Equal): return vk::CompareOp::eEqual;
default: vkcv_log(vkcv::LogLevel::ERROR, "Unknown depth test enum"); return vk::CompareOp::eAlways;
}
}
vk::ShaderStageFlagBits shaderStageToVkShaderStage(vkcv::ShaderStage stage) {
switch (stage) {
case vkcv::ShaderStage::VERTEX: return vk::ShaderStageFlagBits::eVertex;
case vkcv::ShaderStage::FRAGMENT: return vk::ShaderStageFlagBits::eFragment;
case vkcv::ShaderStage::GEOMETRY: return vk::ShaderStageFlagBits::eGeometry;
case vkcv::ShaderStage::TESS_CONTROL: return vk::ShaderStageFlagBits::eTessellationControl;
case vkcv::ShaderStage::TESS_EVAL: return vk::ShaderStageFlagBits::eTessellationEvaluation;
case vkcv::ShaderStage::COMPUTE: return vk::ShaderStageFlagBits::eCompute;
case vkcv::ShaderStage::TASK: return vk::ShaderStageFlagBits::eTaskNV;
case vkcv::ShaderStage::MESH: return vk::ShaderStageFlagBits::eMeshNV;
default: vkcv_log(vkcv::LogLevel::ERROR, "Unknown shader stage"); return vk::ShaderStageFlagBits::eAll;
}
}
bool createPipelineShaderStageCreateInfo(
const vkcv::ShaderProgram& shaderProgram,
ShaderStage stage,
vk::Device device,
vk::PipelineShaderStageCreateInfo* outCreateInfo) {
assert(outCreateInfo);
std::vector<char> code = shaderProgram.getShader(stage).shaderCode;
vk::ShaderModuleCreateInfo vertexModuleInfo({}, code.size(), reinterpret_cast<uint32_t*>(code.data()));
vk::ShaderModule shaderModule;
if (device.createShaderModule(&vertexModuleInfo, nullptr, &shaderModule) != vk::Result::eSuccess)
return false;
const static auto entryName = "main";
*outCreateInfo = vk::PipelineShaderStageCreateInfo(
{},
shaderStageToVkShaderStage(stage),
shaderModule,
entryName,
nullptr);
return true;
}
PipelineHandle PipelineManager::createPipeline(const PipelineConfig &config, PassManager& passManager)
{
const vk::RenderPass &pass = passManager.getVkPass(config.m_PassHandle);
const bool existsTaskShader = config.m_ShaderProgram.existsShader(ShaderStage::TASK);
const bool existsMeshShader = config.m_ShaderProgram.existsShader(ShaderStage::MESH);
const bool existsVertexShader = config.m_ShaderProgram.existsShader(ShaderStage::VERTEX);
const bool validGeometryStages = existsVertexShader || (existsTaskShader && existsMeshShader);
const bool existsFragmentShader = config.m_ShaderProgram.existsShader(ShaderStage::FRAGMENT);
if (!(existsVertexShader && existsFragmentShader))
if (!validGeometryStages)
{
vkcv_log(LogLevel::ERROR, "Requires vertex and fragment shader code");
vkcv_log(LogLevel::ERROR, "Requires vertex or task and mesh shader");
return PipelineHandle();
}
// vertex shader stage
std::vector<char> vertexCode = config.m_ShaderProgram.getShader(ShaderStage::VERTEX).shaderCode;
vk::ShaderModuleCreateInfo vertexModuleInfo({}, vertexCode.size(), reinterpret_cast<uint32_t*>(vertexCode.data()));
vk::ShaderModule vertexModule{};
if (m_Device.createShaderModule(&vertexModuleInfo, nullptr, &vertexModule) != vk::Result::eSuccess)
if (!existsFragmentShader) {
vkcv_log(LogLevel::ERROR, "Requires fragment shader code");
return PipelineHandle();
}
vk::PipelineShaderStageCreateInfo pipelineVertexShaderStageInfo(
{},
vk::ShaderStageFlagBits::eVertex,
vertexModule,
"main",
nullptr
);
std::vector<vk::PipelineShaderStageCreateInfo> shaderStages;
auto destroyShaderModules = [&shaderStages, this] {
for (auto stage : shaderStages) {
m_Device.destroyShaderModule(stage.module);
}
shaderStages.clear();
};
if (existsVertexShader) {
vk::PipelineShaderStageCreateInfo createInfo;
const bool success = createPipelineShaderStageCreateInfo(
config.m_ShaderProgram,
vkcv::ShaderStage::VERTEX,
m_Device,
&createInfo);
if (success) {
shaderStages.push_back(createInfo);
}
else {
destroyShaderModules();
return PipelineHandle();
}
}
if (existsTaskShader) {
vk::PipelineShaderStageCreateInfo createInfo;
const bool success = createPipelineShaderStageCreateInfo(
config.m_ShaderProgram,
vkcv::ShaderStage::TASK,
m_Device,
&createInfo);
if (success) {
shaderStages.push_back(createInfo);
}
else {
destroyShaderModules();
return PipelineHandle();
}
}
if (existsMeshShader) {
vk::PipelineShaderStageCreateInfo createInfo;
const bool success = createPipelineShaderStageCreateInfo(
config.m_ShaderProgram,
vkcv::ShaderStage::MESH,
m_Device,
&createInfo);
if (success) {
shaderStages.push_back(createInfo);
}
else {
destroyShaderModules();
return PipelineHandle();
}
}
// fragment shader stage
std::vector<char> fragCode = config.m_ShaderProgram.getShader(ShaderStage::FRAGMENT).shaderCode;
vk::ShaderModuleCreateInfo fragmentModuleInfo({}, fragCode.size(), reinterpret_cast<uint32_t*>(fragCode.data()));
vk::ShaderModule fragmentModule{};
if (m_Device.createShaderModule(&fragmentModuleInfo, nullptr, &fragmentModule) != vk::Result::eSuccess)
{
m_Device.destroy(vertexModule);
return PipelineHandle();
vk::PipelineShaderStageCreateInfo createInfo;
const bool success = createPipelineShaderStageCreateInfo(
config.m_ShaderProgram,
vkcv::ShaderStage::FRAGMENT,
m_Device,
&createInfo);
if (success) {
shaderStages.push_back(createInfo);
}
else {
destroyShaderModules();
return PipelineHandle();
}
}
vk::PipelineShaderStageCreateInfo pipelineFragmentShaderStageInfo(
{},
vk::ShaderStageFlagBits::eFragment,
fragmentModule,
"main",
nullptr
);
// vertex input state
// Fill up VertexInputBindingDescription and VertexInputAttributeDescription Containers
std::vector<vk::VertexInputAttributeDescription> vertexAttributeDescriptions;
std::vector<vk::VertexInputBindingDescription> vertexBindingDescriptions;
const VertexLayout &layout = config.m_VertexLayout;
// iterate over the layout's specified, mutually exclusive buffer bindings that make up a vertex buffer
for (const auto &vertexBinding : layout.vertexBindings)
{
vertexBindingDescriptions.emplace_back(vertexBinding.bindingLocation,
vertexBinding.stride,
vk::VertexInputRate::eVertex);
// iterate over the bindings' specified, mutually exclusive vertex input attachments that make up a vertex
for(const auto &vertexAttachment: vertexBinding.vertexAttachments)
{
vertexAttributeDescriptions.emplace_back(vertexAttachment.inputLocation,
vertexBinding.bindingLocation,
vertexFormatToVulkanFormat(vertexAttachment.format),
vertexAttachment.offset % vertexBinding.stride);
if (existsVertexShader) {
const VertexLayout& layout = config.m_VertexLayout;
// iterate over the layout's specified, mutually exclusive buffer bindings that make up a vertex buffer
for (const auto& vertexBinding : layout.vertexBindings)
{
vertexBindingDescriptions.emplace_back(vertexBinding.bindingLocation,
vertexBinding.stride,
vk::VertexInputRate::eVertex);
// iterate over the bindings' specified, mutually exclusive vertex input attachments that make up a vertex
for (const auto& vertexAttachment : vertexBinding.vertexAttachments)
{
vertexAttributeDescriptions.emplace_back(vertexAttachment.inputLocation,
vertexBinding.bindingLocation,
vertexFormatToVulkanFormat(vertexAttachment.format),
vertexAttachment.offset % vertexBinding.stride);
}
}
}
}
}
// Handover Containers to PipelineVertexInputStateCreateIngo Struct
vk::PipelineVertexInputStateCreateInfo pipelineVertexInputStateCreateInfo(
......@@ -240,8 +335,7 @@ namespace vkcv
vk::PipelineLayout vkPipelineLayout{};
if (m_Device.createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &vkPipelineLayout) != vk::Result::eSuccess)
{
m_Device.destroy(vertexModule);
m_Device.destroy(fragmentModule);
destroyShaderModules();
return PipelineHandle();
}
......@@ -276,25 +370,28 @@ namespace vkcv
dynamicStates.push_back(vk::DynamicState::eScissor);
}
vk::PipelineDynamicStateCreateInfo dynamicStateCreateInfo({},
static_cast<uint32_t>(dynamicStates.size()),
dynamicStates.data());
// graphics pipeline create
std::vector<vk::PipelineShaderStageCreateInfo> shaderStages = { pipelineVertexShaderStageInfo, pipelineFragmentShaderStageInfo };
const char *geometryShaderName = "main"; // outside of if to make sure it stays in scope
vk::ShaderModule geometryModule;
if (config.m_ShaderProgram.existsShader(ShaderStage::GEOMETRY)) {
const vkcv::Shader geometryShader = config.m_ShaderProgram.getShader(ShaderStage::GEOMETRY);
const auto& geometryCode = geometryShader.shaderCode;
const vk::ShaderModuleCreateInfo geometryModuleInfo({}, geometryCode.size(), reinterpret_cast<const uint32_t*>(geometryCode.data()));
if (m_Device.createShaderModule(&geometryModuleInfo, nullptr, &geometryModule) != vk::Result::eSuccess) {
return PipelineHandle();
}
vk::PipelineShaderStageCreateInfo geometryStage({}, vk::ShaderStageFlagBits::eGeometry, geometryModule, geometryShaderName);
shaderStages.push_back(geometryStage);
}
vk::PipelineDynamicStateCreateInfo dynamicStateCreateInfo(
{},
static_cast<uint32_t>(dynamicStates.size()),
dynamicStates.data());
const bool existsGeometryShader = config.m_ShaderProgram.existsShader(vkcv::ShaderStage::GEOMETRY);
if (existsGeometryShader) {
vk::PipelineShaderStageCreateInfo createInfo;
const bool success = createPipelineShaderStageCreateInfo(
config.m_ShaderProgram,
vkcv::ShaderStage::GEOMETRY,
m_Device,
&createInfo);
if (success) {
shaderStages.push_back(createInfo);
}
else {
destroyShaderModules();
return PipelineHandle();
}
}
const vk::GraphicsPipelineCreateInfo graphicsPipelineCreateInfo(
{},
......@@ -319,20 +416,11 @@ namespace vkcv
vk::Pipeline vkPipeline{};
if (m_Device.createGraphicsPipelines(nullptr, 1, &graphicsPipelineCreateInfo, nullptr, &vkPipeline) != vk::Result::eSuccess)
{
m_Device.destroy(vertexModule);
m_Device.destroy(fragmentModule);
if (geometryModule) {
m_Device.destroy(geometryModule);
}
m_Device.destroy();
destroyShaderModules();
return PipelineHandle();
}
m_Device.destroy(vertexModule);
m_Device.destroy(fragmentModule);
if (geometryModule) {
m_Device.destroy(geometryModule);
}
destroyShaderModules();
const uint64_t id = m_Pipelines.size();
m_Pipelines.push_back({ vkPipeline, vkPipelineLayout, config });
......@@ -457,4 +545,4 @@ namespace vkcv
vk::ShaderModuleCreateInfo moduleInfo({}, code.size(), reinterpret_cast<uint32_t*>(code.data()));
return m_Device.createShaderModule(&moduleInfo, nullptr, &module);
}
}
\ No newline at end of file
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.