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 1064 additions and 400 deletions
...@@ -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
...@@ -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);
} }
...@@ -331,7 +331,7 @@ void Voxelization::renderVoxelVisualisation( ...@@ -331,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);
......
...@@ -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;
...@@ -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;
...@@ -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;
...@@ -679,11 +777,18 @@ int main(int argc, const char** argv) { ...@@ -679,11 +777,18 @@ int main(int argc, const char** argv) {
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) {
...@@ -706,24 +811,58 @@ int main(int argc, const char** argv) { ...@@ -706,24 +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;
vkcv::PushConstants timePushConstants (sizeof(timeF));
timePushConstants.appendDrawcall(timeF);
core.recordComputeDispatchToCmdStream( core.recordComputeDispatchToCmdStream(
cmdStream, cmdStream,
tonemappingPipeline, tonemappingPipeline,
fulsscreenDispatchCount, fulsscreenDispatchCount,
{ vkcv::DescriptorSetUsage(0, core.getDescriptorSet(tonemappingDescriptorSet).vulkanHandle) }, { vkcv::DescriptorSetUsage(0, core.getDescriptorSet(
timePushConstants); 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);
...@@ -751,12 +890,25 @@ int main(int argc, const char** argv) { ...@@ -751,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")) {
......
...@@ -151,7 +151,7 @@ namespace vkcv ...@@ -151,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;
...@@ -180,11 +180,20 @@ namespace vkcv ...@@ -180,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();
...@@ -223,7 +232,7 @@ namespace vkcv ...@@ -223,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,
...@@ -238,8 +247,8 @@ namespace vkcv ...@@ -238,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
...@@ -286,13 +295,39 @@ namespace vkcv ...@@ -286,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
...@@ -300,6 +335,11 @@ namespace vkcv ...@@ -300,6 +335,11 @@ 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( QueueManager queueManager = QueueManager::create(
device, device,
......
This diff is collapsed.
...@@ -11,10 +11,14 @@ namespace vkcv ...@@ -11,10 +11,14 @@ 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, vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet,
...@@ -105,7 +109,6 @@ namespace vkcv ...@@ -105,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;
...@@ -153,10 +156,15 @@ namespace vkcv ...@@ -153,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);
...@@ -165,6 +173,8 @@ namespace vkcv ...@@ -165,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
}; };
...@@ -172,10 +182,15 @@ namespace vkcv ...@@ -172,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);
...@@ -184,6 +199,8 @@ namespace vkcv ...@@ -184,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
}; };
...@@ -239,8 +256,12 @@ namespace vkcv ...@@ -239,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:
......
#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,
...@@ -33,11 +44,59 @@ namespace vkcv { ...@@ -33,11 +44,59 @@ namespace vkcv {
} }
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;
}
}
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
#include "vkcv/ImageConfig.hpp" #include "vkcv/ImageConfig.hpp"
namespace vkcv { namespace vkcv {
bool isDepthImageFormat(vk::Format format);
class ImageManager class ImageManager
{ {
......
...@@ -44,95 +44,190 @@ namespace vkcv ...@@ -44,95 +44,190 @@ namespace vkcv
vk::PrimitiveTopology primitiveTopologyToVulkanPrimitiveTopology(const PrimitiveTopology topology) { vk::PrimitiveTopology primitiveTopologyToVulkanPrimitiveTopology(const PrimitiveTopology topology) {
switch (topology) { switch (topology) {
case(PrimitiveTopology::PointList): return vk::PrimitiveTopology::ePointList; case(PrimitiveTopology::PointList): return vk::PrimitiveTopology::ePointList;
case(PrimitiveTopology::LineList): return vk::PrimitiveTopology::eLineList; case(PrimitiveTopology::LineList): return vk::PrimitiveTopology::eLineList;
case(PrimitiveTopology::TriangleList): return vk::PrimitiveTopology::eTriangleList; case(PrimitiveTopology::TriangleList): return vk::PrimitiveTopology::eTriangleList;
default: std::cout << "Error: Unknown primitive topology type" << std::endl; return vk::PrimitiveTopology::eTriangleList; default: std::cout << "Error: Unknown primitive topology type" << std::endl; return vk::PrimitiveTopology::eTriangleList;
} }
} }
vk::CompareOp depthTestToVkCompareOp(DepthTest depthTest) { vk::CompareOp depthTestToVkCompareOp(DepthTest depthTest) {
switch (depthTest) { switch (depthTest) {
case(DepthTest::None): return vk::CompareOp::eAlways; case(DepthTest::None): return vk::CompareOp::eAlways;
case(DepthTest::Less): return vk::CompareOp::eLess; case(DepthTest::Less): return vk::CompareOp::eLess;
case(DepthTest::LessEqual): return vk::CompareOp::eLessOrEqual; case(DepthTest::LessEqual): return vk::CompareOp::eLessOrEqual;
case(DepthTest::Greater): return vk::CompareOp::eGreater; case(DepthTest::Greater): return vk::CompareOp::eGreater;
case(DepthTest::GreatherEqual): return vk::CompareOp::eGreaterOrEqual; case(DepthTest::GreatherEqual): return vk::CompareOp::eGreaterOrEqual;
case(DepthTest::Equal): return vk::CompareOp::eEqual; case(DepthTest::Equal): return vk::CompareOp::eEqual;
default: vkcv_log(vkcv::LogLevel::ERROR, "Unknown depth test enum"); return vk::CompareOp::eAlways; 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) PipelineHandle PipelineManager::createPipeline(const PipelineConfig &config, PassManager& passManager)
{ {
const vk::RenderPass &pass = passManager.getVkPass(config.m_PassHandle); 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 existsVertexShader = config.m_ShaderProgram.existsShader(ShaderStage::VERTEX);
const bool validGeometryStages = existsVertexShader || (existsTaskShader && existsMeshShader);
const bool existsFragmentShader = config.m_ShaderProgram.existsShader(ShaderStage::FRAGMENT); 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(); return PipelineHandle();
} }
if (!existsFragmentShader) {
// vertex shader stage vkcv_log(LogLevel::ERROR, "Requires fragment shader code");
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)
return PipelineHandle(); return PipelineHandle();
}
vk::PipelineShaderStageCreateInfo pipelineVertexShaderStageInfo( std::vector<vk::PipelineShaderStageCreateInfo> shaderStages;
{}, auto destroyShaderModules = [&shaderStages, this] {
vk::ShaderStageFlagBits::eVertex, for (auto stage : shaderStages) {
vertexModule, m_Device.destroyShaderModule(stage.module);
"main", }
nullptr 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 // 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); vk::PipelineShaderStageCreateInfo createInfo;
return PipelineHandle(); 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 // vertex input state
// Fill up VertexInputBindingDescription and VertexInputAttributeDescription Containers // Fill up VertexInputBindingDescription and VertexInputAttributeDescription Containers
std::vector<vk::VertexInputAttributeDescription> vertexAttributeDescriptions; std::vector<vk::VertexInputAttributeDescription> vertexAttributeDescriptions;
std::vector<vk::VertexInputBindingDescription> vertexBindingDescriptions; std::vector<vk::VertexInputBindingDescription> vertexBindingDescriptions;
const VertexLayout &layout = config.m_VertexLayout; 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) // 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, vertexBindingDescriptions.emplace_back(vertexBinding.bindingLocation,
vk::VertexInputRate::eVertex); 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) // 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, vertexAttributeDescriptions.emplace_back(vertexAttachment.inputLocation,
vertexFormatToVulkanFormat(vertexAttachment.format), vertexBinding.bindingLocation,
vertexAttachment.offset % vertexBinding.stride); vertexFormatToVulkanFormat(vertexAttachment.format),
vertexAttachment.offset % vertexBinding.stride);
}
}
} }
}
// Handover Containers to PipelineVertexInputStateCreateIngo Struct // Handover Containers to PipelineVertexInputStateCreateIngo Struct
vk::PipelineVertexInputStateCreateInfo pipelineVertexInputStateCreateInfo( vk::PipelineVertexInputStateCreateInfo pipelineVertexInputStateCreateInfo(
...@@ -240,8 +335,7 @@ namespace vkcv ...@@ -240,8 +335,7 @@ namespace vkcv
vk::PipelineLayout vkPipelineLayout{}; vk::PipelineLayout vkPipelineLayout{};
if (m_Device.createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &vkPipelineLayout) != vk::Result::eSuccess) if (m_Device.createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &vkPipelineLayout) != vk::Result::eSuccess)
{ {
m_Device.destroy(vertexModule); destroyShaderModules();
m_Device.destroy(fragmentModule);
return PipelineHandle(); return PipelineHandle();
} }
...@@ -276,25 +370,28 @@ namespace vkcv ...@@ -276,25 +370,28 @@ namespace vkcv
dynamicStates.push_back(vk::DynamicState::eScissor); dynamicStates.push_back(vk::DynamicState::eScissor);
} }
vk::PipelineDynamicStateCreateInfo dynamicStateCreateInfo({}, vk::PipelineDynamicStateCreateInfo dynamicStateCreateInfo(
static_cast<uint32_t>(dynamicStates.size()), {},
dynamicStates.data()); static_cast<uint32_t>(dynamicStates.size()),
dynamicStates.data());
// graphics pipeline create
std::vector<vk::PipelineShaderStageCreateInfo> shaderStages = { pipelineVertexShaderStageInfo, pipelineFragmentShaderStageInfo }; const bool existsGeometryShader = config.m_ShaderProgram.existsShader(vkcv::ShaderStage::GEOMETRY);
if (existsGeometryShader) {
const char *geometryShaderName = "main"; // outside of if to make sure it stays in scope vk::PipelineShaderStageCreateInfo createInfo;
vk::ShaderModule geometryModule; const bool success = createPipelineShaderStageCreateInfo(
if (config.m_ShaderProgram.existsShader(ShaderStage::GEOMETRY)) { config.m_ShaderProgram,
const vkcv::Shader geometryShader = config.m_ShaderProgram.getShader(ShaderStage::GEOMETRY); vkcv::ShaderStage::GEOMETRY,
const auto& geometryCode = geometryShader.shaderCode; m_Device,
const vk::ShaderModuleCreateInfo geometryModuleInfo({}, geometryCode.size(), reinterpret_cast<const uint32_t*>(geometryCode.data())); &createInfo);
if (m_Device.createShaderModule(&geometryModuleInfo, nullptr, &geometryModule) != vk::Result::eSuccess) {
return PipelineHandle(); if (success) {
} shaderStages.push_back(createInfo);
vk::PipelineShaderStageCreateInfo geometryStage({}, vk::ShaderStageFlagBits::eGeometry, geometryModule, geometryShaderName); }
shaderStages.push_back(geometryStage); else {
} destroyShaderModules();
return PipelineHandle();
}
}
const vk::GraphicsPipelineCreateInfo graphicsPipelineCreateInfo( const vk::GraphicsPipelineCreateInfo graphicsPipelineCreateInfo(
{}, {},
...@@ -319,20 +416,11 @@ namespace vkcv ...@@ -319,20 +416,11 @@ namespace vkcv
vk::Pipeline vkPipeline{}; vk::Pipeline vkPipeline{};
if (m_Device.createGraphicsPipelines(nullptr, 1, &graphicsPipelineCreateInfo, nullptr, &vkPipeline) != vk::Result::eSuccess) if (m_Device.createGraphicsPipelines(nullptr, 1, &graphicsPipelineCreateInfo, nullptr, &vkPipeline) != vk::Result::eSuccess)
{ {
m_Device.destroy(vertexModule); destroyShaderModules();
m_Device.destroy(fragmentModule);
if (geometryModule) {
m_Device.destroy(geometryModule);
}
m_Device.destroy();
return PipelineHandle(); return PipelineHandle();
} }
m_Device.destroy(vertexModule); destroyShaderModules();
m_Device.destroy(fragmentModule);
if (geometryModule) {
m_Device.destroy(geometryModule);
}
const uint64_t id = m_Pipelines.size(); const uint64_t id = m_Pipelines.size();
m_Pipelines.push_back({ vkPipeline, vkPipelineLayout, config }); m_Pipelines.push_back({ vkPipeline, vkPipelineLayout, config });
...@@ -457,4 +545,4 @@ namespace vkcv ...@@ -457,4 +545,4 @@ namespace vkcv
vk::ShaderModuleCreateInfo moduleInfo({}, code.size(), reinterpret_cast<uint32_t*>(code.data())); vk::ShaderModuleCreateInfo moduleInfo({}, code.size(), reinterpret_cast<uint32_t*>(code.data()));
return m_Device.createShaderModule(&moduleInfo, nullptr, &module); 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.