diff --git a/bin/data/config.json b/bin/data/config.json index d986c6b7..55e767bb 100644 --- a/bin/data/config.json +++ b/bin/data/config.json @@ -38,6 +38,13 @@ "min": [ -1.5, -1.5, -1.5 ], "max": [ 1.5, 1.5, 1.5 ] } + }, + "bloom": { + "scale": 1.0, + "strength": 1.0, + "threshold": 1.0, + "sigma": 0.8, + "samples": 5 } }, "ext": { @@ -69,12 +76,13 @@ "multithreaded command rendering": false, "deferred mode": "", "deferred reconstruct position": true, - "deferred alias output to swapchain": true, + "deferred alias output to swapchain": false, "vsync": true, "hdr": false, "vxgi": true, - "deferred sampling": true, - "culling": false + "deferred sampling": false, + "culling": false, + "bloom": true }, "formats": { "depth": "D32_SFLOAT", diff --git a/bin/data/scenes/mcdonalds/scene.json b/bin/data/scenes/mcdonalds/scene.json index 1ba5f6c8..bb196f40 100644 --- a/bin/data/scenes/mcdonalds/scene.json +++ b/bin/data/scenes/mcdonalds/scene.json @@ -29,10 +29,16 @@ "bgm": 0.75, "voice": 1.0 }, + "bloom": { + "scale": 1.0, + "strength": 0.5, + "sigma": 0.75, + "samples": 8 + }, "light": { "exposure": 1.0, "gamma": 1.0, - + "brightnessThreshold": 1.0, "ambient": [ 0.1, 0.1, 0.1 ], "fog": { diff --git a/bin/data/shaders/common/functions.h b/bin/data/shaders/common/functions.h index bcf01aea..cd53167c 100644 --- a/bin/data/shaders/common/functions.h +++ b/bin/data/shaders/common/functions.h @@ -15,6 +15,9 @@ vec3 orthogonal(vec3 u){ vec4 blend( vec4 source, vec4 dest, float a ) { return source * a + dest * (1.0 - a); } +float gauss( float x, float sigma ) { + return (1.0 / (2.0 * 3.14157 * sigma) * exp(-(x*x) / (2.0 * sigma))); +} bool enabled( uint flag, uint bit ) { return (flag & (1 << bit)) != 0; } @@ -35,7 +38,7 @@ bool validTextureIndex( int textureIndex ) { bool validCubemapIndex( int textureIndex ) { return 0 <= textureIndex && textureIndex < CUBEMAPS; } -#if DEFERRED || COMPUTE +#if !BLOOM && (DEFERRED || COMPUTE) bool validTextureIndex( uint id ) { return 0 <= id && id < MAX_TEXTURES; } diff --git a/bin/data/shaders/display/bloom.comp.glsl b/bin/data/shaders/display/bloom.comp.glsl new file mode 100644 index 00000000..0ae435f4 --- /dev/null +++ b/bin/data/shaders/display/bloom.comp.glsl @@ -0,0 +1,67 @@ +#version 450 +#pragma shader_stage(compute) + +#define COMPUTE 1 +#define TEXTURES 0 +#define CUBEMAPS 0 +#define BLOOM 1 + +layout (local_size_x = 8, local_size_y = 8, local_size_z = 8) in; + +layout( push_constant ) uniform PushBlock { + uint eye; + uint mode; +} PushConstant; + +layout (binding = 0) uniform UBO { + float scale; + float strength; + float threshold; + float sigma; + + float gamma; + float exposure; + uint samples; + uint padding; +} ubo; + +layout (binding = 1, rgba16f) uniform volatile coherent image2D imageColor; +layout (binding = 2, rgba16f) uniform volatile coherent image2D imageBloom; +layout (binding = 3, rgba16f) uniform volatile coherent image2D imagePingPong; + +#include "../common/macros.h" +#include "../common/structs.h" +#include "../common/functions.h" + +void main() { + const uint mode = PushConstant.mode; + const ivec2 texel = ivec2(gl_GlobalInvocationID.xy); + const ivec2 size = imageSize( imageColor ); + if ( texel.x >= size.x || texel.y >= size.y ) return; + + if ( mode == 0 ) { // fill bloom + vec3 result = imageLoad( imageColor, texel ).rgb; + float brightness = dot(result, vec3(0.2126, 0.7152, 0.0722)); + if ( brightness < ubo.threshold ) result = vec3(0, 0, 0); + imageStore( imageBloom, texel, vec4( result, 1.0 ) ); + } else if ( mode == 1 ) { // bloom horizontal + vec3 result = imageLoad( imageBloom, texel ).rgb * gauss( 0, ubo.sigma ) * ubo.strength; + for( int i = 1; i < ubo.samples; ++i ) { + result += imageLoad( imageBloom, texel + ivec2(i * ubo.scale, 0.0)).rgb * gauss( i * ubo.scale / ubo.samples, ubo.sigma ) * ubo.strength; + result += imageLoad( imageBloom, texel - ivec2(i * ubo.scale, 0.0)).rgb * gauss( i * ubo.scale / ubo.samples, ubo.sigma ) * ubo.strength; + } + // write to PingPong + imageStore( imagePingPong, texel, vec4( result, 1.0 ) ); + } else if ( mode == 2 ) { // bloom vertical + vec3 result = imageLoad( imagePingPong, texel ).rgb * gauss( 0, ubo.sigma ) * ubo.strength; + for( int i = 1; i < ubo.samples; ++i ) { + result += imageLoad( imagePingPong, texel + ivec2(0.0, i * ubo.scale)).rgb * gauss( i * ubo.scale / ubo.samples, ubo.sigma ) * ubo.strength; + result += imageLoad( imagePingPong, texel - ivec2(0.0, i * ubo.scale)).rgb * gauss( i * ubo.scale / ubo.samples, ubo.sigma ) * ubo.strength; + } + // write to Bloom + imageStore( imageBloom, texel, vec4( result, 1.0 ) ); + } else if ( mode == 3 ) { // combine + vec3 result = imageLoad( imageColor, texel ).rgb + imageLoad( imageBloom, texel ).rgb; + imageStore( imageColor, texel, vec4( result, 1.0 ) ); + } +} \ No newline at end of file diff --git a/bin/data/shaders/display/subpass.h b/bin/data/shaders/display/subpass.h index df0e64dc..4b685256 100644 --- a/bin/data/shaders/display/subpass.h +++ b/bin/data/shaders/display/subpass.h @@ -49,9 +49,14 @@ layout (binding = 4) uniform UBO { float gamma; float exposure; + float brightnessThreshold; uint msaa; uint shadowSamples; + uint indexSkybox; + uint padding1; + uint padding2; + uint padding3; } ubo; /* layout (std140, binding = 5) readonly buffer DrawCommands { @@ -81,9 +86,10 @@ layout (binding = 11) uniform sampler3D samplerNoise; #endif layout (location = 0) in vec2 inUv; -layout (location = 1) in flat uint inPushConstantPass; +layout (location = 1) in flat uvec2 inPushConstantPass; layout (location = 0) out vec4 outFragColor; +layout (location = 1) out vec4 outFragBright; #include "../common/functions.h" #include "../common/fog.h" @@ -94,6 +100,9 @@ layout (location = 0) out vec4 outFragColor; #endif void postProcess() { + float brightness = dot(surface.fragment.rgb, vec3(0.2126, 0.7152, 0.0722)); + outFragBright = brightness > ubo.brightnessThreshold ? vec4(surface.fragment.rgb, 1.0) : vec4(0, 0, 0, 1); + #if FOG fog( surface.ray, surface.fragment.rgb, surface.fragment.a ); #endif @@ -106,12 +115,12 @@ void postProcess() { #if WHITENOISE if ( enabled(ubo.mode.type, 1) ) whitenoise(surface.fragment.rgb, ubo.mode.parameters); #endif - - outFragColor = vec4(surface.fragment.rgb,1); + + outFragColor = vec4(surface.fragment.rgb, 1.0); } void populateSurface() { - surface.pass = inPushConstantPass; + surface.pass = inPushConstantPass.x; { #if !MULTISAMPLING const float depth = subpassLoad(samplerDepth).r; diff --git a/bin/data/shaders/display/subpass.vert.glsl b/bin/data/shaders/display/subpass.vert.glsl index 23f845c1..1311dca7 100644 --- a/bin/data/shaders/display/subpass.vert.glsl +++ b/bin/data/shaders/display/subpass.vert.glsl @@ -6,7 +6,7 @@ layout (location = 0) in vec2 inPos; layout (location = 1) in vec2 inUv; #endif layout (location = 0) out vec2 outUv; -layout (location = 1) out flat uint outPushConstantPass; +layout (location = 1) out flat uvec2 outPushConstantPass; layout( push_constant ) uniform PushBlock { uint pass; @@ -19,7 +19,7 @@ out gl_PerVertex { void main() { - outPushConstantPass = PushConstant.pass; + outPushConstantPass = uvec2(PushConstant.pass, PushConstant.draw); outUv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); gl_Position = vec4(outUv * 2.0f + -1.0f, 0.0f, 1.0f); #if 0 diff --git a/bin/data/shaders/display/vxgi.comp.h b/bin/data/shaders/display/vxgi.comp.h index 763ca144..0ee103ed 100644 --- a/bin/data/shaders/display/vxgi.comp.h +++ b/bin/data/shaders/display/vxgi.comp.h @@ -32,9 +32,14 @@ layout (binding = 4) uniform UBO { float gamma; float exposure; + float brightnessThreshold; uint msaa; uint shadowSamples; + uint indexSkybox; + uint padding1; + uint padding2; + uint padding3; } ubo; /* layout (std140, binding = 5) readonly buffer DrawCommands { diff --git a/engine/inc/uf/ext/opengl/opengl.h b/engine/inc/uf/ext/opengl/opengl.h index 599deac2..5f7ae471 100644 --- a/engine/inc/uf/ext/opengl/opengl.h +++ b/engine/inc/uf/ext/opengl/opengl.h @@ -40,6 +40,7 @@ namespace ext { extern UF_API bool vxgi; extern UF_API bool deferredSampling; extern UF_API bool culling; + extern UF_API bool bloom; } namespace formats { diff --git a/engine/inc/uf/ext/vulkan/graphic.h b/engine/inc/uf/ext/vulkan/graphic.h index 9b06a638..78811709 100644 --- a/engine/inc/uf/ext/vulkan/graphic.h +++ b/engine/inc/uf/ext/vulkan/graphic.h @@ -36,6 +36,7 @@ namespace ext { void update( const Graphic& graphic ); void update( const Graphic& graphic, const GraphicDescriptor& descriptor ); void record( const Graphic& graphic, VkCommandBuffer, size_t = 0, size_t = 0 ) const; + void record( const Graphic& graphic, const GraphicDescriptor& descriptor, VkCommandBuffer, size_t = 0, size_t = 0 ) const; void destroy(); uf::stl::vector getShaders( uf::stl::vector& ); diff --git a/engine/inc/uf/ext/vulkan/rendertarget.h b/engine/inc/uf/ext/vulkan/rendertarget.h index 8f2af904..41269a61 100644 --- a/engine/inc/uf/ext/vulkan/rendertarget.h +++ b/engine/inc/uf/ext/vulkan/rendertarget.h @@ -27,15 +27,15 @@ namespace ext { uf::stl::vector attachments; struct Subpass { - VkPipelineStageFlags stage; - VkAccessFlags access; - uint8_t layer; + VkPipelineStageFlags stage = {}; + VkAccessFlags access = {}; + uint8_t layer = 0; bool autoBuildPipeline; - uf::stl::vector colors; - uf::stl::vector inputs; - uf::stl::vector resolves; - VkAttachmentReference depth; + uf::stl::vector colors = {}; + uf::stl::vector inputs = {}; + uf::stl::vector resolves = {}; + VkAttachmentReference depth = {}; }; uf::stl::vector passes; diff --git a/engine/inc/uf/ext/vulkan/shader.h b/engine/inc/uf/ext/vulkan/shader.h index b57cb59f..bc38ad09 100644 --- a/engine/inc/uf/ext/vulkan/shader.h +++ b/engine/inc/uf/ext/vulkan/shader.h @@ -98,6 +98,10 @@ namespace ext { ext::vulkan::userdata_t specializationConstants; uf::stl::vector pushConstants; uf::stl::vector uniforms; + + // for per-shader texture allotment, needed for our bloom pipeline + uf::stl::vector textures; + // ~Shader(); void initialize( Device& device, const uf::stl::string&, VkShaderStageFlagBits ); void destroy(); diff --git a/engine/inc/uf/ext/vulkan/vulkan.h b/engine/inc/uf/ext/vulkan/vulkan.h index 950505db..651a849f 100644 --- a/engine/inc/uf/ext/vulkan/vulkan.h +++ b/engine/inc/uf/ext/vulkan/vulkan.h @@ -67,6 +67,7 @@ namespace ext { extern UF_API bool vxgi; extern UF_API bool deferredSampling; extern UF_API bool culling; + extern UF_API bool bloom; } namespace formats { diff --git a/engine/inc/uf/macros.h b/engine/inc/uf/macros.h index 18aa8561..35516d9b 100644 --- a/engine/inc/uf/macros.h +++ b/engine/inc/uf/macros.h @@ -98,4 +98,6 @@ #endif #define MIN(X, Y) X < Y ? X : Y -#define MAX(X, Y) X > Y ? X : Y \ No newline at end of file +#define MAX(X, Y) X > Y ? X : Y +#define LENGTH_OF(X) *(&X + 1) - X +#define FOR_ARRAY(X) for ( auto i = 0; i < LENGTH_OF(X); ++i ) \ No newline at end of file diff --git a/engine/src/engine/graph/graph.cpp b/engine/src/engine/graph/graph.cpp index 00aff8f2..eeaf46ed 100644 --- a/engine/src/engine/graph/graph.cpp +++ b/engine/src/engine/graph/graph.cpp @@ -57,104 +57,104 @@ namespace { } // standard pipeline - uf::stl::string vertexShaderFilename = graph.metadata["shaders"]["vertex"].as("/graph/base.vert.spv"); + uf::stl::string vertexShaderFilename = graph.metadata["shaders"]["vertex"].as("/graph/base.vert.spv"); { + std::pair settings[] = { + { graph.metadata["flags"]["SKINNED"].as(), "skinned.vert" }, + { graph.metadata["flags"]["SEPARATE"].as(), "instanced.vert" }, + }; + FOR_ARRAY(settings) if ( settings[i].first ) vertexShaderFilename = uf::string::replace( vertexShaderFilename, "vert", settings[i].second ); + vertexShaderFilename = entity.grabURI( vertexShaderFilename, root ); + } uf::stl::string geometryShaderFilename = graph.metadata["shaders"]["geometry"].as(""); - uf::stl::string fragmentShaderFilename = graph.metadata["shaders"]["fragment"].as("/graph/base.frag.spv"); + uf::stl::string fragmentShaderFilename = graph.metadata["shaders"]["fragment"].as("/graph/base.frag.spv"); { + std::pair settings[] = { + { uf::renderer::settings::experimental::deferredSampling, "deferredSampling.frag" }, + }; + FOR_ARRAY(settings) if ( settings[i].first ) fragmentShaderFilename = uf::string::replace( fragmentShaderFilename, "frag", settings[i].second ); + fragmentShaderFilename = entity.grabURI( fragmentShaderFilename, root ); + } { graphic.material.metadata.autoInitializeUniforms = false; - if ( uf::renderer::settings::experimental::deferredSampling ) { - fragmentShaderFilename = uf::string::replace( fragmentShaderFilename, "frag", "deferredSampling.frag" ); - } - { - if ( !graph.metadata["flags"]["SEPARATE"].as() ) { - vertexShaderFilename = graph.metadata["flags"]["SKINNED"].as() ? "/graph/skinned.instanced.vert.spv" : "/graph/instanced.vert.spv"; - } else if ( graph.metadata["flags"]["SKINNED"].as() ) vertexShaderFilename = "/graph/skinned.vert.spv"; - vertexShaderFilename = entity.grabURI( vertexShaderFilename, root ); - graphic.material.attachShader(vertexShaderFilename, uf::renderer::enums::Shader::VERTEX); - } - { - fragmentShaderFilename = entity.grabURI( fragmentShaderFilename, root ); - graphic.material.attachShader(fragmentShaderFilename, uf::renderer::enums::Shader::FRAGMENT); - } - #if UF_USE_VULKAN + graphic.material.attachShader(vertexShaderFilename, uf::renderer::enums::Shader::VERTEX); + graphic.material.attachShader(fragmentShaderFilename, uf::renderer::enums::Shader::FRAGMENT); graphic.material.metadata.autoInitializeUniforms = true; - if ( geometryShaderFilename != "" && uf::renderer::device.enabledFeatures.geometryShader ) { - geometryShaderFilename = entity.grabURI( geometryShaderFilename, root ); - graphic.material.attachShader(geometryShaderFilename, uf::renderer::enums::Shader::GEOMETRY); - } - { - uint32_t maxPasses = 6; - - auto& shader = graphic.material.getShader("vertex"); - uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants; - for ( auto pair : shader.metadata.definitions.specializationConstants ) { - auto& sc = pair.second; - if ( sc.name == "PASSES" ) sc.value.ui = (specializationConstants[sc.index] = maxPasses); - } - - uf::renderer::Buffer* indirect = NULL; - for ( auto& buffer : graphic.buffers ) if ( !indirect && buffer.usage & uf::renderer::enums::Buffer::INDIRECT ) indirect = &buffer; - - shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.camera ); - // shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.drawCommands ); - shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.instance ); - shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.joint ); - } - { - uint32_t maxTextures = graph.textures.size(); // texture2Ds; - - auto& shader = graphic.material.getShader("fragment"); - uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants; - for ( auto pair : shader.metadata.definitions.specializationConstants ) { - auto& sc = pair.second; - if ( sc.name == "TEXTURES" ) sc.value.ui = (specializationConstants[sc.index] = maxTextures); - } - for ( auto pair : shader.metadata.definitions.textures ) { - auto& tx = pair.second; - for ( auto& layout : shader.descriptorSetLayoutBindings ) { - if ( layout.binding != tx.binding ) continue; - if ( tx.name == "samplerTextures" ) layout.descriptorCount = maxTextures; - } - } - - shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.material ); - shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.texture ); - shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.light ); - } - #endif } + #if UF_USE_VULKAN + if ( geometryShaderFilename != "" && uf::renderer::device.enabledFeatures.geometryShader ) { + geometryShaderFilename = entity.grabURI( geometryShaderFilename, root ); + graphic.material.attachShader(geometryShaderFilename, uf::renderer::enums::Shader::GEOMETRY); + } + { + uint32_t maxPasses = 6; + + auto& shader = graphic.material.getShader("vertex"); + uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants; + for ( auto pair : shader.metadata.definitions.specializationConstants ) { + auto& sc = pair.second; + if ( sc.name == "PASSES" ) sc.value.ui = (specializationConstants[sc.index] = maxPasses); + } + + uf::renderer::Buffer* indirect = NULL; + for ( auto& buffer : graphic.buffers ) if ( !indirect && buffer.usage & uf::renderer::enums::Buffer::INDIRECT ) indirect = &buffer; + + shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.camera ); + // shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.drawCommands ); + shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.instance ); + shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.joint ); + } + { + uint32_t maxTextures = graph.textures.size(); // texture2Ds; + + auto& shader = graphic.material.getShader("fragment"); + uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants; + for ( auto pair : shader.metadata.definitions.specializationConstants ) { + auto& sc = pair.second; + if ( sc.name == "TEXTURES" ) sc.value.ui = (specializationConstants[sc.index] = maxTextures); + } + for ( auto pair : shader.metadata.definitions.textures ) { + auto& tx = pair.second; + for ( auto& layout : shader.descriptorSetLayoutBindings ) { + if ( layout.binding != tx.binding ) continue; + if ( tx.name == "samplerTextures" ) layout.descriptorCount = maxTextures; + } + } + + shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.material ); + shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.texture ); + shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.light ); + } + #endif // culling pipeline if ( uf::renderer::settings::experimental::culling ) { - graphic.material.metadata.autoInitializeUniforms = false; + uf::renderer::Buffer* indirect = NULL; + for ( auto& buffer : graphic.buffers ) if ( !indirect && buffer.usage & uf::renderer::enums::Buffer::INDIRECT ) indirect = &buffer; + UF_ASSERT( indirect ); + uf::stl::string compShaderFilename = graph.metadata["shaders"]["vertex"].as("/graph/cull.comp.spv"); { + graphic.material.metadata.autoInitializeUniforms = false; compShaderFilename = entity.grabURI( compShaderFilename, root ); graphic.material.attachShader(compShaderFilename, uf::renderer::enums::Shader::COMPUTE, "culling"); + graphic.material.metadata.autoInitializeUniforms = true; } graphic.descriptor.inputs.dispatch = { graphic.descriptor.inputs.indirect.count, 1, 1 }; auto& shader = graphic.material.getShader("compute", "culling"); - uf::renderer::Buffer* indirect = NULL; - for ( auto& buffer : graphic.buffers ) if ( !indirect && buffer.usage & uf::renderer::enums::Buffer::INDIRECT ) indirect = &buffer; - UF_ASSERT( indirect ); - shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.camera ); shader.buffers.emplace_back().aliasBuffer( *indirect ); shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.instance ); } + #if UF_USE_VULKAN // depth only pipeline - #if UF_USE_VULKAN { graphic.material.metadata.autoInitializeUniforms = false; uf::stl::string fragmentShaderFilename = graph.metadata["shaders"]["vertex"].as("/graph/depth.frag.spv"); - { - graphic.material.attachShader(vertexShaderFilename, uf::renderer::enums::Shader::VERTEX, "depth"); - } - { - fragmentShaderFilename = entity.grabURI( fragmentShaderFilename, root ); - graphic.material.attachShader(fragmentShaderFilename, uf::renderer::enums::Shader::FRAGMENT, "depth"); - } + fragmentShaderFilename = entity.grabURI( fragmentShaderFilename, root ); + // graphic.material.attachShader(vertexShaderFilename, uf::renderer::enums::Shader::VERTEX, "depth"); + graphic.material.attachShader(fragmentShaderFilename, uf::renderer::enums::Shader::FRAGMENT, "depth"); + graphic.material.metadata.autoInitializeUniforms = true; + /* { uint32_t maxPasses = 6; @@ -173,6 +173,7 @@ namespace { shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.instance ); shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.joint ); } + */ { uint32_t maxTextures = graph.textures.size(); // texture2Ds; @@ -197,20 +198,16 @@ namespace { } // vxgi pipeline if ( uf::renderer::settings::experimental::vxgi ) { - // graphic.material.metadata.json["shader"]["autoInitializeUniformBuffers"] = false; - graphic.material.metadata.autoInitializeUniforms = false; uf::stl::string vertexShaderFilename = graph.metadata["shaders"]["vertex"].as("/graph/base.vert.spv"); uf::stl::string geometryShaderFilename = graph.metadata["shaders"]["geometry"].as("/graph/voxelize.geom.spv"); uf::stl::string fragmentShaderFilename = graph.metadata["shaders"]["fragment"].as("/graph/voxelize.frag.spv"); - if ( uf::renderer::settings::experimental::deferredSampling ) { - // fragmentShaderFilename = uf::string::replace( fragmentShaderFilename, "frag", "deferredSampling.frag" ); - } + { fragmentShaderFilename = entity.grabURI( fragmentShaderFilename, root ); + graphic.material.metadata.autoInitializeUniforms = false; graphic.material.attachShader(fragmentShaderFilename, uf::renderer::enums::Shader::FRAGMENT, "vxgi"); + graphic.material.metadata.autoInitializeUniforms = true; } - // graphic.material.metadata.json["shader"]["autoInitializeUniformBuffers"] = true; - graphic.material.metadata.autoInitializeUniforms = true; if ( geometryShaderFilename != "" && uf::renderer::device.enabledFeatures.geometryShader ) { geometryShaderFilename = entity.grabURI( geometryShaderFilename, root ); graphic.material.attachShader(geometryShaderFilename, uf::renderer::enums::Shader::GEOMETRY, "vxgi"); @@ -246,36 +243,13 @@ namespace { else if ( tx.name == "voxelRadiance" ) layout.descriptorCount = maxCascades; } } - - /* - uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants; - ext::json::forEach( shader.metadata.json["specializationConstants"], [&]( size_t i, ext::json::Value& sc ){ - uf::stl::string name = sc["name"].as(); - if ( name == "TEXTURES" ) sc["value"] = (specializationConstants[i] = maxTextures); - else if ( name == "CASCADES" ) sc["value"] = (specializationConstants[i] = maxCascades); - }); - ext::json::forEach( shader.metadata.json["definitions"]["textures"], [&]( ext::json::Value& t ){ - size_t binding = t["binding"].as(); - uf::stl::string name = t["name"].as(); - for ( auto& layout : shader.descriptorSetLayoutBindings ) { - if ( layout.binding != binding ) continue; - if ( name == "samplerTextures" ) layout.descriptorCount = maxTextures; - else if ( name == "voxelId" ) layout.descriptorCount = maxCascades; - else if ( name == "voxelUv" ) layout.descriptorCount = maxCascades; - else if ( name == "voxelNormal" ) layout.descriptorCount = maxCascades; - else if ( name == "voxelRadiance" ) layout.descriptorCount = maxCascades; - else if ( name == "voxelDepth" ) layout.descriptorCount = maxCascades; - } - }); - */ shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.material ); shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.texture ); shader.buffers.emplace_back().aliasBuffer( uf::graph::storage.buffers.light ); } } - #endif - // graphic.process = true; + #endif } void initializeGraphics( pod::Graph& graph, uf::Object& entity ) { auto& graphic = entity.getComponent(); diff --git a/engine/src/engine/object/behavior.cpp b/engine/src/engine/object/behavior.cpp index 7607b8f5..84e94db0 100644 --- a/engine/src/engine/object/behavior.cpp +++ b/engine/src/engine/object/behavior.cpp @@ -44,6 +44,9 @@ void uf::ObjectBehavior::initialize( uf::Object& self ) { transform.reference = &controller.getComponent>(); } }); + this->addHook( "object:Reload.%UID%", [&](ext::json::Value& json){ + this->callHook("object:UpdateMetadata.%UID%", json); + }); this->addHook( "object:UpdateMetadata.%UID%", [&](ext::json::Value& json){ if ( ext::json::isNull( json ) ) return; if ( json["type"].as() == "merge" ) { @@ -105,7 +108,7 @@ void uf::ObjectBehavior::initialize( uf::Object& self ) { auto& metadata = this->getComponent(); - this->addHook( "object:UpdateMetadata.%UID%", [&](){ + this->addHook( "object:UpdateMetadata.%UID%", [&](ext::json::Value& json){ metadata.deserialize(self, metadataJson); }); metadata.deserialize(self, metadataJson); diff --git a/engine/src/engine/object/behaviors/graph.cpp b/engine/src/engine/object/behaviors/graph.cpp index cc4367ab..0a4bc33f 100644 --- a/engine/src/engine/object/behaviors/graph.cpp +++ b/engine/src/engine/object/behaviors/graph.cpp @@ -47,6 +47,14 @@ void uf::GraphBehavior::initialize( uf::Object& self ) { sceneMetadataJson["light"]["fog"] = graph.metadata["fog"]; shouldUpdate = true; } + if ( !ext::json::isNull(graph.metadata["gamma"]) ) { + sceneMetadataJson["light"]["gamma"] = graph.metadata["gamma"]; + shouldUpdate = true; + } + if ( !ext::json::isNull(graph.metadata["brightnessThreshold"]) ) { + sceneMetadataJson["light"]["brightnessThreshold"] = graph.metadata["brightnessThreshold"]; + shouldUpdate = true; + } if ( shouldUpdate ) scene.callHook("object:UpdateMetadata.%UID%"); // deferred shader loading diff --git a/engine/src/ext/opengl/opengl.cpp b/engine/src/ext/opengl/opengl.cpp index 44238818..c6d16100 100644 --- a/engine/src/ext/opengl/opengl.cpp +++ b/engine/src/ext/opengl/opengl.cpp @@ -41,6 +41,7 @@ bool ext::opengl::settings::experimental::hdr = true; bool ext::opengl::settings::experimental::vxgi = true; bool ext::opengl::settings::experimental::deferredSampling = true; bool ext::opengl::settings::experimental::culling = false; +bool ext::opengl::settings::experimental::bloom = false; GLhandle(VkColorSpaceKHR) ext::opengl::settings::formats::colorSpace; ext::opengl::enums::Format::type_t ext::opengl::settings::formats::color = ext::opengl::enums::Format::R8G8B8A8_UNORM; diff --git a/engine/src/ext/vulkan/graphic.cpp b/engine/src/ext/vulkan/graphic.cpp index e09914e3..ce33c0cf 100644 --- a/engine/src/ext/vulkan/graphic.cpp +++ b/engine/src/ext/vulkan/graphic.cpp @@ -325,6 +325,9 @@ PIPELINE_INITIALIZATION_INVALID: return; } void ext::vulkan::Pipeline::record( const Graphic& graphic, VkCommandBuffer commandBuffer, size_t pass, size_t draw ) const { + return record( graphic, descriptor, commandBuffer, pass, draw ); +} +void ext::vulkan::Pipeline::record( const Graphic& graphic, const GraphicDescriptor& descriptor, VkCommandBuffer commandBuffer, size_t pass, size_t draw ) const { auto bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; auto shaders = getShaders( graphic.material.shaders ); for ( auto* shader : shaders ) { @@ -424,7 +427,8 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip } } - for ( auto& texture : graphic.material.textures ) { + auto& textures = !shader->textures.empty() ? shader->textures : graphic.material.textures; + for ( auto& texture : textures ) { infos.image.emplace_back(texture.descriptor); switch ( texture.viewType ) { case VK_IMAGE_VIEW_TYPE_2D: infos.image2D.emplace_back(texture.descriptor); break; @@ -957,7 +961,7 @@ void ext::vulkan::Graphic::record( VkCommandBuffer commandBuffer, const GraphicD return; } if ( !pipeline.metadata.process ) return; - pipeline.record(*this, commandBuffer, pass, draw); + pipeline.record(*this, descriptor, commandBuffer, pass, draw); auto shaders = pipeline.getShaders( material.shaders ); for ( auto* shader : shaders ) if ( shader->descriptor.stage == VK_SHADER_STAGE_COMPUTE_BIT ) return; diff --git a/engine/src/ext/vulkan/rendermodes/deferred.cpp b/engine/src/ext/vulkan/rendermodes/deferred.cpp index 5cc87abd..95902f40 100644 --- a/engine/src/ext/vulkan/rendermodes/deferred.cpp +++ b/engine/src/ext/vulkan/rendermodes/deferred.cpp @@ -38,105 +38,115 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { } } + if ( settings::experimental::bloom ) settings::experimental::deferredAliasOutputToSwapchain = false; + ext::vulkan::RenderMode::initialize( device ); renderTarget.device = &device; + renderTarget.views = metadata.eyes; size_t msaa = ext::vulkan::settings::msaa; - for ( size_t eye = 0; eye < metadata.eyes; ++eye ) { - struct { - size_t id, normals, uvs, albedo, depth, output, debug; - } attachments = {}; - attachments.id = renderTarget.attach(RenderTarget::Attachment::Descriptor{ - /*.format = */VK_FORMAT_R16G16_UINT, + struct { + size_t id, normals, uvs, albedo, depth, color, bright, scratch, output; + } attachments = {}; + + attachments.id = renderTarget.attach(RenderTarget::Attachment::Descriptor{ + /*.format = */VK_FORMAT_R16G16_UINT, + /*.layout = */VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + /*.usage = */VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, + /*.blend = */false, + /*.samples = */msaa, + }); + attachments.normals = renderTarget.attach(RenderTarget::Attachment::Descriptor{ + /*.format = */VK_FORMAT_R16G16_SFLOAT, + /*.layout = */VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + /*.usage = */VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, + /*.blend = */false, + /*.samples = */msaa, + }); + if ( ext::vulkan::settings::experimental::deferredSampling ) { + attachments.uvs = renderTarget.attach(RenderTarget::Attachment::Descriptor{ + /*.format = */VK_FORMAT_R16G16_UNORM, /*.layout = */VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, /*.usage = */VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, /*.blend = */false, /*.samples = */msaa, }); - attachments.normals = renderTarget.attach(RenderTarget::Attachment::Descriptor{ - /*.format = */VK_FORMAT_R16G16_SFLOAT, + } else { + attachments.albedo = renderTarget.attach(RenderTarget::Attachment::Descriptor{ + /*.format = */VK_FORMAT_R8G8B8A8_UNORM, /*.layout = */VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, /*.usage = */VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, - /*.blend = */false, - /*.samples = */msaa, - }); - if ( ext::vulkan::settings::experimental::deferredSampling ) { - attachments.uvs = renderTarget.attach(RenderTarget::Attachment::Descriptor{ - /*.format = */VK_FORMAT_R16G16_UNORM, - /*.layout = */VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - /*.usage = */VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, - /*.blend = */false, - /*.samples = */msaa, - }); - } else { - attachments.albedo = renderTarget.attach(RenderTarget::Attachment::Descriptor{ - /*.format = */VK_FORMAT_R8G8B8A8_UNORM, - /*.layout = */VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - /*.usage = */VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, - /*.blend = */true, - /*.samples = */msaa, - }); - } - attachments.depth = renderTarget.attach(RenderTarget::Attachment::Descriptor{ - /*.format = */ext::vulkan::settings::formats::depth, - /*.layout = */VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - /*.usage = */VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, - /*.blend = */false, + /*.blend = */true, /*.samples = */msaa, }); + } + attachments.depth = renderTarget.attach(RenderTarget::Attachment::Descriptor{ + /*.format = */ext::vulkan::settings::formats::depth, + /*.layout = */VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + /*.usage = */VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, + /*.blend = */false, + /*.samples = */msaa, + }); + attachments.color = renderTarget.attach(RenderTarget::Attachment::Descriptor{ + /*.format =*/ VK_FORMAT_R16G16B16A16_SFLOAT, + /*.layout = */ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + /*.usage =*/ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT, + /*.blend =*/ true, + /*.samples =*/ 1, + }); + attachments.bright = renderTarget.attach(RenderTarget::Attachment::Descriptor{ + /*.format =*/ VK_FORMAT_R16G16B16A16_SFLOAT, + /*.layout = */ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + /*.usage =*/ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT, + /*.blend =*/ true, + /*.samples =*/ 1, + }); + attachments.scratch = renderTarget.attach(RenderTarget::Attachment::Descriptor{ + /*.format =*/ VK_FORMAT_R16G16B16A16_SFLOAT, + /*.layout = */ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + /*.usage =*/ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT, + /*.blend =*/ true, + /*.samples =*/ 1, + }); - // Attach swapchain's image as output - if ( settings::experimental::deferredAliasOutputToSwapchain ) { - attachments.output = renderTarget.attachments.size(); - auto& swapchainAttachment = renderTarget.attachments.emplace_back(); - swapchainAttachment.descriptor.format = ext::vulkan::settings::formats::color; //device.formats.color; - swapchainAttachment.descriptor.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - swapchainAttachment.descriptor.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - swapchainAttachment.descriptor.aliased = true; - { - VkBool32 blendEnabled = VK_TRUE; - VkColorComponentFlags writeMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; - VkPipelineColorBlendAttachmentState blendAttachmentState = ext::vulkan::initializers::pipelineColorBlendAttachmentState( - writeMask, - blendEnabled - ); - if ( blendEnabled == VK_TRUE ) { - blendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; - blendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - blendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD; - blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; - blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; - blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD; - } - swapchainAttachment.blendState = blendAttachmentState; + // Attach swapchain's image as output + if ( settings::experimental::deferredAliasOutputToSwapchain ) { + attachments.output = renderTarget.attachments.size(); + auto& swapchainAttachment = renderTarget.attachments.emplace_back(); + swapchainAttachment.descriptor.format = ext::vulkan::settings::formats::color; //device.formats.color; + swapchainAttachment.descriptor.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + swapchainAttachment.descriptor.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + swapchainAttachment.descriptor.aliased = true; + { + VkBool32 blendEnabled = VK_TRUE; + VkColorComponentFlags writeMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + VkPipelineColorBlendAttachmentState blendAttachmentState = ext::vulkan::initializers::pipelineColorBlendAttachmentState( + writeMask, + blendEnabled + ); + if ( blendEnabled == VK_TRUE ) { + blendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + blendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + blendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD; + blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD; } - } else { - attachments.output = renderTarget.attach(RenderTarget::Attachment::Descriptor{ - /*.format =*/ VK_FORMAT_R8G8B8A8_UNORM, - /*.layout = */ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - /*.usage =*/ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, - /*.blend =*/ true, - /*.samples =*/ 1, - }); + swapchainAttachment.blendState = blendAttachmentState; } - attachments.debug = renderTarget.attach(RenderTarget::Attachment::Descriptor{ - /*.format =*/ VK_FORMAT_R32G32B32A32_SFLOAT, + } else { + attachments.output = renderTarget.attach(RenderTarget::Attachment::Descriptor{ + /*.format =*/ VK_FORMAT_R16G16B16A16_SFLOAT, /*.layout = */ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - /*.usage =*/ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, - /*.blend =*/ false, + /*.usage =*/ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, + /*.blend =*/ true, /*.samples =*/ 1, }); - metadata.outputs.emplace_back(attachments.output); - #if 0 - attachments.debug = renderTarget.attach(RenderTarget::Attachment::Descriptor{ - /*.format = */VK_FORMAT_R16G16B16A16_SFLOAT, - /*.layout = */VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - /*.usage = */VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, - /*.blend = */false, - /*.samples = */1, - }); - #endif + } + metadata.outputs.emplace_back(attachments.color); +// metadata.outputs.emplace_back(attachments.output); + for ( size_t eye = 0; eye < metadata.eyes; ++eye ) { if ( ext::vulkan::settings::experimental::deferredSampling ) { // First pass: fill the G-Buffer { @@ -144,24 +154,38 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { /*.*/ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, /*.colors =*/ { attachments.id, attachments.normals, attachments.uvs }, /*.inputs =*/ {}, - /*.resolve =*/ {}, + /*.resolve =*/{}, /*.depth = */ attachments.depth, - /*.layer = */0, + /*.layer = */eye, /*.autoBuildPipeline =*/ true ); } - // Second pass: write to output + // Second pass: write to color { renderTarget.addPass( /*.*/ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, - /*.colors =*/ { attachments.output, attachments.debug }, + /*.colors =*/ { attachments.color, attachments.bright }, /*.inputs =*/ { attachments.id, attachments.normals, attachments.uvs, attachments.depth }, - /*.resolve =*/ {}, - /*.depth = */ attachments.depth, - /*.layer = */0, + /*.resolve =*/{}, + /*.depth = */attachments.depth, + /*.layer = */eye, /*.autoBuildPipeline =*/ false ); } + #if 0 + // Third pass: solely to transition + if ( settings::experimental::bloom ) { + renderTarget.addPass( + /*.*/ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, + /*.colors =*/ {}, + /*.inputs =*/ { attachments.color, attachments.bright, attachments.scratch, attachments.output, attachments.depth }, + /*.resolve =*/{}, + /*.depth = */ attachments.depth, + /*.layer = */eye, + /*.autoBuildPipeline =*/ false + ); + } + #endif } else { // First pass: fill the G-Buffer { @@ -169,26 +193,41 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { /*.*/ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, /*.colors =*/ { attachments.id, attachments.normals, attachments.albedo }, /*.inputs =*/ {}, - /*.resolve =*/ {}, + /*.resolve =*/{}, /*.depth = */ attachments.depth, - /*.layer = */0, + /*.layer = */eye, /*.autoBuildPipeline =*/ true ); } - // Second pass: write to output + // Second pass: write to color { renderTarget.addPass( /*.*/ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, - /*.colors =*/ { attachments.output, attachments.debug }, + /*.colors =*/ { attachments.color, attachments.bright }, /*.inputs =*/ { attachments.id, attachments.normals, attachments.albedo, attachments.depth }, - /*.resolve =*/ {}, + /*.resolve =*/{}, /*.depth = */ attachments.depth, - /*.layer = */0, + /*.layer = */eye, /*.autoBuildPipeline =*/ false ); } + #if 0 + // Third pass: solely to transition + if ( settings::experimental::bloom ) { + renderTarget.addPass( + /*.*/ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, + /*.colors =*/ {}, + /*.inputs =*/ { attachments.color, attachments.bright, attachments.scratch, attachments.output, attachments.depth }, + /*.resolve =*/{}, + /*.depth = */ attachments.depth, + /*.layer = */eye, + /*.autoBuildPipeline =*/ false + ); + } + #endif } } + renderTarget.initialize( device ); { @@ -215,25 +254,40 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { blitter.initializeMesh( mesh ); uf::stl::string vertexShaderFilename = uf::io::root+"/shaders/display/subpass.vert.spv"; - uf::stl::string fragmentShaderFilename = uf::io::root+"/shaders/display/subpass.frag.spv"; - if ( uf::renderer::settings::experimental::vxgi ) { - fragmentShaderFilename = uf::string::replace( fragmentShaderFilename, "frag", "vxgi.frag" ); - } - if ( msaa > 1 ) { - fragmentShaderFilename = uf::string::replace( fragmentShaderFilename, "frag", "msaa.frag" ); - } - if ( uf::renderer::settings::experimental::deferredSampling ) { - fragmentShaderFilename = uf::string::replace( fragmentShaderFilename, "frag", "deferredSampling.frag" ); + uf::stl::string fragmentShaderFilename = uf::io::root+"/shaders/display/subpass.frag.spv"; { + std::pair settings[] = { + { uf::renderer::settings::experimental::vxgi, "vxgi.frag" }, + { msaa > 1, "msaa.frag" }, + { uf::renderer::settings::experimental::deferredSampling, "deferredSampling.frag" }, + }; + FOR_ARRAY( settings ) if ( settings[i].first ) fragmentShaderFilename = uf::string::replace( fragmentShaderFilename, "frag", settings[i].second ); } + blitter.material.initializeShaders({ {uf::io::resolveURI(vertexShaderFilename), VK_SHADER_STAGE_VERTEX_BIT}, {uf::io::resolveURI(fragmentShaderFilename), VK_SHADER_STAGE_FRAGMENT_BIT} }); - { - auto& scene = uf::scene::getCurrentScene(); + + auto& scene = uf::scene::getCurrentScene(); + auto& sceneMetadataJson = scene.getComponent(); + + if ( settings::experimental::bloom ) { + uf::stl::string computeShaderFilename = uf::io::resolveURI(uf::io::root+"/shaders/display/bloom.comp.spv"); + blitter.material.attachShader(computeShaderFilename, uf::renderer::enums::Shader::COMPUTE, "bloom"); + auto& shader = blitter.material.getShader("compute", "bloom"); + shader.textures.clear(); + shader.textures.emplace_back().aliasAttachment( renderTarget.attachments[attachments.color], (size_t) 0 ); + shader.textures.emplace_back().aliasAttachment( renderTarget.attachments[attachments.bright], (size_t) 0 ); + shader.textures.emplace_back().aliasAttachment( renderTarget.attachments[attachments.scratch], (size_t) 0 ); + for ( auto& texture : shader.textures ) { + texture.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + texture.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + } + } + { auto& shader = blitter.material.getShader("fragment"); - auto& sceneMetadataJson = scene.getComponent(); + size_t maxLights = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["lights"]["max"].as(512); size_t maxTextures2D = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["textures"]["max"]["2D"].as(512); size_t maxTexturesCube = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["textures"]["max"]["cube"].as(128); @@ -267,28 +321,6 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { else if ( tx.name == "voxelRadiance" ) layout.descriptorCount = maxCascades; } } - /* - uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants; - ext::json::forEach( shader.metadata.json["specializationConstants"], [&]( size_t i, ext::json::Value& sc ){ - uf::stl::string name = sc["name"].as(); - if ( name == "TEXTURES" ) sc["value"] = (specializationConstants[i] = maxTextures2D); - else if ( name == "CUBEMAPS" ) sc["value"] = (specializationConstants[i] = maxTexturesCube); - else if ( name == "CASCADES" ) sc["value"] = (specializationConstants[i] = maxCascades); - }); - ext::json::forEach( shader.metadata.json["definitions"]["textures"], [&]( ext::json::Value& t ){ - size_t binding = t["binding"].as(); - uf::stl::string name = t["name"].as(); - for ( auto& layout : shader.descriptorSetLayoutBindings ) { - if ( layout.binding != binding ) continue; - if ( name == "samplerTextures" ) layout.descriptorCount = maxTextures2D; - else if ( name == "samplerCubemaps" ) layout.descriptorCount = maxTexturesCube; - else if ( name == "voxelId" ) layout.descriptorCount = maxCascades; - else if ( name == "voxelUv" ) layout.descriptorCount = maxCascades; - else if ( name == "voxelNormal" ) layout.descriptorCount = maxCascades; - else if ( name == "voxelRadiance" ) layout.descriptorCount = maxCascades; - } - }); - */ } else { uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants; for ( auto pair : shader.metadata.definitions.specializationConstants ) { @@ -304,63 +336,22 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { else if ( tx.name == "samplerCubemaps" ) layout.descriptorCount = maxTexturesCube; } } - /* - uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants; - ext::json::forEach( shader.metadata.json["specializationConstants"], [&]( size_t i, ext::json::Value& sc ){ - uf::stl::string name = sc["name"].as(); - if ( name == "TEXTURES" ) sc["value"] = (specializationConstants[i] = maxTextures2D); - else if ( name == "CUBEMAPS" ) sc["value"] = (specializationConstants[i] = maxTexturesCube); - }); - - ext::json::forEach( shader.metadata.json["definitions"]["textures"], [&]( ext::json::Value& t ){ - size_t binding = t["binding"].as(); - uf::stl::string name = t["name"].as(); - for ( auto& layout : shader.descriptorSetLayoutBindings ) { - if ( layout.binding != binding ) continue; - if ( name == "samplerTextures" ) layout.descriptorCount = maxTextures2D; - else if ( name == "samplerCubemaps" ) layout.descriptorCount = maxTexturesCube; - } - }); - */ } - /* - uf::stl::vector lights(maxLights); - uf::stl::vector materials(maxTextures2D); - uf::stl::vector textures(maxTextures2D); - uf::stl::vector drawCommands(maxTextures2D); - - for ( auto& material : materials ) material.colorBase = {0,0,0,0}; - metadata.lightBufferIndex = shader.initializeBuffer( - (const void*) lights.data(), - lights.size() * sizeof(pod::Light), - VK_BUFFER_USAGE_STORAGE_BUFFER_BIT - ); - metadata.materialBufferIndex = shader.initializeBuffer( - (const void*) materials.data(), - materials.size() * sizeof(pod::Material), - VK_BUFFER_USAGE_STORAGE_BUFFER_BIT - ); - - metadata.textureBufferIndex = shader.initializeBuffer( - (const void*) textures.data(), - textures.size() * sizeof(pod::Texture), - VK_BUFFER_USAGE_STORAGE_BUFFER_BIT - ); - - metadata.drawCallBufferIndex = shader.initializeBuffer( - (const void*) drawCommands.data(), - drawCommands.size() * sizeof(pod::DrawCommand), - VK_BUFFER_USAGE_STORAGE_BUFFER_BIT - ); - */ } - // blitter.initializePipeline(); for ( size_t eye = 0; eye < metadata.eyes; ++eye ) { - blitter.descriptor.subpass = 2 * eye + 1; - if ( blitter.hasPipeline( blitter.descriptor ) ) continue; - blitter.initializePipeline( blitter.descriptor ); + auto descriptor = blitter.descriptor; + descriptor.subpass = (renderTarget.passes.size() / metadata.eyes) * eye + 1; + if ( !blitter.hasPipeline( descriptor ) ) blitter.initializePipeline( descriptor ); + + if ( settings::experimental::bloom ) { + descriptor.inputs.dispatch = { (width / 8) + 1, (height / 8) + 1, 1 }; + descriptor.pipeline = "bloom"; + descriptor.subpass = 0; + if ( !blitter.hasPipeline( descriptor ) ) { + blitter.initializePipeline( descriptor ); + } + } } - blitter.descriptor.subpass = 1; } } void ext::vulkan::DeferredRenderMode::tick() { @@ -371,15 +362,37 @@ void ext::vulkan::DeferredRenderMode::tick() { if ( resized ) { renderTarget.initialize( *renderTarget.device ); + + if ( settings::experimental::bloom ) { + auto& shader = blitter.material.getShader("compute", "bloom"); + #if 1 + shader.textures.clear(); + shader.textures.emplace_back().aliasAttachment( renderTarget.attachments[renderTarget.attachments.size() - 5], (size_t) 0 ); // attachments.color + shader.textures.emplace_back().aliasAttachment( renderTarget.attachments[renderTarget.attachments.size() - 4], (size_t) 0 ); // attachments.bright + shader.textures.emplace_back().aliasAttachment( renderTarget.attachments[renderTarget.attachments.size() - 3], (size_t) 0 ); // attachments.scratch + for ( auto& texture : shader.textures ) { + texture.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + texture.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + } + #endif + } } // update blitter descriptor set if ( rebuild && blitter.initialized ) { for ( size_t eye = 0; eye < metadata.eyes; ++eye ) { - blitter.descriptor.subpass = 2 * eye + 1; - if ( !blitter.hasPipeline( blitter.descriptor ) ) continue; - blitter.getPipeline( blitter.descriptor ).update( blitter, blitter.descriptor ); + auto descriptor = blitter.descriptor; + descriptor.subpass = (renderTarget.passes.size() / metadata.eyes) * eye + 1; + if ( blitter.hasPipeline( blitter.descriptor ) ) blitter.getPipeline( blitter.descriptor ).update( blitter, blitter.descriptor ); + + if ( settings::experimental::bloom ) { + descriptor.inputs.dispatch = { (width / 8) + 1, (height / 8) + 1, 1 }; + descriptor.pipeline = "bloom"; + descriptor.subpass = 0; + if ( blitter.hasPipeline( descriptor ) ) { + blitter.getPipeline( descriptor ).update( blitter, descriptor ); + } + } } - blitter.descriptor.subpass = 1; } } void ext::vulkan::DeferredRenderMode::destroy() { @@ -530,6 +543,57 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto } vkCmdEndRenderPass(commands[i]); + if ( settings::experimental::bloom ) { + ext::vulkan::GraphicDescriptor descriptor = blitter.descriptor; + descriptor.inputs.dispatch = { (width / 8) + 1, (height / 8) + 1, 1 }; + descriptor.pipeline = "bloom"; + descriptor.subpass = 0; + + auto& shader = blitter.material.getShader("compute", "bloom"); + + imageMemoryBarrier.srcAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT; + imageMemoryBarrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT; + imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; + for ( auto& attachment : shader.textures ) { + imageMemoryBarrier.image = attachment.image; + vkCmdPipelineBarrier( commands[i], VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_FLAGS_NONE, 0, NULL, 0, NULL, 1, &imageMemoryBarrier ); + } + #if 0 + blitter.record(commands[i], descriptor, 0, 0); + + imageMemoryBarrier.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT; + imageMemoryBarrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT; + imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; + imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; + for ( auto& attachment : shader.textures ) { + imageMemoryBarrier.image = attachment.image; + vkCmdPipelineBarrier( commands[i], VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_FLAGS_NONE, 0, NULL, 0, NULL, 1, &imageMemoryBarrier ); + } + #endif + blitter.record(commands[i], descriptor, 0, 1); + for ( auto& attachment : shader.textures ) { + imageMemoryBarrier.image = attachment.image; + vkCmdPipelineBarrier( commands[i], VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_FLAGS_NONE, 0, NULL, 0, NULL, 1, &imageMemoryBarrier ); + } + blitter.record(commands[i], descriptor, 0, 2); + for ( auto& attachment : shader.textures ) { + imageMemoryBarrier.image = attachment.image; + vkCmdPipelineBarrier( commands[i], VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_FLAGS_NONE, 0, NULL, 0, NULL, 1, &imageMemoryBarrier ); + } + for ( auto& attachment : shader.textures ) { + imageMemoryBarrier.image = attachment.image; + vkCmdPipelineBarrier( commands[i], VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_FLAGS_NONE, 0, NULL, 0, NULL, 1, &imageMemoryBarrier ); + } + blitter.record(commands[i], descriptor, 0, 3); + imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; + imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + for ( auto& attachment : shader.textures ) { + imageMemoryBarrier.image = attachment.image; + vkCmdPipelineBarrier( commands[i], VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_FLAGS_NONE, 0, NULL, 0, NULL, 1, &imageMemoryBarrier ); + } + } + for ( auto layer : layers ) { layer->pipelineBarrier( commands[i], 1 ); } @@ -581,7 +645,7 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto imageMemoryBarrier.oldLayout = outputAttachment.descriptor.layout; imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; vkCmdPipelineBarrier( commands[i], VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_BY_REGION_BIT, 0, NULL, 0, NULL, 1, &imageMemoryBarrier ); - outputAttachment.descriptor.layout = imageMemoryBarrier.newLayout; + // outputAttachment.descriptor.layout = imageMemoryBarrier.newLayout; } { imageMemoryBarrier.image = swapchainRender.renderTarget.attachments[i].image; @@ -608,10 +672,10 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto imageMemoryBarrier.image = outputAttachment.image; imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - imageMemoryBarrier.oldLayout = outputAttachment.descriptor.layout; - imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; //outputAttachment.descriptor.layout; + imageMemoryBarrier.newLayout = outputAttachment.descriptor.layout; //VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; vkCmdPipelineBarrier( commands[i], VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_DEPENDENCY_BY_REGION_BIT, 0, NULL, 0, NULL, 1, &imageMemoryBarrier ); - outputAttachment.descriptor.layout = imageMemoryBarrier.newLayout; + // outputAttachment.descriptor.layout = imageMemoryBarrier.newLayout; } { imageMemoryBarrier.image = swapchainRender.renderTarget.attachments[i].image; diff --git a/engine/src/ext/vulkan/rendermodes/rendertarget.cpp b/engine/src/ext/vulkan/rendermodes/rendertarget.cpp index 6df1f6d1..b6b756fa 100644 --- a/engine/src/ext/vulkan/rendermodes/rendertarget.cpp +++ b/engine/src/ext/vulkan/rendermodes/rendertarget.cpp @@ -211,7 +211,7 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) { /*.blend = */false, /*.samples = */msaa, }); - if ( false && ext::vulkan::settings::experimental::deferredMode != "" ) { + if ( !true && ext::vulkan::settings::experimental::deferredMode != "" ) { attachments.uvs = renderTarget.attach(RenderTarget::Attachment::Descriptor{ /*.format = */VK_FORMAT_R16G16_UNORM, /*.layout = */VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, @@ -242,7 +242,7 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) { /*.blend =*/ true, /*.samples =*/ 1, }); - if ( false && ext::vulkan::settings::experimental::deferredMode != "" ) { + if ( !true && ext::vulkan::settings::experimental::deferredMode != "" ) { // First pass: fill the G-Buffer { renderTarget.addPass( @@ -346,16 +346,6 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) { else if ( sType == "geometry" ) type = ext::vulkan::enums::Shader::GEOMETRY; else if ( sType == "compute" ) type = ext::vulkan::enums::Shader::COMPUTE; } - #if 0 - if ( type == ext::vulkan::enums::Shader::FRAGMENT ) { - if ( msaa > 1 ) { - filename = uf::string::replace( filename, "frag", "msaa.frag" ); - } - if ( uf::renderer::settings::experimental::deferredSampling ) { - filename = uf::string::replace( filename, "frag", "deferredSampling.frag" ); - } - } - #endif blitter.material.attachShader( uf::io::root+filename, type, pipeline ); }); } else if ( ext::json::isObject( metadata.json["shaders"] ) ) { @@ -373,16 +363,6 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) { else if ( key == "fragment" ) type = ext::vulkan::enums::Shader::FRAGMENT; else if ( key == "geometry" ) type = ext::vulkan::enums::Shader::GEOMETRY; else if ( key == "compute" ) type = ext::vulkan::enums::Shader::COMPUTE; - #if 0 - if ( type == ext::vulkan::enums::Shader::FRAGMENT ) { - if ( msaa > 1 ) { - filename = uf::string::replace( filename, "frag", "msaa.frag" ); - } - if ( uf::renderer::settings::experimental::deferredSampling ) { - filename = uf::string::replace( filename, "frag", "deferredSampling.frag" ); - } - } - #endif blitter.material.attachShader( uf::io::root+filename, type, pipeline ); }); } else if ( metadata.json["shaders"].is() && !metadata.json["shaders"].as() ) { @@ -390,13 +370,13 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) { blitter.process = false; } else { uf::stl::string vertexShaderFilename = uf::io::root+"/shaders/display/renderTarget.vert.spv"; - uf::stl::string fragmentShaderFilename = uf::io::root+"/shaders/display/renderTarget.frag.spv"; - if ( msaa > 1 ) { - fragmentShaderFilename = uf::string::replace( fragmentShaderFilename, "frag", "msaa.frag" ); - } - // I don't actually have support for deferred sampling within a render target - if ( uf::renderer::settings::experimental::deferredSampling ) { - // fragmentShaderFilename = uf::string::replace( fragmentShaderFilename, "frag", "deferredSampling.frag" ); + uf::stl::string fragmentShaderFilename = uf::io::root+"/shaders/display/renderTarget.frag.spv"; { + std::pair settings[] = { + { msaa > 1, "msaa.frag" }, + // I don't actually have support for deferred sampling within a render target + // { uf::renderer::settings::experimental::deferredSampling, "deferredSampling.frag" }, + }; + FOR_ARRAY( settings ) if ( settings[i].first ) fragmentShaderFilename = uf::string::replace( fragmentShaderFilename, "frag", settings[i].second ); } blitter.material.initializeShaders({ {uf::io::resolveURI(vertexShaderFilename), VK_SHADER_STAGE_VERTEX_BIT}, diff --git a/engine/src/ext/vulkan/rendertarget.cpp b/engine/src/ext/vulkan/rendertarget.cpp index eaa2d03f..85152ce1 100644 --- a/engine/src/ext/vulkan/rendertarget.cpp +++ b/engine/src/ext/vulkan/rendertarget.cpp @@ -11,15 +11,15 @@ void ext::vulkan::RenderTarget::addPass( VkPipelineStageFlags stage, VkAccessFla pass.access = access; pass.layer = layer; pass.autoBuildPipeline = autoBuildPipeline; - for ( auto& i : colors ) pass.colors.push_back( { (uint32_t) i, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL } ); - for ( auto& i : inputs ) pass.inputs.push_back( { (uint32_t) i, i == depth ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL } ); - for ( auto& i : resolves ) pass.resolves.push_back( { (uint32_t) i, i == depth ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL } ); + for ( auto& i : colors ) pass.colors.emplace_back( VkAttachmentReference{ (uint32_t) i, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL } ); + for ( auto& i : inputs ) pass.inputs.emplace_back( VkAttachmentReference{ (uint32_t) i, i == depth ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL } ); + for ( auto& i : resolves ) pass.resolves.emplace_back( VkAttachmentReference{ (uint32_t) i, i == depth ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL } ); if ( depth < attachments.size() ) pass.depth = { (uint32_t) depth, attachments[depth].descriptor.layout }; if ( !resolves.empty() && resolves.size() != colors.size() ) VK_VALIDATION_MESSAGE("Mismatching resolves count: Expecting " << colors.size() << ", got " << resolves.size()); - passes.push_back(pass); + passes.emplace_back(pass); } size_t ext::vulkan::RenderTarget::attach( const Attachment::Descriptor& descriptor, Attachment* attachment ) { if ( this->views == 0 ) this->views = 1; @@ -180,7 +180,7 @@ void ext::vulkan::RenderTarget::initialize( Device& device ) { description.finalLayout = attachment.descriptor.layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL : attachment.descriptor.layout; description.flags = 0; - attachments.push_back(description); + attachments.emplace_back(description); } } @@ -208,7 +208,9 @@ void ext::vulkan::RenderTarget::initialize( Device& device ) { dependency.dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; dependency.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; size_t i = 0; - // std::cout << this << ": " << std::endl; + #if 0 + UF_MSG_DEBUG(this << ": "); + #endif for ( auto& pass : passes ) { VkSubpassDescription description; // describe renderpass @@ -228,13 +230,12 @@ void ext::vulkan::RenderTarget::initialize( Device& device ) { break; } } - descriptions.push_back(description); + descriptions.emplace_back(description); #if 0 UF_MSG_DEBUG("Pass: " << descriptions.size() - 1); for ( auto& color : pass.colors ) UF_MSG_DEBUG("Color: " << color.attachment << "\t" << std::hex << color.layout << "\t" << this->attachments[color.attachment].image); for ( auto& input : pass.inputs ) UF_MSG_DEBUG("Input: " << input.attachment << "\t" << std::hex << input.layout << "\t" << this->attachments[input.attachment].image); - std::cout << std::endl; #endif // transition dependency between subpasses dependency.srcSubpass = dependency.dstSubpass; @@ -243,7 +244,7 @@ void ext::vulkan::RenderTarget::initialize( Device& device ) { dependency.dstSubpass = i++; dependency.dstStageMask = pass.stage; dependency.dstAccessMask = pass.access; - dependencies.push_back(dependency); + dependencies.emplace_back(dependency); } // dependency: transition to final { @@ -253,7 +254,7 @@ void ext::vulkan::RenderTarget::initialize( Device& device ) { dependency.dstSubpass = VK_SUBPASS_EXTERNAL; dependency.dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; dependency.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; - dependencies.push_back(dependency); + dependencies.emplace_back(dependency); } // depth dependency @@ -270,7 +271,7 @@ void ext::vulkan::RenderTarget::initialize( Device& device ) { dependency.dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; dependency.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - dependencies.push_back(dependency); + dependencies.emplace_back(dependency); } { VkSubpassDependency dependency; @@ -284,7 +285,7 @@ void ext::vulkan::RenderTarget::initialize( Device& device ) { dependency.dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; dependency.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - dependencies.push_back(dependency); + dependencies.emplace_back(dependency); } #if 0 @@ -293,7 +294,6 @@ void ext::vulkan::RenderTarget::initialize( Device& device ) { UF_MSG_DEBUG("\tStage: " << std::hex << dependency.srcStageMask << " -> " << std::hex << dependency.dstStageMask); UF_MSG_DEBUG("\tAccess: " << std::hex << dependency.srcAccessMask << " -> " << std::hex << dependency.dstAccessMask); } - std::cout << std::endl; #endif VkRenderPassCreateInfo renderPassInfo = {}; renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; @@ -327,7 +327,7 @@ void ext::vulkan::RenderTarget::initialize( Device& device ) { */ VK_CHECK_RESULT(vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass)); - // std::cout << renderPass << ": " << attachments.size() << std::endl; + // UF_MSG_DEBUG(renderPass << ": " << attachments.size()); } { // destroy previous framebuffers @@ -340,8 +340,8 @@ void ext::vulkan::RenderTarget::initialize( Device& device ) { for ( size_t j = 0; j < this->views; ++j ) { for ( auto& attachment : this->attachments ) { if ( attachment.descriptor.aliased && attachment.descriptor.layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR ) { - attachmentViews.push_back(base.renderTarget.attachments[i].view); - } else attachmentViews.push_back(attachment.views[j]); + attachmentViews.emplace_back(base.renderTarget.attachments[i].view); + } else attachmentViews.emplace_back(attachment.views[j]); } } diff --git a/engine/src/ext/vulkan/vulkan.cpp b/engine/src/ext/vulkan/vulkan.cpp index a289a0da..2bdc8df6 100644 --- a/engine/src/ext/vulkan/vulkan.cpp +++ b/engine/src/ext/vulkan/vulkan.cpp @@ -41,6 +41,7 @@ bool ext::vulkan::settings::experimental::hdr = true; bool ext::vulkan::settings::experimental::vxgi = true; bool ext::vulkan::settings::experimental::deferredSampling = true; bool ext::vulkan::settings::experimental::culling = false; +bool ext::vulkan::settings::experimental::bloom = false; VkColorSpaceKHR ext::vulkan::settings::formats::colorSpace; ext::vulkan::enums::Format::type_t ext::vulkan::settings::formats::color = ext::vulkan::enums::Format::R8G8B8A8_UNORM; diff --git a/ext/behaviors/light/behavior.cpp b/ext/behaviors/light/behavior.cpp index c4b23d2a..4f1b6a01 100644 --- a/ext/behaviors/light/behavior.cpp +++ b/ext/behaviors/light/behavior.cpp @@ -99,7 +99,7 @@ void ext::LightBehavior::initialize( uf::Object& self ) { renderMode.height = size.y; } - this->addHook( "object:UpdateMetadata.%UID%", [&](){ + this->addHook( "object:UpdateMetadata.%UID%", [&](ext::json::Value& json){ metadata.deserialize(self, metadataJson); }); metadata.deserialize(self, metadataJson); diff --git a/ext/behaviors/player/behavior.cpp b/ext/behaviors/player/behavior.cpp index 6f9a868c..1735102f 100644 --- a/ext/behaviors/player/behavior.cpp +++ b/ext/behaviors/player/behavior.cpp @@ -121,7 +121,7 @@ void ext::PlayerBehavior::initialize( uf::Object& self ) { this->queueHook("discord.Activity.Update.%UID%", ext::json::null(), 1.0); #endif - this->addHook( "object:UpdateMetadata.%UID%", [&](){ + this->addHook( "object:UpdateMetadata.%UID%", [&](ext::json::Value& json){ metadata.deserialize(self, metadataJson); }); metadata.deserialize(self, metadataJson); diff --git a/ext/behaviors/player/model/behavior.cpp b/ext/behaviors/player/model/behavior.cpp index fb65a40f..0c2cd9de 100644 --- a/ext/behaviors/player/model/behavior.cpp +++ b/ext/behaviors/player/model/behavior.cpp @@ -28,7 +28,7 @@ void ext::PlayerModelBehavior::initialize( uf::Object& self ) { metadata.reference = &controllerTransform; - this->addHook( "object:UpdateMetadata.%UID%", [&](){ + this->addHook( "object:UpdateMetadata.%UID%", [&](ext::json::Value& json){ metadata.deserialize(self, metadataJson); }); metadata.deserialize(self, metadataJson); diff --git a/ext/behaviors/scene/behavior.cpp b/ext/behaviors/scene/behavior.cpp index ca648d26..9e7d491b 100644 --- a/ext/behaviors/scene/behavior.cpp +++ b/ext/behaviors/scene/behavior.cpp @@ -190,7 +190,7 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) { } #endif - this->addHook( "object:UpdateMetadata.%UID%", [&](){ + this->addHook( "object:UpdateMetadata.%UID%", [&]( ext::json::Value& json ){ metadata.deserialize(self, metadataJson); }); metadata.deserialize(self, metadataJson); @@ -502,6 +502,7 @@ void ext::ExtSceneBehavior::Metadata::serialize( uf::Object& self, uf::Serialize serializer["light"]["specular"] = uf::vector::encode( /*this->*/light.specular ); serializer["light"]["exposure"] = /*this->*/light.exposure; serializer["light"]["gamma"] = /*this->*/light.gamma; + serializer["light"]["brightnessThreshold"] = /*this->*/light.brightnessThreshold; serializer["light"]["fog"]["color"] = uf::vector::encode( /*this->*/fog.color ); serializer["light"]["fog"]["step scale"] = /*this->*/fog.stepScale; @@ -518,26 +519,30 @@ void ext::ExtSceneBehavior::Metadata::serialize( uf::Object& self, uf::Serialize serializer["system"]["renderer"]["shader"]["parameters"] = uf::vector::encode( /*this->*/shader.parameters ); } void ext::ExtSceneBehavior::Metadata::deserialize( uf::Object& self, uf::Serializer& serializer ) { - if ( !serializer["light"]["point light eye depth scale"].is() ) - serializer["light"]["point light eye depth scale"] = ext::config["engine"]["scenes"]["lights"]["point light eye depth scale"]; - /*this->*/max.textures2D = ext::config["engine"]["scenes"]["textures"]["max"]["2D"].as(/*this->*/max.textures2D); /*this->*/max.texturesCube = ext::config["engine"]["scenes"]["textures"]["max"]["cube"].as(/*this->*/max.texturesCube); /*this->*/max.textures3D = ext::config["engine"]["scenes"]["textures"]["max"]["3D"].as(/*this->*/max.textures3D); /*this->*/max.lights = ext::config["engine"]["scenes"]["lights"]["max"].as(/*this->*/max.lights); - /*this->*/light.enabled = ext::config["engine"]["scenes"]["lights"]["enabled"].as(true) && serializer["light"]["should"].as(true); - /*this->*/shadow.enabled = ext::config["engine"]["scenes"]["shadows"]["enabled"].as(true) && serializer["light"]["shadows"].as(true); /*this->*/shadow.samples = ext::config["engine"]["scenes"]["shadows"]["samples"].as(); /*this->*/shadow.max = ext::config["engine"]["scenes"]["shadows"]["max"].as(); /*this->*/shadow.update = ext::config["engine"]["scenes"]["shadows"]["update"].as(); /*this->*/shadow.experimentalMode = ext::config["engine"]["scenes"]["shadows"]["experimental mode"].as(0); + /*this->*/light.enabled = ext::config["engine"]["scenes"]["lights"]["enabled"].as(true) && serializer["light"]["should"].as(true); /*this->*/light.ambient = uf::vector::decode( serializer["light"]["ambient"], pod::Vector4f{ 1, 1, 1, 1 } ); /*this->*/light.specular = uf::vector::decode( serializer["light"]["specular"], pod::Vector4f{ 1, 1, 1, 1 } ); /*this->*/light.exposure = serializer["light"]["exposure"].as(1.0f); /*this->*/light.gamma = serializer["light"]["gamma"].as(2.2f); + /*this->*/light.brightnessThreshold = serializer["light"]["brightnessThreshold"].as(ext::config["engine"]["scenes"]["bloom"]["brightnessThreshold"].as(1.0f)); + + UF_MSG_DEBUG( serializer["bloom"] ); + + /*this->*/bloom.scale = serializer["bloom"]["scale"].as(ext::config["engine"]["scenes"]["bloom"]["scale"].as(bloom.scale)); + /*this->*/bloom.strength = serializer["bloom"]["strength"].as(ext::config["engine"]["scenes"]["bloom"]["strength"].as(bloom.strength)); + /*this->*/bloom.sigma = serializer["bloom"]["sigma"].as(ext::config["engine"]["scenes"]["bloom"]["sigma"].as(bloom.sigma)); + /*this->*/bloom.samples = serializer["bloom"]["samples"].as(ext::config["engine"]["scenes"]["bloom"]["samples"].as(bloom.samples)); /*this->*/fog.color = uf::vector::decode( serializer["light"]["fog"]["color"], pod::Vector3f{ 1, 1, 1 } ); /*this->*/fog.stepScale = serializer["light"]["fog"]["step scale"].as(); @@ -561,6 +566,39 @@ void ext::ExtSceneBehavior::Metadata::deserialize( uf::Object& self, uf::Seriali #if UF_USE_OPENGL_FIXED_FUNCTION uf::renderer::states::rebuild = true; #endif + + if ( uf::renderer::settings::experimental::bloom ) { + auto& renderMode = uf::renderer::getRenderMode("", true); + auto& blitter = *renderMode.getBlitters().front(); + auto& shader = blitter.material.getShader("compute", "bloom"); + + struct UniformDescriptor { + float scale; + float strength; + float threshold; + float sigma; + + float gamma; + float exposure; + uint32_t samples; + uint32_t padding; + }; + + UniformDescriptor uniforms = { + .scale = bloom.scale, + .strength = bloom.strength, + .threshold = light.brightnessThreshold, + .sigma = bloom.sigma, + + .gamma = light.gamma, + .exposure = light.exposure, + .samples = bloom.samples, + }; + + UF_MSG_DEBUG( bloom.scale << " " << bloom.strength << " " << light.brightnessThreshold << " " << bloom.sigma << " " << light.gamma << " " << light.exposure << " " << bloom.samples ); + + shader.updateBuffer( uniforms, shader.getUniformBuffer("UBO") ); + } } void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const uf::stl::string& renderModeName, bool isCompute ) { @@ -574,7 +612,7 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const uf::stl::string auto& metadataJson = this->getComponent(); auto& renderMode = uf::renderer::getRenderMode(renderModeName, true); - uf::stl::vector blitters = renderMode.getBlitters(); + auto blitters = renderMode.getBlitters(); #if UF_USE_OPENGL struct LightInfo { @@ -680,9 +718,14 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const uf::stl::string alignas(4) float gamma; alignas(4) float exposure; + alignas(4) float brightnessThreshold; alignas(4) uint32_t msaa; - alignas(4) uint32_t shadowSamples; + alignas(4) uint32_t shadowSamples; + alignas(4) uint32_t indexSkybox; + alignas(4) uint32_t padding1; + alignas(4) uint32_t padding2; + alignas(4) uint32_t padding3; }; // struct that contains our skybox cubemap, noise texture, and VXGI voxels @@ -774,8 +817,10 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const uf::stl::string uniforms.gamma = metadata.light.gamma; uniforms.exposure = metadata.light.exposure; + uniforms.brightnessThreshold = metadata.light.brightnessThreshold; uniforms.msaa = ext::vulkan::settings::msaa; uniforms.shadowSamples = std::min( 0, metadata.shadow.samples ); + uniforms.indexSkybox = indexSkybox; } diff --git a/ext/behaviors/scene/behavior.h b/ext/behaviors/scene/behavior.h index d10dfcce..7ba0609e 100644 --- a/ext/behaviors/scene/behavior.h +++ b/ext/behaviors/scene/behavior.h @@ -24,7 +24,14 @@ namespace ext { pod::Vector4f specular = {1,1,1,1}; float exposure = 1.0f; float gamma = 1.0f; + float brightnessThreshold = 1.0f; } light; + struct { + float scale = 1.0f; + float strength = 1.0f; + float sigma = 0.8f; + uint32_t samples = 1; + } bloom; struct { bool enabled = true; int samples = 4; diff --git a/ext/gui/behavior.cpp b/ext/gui/behavior.cpp index fadb5e28..ac8fd20f 100644 --- a/ext/gui/behavior.cpp +++ b/ext/gui/behavior.cpp @@ -426,7 +426,7 @@ void ext::GuiBehavior::initialize( uf::Object& self ) { auto& metadata = this->getComponent(); auto& metadataJson = this->getComponent(); - this->addHook( "object:UpdateMetadata.%UID%", [&](){ + this->addHook( "object:UpdateMetadata.%UID%", [&](ext::json::Value& json){ metadata.deserialize(self, metadataJson); }); metadata.deserialize(self, metadataJson); @@ -570,7 +570,7 @@ void ext::GuiBehavior::initialize( uf::Object& self ) { }); auto& metadataGlyph = this->getComponent(); - this->addHook( "object:UpdateMetadata.%UID%", [&](){ + this->addHook( "object:UpdateMetadata.%UID%", [&](ext::json::Value& json){ metadataGlyph.deserialize(self, metadataJson); }); // metadataGlyph.deserialize(self, metadataJson); diff --git a/ext/gui/manager/behavior.cpp b/ext/gui/manager/behavior.cpp index be111d07..96ba6c7b 100644 --- a/ext/gui/manager/behavior.cpp +++ b/ext/gui/manager/behavior.cpp @@ -84,7 +84,7 @@ void ext::GuiManagerBehavior::initialize( uf::Object& self ) { } }); - this->addHook( "object:UpdateMetadata.%UID%", [&](){ + this->addHook( "object:UpdateMetadata.%UID%", [&](ext::json::Value& json){ metadata.deserialize(self, metadataJson); }); metadata.deserialize(self, metadataJson); diff --git a/ext/main.cpp b/ext/main.cpp index aa186be5..626e6fda 100644 --- a/ext/main.cpp +++ b/ext/main.cpp @@ -354,6 +354,7 @@ void EXT_API ext::initialize() { uf::renderer::settings::experimental::vxgi = ::config["engine"]["ext"][RENDERER]["experimental"]["vxgi"].as( uf::renderer::settings::experimental::vxgi ); uf::renderer::settings::experimental::deferredSampling = ::config["engine"]["ext"][RENDERER]["experimental"]["deferred sampling"].as( uf::renderer::settings::experimental::deferredSampling ); uf::renderer::settings::experimental::culling = ::config["engine"]["ext"][RENDERER]["experimental"]["culling"].as( uf::renderer::settings::experimental::culling ); + uf::renderer::settings::experimental::bloom = ::config["engine"]["ext"][RENDERER]["experimental"]["bloom"].as( uf::renderer::settings::experimental::bloom ); #define JSON_TO_VKFORMAT( key ) if ( ::config["engine"]["ext"][RENDERER]["formats"][#key].is() ) {\ uf::stl::string format = ::config["engine"]["ext"][RENDERER]["formats"][#key].as();\ format = uf::string::replace( uf::string::uppercase(format), " ", "_" );\