From b3df72bfabcbf942390bc3aabb7029cc01e41ea6 Mon Sep 17 00:00:00 2001 From: ecker Date: Wed, 13 May 2026 22:14:46 -0500 Subject: [PATCH] validation errors squishing, finally bothered to seamlessly handle N-buffered UBOs, fixed shadowmapping not require a constant rebuild every time the lights changed (by instead binding all shadow textures and not-so-clever tricks), some other things --- bin/data/config.json | 13 +- bin/data/entities/gui/hud/scripts/hud.lua | 4 + bin/data/entities/gui/hud/text.json | 2 +- bin/data/entities/light.json | 2 +- bin/data/shaders/common/lambert.h | 2 +- bin/data/shaders/common/pbr.h | 4 +- engine/inc/uf/ext/vulkan/buffer.h | 11 +- engine/inc/uf/ext/vulkan/device.h | 6 +- engine/inc/uf/ext/vulkan/vk.h | 2 +- engine/src/engine/ext/scene/behavior.cpp | 149 ++++++++++------- engine/src/engine/ext/voxelizer/behavior.cpp | 11 +- engine/src/engine/graph/graph.cpp | 2 +- engine/src/ext/gltf/gltf.cpp | 10 +- engine/src/ext/meshopt/meshopt.cpp | 3 + engine/src/ext/vulkan/buffer.cpp | 111 ++++++------- engine/src/ext/vulkan/device.cpp | 9 +- engine/src/ext/vulkan/graphic.cpp | 150 +++++++++++------- engine/src/ext/vulkan/rendermodes/base.cpp | 17 +- .../src/ext/vulkan/rendermodes/deferred.cpp | 5 +- .../ext/vulkan/rendermodes/rendertarget.cpp | 5 +- 20 files changed, 286 insertions(+), 232 deletions(-) diff --git a/bin/data/config.json b/bin/data/config.json index d80c85a1..f6989b9e 100644 --- a/bin/data/config.json +++ b/bin/data/config.json @@ -110,7 +110,7 @@ "invariant": { "default stage buffers": true, "default defer buffer destroy": true, - "default command buffer immediate": false, + "default command buffer immediate": true, "multithreaded recording": true }, "pipelines": { @@ -118,9 +118,9 @@ "gui": true, "vsync": true, // vsync on vulkan side rather than engine-side "hdr": true, - "vxgi": true, + "vxgi": false, // to-do: fix issues "culling": false, - "bloom": false, + "bloom": true, "dof": false, "rt": false, "fsr": false, @@ -175,6 +175,7 @@ "features": [ // 1.1 "multiview" + ,"multiviewGeometryShader" // ,"nullDescriptor" ,"fragmentStoresAndAtomics" @@ -192,6 +193,12 @@ ,"shaderSampledImageArrayNonUniformIndexing" ,"shaderStorageImageArrayNonUniformIndexing" + ,"descriptorBindingAccelerationStructureUpdateAfterBind" + ,"descriptorBindingSampledImageUpdateAfterBind" + ,"descriptorBindingStorageImageUpdateAfterBind" + ,"descriptorBindingStorageBufferUpdateAfterBind" + ,"descriptorBindingUniformBufferUpdateAfterBind" + ,"descriptorBindingPartiallyBound" ,"descriptorIndexing" ,"bufferDeviceAddress" ], diff --git a/bin/data/entities/gui/hud/scripts/hud.lua b/bin/data/entities/gui/hud/scripts/hud.lua index 49f106ae..c283d31b 100644 --- a/bin/data/entities/gui/hud/scripts/hud.lua +++ b/bin/data/entities/gui/hud/scripts/hud.lua @@ -111,9 +111,11 @@ local fpsCounter = { time = 0, freq = 0.1 } +--[[ text:callHook( "gui:UpdateText.%UID%", { string = "" } ) +]] ent:bind( "tick", function(self) --[[ @@ -126,6 +128,7 @@ ent:bind( "tick", function(self) end ]] +--[[ if fpsCounter["time"] > fpsCounter["freq"] then -- update text text:callHook( "gui:UpdateText.%UID%", { @@ -138,6 +141,7 @@ ent:bind( "tick", function(self) fpsCounter["frames"] = fpsCounter["frames"] + 1 fpsCounter["time"] = fpsCounter["time"] + time.delta() end +]] local controllerTransform = controller:getComponent("Transform") diff --git a/bin/data/entities/gui/hud/text.json b/bin/data/entities/gui/hud/text.json index 5d94321c..5d815165 100644 --- a/bin/data/entities/gui/hud/text.json +++ b/bin/data/entities/gui/hud/text.json @@ -1,7 +1,7 @@ { "name": "HUD Overlay", "type": "Gui", - "ignore": false, + "ignore": true, "assets": [ ], diff --git a/bin/data/entities/light.json b/bin/data/entities/light.json index a5ee8d7b..35efce45 100644 --- a/bin/data/entities/light.json +++ b/bin/data/entities/light.json @@ -26,7 +26,7 @@ "bias": { "constant": 1.25, "slope": 1.75, - "shader": 0.00005 // 0.000005 //0.000000005 + "shader": 0.000005 // 0.000005 //0.000000005 }, "radius": [0.5, 0], "resolution": 1024, diff --git a/bin/data/shaders/common/lambert.h b/bin/data/shaders/common/lambert.h index e439ab77..e36674c0 100644 --- a/bin/data/shaders/common/lambert.h +++ b/bin/data/shaders/common/lambert.h @@ -28,7 +28,7 @@ void lambert() { // skip if attenuation factor is too low // if ( Lattenuation <= LIGHT_POWER_CUTOFF ) continue; // ray cast if our surface is occluded from the light - const float Lshadow = ( shadows++ < MAX_SHADOWS ) ? shadowFactor( lights[i], 0.0 ) : 1; + const float Lshadow = shadowFactor( lights[i], 0.0 ); // skip if our shadow factor is too low // if ( Lshadow <= LIGHT_POWER_CUTOFF ) continue; // in case of any divergence // light radiance diff --git a/bin/data/shaders/common/pbr.h b/bin/data/shaders/common/pbr.h index 47e02cdf..3ad92ab4 100644 --- a/bin/data/shaders/common/pbr.h +++ b/bin/data/shaders/common/pbr.h @@ -35,7 +35,7 @@ void pbr() { // skip if attenuation factor is too low // if ( Lattenuation <= LIGHT_POWER_CUTOFF ) continue; // ray cast if our surface is occluded from the light - const float Lshadow = ( shadows++ < MAX_SHADOWS ) ? shadowFactor( lights[i], 0.0 ) : 1; + const float Lshadow = shadowFactor( lights[i], 0.0 ); // skip if our shadow factor is too low // if ( Lshadow <= LIGHT_POWER_CUTOFF ) continue; // in case of any divergence // light radiance @@ -58,7 +58,7 @@ void pbr() { // final lighting const vec3 diffuse = mix(vec3(1.0) - F, vec3(0), surface.material.metallic) * surface.material.albedo.rgb; - const vec3 specular = ( shadows < MAX_SHADOWS ) ? ((F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo)) : vec3(0); + const vec3 specular = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo); surface.light.rgb += (diffuse + specular) * Lr * cosLi; surface.light.a += lights[i].power * Lattenuation * Lshadow; diff --git a/engine/inc/uf/ext/vulkan/buffer.h b/engine/inc/uf/ext/vulkan/buffer.h index f1f15a0b..5b7a7130 100644 --- a/engine/inc/uf/ext/vulkan/buffer.h +++ b/engine/inc/uf/ext/vulkan/buffer.h @@ -21,6 +21,7 @@ namespace ext { mutable size_t address = {}; void* mapped = nullptr; int32_t count = 1; + mutable bool written = false; VkBufferUsageFlags usage = 0; VkMemoryPropertyFlags memoryProperties = 0; @@ -41,8 +42,8 @@ namespace ext { ~Buffer(); void initialize( ext::vulkan::Device& device, size_t = {} ); - void initialize( const void*, VkDeviceSize, VkBufferUsageFlags, VkMemoryPropertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, bool = VK_DEFAULT_STAGE_BUFFERS ); - bool update( const void*, VkDeviceSize, bool = VK_DEFAULT_STAGE_BUFFERS ) const; // returns true if a reallocation occurred (to signal rebuilding command buffers) + void initialize( const void*, VkDeviceSize, VkBufferUsageFlags, VkMemoryPropertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ); + bool update( const void*, VkDeviceSize ) const; // returns true if a reallocation occurred (to signal rebuilding command buffers) void destroy(bool = VK_DEFAULT_DEFER_BUFFER_DESTROY); void swap( Buffer& ); @@ -60,9 +61,9 @@ namespace ext { void destroy(bool = VK_DEFAULT_DEFER_BUFFER_DESTROY); // - size_t initializeBuffer( const void*, VkDeviceSize, VkBufferUsageFlags, VkMemoryPropertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, bool = VK_DEFAULT_STAGE_BUFFERS ); - bool updateBuffer( const void*, VkDeviceSize, const Buffer&, bool = VK_DEFAULT_STAGE_BUFFERS ) const; - inline bool updateBuffer( const void* data, VkDeviceSize length, size_t index = 0, bool stage = VK_DEFAULT_STAGE_BUFFERS ) const { return updateBuffer( data, length, buffers.at(index), stage ); } + size_t initializeBuffer( const void*, VkDeviceSize, VkBufferUsageFlags, VkMemoryPropertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ); + bool updateBuffer( const void*, VkDeviceSize, const Buffer& ) const; + inline bool updateBuffer( const void* data, VkDeviceSize length, size_t index = 0 ) const { return updateBuffer( data, length, buffers.at(index) ); } }; struct AccelerationStructure { diff --git a/engine/inc/uf/ext/vulkan/device.h b/engine/inc/uf/ext/vulkan/device.h index c2330561..5ecd92b4 100644 --- a/engine/inc/uf/ext/vulkan/device.h +++ b/engine/inc/uf/ext/vulkan/device.h @@ -139,12 +139,12 @@ namespace ext { uint32_t getQueueFamilyIndex( VkQueueFlagBits queueFlags ); uint32_t getMemoryType( uint32_t typeBits, VkMemoryPropertyFlags properties, VkBool32 *memTypeFound = nullptr ); - VkCommandBuffer createCommandBuffer( VkCommandBufferLevel level, QueueEnum queue, bool begin = true ); + VkCommandBuffer createCommandBuffer( VkCommandBufferLevel level, QueueEnum queue, bool begin = true, bool singleton = true ); void flushCommandBuffer( VkCommandBuffer commandBuffer, QueueEnum queue, bool wait = VK_DEFAULT_COMMAND_BUFFER_IMMEDIATE ); pod::Checkpoint* markCommandBuffer( VkCommandBuffer commandBuffer, pod::Checkpoint::Type type, const uf::stl::string& name, const uf::stl::string& info ); - CommandBuffer fetchCommandBuffer( QueueEnum queue, bool waits = VK_DEFAULT_COMMAND_BUFFER_IMMEDIATE ); - CommandBuffer fetchCommandBuffer( QueueEnum queue, VkCommandBufferLevel, bool waits = VK_DEFAULT_COMMAND_BUFFER_IMMEDIATE ); + CommandBuffer fetchCommandBuffer( QueueEnum queue, bool immediate = VK_DEFAULT_COMMAND_BUFFER_IMMEDIATE ); + CommandBuffer fetchCommandBuffer( QueueEnum queue, VkCommandBufferLevel, bool immediate = VK_DEFAULT_COMMAND_BUFFER_IMMEDIATE ); void flushCommandBuffer( CommandBuffer& commandBuffer ); pod::Checkpoint* markCommandBuffer( CommandBuffer& commandBuffer, pod::Checkpoint::Type type, const uf::stl::string& name, const uf::stl::string& info ); diff --git a/engine/inc/uf/ext/vulkan/vk.h b/engine/inc/uf/ext/vulkan/vk.h index 71dc01dc..9004ec78 100644 --- a/engine/inc/uf/ext/vulkan/vk.h +++ b/engine/inc/uf/ext/vulkan/vk.h @@ -22,7 +22,7 @@ #define VK_DEFAULT_STAGE_BUFFERS ext::vulkan::settings::defaultStageBuffers #define VK_DEFAULT_DEFER_BUFFER_DESTROY ext::vulkan::settings::defaultDeferBufferDestroy #define VK_DEFAULT_COMMAND_BUFFER_IMMEDIATE ext::vulkan::settings::defaultCommandBufferImmediate -#define VK_UBO_USE_N_BUFFERS 0 +#define VK_UBO_USE_N_BUFFERS 1 #define VK_USE_MULTIVIEW 1 namespace ext { diff --git a/engine/src/engine/ext/scene/behavior.cpp b/engine/src/engine/ext/scene/behavior.cpp index 3e1be272..2a6d5b33 100644 --- a/engine/src/engine/ext/scene/behavior.cpp +++ b/engine/src/engine/ext/scene/behavior.cpp @@ -578,8 +578,13 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) { .global = metadata.global, }); } + uf::stl::vector indices(entities.size()); + std::iota(indices.begin(), indices.end(), 0); + // prioritize closer lights; it would be nice to also prioritize lights in view, but because of VXGI it's not really something to do - std::sort( entities.begin(), entities.end(), [&]( LightInfo& l, LightInfo& r ){ + std::sort(indices.begin(), indices.end(), [&](size_t a, size_t b) { + auto& l = entities[a]; + auto& r = entities[b]; if ( l.global && !r.global ) return true; if ( !l.global && r.global ) return false; return l.distance < r.distance; @@ -589,63 +594,89 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) { int32_t shadowCount = metadata.shadow.max; // how many shadow maps we should pass, based on range if ( shadowCount <= 0 ) shadowCount = std::numeric_limits::max(); - // disable shadows if that light is outside our threshold - for ( auto& info : entities ) if ( info.shadows && shadowCount-- <= 0 ) info.shadows = false; + // iterate over sorted indices + for ( auto idx : indices ) { + auto& info = entities[idx]; + if ( !info.shadows ) continue; + // outside of top-k, disable + if ( shadowCount-- <= 0 ) info.shadows = false; + else { + // enable if also in-range + auto* entity = info.entity; + if ( entity->hasComponent() ) { + auto& lightMetadata = entity->getComponent(); - // bind lighting and requested shadow maps - for ( uint32_t i = 0; i < entities.size() && storage.lights.size() < metadata.light.max; ++i ) { + if ( lightMetadata.renderer.mode == "in-range" && shadowUpdateThreshold-- > 0 ) { + auto& renderMode = entity->getComponent(); + renderMode.execute = true; + renderMode.metadata.limiter.execute = true; + } + } + } + } + + constexpr uint32_t MODE_SPLIT = 0; + constexpr uint32_t MODE_CUBEMAP = 1; + constexpr uint32_t MODE_SEPARATE_2DS = 2; + + for ( uint32_t i = 0; i < entities.size(); ++i ) { auto& info = entities[i]; uf::Entity* entity = info.entity; - if ( !info.shadows ) { - storage.lights.emplace_back(pod::Light{ - .view = uf::matrix::identity(), - .projection = uf::matrix::identity(), - .position = info.position, - .range = info.range, - .color = info.color, - .intensity = info.intensity, - .type = info.type, - .typeMap = 0, - .indexMap = -1, - .depthBias = info.bias, - }); - } else { + int32_t boundIndexMap = -1; + int32_t boundTypeMap = 0; + uint32_t views = 1; + + bool hasRT = entity->hasComponent(); + if ( hasRT ) { auto& renderMode = entity->getComponent(); - auto& lightCamera = entity->getComponent(); auto& lightMetadata = entity->getComponent(); + + views = renderMode.renderTarget.views; lightMetadata.renderer.rendered = true; - // activate our shadow mapper if it's range-basedd - if ( lightMetadata.renderer.mode == "in-range" && shadowUpdateThreshold-- > 0 ) { - renderMode.execute = true; - renderMode.metadata.limiter.execute = true; - } - constexpr uint32_t MODE_SPLIT = 0; - constexpr uint32_t MODE_CUBEMAP = 1; - constexpr uint32_t MODE_SEPARATE_2DS = 2; - // if point light, and combining is requested - if ( metadata.shadow.typeMap > MODE_SPLIT && renderMode.renderTarget.views == 6 ) { - int32_t index = -1; - // separated texture2Ds + + if ( metadata.shadow.typeMap > MODE_SPLIT && views == 6 ) { + // split cubemap (shouldn't actually get used) if ( metadata.shadow.typeMap == MODE_SEPARATE_2DS ) { UF_MSG_WARNING("deprecated feature used: separate Texture2Ds for shadow maps"); - index = storage.shadow2Ds.size(); + boundIndexMap = storage.shadow2Ds.size(); + boundTypeMap = MODE_SEPARATE_2DS; for ( auto& attachment : renderMode.renderTarget.attachments ) { - if ( !(attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ) continue; - for ( size_t view = 0; view < renderMode.renderTarget.views; ++view ) { + if (!(attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) continue; + for ( size_t view = 0; view < views; ++view ) { storage.shadow2Ds.emplace_back().aliasAttachment(attachment, view); } break; } - // cubemapped + // cubemap } else if ( metadata.shadow.typeMap == MODE_CUBEMAP ) { - index = storage.shadowCubes.size(); + boundIndexMap = storage.shadowCubes.size(); + boundTypeMap = MODE_CUBEMAP; for ( auto& attachment : renderMode.renderTarget.attachments ) { - if ( !(attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ) continue; + if (!(attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) continue; storage.shadowCubes.emplace_back().aliasAttachment(attachment); break; } } + } else { + // separate 2D maps + boundIndexMap = storage.shadow2Ds.size(); + for ( auto& attachment : renderMode.renderTarget.attachments ) { + if ( !(attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) continue; + if (attachment.descriptor.layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) continue; + for (size_t view = 0; view < views; ++view) { + storage.shadow2Ds.emplace_back().aliasAttachment(attachment, view); + } + } + } + } + + if ( storage.lights.size() < metadata.light.max ) { + auto& lightCamera = entity->getComponent(); + + if ( !info.shadows ) boundIndexMap = -1; + + if ( boundTypeMap > MODE_SPLIT && views == 6 ) { storage.lights.emplace_back(pod::Light{ .view = lightCamera.getView(0), .projection = lightCamera.getProjection(0), @@ -654,30 +685,26 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) { .color = info.color, .intensity = info.intensity, .type = info.type, - .typeMap = metadata.shadow.typeMap, - .indexMap = index, + .typeMap = boundTypeMap, + .indexMap = boundIndexMap, .depthBias = info.bias, }); - // any other shadowing light, even point lights, are split by shadow maps } else { - for ( auto& attachment : renderMode.renderTarget.attachments ) { - if ( !(attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ) continue; - if ( attachment.descriptor.layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR ) continue; - for ( size_t view = 0; view < renderMode.renderTarget.views; ++view ) { - storage.lights.emplace_back(pod::Light{ - .view = lightCamera.getView(view), - .projection = lightCamera.getProjection(view), - .position = info.position, - .range = info.range, - .color = info.color, - .intensity = info.intensity, - .type = info.type, - .typeMap = 0, - .indexMap = storage.shadow2Ds.size(), - .depthBias = info.bias, - }); - storage.shadow2Ds.emplace_back().aliasAttachment(attachment, view); - } + for ( size_t view = 0; view < views; ++view ) { + if ( storage.lights.size() >= metadata.light.max ) break; + + storage.lights.emplace_back(pod::Light{ + .view = hasRT ? lightCamera.getView(view) : uf::matrix::identity(), + .projection = hasRT ? lightCamera.getProjection(view) : uf::matrix::identity(), + .position = info.position, + .range = info.range, + .color = info.color, + .intensity = info.intensity, + .type = info.type, + .typeMap = 0, + .indexMap = info.shadows ? (boundIndexMap == -1 ? -1 : boundIndexMap + view) : -1, + .depthBias = info.bias, + }); } } } @@ -1248,9 +1275,9 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, uf::renderer::Graphic } if ( shouldUpdate ) { // graphic.updatePipelines(); - graphic.update(); + // graphic.update(); renderMode.rebuild = true; - metadata.shader.invalidated = false; + // metadata.shader.invalidated = false; } if ( !graphic.material.hasShader(shaderType, shaderPipeline) ) { diff --git a/engine/src/engine/ext/voxelizer/behavior.cpp b/engine/src/engine/ext/voxelizer/behavior.cpp index 9c69be15..b7de94d6 100644 --- a/engine/src/engine/ext/voxelizer/behavior.cpp +++ b/engine/src/engine/ext/voxelizer/behavior.cpp @@ -235,11 +235,7 @@ void ext::VoxelizerSceneBehavior::initialize( uf::Object& self ) { if ( blitter.initialized ) { auto descriptor = blitter.descriptor; //descriptor.pipeline = "lighting"; - - auto& pipeline = blitter.getPipeline( descriptor ); - auto& descriptorSet = blitter.getDescriptorSet( descriptor ); - pipeline.record( blitter, commandBuffer ); - descriptorSet.record( blitter, commandBuffer ); + blitter.record( commandBuffer, descriptor ); } // generate mipmaps @@ -266,10 +262,7 @@ void ext::VoxelizerSceneBehavior::initialize( uf::Object& self ) { auto descriptor = blitter.descriptor; descriptor.pipeline = "mipmap"; - auto& pipeline = blitter.getPipeline( descriptor ); - auto& descriptorSet = blitter.getDescriptorSet( descriptor ); - pipeline.record( blitter, commandBuffer ); - descriptorSet.record( blitter, commandBuffer ); + blitter.record( commandBuffer, descriptor ); } } #else diff --git a/engine/src/engine/graph/graph.cpp b/engine/src/engine/graph/graph.cpp index 09e9849f..2987afb7 100644 --- a/engine/src/engine/graph/graph.cpp +++ b/engine/src/engine/graph/graph.cpp @@ -1961,7 +1961,7 @@ void uf::graph::reload( pod::Graph& graph, pod::Node& node ) { // necessary for OpenGL because recorded descriptors have invalidated pointers // Vulkan doesn't care about the CPU-side mesh data -#if UF_USE_OPENGL +#if 1 || UF_USE_OPENGL uf::renderer::states::rebuild = true; #endif diff --git a/engine/src/ext/gltf/gltf.cpp b/engine/src/ext/gltf/gltf.cpp index eb1b8345..2ba29659 100644 --- a/engine/src/ext/gltf/gltf.cpp +++ b/engine/src/ext/gltf/gltf.cpp @@ -553,10 +553,12 @@ void ext::gltf::load( pod::Graph& graph, const uf::stl::string& filename, const auto& mesh = storage.meshes[keyName]; auto& primitives = storage.primitives[keyName]; - - UF_MSG_DEBUG("Optimizing mesh at level {}: {}", level, keyName); - if ( !ext::meshopt::optimize( mesh, simplify, level, print ) ) { - UF_MSG_ERROR("Mesh optimization failed: {}", keyName ); + + if ( level ) { + UF_MSG_DEBUG("Optimizing mesh at level {}: {}", level, keyName); + if ( !ext::meshopt::optimize( mesh, simplify, level, print ) ) { + UF_MSG_ERROR("Mesh optimization failed: {}", keyName ); + } } if ( lods ) { auto factors = ext::meshopt::computeLODs( mesh.index.count ); diff --git a/engine/src/ext/meshopt/meshopt.cpp b/engine/src/ext/meshopt/meshopt.cpp index 15ed8e1f..1663e64e 100644 --- a/engine/src/ext/meshopt/meshopt.cpp +++ b/engine/src/ext/meshopt/meshopt.cpp @@ -23,6 +23,9 @@ namespace { } bool ext::meshopt::optimize( uf::Mesh& mesh, float simplify, size_t o, bool verbose ) { + if ( o == 0 ) { + return false; // true, since theres no error technically? + } if ( mesh.isInterleaved() ) { UF_MSG_ERROR("Optimization of interleaved meshes is currently not supported."); return false; diff --git a/engine/src/ext/vulkan/buffer.cpp b/engine/src/ext/vulkan/buffer.cpp index a07e6e7d..a90eb4c1 100644 --- a/engine/src/ext/vulkan/buffer.cpp +++ b/engine/src/ext/vulkan/buffer.cpp @@ -21,6 +21,8 @@ void ext::vulkan::Buffer::swap( ext::vulkan::Buffer& buffer ) { std::swap(this->memoryProperties, buffer.memoryProperties); std::swap(this->allocation, buffer.allocation); std::swap(this->allocationInfo, buffer.allocationInfo); + std::swap(this->count, buffer.count); + std::swap(this->written, buffer.written); } ext::vulkan::Buffer ext::vulkan::Buffer::alias() const { ext::vulkan::Buffer buffer; @@ -40,6 +42,8 @@ void ext::vulkan::Buffer::aliasBuffer( const ext::vulkan::Buffer& buffer ) { this->memoryProperties = buffer.memoryProperties; this->allocation = buffer.allocation; this->allocationInfo = buffer.allocationInfo; + this->count = buffer.count; + this->written = buffer.written; } void* ext::vulkan::Buffer::map( VkDeviceSize size, VkDeviceSize offset ) { @@ -116,10 +120,12 @@ void ext::vulkan::Buffer::destroy(bool defer) { // this->memoryProperties = {}; this->allocation = {}; this->allocationInfo = {}; + this->count = 1; + this->written = false; } -void ext::vulkan::Buffer::initialize( const void* data, VkDeviceSize length, VkBufferUsageFlags usage, VkMemoryPropertyFlags memoryProperties, bool stage ) { +void ext::vulkan::Buffer::initialize( const void* data, VkDeviceSize length, VkBufferUsageFlags usage, VkMemoryPropertyFlags memoryProperties ) { if ( !device ) device = &ext::vulkan::device; - if ( stage ) usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; // implicitly set properties + if ( VK_DEFAULT_STAGE_BUFFERS ) usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; // implicitly set properties // assume all UBOs are dynamic auto totalLength = length; @@ -130,56 +136,16 @@ void ext::vulkan::Buffer::initialize( const void* data, VkDeviceSize length, VkB totalLength = ALIGNED_SIZE( length, this->alignment ) * this->count; } #endif + VK_CHECK_RESULT(device->createBuffer( nullptr, totalLength, usage, memoryProperties, *this )); - VK_CHECK_RESULT(device->createBuffer( - nullptr, - totalLength, - usage, - memoryProperties, - *this - )); - - if ( length != totalLength ) { - this->updateDescriptor( length, 0 ); - } - - if ( data && length ) update( data, length, stage ); - -/* - { - uf::stl::string type; - - if ( usage & VK_BUFFER_USAGE_TRANSFER_SRC_BIT ) type += "transfer_src,"; - if ( usage & VK_BUFFER_USAGE_TRANSFER_DST_BIT ) type += "transfer_dst,"; - if ( usage & VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT ) type += "uniform_texel,"; - if ( usage & VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT ) type += "storage_texel,"; - if ( usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ) type += "uniform,"; - if ( usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT ) type += "storage,"; - if ( usage & VK_BUFFER_USAGE_INDEX_BUFFER_BIT ) type += "index,"; - if ( usage & VK_BUFFER_USAGE_VERTEX_BUFFER_BIT ) type += "vertex,"; - if ( usage & VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT ) type += "indirect,"; - if ( usage & VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR ) type += "acceleration_structure,"; - if ( usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT ) type += "address,"; - if ( usage & VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR ) type += "binding_table,"; - - UF_MSG_DEBUG("CREATING BUFFER: {}: {}({})", fmt::ptr(this->buffer), type, usage); - } -*/ - - this->usage = usage; + if ( length != totalLength ) this->updateDescriptor( length, 0 ); + if ( data && length ) update( data, length ); } -bool ext::vulkan::Buffer::update( const void* data, VkDeviceSize length, bool stage ) const { +bool ext::vulkan::Buffer::update( const void* data, VkDeviceSize length ) const { // if ( !data || !length ) return false; if ( !length ) return false; if ( !buffer ) return false; - VkDeviceSize offset = 0; -#if VK_UBO_USE_N_BUFFERS - if ( this->count == ext::vulkan::swapchain.buffers ) { - offset = this->getOffset( states::currentBuffer ); - } -#endif - // to-do: fix this because it's a thorn in my side when a mesh needs to update if ( length > allocationInfo.size ) { UF_MSG_WARNING("Buffer update of {} exceeds buffer size of {}", length, allocationInfo.size); @@ -192,15 +158,40 @@ bool ext::vulkan::Buffer::update( const void* data, VkDeviceSize length, bool st self.destroy(true); self.initialize(*device, savedAlignment); - self.initialize(data, length, savedUsage, savedMemProps, stage); + self.initialize(data, length, savedUsage, savedMemProps); return true; } if ( !data ) return false; - if ( !stage ) { + + bool broadcast = !this->written; + this->written = true; + + STATIC_THREAD_LOCAL(uf::stl::vector, regions); + + if ( broadcast && this->count > 1 ) { + for ( size_t i = 0; i < this->count; i++ ) { + auto& region = regions.emplace_back(); + region.size = length; + region.srcOffset = 0; + region.dstOffset = this->getOffset( i ); + } + } else { + auto& region = regions.emplace_back(); + region.size = length; + region.srcOffset = 0; + region.dstOffset = 0; + #if VK_UBO_USE_N_BUFFERS + if ( this->count == ext::vulkan::swapchain.buffers ) { + region.dstOffset = this->getOffset( states::currentBuffer ); + } + #endif + } + + if ( !VK_DEFAULT_STAGE_BUFFERS ) { auto* self = const_cast(this); - void* map = self->map(length, offset); - memcpy(map, data, length); + void* map = self->map(length); + for ( const auto& region : regions ) memcpy(static_cast(map) + region.dstOffset, data, length); self->unmap(); return false; } @@ -208,18 +199,12 @@ bool ext::vulkan::Buffer::update( const void* data, VkDeviceSize length, bool st ext::vulkan::Device* device = this->device ? this->device : &ext::vulkan::device; Buffer staging = device->fetchTransientBuffer( -// Buffer staging = device->createBuffer( - data, - length, - VK_BUFFER_USAGE_TRANSFER_SRC_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT + data, length, + VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ); auto commandBuffer = device->fetchCommandBuffer(QueueEnum::TRANSFER); // waits on finish - VkBufferCopy region = {}; - region.size = length; - region.dstOffset = offset; device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "copyBuffer" ); - vkCmdCopyBuffer(commandBuffer, staging.buffer, buffer, 1, ®ion); + vkCmdCopyBuffer(commandBuffer, staging.buffer, buffer, regions.size(), regions.data()); device->flushCommandBuffer(commandBuffer); return false; } @@ -240,14 +225,14 @@ void ext::vulkan::Buffers::destroy(bool defer) { buffers.clear(); } -size_t ext::vulkan::Buffers::initializeBuffer( const void* data, VkDeviceSize length, VkBufferUsageFlags usage, VkMemoryPropertyFlags memoryProperties, bool stage ) { +size_t ext::vulkan::Buffers::initializeBuffer( const void* data, VkDeviceSize length, VkBufferUsageFlags usage, VkMemoryPropertyFlags memoryProperties ) { size_t index = buffers.size(); auto& buffer = buffers.emplace_back(); buffer.initialize( *device, requestedAlignment ); - buffer.initialize( data, length, usage, memoryProperties, stage ); + buffer.initialize( data, length, usage, memoryProperties ); return index; } -bool ext::vulkan::Buffers::updateBuffer( const void* data, VkDeviceSize length, const Buffer& buffer, bool stage ) const { - return buffer.update( data, length, stage ); +bool ext::vulkan::Buffers::updateBuffer( const void* data, VkDeviceSize length, const Buffer& buffer ) const { + return buffer.update( data, length ); } #endif \ No newline at end of file diff --git a/engine/src/ext/vulkan/device.cpp b/engine/src/ext/vulkan/device.cpp index 010ce2f9..8a1f7403 100644 --- a/engine/src/ext/vulkan/device.cpp +++ b/engine/src/ext/vulkan/device.cpp @@ -609,7 +609,7 @@ uint32_t ext::vulkan::Device::getMemoryType( uint32_t typeBits, VkMemoryProperty UF_EXCEPTION("Vulkan error: could not find a matching memory type"); } -VkCommandBuffer ext::vulkan::Device::createCommandBuffer( VkCommandBufferLevel level, QueueEnum queue, bool begin ){ +VkCommandBuffer ext::vulkan::Device::createCommandBuffer( VkCommandBufferLevel level, QueueEnum queue, bool begin, bool singleton ){ VkCommandBufferAllocateInfo cmdBufAllocateInfo = ext::vulkan::initializers::commandBufferAllocateInfo( getCommandPool(queue), level, 1 ); VkCommandBuffer commandBuffer; @@ -617,6 +617,8 @@ VkCommandBuffer ext::vulkan::Device::createCommandBuffer( VkCommandBufferLevel l // If requested, also start recording for the new command buffer if ( begin ) { VkCommandBufferBeginInfo cmdBufInfo = ext::vulkan::initializers::commandBufferBeginInfo(); + if ( singleton ) cmdBufInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + VK_CHECK_RESULT( vkBeginCommandBuffer( commandBuffer, &cmdBufInfo ) ); UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::BEGIN, "begin" ); } @@ -674,7 +676,7 @@ ext::vulkan::CommandBuffer ext::vulkan::Device::fetchCommandBuffer( ext::vulkan: return { .immediate = immediate, .queueType = queueType, - .handle = this->createCommandBuffer( level, queueType, true ), + .handle = this->createCommandBuffer( level, queueType, true, true ), .threadId = std::this_thread::get_id(), }; } @@ -1346,6 +1348,7 @@ void ext::vulkan::Device::initialize() { accelerationStructureFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR; accelerationStructureFeatures.accelerationStructure = VK_TRUE; // accelerationStructureFeatures.accelerationStructureHostCommands = VK_TRUE; + accelerationStructureFeatures.descriptorBindingAccelerationStructureUpdateAfterBind = VK_TRUE; chain.push( &accelerationStructureFeatures ); VK_VALIDATION_MESSAGE("Enabled feature chain: {}", "accelerationStructureFeatures" ); } @@ -1698,7 +1701,7 @@ void ext::vulkan::DescriptorAllocator::destroy() { VkDescriptorPool ext::vulkan::DescriptorAllocator::createPool() { VkDescriptorPoolCreateInfo poolInfo = {}; poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - poolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; + poolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT | VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT; poolInfo.maxSets = 1000; poolInfo.poolSizeCount = (uint32_t) poolSizes.size(); poolInfo.pPoolSizes = poolSizes.data(); diff --git a/engine/src/ext/vulkan/graphic.cpp b/engine/src/ext/vulkan/graphic.cpp index 459aed1d..543fd574 100644 --- a/engine/src/ext/vulkan/graphic.cpp +++ b/engine/src/ext/vulkan/graphic.cpp @@ -48,8 +48,6 @@ void ext::vulkan::Pipeline::initialize( const Graphic& graphic, const GraphicDes auto shaders = graphic.material.getShaders( descriptor.pipeline ); assert( shaders.size() > 0 ); - - uint32_t subpass = descriptor.subpass; uf::stl::vector descriptorSetLayoutBindings; uf::stl::vector pushConstantRanges; @@ -61,22 +59,41 @@ void ext::vulkan::Pipeline::initialize( const Graphic& graphic, const GraphicDes uf::stl::vector shaderSpecializationInfos; uf::stl::vector inputBindingDescriptions; uf::stl::vector attributeDescriptions; - { - for ( auto* shaderPointer : shaders ) { - auto& shader = *shaderPointer; - descriptorSetLayoutBindings.insert( descriptorSetLayoutBindings.end(), shader.descriptorSetLayoutBindings.begin(), shader.descriptorSetLayoutBindings.end() ); + { + uf::stl::vector bindingFlags; + + bool hasDynamicBuffer = false; + for ( auto* shader : shaders ) { + for ( auto& binding : shader->descriptorSetLayoutBindings ) { + switch ( binding.descriptorType ) { + case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: + case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: + hasDynamicBuffer = true; + break; + } + } + } + + for ( auto* shader : shaders ) { + for ( auto& binding : shader->descriptorSetLayoutBindings ) { + descriptorSetLayoutBindings.emplace_back( binding ); + auto& flags = bindingFlags.emplace_back(); + + flags |= VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT; + if ( !hasDynamicBuffer ) flags |= VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT; + } size_t offset = 0; - for ( auto& pushConstant : shader.pushConstants ) { + for ( auto& pushConstant : shader->pushConstants ) { size_t len = pushConstant.data().len; if ( len <= 0 || len > device.properties.limits.maxPushConstantsSize ) { - VK_DEBUG_VALIDATION_MESSAGE("Invalid push constant length of {} for shader {}", len, shader.filename); + VK_DEBUG_VALIDATION_MESSAGE("Invalid push constant length of {} for shader {}", len, shader->filename); // goto PIPELINE_INITIALIZATION_INVALID; len = device.properties.limits.maxPushConstantsSize; } pushConstantRanges.emplace_back(ext::vulkan::initializers::pushConstantRange( - shader.descriptor.stage, + shader->descriptor.stage, len, offset )); @@ -84,10 +101,19 @@ void ext::vulkan::Pipeline::initialize( const Graphic& graphic, const GraphicDes } } + VkDescriptorSetLayoutBindingFlagsCreateInfo layoutBindingFlags = {}; + layoutBindingFlags.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO; + layoutBindingFlags.bindingCount = bindingFlags.size(); + layoutBindingFlags.pBindingFlags = bindingFlags.data(); + VkDescriptorSetLayoutCreateInfo descriptorLayout = ext::vulkan::initializers::descriptorSetLayoutCreateInfo( descriptorSetLayoutBindings.data(), descriptorSetLayoutBindings.size() ); + + descriptorLayout.flags |= VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT; + descriptorLayout.pNext = &layoutBindingFlags; + VK_CHECK_RESULT(vkCreateDescriptorSetLayout( device, &descriptorLayout, nullptr, &descriptorSetLayout )); VK_REGISTER_HANDLE( descriptorSetLayout ); @@ -189,16 +215,15 @@ void ext::vulkan::Pipeline::initialize( const Graphic& graphic, const GraphicDes } // Compute - for ( auto* shaderPointer : shaders ) { - auto& shader = *shaderPointer; - if ( shader.descriptor.stage != VK_SHADER_STAGE_COMPUTE_BIT ) continue; + for ( auto* shader : shaders ) { + if ( shader->descriptor.stage != VK_SHADER_STAGE_COMPUTE_BIT ) continue; // Create compute shader pipelines VkComputePipelineCreateInfo computePipelineCreateInfo = ext::vulkan::initializers::computePipelineCreateInfo( pipelineLayout, 0 ); - computePipelineCreateInfo.stage = shader.descriptor; + computePipelineCreateInfo.stage = shader->descriptor; VK_CHECK_RESULT(vkCreateComputePipelines(device, device.pipelineCache, 1, &computePipelineCreateInfo, nullptr, &pipeline)); VK_REGISTER_HANDLE( pipeline ); @@ -242,8 +267,6 @@ void ext::vulkan::Pipeline::initialize( const Graphic& graphic, const GraphicDes } } } else { - subpass = 0; - VkPipelineColorBlendAttachmentState blendAttachmentState = ext::vulkan::initializers::pipelineColorBlendAttachmentState( descriptor.blend.colorWriteMask, descriptor.blend.enabled ? VK_TRUE : VK_FALSE @@ -507,7 +530,9 @@ void ext::vulkan::DescriptorSet::record( const Graphic& graphic, const GraphicDe else continue; } + #if VK_UBO_USE_N_BUFFERS dynamicOffsets.insert( dynamicOffsets.end(), shader->metadata.dynamicRanges.begin(), shader->metadata.dynamicRanges.end() ); + #endif } for ( auto& dynamicOffset : dynamicOffsets ) { @@ -520,44 +545,7 @@ void ext::vulkan::DescriptorSet::record( const Graphic& graphic, const GraphicDe } // Bind descriptor sets describing shader binding points -#if VK_UBO_USE_N_BUFFERS vkCmdBindDescriptorSets(commandBuffer, (VkPipelineBindPoint) descriptor.bind.point, pipeline.pipelineLayout, 0, 1, &descriptorSet, dynamicOffsets.size(), dynamicOffsets.data()); -#else - vkCmdBindDescriptorSets(commandBuffer, (VkPipelineBindPoint) descriptor.bind.point, pipeline.pipelineLayout, 0, 1, &descriptorSet, 0, nullptr); -#endif - - uint32_t width = descriptor.bind.width ? descriptor.bind.width : ext::vulkan::settings::width; - uint32_t height = descriptor.bind.height ? descriptor.bind.height : ext::vulkan::settings::height; - uint32_t depth = descriptor.bind.depth ? descriptor.bind.depth : 1; - - if ( descriptor.bind.point == VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR ) { - uf::renderer::vkCmdTraceRaysKHR( - commandBuffer, - &pipeline.sbtEntries[0], - &pipeline.sbtEntries[1], - &pipeline.sbtEntries[2], - &pipeline.sbtEntries[3], - width, - height, - 1 - ); - } else if ( descriptor.bind.point == VK_PIPELINE_BIND_POINT_COMPUTE ) { - for ( auto* shader : shaders ) { - if ( shader->descriptor.stage != VK_SHADER_STAGE_COMPUTE_BIT ) continue; - auto& localSize = shader->metadata.definitions.localSize; - auto dispatch = pod::Vector3ui{ - std::ceil( (float) width / localSize.x ), - std::ceil( (float) height / localSize.y ), - std::ceil( (float) depth / localSize.z ), - }; - - vkCmdDispatch(commandBuffer, - dispatch.x, - dispatch.y, - dispatch.z - ); - } - } } void ext::vulkan::DescriptorSet::update( const Graphic& graphic ) { return this->update( graphic, descriptor ); @@ -1637,24 +1625,32 @@ void ext::vulkan::Graphic::generateTopAccelerationStructure( const uf::stl::vect size_t tlasBufferIndex{}; size_t tlasBackBufferIndex{}; + // do not stage, because apparently vkQueueWaitIdle doesn't actually wait for the transfer to complete + // manually copy because I can't be assed to expose an un-staged API now if ( !update ) { - // do not stage, because apparently vkQueueWaitIdle doesn't actually wait for the transfer to complete - this->requestedAlignment = 16; - instanceIndex = this->initializeBuffer( + instanceIndex = this->buffers.size(); + auto& buffer = this->buffers.emplace_back(); + buffer.alignment = 16; + device.createBuffer( (const void*) instancesVK.data(), instancesVK.size() * sizeof(VkAccelerationStructureInstanceKHR), - VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR, false + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + buffer ); - this->requestedAlignment = 0; this->metadata.buffers["tlasInstance"] = instanceIndex; } else { if ( this->metadata.buffers.count("tlasInstance") > 0 ) { instanceIndex = this->metadata.buffers["tlasInstance"]; } else UF_EXCEPTION("Buffers not found: {}", "tlasInstance"); - /*rebuild = rebuild ||*/ this->updateBuffer( (const void*) instancesVK.data(), instancesVK.size() * sizeof(VkAccelerationStructureInstanceKHR), instanceIndex, false ); + + auto& buffer = this->buffers.at(instanceIndex); + void* map = buffer.map(); + memcpy(map, instancesVK.data(), instancesVK.size() * sizeof(VkAccelerationStructureInstanceKHR)); + buffer.unmap(); } size_t instanceBufferAddress = this->buffers[instanceIndex].getAddress(); - auto& tlas = this->accelerationStructures.tops[0]; + auto& tlas = this->accelerationStructures.tops[0]; { VkBuildAccelerationStructureFlagsKHR flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR | VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR; @@ -1930,6 +1926,42 @@ void ext::vulkan::Graphic::record( VkCommandBuffer commandBuffer, const GraphicD descriptorSet.record( *this, descriptor, commandBuffer, pass, draw, offset ); auto shaders = material.getShaders( descriptor.pipeline ); + + uint32_t width = descriptor.bind.width ? descriptor.bind.width : ext::vulkan::settings::width; + uint32_t height = descriptor.bind.height ? descriptor.bind.height : ext::vulkan::settings::height; + uint32_t depth = descriptor.bind.depth ? descriptor.bind.depth : 1; + + if ( descriptor.bind.point == VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR ) { + uf::renderer::vkCmdTraceRaysKHR( + commandBuffer, + &pipeline.sbtEntries[0], + &pipeline.sbtEntries[1], + &pipeline.sbtEntries[2], + &pipeline.sbtEntries[3], + width, + height, + 1 + ); + return; + } + if ( descriptor.bind.point == VK_PIPELINE_BIND_POINT_COMPUTE ) { + for ( auto* shader : shaders ) { + if ( shader->descriptor.stage != VK_SHADER_STAGE_COMPUTE_BIT ) continue; + auto& localSize = shader->metadata.definitions.localSize; + auto dispatch = pod::Vector3ui{ + std::ceil( (float) width / localSize.x ), + std::ceil( (float) height / localSize.y ), + std::ceil( (float) depth / localSize.z ), + }; + + vkCmdDispatch(commandBuffer, + dispatch.x, + dispatch.y, + dispatch.z + ); + } + return; + } for ( auto* shader : shaders ) { if ( shader->descriptor.stage == VK_SHADER_STAGE_COMPUTE_BIT ) return; if ( diff --git a/engine/src/ext/vulkan/rendermodes/base.cpp b/engine/src/ext/vulkan/rendermodes/base.cpp index afc6cfa4..f88d1418 100644 --- a/engine/src/ext/vulkan/rendermodes/base.cpp +++ b/engine/src/ext/vulkan/rendermodes/base.cpp @@ -118,10 +118,10 @@ void ext::vulkan::BaseRenderMode::render() { //lockMutex( this->mostRecentCommandPoolId ); auto& commands = getCommands( this->mostRecentCommandPoolId ); - - VK_CHECK_RESULT(swapchain.acquireNextImage(&states::currentBuffer, swapchain.presentCompleteSemaphores[0])); - + uint32_t imageIndex; + VK_CHECK_RESULT(vkWaitForFences(*device, 1, &fences[states::currentBuffer], VK_TRUE, VK_DEFAULT_FENCE_TIMEOUT)); + VK_CHECK_RESULT(swapchain.acquireNextImage(&imageIndex, swapchain.presentCompleteSemaphores[states::currentBuffer])); VK_CHECK_RESULT(vkResetFences(*device, 1, &fences[states::currentBuffer])); VkPipelineStageFlags waitStageMask[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT}; @@ -129,7 +129,7 @@ void ext::vulkan::BaseRenderMode::render() { VkSubmitInfo submitInfo = {}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.pWaitDstStageMask = waitStageMask; - submitInfo.pWaitSemaphores = &swapchain.presentCompleteSemaphores[0]; + submitInfo.pWaitSemaphores = &swapchain.presentCompleteSemaphores[states::currentBuffer]; submitInfo.waitSemaphoreCount = 1; submitInfo.pSignalSemaphores = &renderCompleteSemaphores[states::currentBuffer]; submitInfo.signalSemaphoreCount = 1; @@ -142,8 +142,7 @@ void ext::vulkan::BaseRenderMode::render() { VK_CHECK_QUEUE_CHECKPOINT( queue, res ); } - VK_CHECK_RESULT(swapchain.queuePresent(device->getQueue( QueueEnum::PRESENT ), states::currentBuffer, renderCompleteSemaphores[states::currentBuffer])); - + VK_CHECK_RESULT(swapchain.queuePresent(device->getQueue( QueueEnum::PRESENT ), imageIndex, renderCompleteSemaphores[states::currentBuffer])); #if 0 { VkQueue queue = device->getQueue( QueueEnum::PRESENT ); @@ -152,6 +151,7 @@ void ext::vulkan::BaseRenderMode::render() { } #endif + states::currentBuffer = (states::currentBuffer + 1) % ext::vulkan::swapchain.buffers; this->executed = true; //unlockMutex( this->mostRecentCommandPoolId ); @@ -183,9 +183,8 @@ void ext::vulkan::BaseRenderMode::createCommandBuffers( const uf::stl::vectorwidth > 0 ? this->width : windowSize.x; float height = windowSize.y; //this->height > 0 ? this->height : windowSize.y; - VkCommandBufferBeginInfo cmdBufInfo = {}; - cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - cmdBufInfo.pNext = nullptr; + VkCommandBufferBeginInfo cmdBufInfo = ext::vulkan::initializers::commandBufferBeginInfo(); + cmdBufInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; VkImageMemoryBarrier imageMemoryBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // ext::vulkan::device.queueFamilyIndices.graphics; //VK_QUEUE_FAMILY_IGNORED diff --git a/engine/src/ext/vulkan/rendermodes/deferred.cpp b/engine/src/ext/vulkan/rendermodes/deferred.cpp index 8319d34e..b37d40e6 100644 --- a/engine/src/ext/vulkan/rendermodes/deferred.cpp +++ b/engine/src/ext/vulkan/rendermodes/deferred.cpp @@ -695,9 +695,8 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto uint32_t width = this->width > 0 ? this->width : (ext::vulkan::settings::width * this->scale); uint32_t height = this->height > 0 ? this->height : (ext::vulkan::settings::height * this->scale); - VkCommandBufferBeginInfo cmdBufInfo = {}; - cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - cmdBufInfo.pNext = nullptr; + VkCommandBufferBeginInfo cmdBufInfo = ext::vulkan::initializers::commandBufferBeginInfo(); + cmdBufInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; VkImageMemoryBarrier imageMemoryBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // ext::vulkan::device.queueFamilyIndices.graphics; //VK_QUEUE_FAMILY_IGNORED diff --git a/engine/src/ext/vulkan/rendermodes/rendertarget.cpp b/engine/src/ext/vulkan/rendermodes/rendertarget.cpp index 66cc533e..6eb60b53 100644 --- a/engine/src/ext/vulkan/rendermodes/rendertarget.cpp +++ b/engine/src/ext/vulkan/rendermodes/rendertarget.cpp @@ -312,9 +312,8 @@ void ext::vulkan::RenderTargetRenderMode::createCommandBuffers( const uf::stl::v uint32_t width = this->width > 0 ? this->width : (ext::vulkan::settings::width * this->scale); uint32_t height = this->height > 0 ? this->height : (ext::vulkan::settings::height * this->scale); - VkCommandBufferBeginInfo cmdBufInfo = {}; - cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - cmdBufInfo.pNext = nullptr; + VkCommandBufferBeginInfo cmdBufInfo = ext::vulkan::initializers::commandBufferBeginInfo(); + cmdBufInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; auto& scene = uf::scene::getCurrentScene(); auto& sceneMetadataJson = scene.getComponent();