From dcdd0845633ab53463a7ef4716e6674cfb62c8da Mon Sep 17 00:00:00 2001 From: MatejSakmary Date: Sat, 28 Oct 2023 00:24:39 +0200 Subject: [PATCH 01/18] Modified graphics pipeline so that it can now be created with dynamic rendering --- README.md | 2 +- include/avk/attachment.hpp | 33 ++++ include/avk/avk.hpp | 37 +++-- include/avk/graphics_pipeline.hpp | 28 +++- include/avk/graphics_pipeline_config.hpp | 32 +++- src/avk.cpp | 187 +++++++++++++++++++---- 6 files changed, 272 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index 88d6acf..0a35544 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ avk::framebuffer framebuffer = myRoot.create_framebuffer(...); avk::semaphore imageAvailableSemaphore = ...; mRoot.record({ - avk::command::render_pass(graphicsPipeline->renderpass_reference(), framebuffer.as_reference(), { + avk::command::render_pass(*graphicsPipeline->renderpass_pointer().value(), framebuffer.as_reference(), { avk::command::bind_pipeline(graphicsPipeline.as_reference()), avk::command::draw(3u, 1u, 0u, 0u) }) diff --git a/include/avk/attachment.hpp b/include/avk/attachment.hpp index c3565b9..74fbf93 100644 --- a/include/avk/attachment.hpp +++ b/include/avk/attachment.hpp @@ -3,6 +3,39 @@ namespace avk { + + /** Describes a dynamic rendering attachment. It can only be used with pipeline that has dynamic rendering enabled. + * It has fewever parameters than regular attachment since some of its values (load/store ops etc...) are set + * when starting the dynamic render pass as opposed to being declared beforehand. + * It can describe color attachments as well as depth/stencil attachments + * and holds some additional config parameters for these attachments. + */ + struct dynamic_rendering_attachment + { + /** Declare multisampled format of an attachment for a dynamic rendering pipeline + * @param aFormatAndSamples Multisampled format definition: A tuple with the format of the attachment in its first element, and with the number of samples in its second element. + */ + static dynamic_rendering_attachment declare(std::tuple aFormatAndSamples); + /** Declare format of an attachment for a dynamic rendering pipeline + * @param aFormat The format of the attachment + */ + static dynamic_rendering_attachment declare(vk::Format aFormat); + + /** Declare format of an attachment for a dynamic rendering pipeline + * @param aImageView The format of the attachment is copied from the given image view. + */ + static dynamic_rendering_attachment declare_for(const image_view_t& aImageView); + + /** The color/depth/stencil format of the attachment */ + auto format() const { return mFormat; } + /** True if the sample count is greater than 1 */ + bool is_multisampled() const { return mSampleCount != vk::SampleCountFlagBits::e1; } + /** The sample count for this attachment. */ + auto sample_count() const { return mSampleCount; } + + vk::Format mFormat; + vk::SampleCountFlagBits mSampleCount; + }; /** Describes an attachment to a framebuffer or a renderpass. * It can describe color attachments as well as depth/stencil attachments * and holds some additional config parameters for these attachments. diff --git a/include/avk/avk.hpp b/include/avk/avk.hpp index 72f3915..2300aca 100644 --- a/include/avk/avk.hpp +++ b/include/avk/avk.hpp @@ -711,11 +711,12 @@ namespace avk * @param aAlterConfigBeforeCreation Optional custom callback function which can be used to alter the new pipeline's config right before it is being created on the device. * @return A new graphics pipeline instance. */ - graphics_pipeline create_graphics_pipeline_from_template(const graphics_pipeline_t& aTemplate, renderpass aNewRenderpass, std::optional aSubpassIndex = {}, std::function aAlterConfigBeforeCreation = {}); + graphics_pipeline create_graphics_pipeline_from_template(const graphics_pipeline_t& aTemplate, std::optional aNewRenderpass, std::optional aSubpassIndex = {}, std::function aAlterConfigBeforeCreation = {}); - /** Creates a graphics pipeline based on another graphics pipeline, which serves as a template, - * which either uses the same renderpass (if it has shared ownership enabled) or creates a new - * renderpass internally using create_renderpass_from_template with the template's renderpass. + /** Creates a graphics pipeline based on another graphics pipeline, which serves as a template, which either: + * - uses the same renderpass (if it has shared ownership enabled) + * - creates a new renderpass internally using create_renderpass_from_template with the template's renderpass + * - uses dynamic rendering and thus does not need to create new renderpass * @param aTemplate Another, already existing graphics pipeline, which serves as a template for the newly created graphics pipeline. * @param aAlterConfigBeforeCreation Optional custom callback function which can be used to alter the new pipeline's config right before it is being created on the device. * @return A new graphics pipeline instance. @@ -728,6 +729,7 @@ namespace avk * - cfg::pipeline_settings (flags) * - renderpass * - avk::attachment (use either attachments or renderpass!) + * - avk::dynamic_rendering_attachment (only use if dynamic_rendering::enabled) * - input_binding_location_data (vertex input) * - cfg::primitive_topology * - shader_info @@ -736,6 +738,7 @@ namespace avk * - cfg::depth_write * - cfg::viewport_depth_scissors_config * - cfg::culling_mode + * - cfg::dynamic_rendering * - cfg::front_face * - cfg::polygon_drawing * - cfg::rasterizer_geometry_mode @@ -760,15 +763,27 @@ namespace avk graphics_pipeline_config config; add_config(config, renderPassAttachments, alterConfigFunction, std::move(args)...); - // Check if render pass attachments are in renderPassAttachments XOR config => only in that case, it is clear how to proceed, fail in other cases - if (renderPassAttachments.size() > 0 == (config.mRenderPassSubpass.has_value() && static_cast(std::get(*config.mRenderPassSubpass)->handle()))) { - if (renderPassAttachments.size() == 0) { - throw avk::runtime_error("No renderpass config provided! Please provide a renderpass or attachments!"); - } - throw avk::runtime_error("Ambiguous renderpass config! Either set a renderpass XOR provide attachments!"); + const bool hasValidRenderPass = config.mRenderPassSubpass.has_value() && static_cast(std::get(*config.mRenderPassSubpass)->handle()); + const bool hasRenderPassAttachments = renderPassAttachments.size() > 0; + const bool isDynamicRenderingSet = config.mDynamicRendering == avk::cfg::dynamic_rendering::enabled; + // .has_value() should be enough since I don't fill in the optional unless there was dynamic_rendering_attachment provided + const bool hasDynamicRenderingAttachments = config.mDynamicRenderingAttachments.has_value(); + // Check all invalid configurations when dynamic rendering is set + if (isDynamicRenderingSet ) + { + if(hasValidRenderPass) { throw avk::runtime_error("Dynamic rendering does not accept renderpasses! They are set dynamically during rendering!"); } + if(hasRenderPassAttachments) { throw avk::runtime_error("Usage of avk::attachment is not allowed when dynamic rendering is enabled! Use avk::dynamic_rendering_attachment instead!"); } + if(!hasDynamicRenderingAttachments) { throw avk::runtime_error("Dynamic rendering enabled but no avk::dynamic_rendering_attachments provided! Please provide at least one attachment!"); } + } + // Check all invalid configurations when normal rendering (with renderpasses) is used + else + { + if(hasValidRenderPass && hasRenderPassAttachments) { throw avk::runtime_error("Ambiguous renderpass config! Either set a renderpass OR provide attachments but not both at the same time!"); } + if(!(hasValidRenderPass || hasRenderPassAttachments)) { throw avk::runtime_error("No renderpass config provided! Please provide a renderpass or attachments!"); } } + // ^ that was the sanity check. See if we have to build the renderpass from the attachments: - if (renderPassAttachments.size() > 0) { + if (hasRenderPassAttachments) { add_config(config, renderPassAttachments, alterConfigFunction, create_renderpass(std::move(renderPassAttachments))); } diff --git a/include/avk/graphics_pipeline.hpp b/include/avk/graphics_pipeline.hpp index e0a10e8..b7a7a7c 100644 --- a/include/avk/graphics_pipeline.hpp +++ b/include/avk/graphics_pipeline.hpp @@ -16,10 +16,25 @@ namespace avk graphics_pipeline_t& operator=(const graphics_pipeline_t&) = delete; ~graphics_pipeline_t() = default; - [[nodiscard]] avk::renderpass renderpass() const { return mRenderPass; } - [[nodiscard]] const avk::renderpass_t& renderpass_reference() const { return mRenderPass.get(); } - auto renderpass_handle() const { return mRenderPass->handle(); } - auto subpass_id() const { return mSubpassIndex; } + [[nodiscard]] auto renderpass() const { return mRenderPass; } + // TODO(msakmary) I can also keep the consistent naming aka renderpass_reference() return std::optional> I feel like this is way cleaner? + [[nodiscard]] auto renderpass_pointer() const -> std::optional + { + if(mRenderPass.has_value()) { return &(mRenderPass.value().get()); } + else { return std::nullopt; } + } + // TODO(msakmary) Perhaps I just return std::optional here? It would probably be more readable then declval + auto renderpass_handle() const -> std::optional().handle())> + { + if(mRenderPass.has_value()) {return mRenderPass.value()->handle();} + else {return std::nullopt;} + } + auto subpass_id() const -> std::optional + { + if(mRenderPass.has_value()) {return mSubpassIndex;} + // TODO(msakmary) change subpass index to int and make -1 invalid value or perhaps add on optional here? + else {return -1;} + }; auto& vertex_input_binding_descriptions() { return mOrderedVertexInputBindingDescriptions; } auto& vertex_input_attribute_descriptions() { return mVertexInputAttributeDescriptions; } auto& vertex_input_state_create_info() { return mPipelineVertexInputStateCreateInfo; } @@ -69,7 +84,7 @@ namespace avk const auto& handle() const { return mPipeline.get(); } private: - avk::renderpass mRenderPass; + std::optional mRenderPass; uint32_t mSubpassIndex; // The vertex input data: std::vector mOrderedVertexInputBindingDescriptions; @@ -85,6 +100,9 @@ namespace avk std::vector mViewports; std::vector mScissors; vk::PipelineViewportStateCreateInfo mViewportStateCreateInfo; + // Dynamic rendering state + std::vector mDynamicRenderingColorFormats; + std::optional mRenderingCreateInfo; // Rasterization state: vk::PipelineRasterizationStateCreateInfo mRasterizationStateCreateInfo; // Depth stencil config: diff --git a/include/avk/graphics_pipeline_config.hpp b/include/avk/graphics_pipeline_config.hpp index eaea507..94bb9dd 100644 --- a/include/avk/graphics_pipeline_config.hpp +++ b/include/avk/graphics_pipeline_config.hpp @@ -164,6 +164,13 @@ namespace avk bool mDynamicScissorEnabled; }; + /** Dyanmic rendering*/ + enum struct dynamic_rendering + { + disabled, + enabled + }; + /** Pipeline configuration data: Culling Mode */ enum struct culling_mode { @@ -608,6 +615,7 @@ namespace avk ~graphics_pipeline_config() = default; cfg::pipeline_settings mPipelineSettings; // TODO: Handle settings! + std::optional> mDynamicRenderingAttachments; std::optional> mRenderPassSubpass; std::vector mInputBindingLocations; cfg::primitive_topology mPrimitiveTopology; @@ -616,6 +624,7 @@ namespace avk cfg::rasterizer_geometry_mode mRasterizerGeometryMode; cfg::polygon_drawing mPolygonDrawingModeAndConfig; cfg::culling_mode mCullingMode; + cfg::dynamic_rendering mDynamicRendering; cfg::front_face mFrontFaceWindingOrder; cfg::depth_clamp_bias mDepthClampBiasConfig; cfg::depth_test mDepthTestConfig; @@ -672,7 +681,20 @@ namespace avk add_config(aConfig, aAttachments, aFunc, std::move(args)...); } - // Add a renderpass attachment to the (temporary) attachments vector and build renderpass afterwards + // Add a dynamic rendering attachment which are used when dynamic_rendering is enabled for this pipeline + template + void add_config(graphics_pipeline_config& aConfig, std::vector& aAttachments, std::function& aFunc, avk::dynamic_rendering_attachment aDynAttachment, Ts... args) + { + if(aConfig.mDynamicRenderingAttachments.has_value()) + { + aConfig.mDynamicRenderingAttachments.value().push_back(aDynAttachment); + } else { + aConfig.mDynamicRenderingAttachments = std::vector{aDynAttachment}; + } + add_config(aConfig, aAttachments, aFunc, std::move(args)...); + } + + // Add a renderpass attachment to the (temporary) attachments vector and later build renderpass from them template void add_config(graphics_pipeline_config& aConfig, std::vector& aAttachments, std::function& aFunc, avk::attachment aAttachment, Ts... args) { @@ -752,6 +774,14 @@ namespace avk add_config(aConfig, aAttachments, aFunc, std::move(args)...); } + // Set dynamic rendering + template + void add_config(graphics_pipeline_config& aConfig, std::vector& aAttachments, std::function& aFunc, cfg::dynamic_rendering aDynamicRendering, Ts... args) + { + aConfig.mDynamicRendering = aDynamicRendering; + add_config(aConfig, aAttachments, aFunc, std::move(args)...); + } + // Set the definition of front faces in the pipeline config template void add_config(graphics_pipeline_config& aConfig, std::vector& aAttachments, std::function& aFunc, cfg::front_face aFrontFace, Ts... args) diff --git a/src/avk.cpp b/src/avk.cpp index a25e7ec..9dd8c31 100644 --- a/src/avk.cpp +++ b/src/avk.cpp @@ -579,6 +579,17 @@ namespace avk return it != depthFormats.end(); } + bool is_stencil_format(const vk::Format& aImageFormat) + { + static std::set stencilFormats = { + vk::Format::eD16UnormS8Uint, + vk::Format::eD24UnormS8Uint, + vk::Format::eD32SfloatS8Uint, + }; + auto it = std::find(std::begin(stencilFormats), std::end(stencilFormats), aImageFormat); + return it != stencilFormats.end(); + } + bool is_1component_format(const vk::Format& aImageFormat) { static std::set singleCompFormats = { @@ -1403,6 +1414,28 @@ namespace avk #pragma endregion +#pragma region dynamic rendering attachment definitions + dynamic_rendering_attachment dynamic_rendering_attachment::declare(std::tuple aFormatAndSamples) + { + return dynamic_rendering_attachment{ + std::get(aFormatAndSamples), + std::get(aFormatAndSamples), + }; + } + + dynamic_rendering_attachment dynamic_rendering_attachment::declare(vk::Format aFormat) + { + return declare({aFormat, vk::SampleCountFlagBits::e1}); + } + + dynamic_rendering_attachment dynamic_rendering_attachment::declare_for(const image_view_t& aImageView) + { + const auto& imageConfig = aImageView.get_image().create_info(); + const auto format = imageConfig.format; + return declare(format); + } +#pragma endregion + #pragma region attachment definitions attachment attachment::declare(std::tuple aFormatAndSamples, attachment_load_config aLoadOp, subpass_usages aUsageInSubpasses, attachment_store_config aStoreOp) { @@ -4266,11 +4299,13 @@ namespace avk // Set sensible defaults: graphics_pipeline_config::graphics_pipeline_config() : mPipelineSettings{ cfg::pipeline_settings::nothing } + , mDynamicRenderingAttachments {} , mRenderPassSubpass {} // not set by default , mPrimitiveTopology{ cfg::primitive_topology::triangles } // triangles after one another , mRasterizerGeometryMode{ cfg::rasterizer_geometry_mode::rasterize_geometry } // don't discard, but rasterize! , mPolygonDrawingModeAndConfig{ cfg::polygon_drawing::config_for_filling() } // Fill triangles , mCullingMode{ cfg::culling_mode::cull_back_faces } // Cull back faces + , mDynamicRendering {cfg::dynamic_rendering::disabled } , mFrontFaceWindingOrder{ cfg::front_face::define_front_faces_to_be_counter_clockwise() } // CCW == front face , mDepthClampBiasConfig{ cfg::depth_clamp_bias::config_nothing_special() } // no clamp, no bias, no factors , mDepthTestConfig{ cfg::depth_test::enabled() } // enable depth testing @@ -4332,9 +4367,17 @@ namespace avk .setAttachmentCount(static_cast(aPreparedPipeline.mBlendingConfigsForColorAttachments.size())) .setPAttachments(aPreparedPipeline.mBlendingConfigsForColorAttachments.data()); - aPreparedPipeline.mMultisampleStateCreateInfo - .setRasterizationSamples(aPreparedPipeline.renderpass_reference().num_samples_for_subpass(aPreparedPipeline.subpass_id())) - .setPSampleMask(nullptr); + + // NOTE(msakmary) Not really sure why we set the samples again when they were previously set in root::create_graphics_pipeline + // (ask for clarification) - but if dynamic rendering is enabled there is no renderpass... + const bool dynamicRenderingEnabled = aPreparedPipeline.mRenderingCreateInfo.has_value(); + if(!dynamicRenderingEnabled) + { + aPreparedPipeline.mMultisampleStateCreateInfo + .setRasterizationSamples( + aPreparedPipeline.renderpass_pointer().value()->num_samples_for_subpass(aPreparedPipeline.subpass_id().value())) + .setPSampleMask(nullptr); + } aPreparedPipeline.mDynamicStateCreateInfo .setDynamicStateCount(static_cast(aPreparedPipeline.mDynamicStateEntries.size())) @@ -4346,10 +4389,17 @@ namespace avk aPreparedPipeline.mPipelineLayout = device().createPipelineLayoutUnique(aPreparedPipeline.mPipelineLayoutCreateInfo, nullptr, dispatch_loader_core()); assert(static_cast(aPreparedPipeline.layout_handle())); + const void * pNext = dynamicRenderingEnabled ? &(aPreparedPipeline.mRenderingCreateInfo.value()) : nullptr; + VkRenderPass render_pass{}; + if(!dynamicRenderingEnabled) + { + render_pass = (aPreparedPipeline.mRenderPass.value())->handle(); + } // Create the PIPELINE, a.k.a. putting it all together: auto pipelineInfo = vk::GraphicsPipelineCreateInfo{} // 0. Render Pass - .setRenderPass((*aPreparedPipeline.mRenderPass).handle()) + .setPNext(pNext) + .setRenderPass(render_pass) .setSubpass(aPreparedPipeline.mSubpassIndex) // 1., 2., and 3. .setPVertexInputState(&aPreparedPipeline.mPipelineVertexInputStateCreateInfo) @@ -4431,12 +4481,16 @@ namespace avk graphics_pipeline_t result; - // 0. Own the renderpass + // 0. Own the renderpass - if one is required + const bool dynamic_rendering_enabled = aConfig.mDynamicRendering == avk::cfg::dynamic_rendering::enabled; { - assert(aConfig.mRenderPassSubpass.has_value()); - auto [rp, sp] = std::move(aConfig.mRenderPassSubpass.value()); - result.mRenderPass = std::move(rp); - result.mSubpassIndex = sp; + if(!dynamic_rendering_enabled) + { + assert(aConfig.mRenderPassSubpass.has_value()); + auto [rp, sp] = std::move(aConfig.mRenderPassSubpass.value()); + result.mRenderPass = std::move(rp); + result.mSubpassIndex = sp; + } } // 1. Compile the array of vertex input binding descriptions @@ -4619,18 +4673,36 @@ namespace avk "config (which is not attached to a specific color target) or assign them to specific color target attachment ids."); } - // Iterate over all color target attachments and set a color blending config - if (result.subpass_id() >= result.mRenderPass->attachment_descriptions().size()) { - throw avk::runtime_error( - "There are fewer subpasses in the renderpass (" - + std::to_string(result.mRenderPass->attachment_descriptions().size()) + - ") than the subpass index (" - + std::to_string(result.subpass_id()) + - ") indicates. I.e. the subpass index is out of bounds."); + // Iterate over all color target attachments and set a color blending config + size_t blending_config_num; + if (!dynamic_rendering_enabled) + { + const auto & renderPassVal = result.mRenderPass.value(); + if (result.subpass_id() >= renderPassVal->attachment_descriptions().size()) { + throw avk::runtime_error( + "There are fewer subpasses in the renderpass (" + + std::to_string(renderPassVal->attachment_descriptions().size()) + + ") than the subpass index (" + + std::to_string(result.subpass_id().value()) + + ") indicates. I.e. the subpass index is out of bounds."); + } + blending_config_num = renderPassVal->color_attachments_for_subpass(result.subpass_id().value()).size(); /////////////////// TODO: (doublecheck or) FIX this section (after renderpass refactoring) + } + // Renderpasses and Subpasses are not supported when dynamic rendering is enabled + // Instead we read size of the dynamic_rendering_attachments provided + else + { + blending_config_num = 0; + for(const auto & dyn_rendering_attachment : aConfig.mDynamicRenderingAttachments.value()) + { + if(!is_depth_format(dyn_rendering_attachment.format())) + { + blending_config_num++; + } + } } - const auto n = result.mRenderPass->color_attachments_for_subpass(result.subpass_id()).size(); /////////////////// TODO: (doublecheck or) FIX this section (after renderpass refactoring) - result.mBlendingConfigsForColorAttachments.reserve(n); // Important! Otherwise the vector might realloc and .data() will become invalid! - for (size_t i = 0; i < n; ++i) { + result.mBlendingConfigsForColorAttachments.reserve(blending_config_num); // Important! Otherwise the vector might realloc and .data() will become invalid! + for (size_t i = 0; i < blending_config_num; ++i) { // Do we have a specific blending config for color attachment i? #if defined(_MSC_VER) && _MSC_VER < 1930 auto configForI = aConfig.mColorBlendingPerAttachment @@ -4677,7 +4749,24 @@ namespace avk // 10. Multisample state // TODO: Can the settings be inferred from the renderpass' color attachments (as they are right now)? If they can't, how to handle this situation? { /////////////////// TODO: FIX this section (after renderpass refactoring) - vk::SampleCountFlagBits numSamples = (*result.mRenderPass).num_samples_for_subpass(result.subpass_id()); + vk::SampleCountFlagBits numSamples = vk::SampleCountFlagBits::e1; + if(!dynamic_rendering_enabled) + { + numSamples = result.mRenderPass.value()->num_samples_for_subpass(result.subpass_id().value()); + } else { + const auto & dynamicRenderingAttachments = aConfig.mDynamicRenderingAttachments.value(); + numSamples = dynamicRenderingAttachments.at(0).sample_count(); +#if defined(_DEBUG) + for(int attachment_idx = 1; attachment_idx < dynamicRenderingAttachments.size(); attachment_idx++) + { + if(numSamples != dynamicRenderingAttachments.at(attachment_idx).sample_count()) + { + //TODO(msakmary) This may be possible with some extension I'm not 100% sure... + throw avk::runtime_error("Cannot have different sample counts for attachments in the same renderpass"); + } + } +#endif + } // Evaluate and set the PER SAMPLE shading configuration: auto perSample = aConfig.mPerSampleShading.value_or(per_sample_shading_config{ false, 1.0f }); @@ -4770,19 +4859,49 @@ namespace avk .setPushConstantRangeCount(static_cast(result.mPushConstantRanges.size())) .setPPushConstantRanges(result.mPushConstantRanges.data()); - // 15. Maybe alter the config?! + // 15. Set Rendering info if dynamic rendering is enabled + if(dynamic_rendering_enabled) + { + std::vector depth_attachments; + std::vector stencil_attachments; + for(const auto & dynamic_rendering_attachment : aConfig.mDynamicRenderingAttachments.value()) + { + if(is_depth_format(dynamic_rendering_attachment.format())) + { + depth_attachments.push_back(dynamic_rendering_attachment.format()); + } else if (is_stencil_format(dynamic_rendering_attachment.format())) { + stencil_attachments.push_back(dynamic_rendering_attachment.format()); + } else { + result.mDynamicRenderingColorFormats.push_back(dynamic_rendering_attachment.format()); + } + } + if(depth_attachments.size() > 1) { throw avk::runtime_error("Provided multiple depth attachments! Only one is supported!"); } + if(stencil_attachments.size() > 1) { throw avk::runtime_error("Provided multiple stencil attachments! Only one is supported!"); } + + result.mRenderingCreateInfo = vk::PipelineRenderingCreateInfo{} + .setColorAttachmentCount(static_cast(result.mDynamicRenderingColorFormats.size())) + .setPColorAttachmentFormats(result.mDynamicRenderingColorFormats.data()) + .setDepthAttachmentFormat(depth_attachments.size() == 1 ? depth_attachments.at(0) : vk::Format{}) + .setStencilAttachmentFormat(stencil_attachments.size() == 1 ? stencil_attachments.at(0) : vk::Format{}); + } + + // 16. Maybe alter the config?! if (aAlterConfigBeforeCreation) { aAlterConfigBeforeCreation(result); } - assert (aConfig.mRenderPassSubpass.has_value()); + assert (aConfig.mRenderPassSubpass.has_value() || dynamic_rendering_enabled); rewire_config_and_create_graphics_pipeline(result); return result; } - graphics_pipeline root::create_graphics_pipeline_from_template(const graphics_pipeline_t& aTemplate, renderpass aNewRenderpass, std::optional aSubpassIndex, std::function aAlterConfigBeforeCreation) + graphics_pipeline root::create_graphics_pipeline_from_template(const graphics_pipeline_t& aTemplate, std::optional aNewRenderpass, std::optional aSubpassIndex, std::function aAlterConfigBeforeCreation) { graphics_pipeline_t result; + if(aTemplate.mRenderingCreateInfo.has_value() && aNewRenderpass.has_value()) + { + throw avk::runtime_error("Attempting to create pipeline using renderpass from a template pipeline using dynamic rendering (which has no renderpasses) is not valid!"); + } result.mRenderPass = std::move(aNewRenderpass); result.mSubpassIndex = aSubpassIndex.value_or(cfg::subpass_index{ aTemplate.mSubpassIndex }).mSubpassIndex; @@ -4832,26 +4951,36 @@ namespace avk graphics_pipeline root::create_graphics_pipeline_from_template(const graphics_pipeline_t& aTemplate, std::function aAlterConfigBeforeCreation) { - renderpass renderpassForPipeline; - if (aTemplate.mRenderPass.is_shared_ownership_enabled()) { + // If dynamic rendering is enabled we don't want to create new renderpass + if(aTemplate.mRenderingCreateInfo.has_value()) + { + return create_graphics_pipeline_from_template(aTemplate, std::nullopt, std::nullopt, std::move(aAlterConfigBeforeCreation)); + } + std::optional renderpassForPipeline; + if (aTemplate.mRenderPass.value().is_shared_ownership_enabled()) { renderpassForPipeline = aTemplate.mRenderPass; } else { - renderpassForPipeline = create_renderpass_from_template(*aTemplate.mRenderPass, {}); + renderpassForPipeline = create_renderpass_from_template(*(aTemplate.mRenderPass.value()), {}); } return create_graphics_pipeline_from_template(aTemplate, std::move(renderpassForPipeline), std::nullopt, std::move(aAlterConfigBeforeCreation)); } renderpass root::replace_render_pass_for_pipeline(graphics_pipeline& aPipeline, renderpass aNewRenderPass) { - if (aPipeline->mRenderPass.is_shared_ownership_enabled()) { + if(aPipeline.get().mRenderingCreateInfo.has_value()) + { + throw avk::runtime_error("Attempting to replace renderpass of pipeline using dynamic rendering (which has no renderpasses) is not valid!"); + } + + if (aPipeline->mRenderPass.value().is_shared_ownership_enabled()) { aNewRenderPass.enable_shared_ownership(); } auto oldRenderPass = std::move(aPipeline->mRenderPass); aPipeline->mRenderPass = std::move(aNewRenderPass); - return oldRenderPass; + return oldRenderPass.value(); } #pragma endregion From acd4e353f0fbf984973b43ba0e29bca3338493b5 Mon Sep 17 00:00:00 2001 From: MatejSakmary Date: Sat, 28 Oct 2023 00:43:09 +0200 Subject: [PATCH 02/18] Use KHR types to fix build issues with Vulkan 1.2 --- include/avk/graphics_pipeline.hpp | 2 +- src/avk.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/avk/graphics_pipeline.hpp b/include/avk/graphics_pipeline.hpp index b7a7a7c..c1f91c4 100644 --- a/include/avk/graphics_pipeline.hpp +++ b/include/avk/graphics_pipeline.hpp @@ -102,7 +102,7 @@ namespace avk vk::PipelineViewportStateCreateInfo mViewportStateCreateInfo; // Dynamic rendering state std::vector mDynamicRenderingColorFormats; - std::optional mRenderingCreateInfo; + std::optional mRenderingCreateInfo; // Rasterization state: vk::PipelineRasterizationStateCreateInfo mRasterizationStateCreateInfo; // Depth stencil config: diff --git a/src/avk.cpp b/src/avk.cpp index 9dd8c31..3682583 100644 --- a/src/avk.cpp +++ b/src/avk.cpp @@ -4878,7 +4878,7 @@ namespace avk if(depth_attachments.size() > 1) { throw avk::runtime_error("Provided multiple depth attachments! Only one is supported!"); } if(stencil_attachments.size() > 1) { throw avk::runtime_error("Provided multiple stencil attachments! Only one is supported!"); } - result.mRenderingCreateInfo = vk::PipelineRenderingCreateInfo{} + result.mRenderingCreateInfo = vk::PipelineRenderingCreateInfoKHR{} .setColorAttachmentCount(static_cast(result.mDynamicRenderingColorFormats.size())) .setPColorAttachmentFormats(result.mDynamicRenderingColorFormats.data()) .setDepthAttachmentFormat(depth_attachments.size() == 1 ? depth_attachments.at(0) : vk::Format{}) From 38350f20b6cf93754b09fdf0f41f391afdf0a399 Mon Sep 17 00:00:00 2001 From: MatejSakmary Date: Tue, 31 Oct 2023 01:23:25 +0100 Subject: [PATCH 03/18] Added begin and end rendering commands --- include/avk/commands.hpp | 26 ++++++ src/avk.cpp | 165 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 191 insertions(+) diff --git a/include/avk/commands.hpp b/include/avk/commands.hpp index 0987fec..e97a5c0 100644 --- a/include/avk/commands.hpp +++ b/include/avk/commands.hpp @@ -3,6 +3,7 @@ #include "buffer.hpp" #include "image.hpp" +#include namespace avk { @@ -506,6 +507,19 @@ namespace avk }; } + /** Begins dynamic rendering scope + * @param aAttachemnts attachments used in during this dynamic rendering pass + * @param aImageViews image views bound for each attachment + * @param aRenderAreaOffset Render area offset (default is (0,0), i.e., no offset) + * @param aRenderAreaExtent Render area extent (default is full extent inferred from images passed in aImageViews) + * @param aLayerCount number of layers that will be used for rendering (default is 1) + */ + extern action_type_command begin_dynamic_rendering(std::vector aAttachments, std::vector aImageViews, vk::Offset2D aRenderAreaOffset = {0, 0}, std::optional aRenderAreaExtent = {}, uint32_t aLayerCount = 1); + + /** Ends dynamic rendering scope + */ + extern action_type_command end_dynamic_rendering(); + /** Begins a render pass for a given framebuffer * @param aRenderpass Renderpass which shall begin (auto lifetime handling not supported by this command) * @param aFramebuffer Framebuffer to use with the renderpass (auto lifetime handling not supported by this command) @@ -515,6 +529,7 @@ namespace avk */ extern action_type_command begin_render_pass_for_framebuffer(const renderpass_t& aRenderpass, const framebuffer_t& aFramebuffer, vk::Offset2D aRenderAreaOffset = { 0, 0 }, std::optional aRenderAreaExtent = {}, bool aSubpassesInline = true); + /** Ends a render pass */ extern action_type_command end_render_pass(); @@ -536,6 +551,17 @@ namespace avk bool aSubpassesInline = true ); + /** Begins dynamic rendering and supports nested commands in between + * @param aNestedCommands Nested commands to be recorded between begin and end + * @param aRenderAreaOffset Render area offset (default is (0,0), i.e., no offset) + * @param aRenderAreaExtent Render area extent (default is full extent) + */ + // extern action_type_command dynamic_renderpass( + // std::vector aNestedCommands = {}, + // vk::Offset2D aRenderAreaOffset = {0, 0}, + // std::optional aRenderAreaExtent = {} + // ); + /** Advances to the next subpass within a render pass. */ extern action_type_command next_subpass(bool aSubpassesInline = true); diff --git a/src/avk.cpp b/src/avk.cpp index 3682583..6dce7e1 100644 --- a/src/avk.cpp +++ b/src/avk.cpp @@ -1,3 +1,5 @@ +#include +#include #define NOMINMAX #include #include "avk/avk.hpp" @@ -585,6 +587,7 @@ namespace avk vk::Format::eD16UnormS8Uint, vk::Format::eD24UnormS8Uint, vk::Format::eD32SfloatS8Uint, + vk::Format::eS8Uint, }; auto it = std::find(std::begin(stencilFormats), std::end(stencilFormats), aImageFormat); return it != stencilFormats.end(); @@ -8364,6 +8367,168 @@ namespace avk namespace command { + + action_type_command begin_dynamic_rendering( + std::vector aAttachments, + std::vector aImageViews, + vk::Offset2D aRenderAreaOffset, + std::optional aRenderAreaExtent, + uint32_t aLayerCount) + { +#ifdef _DEBUG + if (aAttachments.size() != aImageViews.size()) { + throw avk::runtime_error("Incomplete config for begin dynamic rendering: number of attachments (" + std::to_string(aAttachments.size()) + ") does not equal the number of image views (" + std::to_string(aImageViews.size()) + ")"); + } + auto n = aAttachments.size(); + for (size_t i = 0; i < n; ++i) { + auto& a = aAttachments[i]; + auto& v = aImageViews[i]; + if ((is_depth_format(v->get_image().format()) || has_stencil_component(v->get_image().format())) && !a.is_used_as_depth_stencil_attachment()) { + AVK_LOG_WARNING("Possibly misconfigured framebuffer: image[" + std::to_string(i) + "] is a depth/stencil format, but it is never indicated to be used as such in the attachment-description[" + std::to_string(i) + "]."); + } + } +#endif //_DEBUG + const bool detectExtent = aRenderAreaExtent.has_value(); + std::vector colorAttachments = {}; + std::optional depthAttachment = {}; + std::optional stencilAttachment = {}; + // First parse all the attachments into vulkan structs + for(uint32_t attachmentIndex = 0; attachmentIndex < aAttachments.size(); attachmentIndex++) + { + const auto & currAttachment = aAttachments.at(attachmentIndex); + const auto & currImageView = aImageViews.at(attachmentIndex); + if(detectExtent && !aRenderAreaExtent.has_value()) + { + const auto imageExtent = currImageView->get_image().create_info().extent; + aRenderAreaExtent = vk::Extent2D{ + imageExtent.width - static_cast(aRenderAreaOffset.x), + imageExtent.height - static_cast(aRenderAreaOffset.y) + }; + } +#ifdef _DEBUG + else if(detectExtent) + { + const auto imageExtent = currImageView->get_image().create_info().extent; + const auto currAreaExtent = vk::Extent2D{ + imageExtent.width - static_cast(aRenderAreaOffset.x), + imageExtent.height - static_cast(aRenderAreaOffset.y) + }; + if(currAreaExtent != aRenderAreaExtent.value()) + { + throw avk::runtime_error("Autodetect extent failed because the images passed in image views have differing extents"); + } + } +#endif //_DEBUG + if(currAttachment.is_used_as_color_attachment()) + { + colorAttachments.push_back( + vk::RenderingAttachmentInfoKHR{} + .setImageView(currImageView->handle()) + .setImageLayout(vk::ImageLayout::eColorAttachmentOptimal) + // TODO(msakmary) add support for resolve and MSAA + // .setResolveMode() + // .setResolveImageView() + // .setResolveImageLayout() + .setLoadOp(to_vk_load_op(currAttachment.mLoadOperation.mLoadBehavior)) + .setStoreOp(to_vk_store_op(currAttachment.mStoreOperation.mStoreBehavior)) + .setClearValue(vk::ClearColorValue(currAttachment.clear_color())) + ); + } + else // currAttachment is either used as depth or as stencil + { + // TODO(msakmary): This will brake if we want depth image and stencil both D24S8 but separate images (so two D24S8 images + // one used as depth one as stencil) probably should have this info in a custom attachment type. + // I think something like begin_rendering_attachment should be added which would have an explicit field + // which would denote how to use the attachment - use this attachment as stencil, depth or color + if(is_depth_format(currAttachment.format())) + { + if(depthAttachment.has_value()) + { + throw avk::runtime_error("Multiple depth attachments provided! Please provide only a single depth attachment"); + } + depthAttachment = vk::RenderingAttachmentInfoKHR{} + .setImageView(currImageView->handle()) + .setImageLayout(vk::ImageLayout::eAttachmentOptimal) + // TODO(msakmary) add support for resolve and MSAA + // .setResolveMode() + // .setResolveImageView() + // .setResolveImageLayout() + .setLoadOp(to_vk_load_op(currAttachment.mLoadOperation.mLoadBehavior)) + .setStoreOp(to_vk_store_op(currAttachment.mStoreOperation.mStoreBehavior)) + .setClearValue(vk::ClearDepthStencilValue( + currAttachment.depth_clear_value(), + currAttachment.stencil_clear_value())); + } + if(is_stencil_format(currAttachment.format())) + { + if(stencilAttachment.has_value()) + { + throw avk::runtime_error("Multiple stencil attachments provided! Please provide only a single stencil attachment"); + } + stencilAttachment = vk::RenderingAttachmentInfoKHR{} + .setImageView(currImageView->handle()) + .setImageLayout(vk::ImageLayout::eAttachmentOptimal) + // TODO(msakmary) add support for resolve and MSAA + // .setResolveMode() + // .setResolveImageView() + // .setResolveImageLayout() + .setLoadOp(to_vk_load_op(currAttachment.mLoadOperation.mLoadBehavior)) + .setStoreOp(to_vk_store_op(currAttachment.mStoreOperation.mStoreBehavior)) + .setClearValue(vk::ClearDepthStencilValue( + currAttachment.depth_clear_value(), + currAttachment.stencil_clear_value())); + } + } + } + auto const renderingInfo = vk::RenderingInfoKHR{} + .setRenderArea(vk::Rect2D(aRenderAreaOffset, aRenderAreaExtent.value())) + .setLayerCount(aLayerCount) + .setViewMask(0) //TODO(msakmary) this is for multiview - do we want to support it? + .setColorAttachmentCount(static_cast(colorAttachments.size())) + .setPColorAttachments(colorAttachments.data()) + .setPDepthAttachment(depthAttachment.has_value() ? &depthAttachment.value() : nullptr) + .setPStencilAttachment(stencilAttachment.has_value() ? &stencilAttachment.value() : nullptr); + + return action_type_command{ + avk::sync::sync_hint { + {{ // What previous commands must synchronize with: + vk::PipelineStageFlagBits2KHR::eAllGraphics, + vk::AccessFlagBits2KHR::eColorAttachmentRead | vk::AccessFlagBits2KHR::eColorAttachmentWrite | vk::AccessFlagBits2KHR::eDepthStencilAttachmentRead | vk::AccessFlagBits2KHR::eDepthStencilAttachmentWrite + }}, + {{ // What subsequent commands must synchronize with: + vk::PipelineStageFlagBits2KHR::eAllGraphics, + vk::AccessFlagBits2KHR::eColorAttachmentWrite | vk::AccessFlagBits2KHR::eDepthStencilAttachmentWrite + }} + }, + {}, + [renderingInfo](avk::command_buffer_t& cb) { + cb.handle().beginRenderingKHR(renderingInfo, cb.root_ptr()->dispatch_loader_ext()); + } + }; + } + + action_type_command end_dynamic_rendering() + { + return action_type_command + { + // TODO(msakmary) I'm copying end renderpass here but I'm not sure this is correct? + avk::sync::sync_hint { + {{ // What previous commands must synchronize with: + vk::PipelineStageFlagBits2KHR::eAllCommands, // eAllGraphics does not include new stages or ext-stages. Therefore, eAllCommands! + vk::AccessFlagBits2KHR::eColorAttachmentRead | vk::AccessFlagBits2KHR::eColorAttachmentWrite | vk::AccessFlagBits2KHR::eDepthStencilAttachmentRead | vk::AccessFlagBits2KHR::eDepthStencilAttachmentWrite + }}, + {{ // What subsequent commands must synchronize with: + vk::PipelineStageFlagBits2KHR::eAllCommands, // Same comment as above regarding eAllCommands vs. eAllGraphics + vk::AccessFlagBits2KHR::eColorAttachmentWrite | vk::AccessFlagBits2KHR::eDepthStencilAttachmentWrite + }} + }, + {}, + [](avk::command_buffer_t& cb){ + cb.handle().endRenderingKHR(cb.root_ptr()->dispatch_loader_ext()); + } + }; + } + action_type_command begin_render_pass_for_framebuffer(const renderpass_t& aRenderpass, const framebuffer_t& aFramebuffer, vk::Offset2D aRenderAreaOffset, std::optional aRenderAreaExtent, bool aSubpassesInline) { return action_type_command{ From 8c3acbdedbee47bcd18004ae4eba67d1bf039a8b Mon Sep 17 00:00:00 2001 From: MatejSakmary Date: Tue, 31 Oct 2023 19:03:07 +0100 Subject: [PATCH 04/18] Fix bugs in begin_dynamic_rendering() --- src/avk.cpp | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/avk.cpp b/src/avk.cpp index 6dce7e1..a0caf38 100644 --- a/src/avk.cpp +++ b/src/avk.cpp @@ -8388,7 +8388,7 @@ namespace avk } } #endif //_DEBUG - const bool detectExtent = aRenderAreaExtent.has_value(); + const bool detectExtent = !aRenderAreaExtent.has_value(); std::vector colorAttachments = {}; std::optional depthAttachment = {}; std::optional stencilAttachment = {}; @@ -8480,14 +8480,6 @@ namespace avk } } } - auto const renderingInfo = vk::RenderingInfoKHR{} - .setRenderArea(vk::Rect2D(aRenderAreaOffset, aRenderAreaExtent.value())) - .setLayerCount(aLayerCount) - .setViewMask(0) //TODO(msakmary) this is for multiview - do we want to support it? - .setColorAttachmentCount(static_cast(colorAttachments.size())) - .setPColorAttachments(colorAttachments.data()) - .setPDepthAttachment(depthAttachment.has_value() ? &depthAttachment.value() : nullptr) - .setPStencilAttachment(stencilAttachment.has_value() ? &stencilAttachment.value() : nullptr); return action_type_command{ avk::sync::sync_hint { @@ -8501,7 +8493,22 @@ namespace avk }} }, {}, - [renderingInfo](avk::command_buffer_t& cb) { + [ + colorAttachments, + depthAttachment, + stencilAttachment, + aLayerCount, + aRenderAreaOffset, + aRenderAreaExtent + ](avk::command_buffer_t& cb) { + auto const renderingInfo = vk::RenderingInfoKHR{} + .setRenderArea(vk::Rect2D(aRenderAreaOffset, aRenderAreaExtent.value())) + .setLayerCount(aLayerCount) + .setViewMask(0) //TODO(msakmary) this is for multiview - do we want to support it? + .setColorAttachmentCount(static_cast(colorAttachments.size())) + .setPColorAttachments(colorAttachments.data()) + .setPDepthAttachment(depthAttachment.has_value() ? &depthAttachment.value() : nullptr) + .setPStencilAttachment(stencilAttachment.has_value() ? &stencilAttachment.value() : nullptr); cb.handle().beginRenderingKHR(renderingInfo, cb.root_ptr()->dispatch_loader_ext()); } }; From 0d1e5e58f234fb373e71c59514a16f342674dd70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Sakmary?= Date: Mon, 13 Nov 2023 15:18:22 +0100 Subject: [PATCH 05/18] Apply suggestions from code review Changing local variables naming to lowerCamelCase Co-authored-by: Johannes Unterguggenberger --- src/avk.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/avk.cpp b/src/avk.cpp index a0caf38..55ebe41 100644 --- a/src/avk.cpp +++ b/src/avk.cpp @@ -4485,7 +4485,8 @@ namespace avk graphics_pipeline_t result; // 0. Own the renderpass - if one is required - const bool dynamic_rendering_enabled = aConfig.mDynamicRendering == avk::cfg::dynamic_rendering::enabled; + const bool dynamicRenderingEnabled = aConfig.mDynamicRendering == avk::cfg::dynamic_rendering::enabled; + { if(!dynamic_rendering_enabled) { @@ -4695,7 +4696,8 @@ namespace avk // Instead we read size of the dynamic_rendering_attachments provided else { - blending_config_num = 0; + blendingConfigNum = 0; + for(const auto & dyn_rendering_attachment : aConfig.mDynamicRenderingAttachments.value()) { if(!is_depth_format(dyn_rendering_attachment.format())) From e69b0ff59add62a248d973dd42a6d97bc69b929b Mon Sep 17 00:00:00 2001 From: MatejSakmary Date: Sun, 10 Mar 2024 19:26:34 +0100 Subject: [PATCH 06/18] Add fixes to issues raised in pr review: - removed dynamic_rendering_attachment - added declare_dynamic(_for) functions to avk::attachment which create dynamic rendering attachments - changed graphics_pipeline_t::renderpass_pointer() back to renderpass_reference() which now returns a reference wrapper --- README.md | 2 +- include/avk/attachment.hpp | 57 +++++++--------- include/avk/avk.hpp | 20 ++++-- include/avk/graphics_pipeline.hpp | 6 +- include/avk/graphics_pipeline_config.hpp | 15 +---- src/avk.cpp | 84 +++++++++++++----------- 6 files changed, 88 insertions(+), 96 deletions(-) diff --git a/README.md b/README.md index 0a35544..7cc489a 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ avk::framebuffer framebuffer = myRoot.create_framebuffer(...); avk::semaphore imageAvailableSemaphore = ...; mRoot.record({ - avk::command::render_pass(*graphicsPipeline->renderpass_pointer().value(), framebuffer.as_reference(), { + avk::command::render_pass(graphicsPipeline->renderpass_reference().value(), framebuffer.as_reference(), { avk::command::bind_pipeline(graphicsPipeline.as_reference()), avk::command::draw(3u, 1u, 0u, 0u) }) diff --git a/include/avk/attachment.hpp b/include/avk/attachment.hpp index 74fbf93..71e9d3e 100644 --- a/include/avk/attachment.hpp +++ b/include/avk/attachment.hpp @@ -3,39 +3,6 @@ namespace avk { - - /** Describes a dynamic rendering attachment. It can only be used with pipeline that has dynamic rendering enabled. - * It has fewever parameters than regular attachment since some of its values (load/store ops etc...) are set - * when starting the dynamic render pass as opposed to being declared beforehand. - * It can describe color attachments as well as depth/stencil attachments - * and holds some additional config parameters for these attachments. - */ - struct dynamic_rendering_attachment - { - /** Declare multisampled format of an attachment for a dynamic rendering pipeline - * @param aFormatAndSamples Multisampled format definition: A tuple with the format of the attachment in its first element, and with the number of samples in its second element. - */ - static dynamic_rendering_attachment declare(std::tuple aFormatAndSamples); - /** Declare format of an attachment for a dynamic rendering pipeline - * @param aFormat The format of the attachment - */ - static dynamic_rendering_attachment declare(vk::Format aFormat); - - /** Declare format of an attachment for a dynamic rendering pipeline - * @param aImageView The format of the attachment is copied from the given image view. - */ - static dynamic_rendering_attachment declare_for(const image_view_t& aImageView); - - /** The color/depth/stencil format of the attachment */ - auto format() const { return mFormat; } - /** True if the sample count is greater than 1 */ - bool is_multisampled() const { return mSampleCount != vk::SampleCountFlagBits::e1; } - /** The sample count for this attachment. */ - auto sample_count() const { return mSampleCount; } - - vk::Format mFormat; - vk::SampleCountFlagBits mSampleCount; - }; /** Describes an attachment to a framebuffer or a renderpass. * It can describe color attachments as well as depth/stencil attachments * and holds some additional config parameters for these attachments. @@ -93,6 +60,27 @@ namespace avk */ static attachment declare_for(const image_view_t& aImageView, attachment_load_config aLoadOp, subpass_usages aUsageInSubpasses, attachment_store_config aStoreOp); + /** Declare multisampled format of an attachment for a dynamic rendering pipeline. This attachment can only be used with pipeline that has dynamic rendering enabled. + * It has fewever parameters than regular attachment since some of its values (load/store ops etc...) are set when starting the dynamic render pass + * as opposed to being declared beforehand.. + * @param aFormatAndSamples Multisampled format definition: A tuple with the format of the attachment in its first element, and with the number of samples in its second element. + */ + static attachment declare_dynamic(std::tuple aFormatAndSamples); + + /** Declare multisampled format of an attachment for a dynamic rendering pipeline. This attachment can only be used with pipeline that has dynamic rendering enabled. + * It has fewever parameters than regular attachment since some of its values (load/store ops etc...) are set when starting the dynamic render pass + * as opposed to being declared beforehand.. + * @param aFormat The format of the attachment + */ + static attachment declare_dynamic(vk::Format aFormat); + + /** Declare multisampled format of an attachment for a dynamic rendering pipeline. This attachment can only be used with pipeline that has dynamic rendering enabled. + * It has fewever parameters than regular attachment since some of its values (load/store ops etc...) are set when starting the dynamic render pass + * as opposed to being declared beforehand.. + * @param aImageView The format of the attachment is copied from the given image view. + */ + static attachment declare_dynamic_for(const image_view_t& aImageView); + attachment& set_clear_color(std::array aColor) { mColorClearValue = aColor; return *this; } attachment& set_depth_clear_value(float aDepthClear) { mDepthClearValue = aDepthClear; return *this; } attachment& set_stencil_clear_value(uint32_t aStencilClear) { mStencilClearValue = aStencilClear; return *this; } @@ -121,6 +109,8 @@ namespace avk auto sample_count() const { return mSampleCount; } /** True if a multisample resolve pass shall be set up. */ auto is_to_be_resolved() const { return mSubpassUsages.contains_resolve(); } + /** True if this attachment is declared for dynamic rendering pipelines ie. using one of the dynamic declare functions*/ + bool is_for_dynamic_rendering() const { return mDynamicRenderingAttachment; } /** Returns the stencil load operation */ auto get_stencil_load_op() const { return mStencilLoadOperation.value_or(mLoadOperation); } @@ -141,5 +131,6 @@ namespace avk std::array mColorClearValue; float mDepthClearValue; uint32_t mStencilClearValue; + bool mDynamicRenderingAttachment; }; } diff --git a/include/avk/avk.hpp b/include/avk/avk.hpp index 2300aca..f334344 100644 --- a/include/avk/avk.hpp +++ b/include/avk/avk.hpp @@ -762,18 +762,26 @@ namespace avk std::function alterConfigFunction; graphics_pipeline_config config; add_config(config, renderPassAttachments, alterConfigFunction, std::move(args)...); + bool hasRenderPassAttachments = false; + bool hasDynamicRenderingAttachments = false; + for(const auto & attachment : renderPassAttachments) + { + if(attachment.is_for_dynamic_rendering()) + { + hasDynamicRenderingAttachments = true; + } else { + hasRenderPassAttachments = true; + } + } const bool hasValidRenderPass = config.mRenderPassSubpass.has_value() && static_cast(std::get(*config.mRenderPassSubpass)->handle()); - const bool hasRenderPassAttachments = renderPassAttachments.size() > 0; const bool isDynamicRenderingSet = config.mDynamicRendering == avk::cfg::dynamic_rendering::enabled; - // .has_value() should be enough since I don't fill in the optional unless there was dynamic_rendering_attachment provided - const bool hasDynamicRenderingAttachments = config.mDynamicRenderingAttachments.has_value(); // Check all invalid configurations when dynamic rendering is set if (isDynamicRenderingSet ) { if(hasValidRenderPass) { throw avk::runtime_error("Dynamic rendering does not accept renderpasses! They are set dynamically during rendering!"); } - if(hasRenderPassAttachments) { throw avk::runtime_error("Usage of avk::attachment is not allowed when dynamic rendering is enabled! Use avk::dynamic_rendering_attachment instead!"); } - if(!hasDynamicRenderingAttachments) { throw avk::runtime_error("Dynamic rendering enabled but no avk::dynamic_rendering_attachments provided! Please provide at least one attachment!"); } + if(hasRenderPassAttachments) { throw avk::runtime_error("Only avk::attachments created by declare_dynamic(_for) functions are allowed when dynamic rendering is enabled!"); } + if(!hasDynamicRenderingAttachments) { throw avk::runtime_error("Dynamic rendering enabled but no avk::attachmenst created by declare_dynamic(_for) functions provided! Please provide at least one attachment!"); } } // Check all invalid configurations when normal rendering (with renderpasses) is used else @@ -785,6 +793,8 @@ namespace avk // ^ that was the sanity check. See if we have to build the renderpass from the attachments: if (hasRenderPassAttachments) { add_config(config, renderPassAttachments, alterConfigFunction, create_renderpass(std::move(renderPassAttachments))); + } else { + config.mDynamicRenderingAttachments = std::move(renderPassAttachments); } // 2. CREATE PIPELINE according to the config diff --git a/include/avk/graphics_pipeline.hpp b/include/avk/graphics_pipeline.hpp index c1f91c4..d9a97d7 100644 --- a/include/avk/graphics_pipeline.hpp +++ b/include/avk/graphics_pipeline.hpp @@ -1,5 +1,6 @@ #pragma once #include "avk/avk.hpp" +#include namespace avk { @@ -17,10 +18,9 @@ namespace avk ~graphics_pipeline_t() = default; [[nodiscard]] auto renderpass() const { return mRenderPass; } - // TODO(msakmary) I can also keep the consistent naming aka renderpass_reference() return std::optional> I feel like this is way cleaner? - [[nodiscard]] auto renderpass_pointer() const -> std::optional + [[nodiscard]] auto renderpass_reference() const -> std::optional> { - if(mRenderPass.has_value()) { return &(mRenderPass.value().get()); } + if(mRenderPass.has_value()) { return std::cref(mRenderPass.value().get()); } else { return std::nullopt; } } // TODO(msakmary) Perhaps I just return std::optional here? It would probably be more readable then declval diff --git a/include/avk/graphics_pipeline_config.hpp b/include/avk/graphics_pipeline_config.hpp index 94bb9dd..6e90519 100644 --- a/include/avk/graphics_pipeline_config.hpp +++ b/include/avk/graphics_pipeline_config.hpp @@ -615,8 +615,8 @@ namespace avk ~graphics_pipeline_config() = default; cfg::pipeline_settings mPipelineSettings; // TODO: Handle settings! - std::optional> mDynamicRenderingAttachments; std::optional> mRenderPassSubpass; + std::optional> mDynamicRenderingAttachments; std::vector mInputBindingLocations; cfg::primitive_topology mPrimitiveTopology; std::vector mShaderInfos; @@ -681,19 +681,6 @@ namespace avk add_config(aConfig, aAttachments, aFunc, std::move(args)...); } - // Add a dynamic rendering attachment which are used when dynamic_rendering is enabled for this pipeline - template - void add_config(graphics_pipeline_config& aConfig, std::vector& aAttachments, std::function& aFunc, avk::dynamic_rendering_attachment aDynAttachment, Ts... args) - { - if(aConfig.mDynamicRenderingAttachments.has_value()) - { - aConfig.mDynamicRenderingAttachments.value().push_back(aDynAttachment); - } else { - aConfig.mDynamicRenderingAttachments = std::vector{aDynAttachment}; - } - add_config(aConfig, aAttachments, aFunc, std::move(args)...); - } - // Add a renderpass attachment to the (temporary) attachments vector and later build renderpass from them template void add_config(graphics_pipeline_config& aConfig, std::vector& aAttachments, std::function& aFunc, avk::attachment aAttachment, Ts... args) diff --git a/src/avk.cpp b/src/avk.cpp index ee5dc65..fa1dd91 100644 --- a/src/avk.cpp +++ b/src/avk.cpp @@ -1418,25 +1418,6 @@ namespace avk #pragma endregion #pragma region dynamic rendering attachment definitions - dynamic_rendering_attachment dynamic_rendering_attachment::declare(std::tuple aFormatAndSamples) - { - return dynamic_rendering_attachment{ - std::get(aFormatAndSamples), - std::get(aFormatAndSamples), - }; - } - - dynamic_rendering_attachment dynamic_rendering_attachment::declare(vk::Format aFormat) - { - return declare({aFormat, vk::SampleCountFlagBits::e1}); - } - - dynamic_rendering_attachment dynamic_rendering_attachment::declare_for(const image_view_t& aImageView) - { - const auto& imageConfig = aImageView.get_image().create_info(); - const auto format = imageConfig.format; - return declare(format); - } #pragma endregion #pragma region attachment definitions @@ -1449,7 +1430,8 @@ namespace avk {}, {}, std::move(aUsageInSubpasses), { 0.0, 0.0, 0.0, 0.0 }, - 1.0f, 0u + 1.0f, 0u, + false }; } @@ -1465,6 +1447,28 @@ namespace avk auto result = declare({format, imageConfig.samples}, aLoadOp, std::move(aUsageInSubpasses), aStoreOp); return result; } + + attachment attachment::declare_dynamic(std::tuple aFormatAndSamples) + { + return attachment{ + .mFormat = std::get(aFormatAndSamples), + .mSampleCount = std::get(aFormatAndSamples), + .mSubpassUsages = subpass_usages(subpass_usage_type::create_unused()), + .mDynamicRenderingAttachment = true + }; + } + + attachment attachment::declare_dynamic(vk::Format aFormat) + { + return declare_dynamic({aFormat, vk::SampleCountFlagBits::e1}); + } + + attachment attachment::declare_dynamic_for(const image_view_t& aImageView) + { + const auto& imageConfig = aImageView.get_image().create_info(); + const auto format = imageConfig.format; + return declare_dynamic(format); + } #pragma endregion #pragma region acceleration structure definitions @@ -4378,7 +4382,7 @@ namespace avk { aPreparedPipeline.mMultisampleStateCreateInfo .setRasterizationSamples( - aPreparedPipeline.renderpass_pointer().value()->num_samples_for_subpass(aPreparedPipeline.subpass_id().value())) + aPreparedPipeline.renderpass_reference().value().get().num_samples_for_subpass(aPreparedPipeline.subpass_id().value())) .setPSampleMask(nullptr); } @@ -4393,7 +4397,7 @@ namespace avk assert(static_cast(aPreparedPipeline.layout_handle())); const void * pNext = dynamicRenderingEnabled ? &(aPreparedPipeline.mRenderingCreateInfo.value()) : nullptr; - VkRenderPass render_pass{}; + VkRenderPass render_pass = VK_NULL_HANDLE; if(!dynamicRenderingEnabled) { render_pass = (aPreparedPipeline.mRenderPass.value())->handle(); @@ -4488,7 +4492,7 @@ namespace avk const bool dynamicRenderingEnabled = aConfig.mDynamicRendering == avk::cfg::dynamic_rendering::enabled; { - if(!dynamic_rendering_enabled) + if(!dynamicRenderingEnabled) { assert(aConfig.mRenderPassSubpass.has_value()); auto [rp, sp] = std::move(aConfig.mRenderPassSubpass.value()); @@ -4678,8 +4682,8 @@ namespace avk } // Iterate over all color target attachments and set a color blending config - size_t blending_config_num; - if (!dynamic_rendering_enabled) + size_t blendingConfigNum; + if (!dynamicRenderingEnabled) { const auto & renderPassVal = result.mRenderPass.value(); if (result.subpass_id() >= renderPassVal->attachment_descriptions().size()) { @@ -4690,7 +4694,7 @@ namespace avk + std::to_string(result.subpass_id().value()) + ") indicates. I.e. the subpass index is out of bounds."); } - blending_config_num = renderPassVal->color_attachments_for_subpass(result.subpass_id().value()).size(); /////////////////// TODO: (doublecheck or) FIX this section (after renderpass refactoring) + blendingConfigNum = renderPassVal->color_attachments_for_subpass(result.subpass_id().value()).size(); /////////////////// TODO: (doublecheck or) FIX this section (after renderpass refactoring) } // Renderpasses and Subpasses are not supported when dynamic rendering is enabled // Instead we read size of the dynamic_rendering_attachments provided @@ -4698,16 +4702,16 @@ namespace avk { blendingConfigNum = 0; - for(const auto & dyn_rendering_attachment : aConfig.mDynamicRenderingAttachments.value()) + for(const auto & dynRenderingAttachment : aConfig.mDynamicRenderingAttachments.value()) { - if(!is_depth_format(dyn_rendering_attachment.format())) + if(!is_depth_format(dynRenderingAttachment.format())) { - blending_config_num++; + blendingConfigNum++; } } } - result.mBlendingConfigsForColorAttachments.reserve(blending_config_num); // Important! Otherwise the vector might realloc and .data() will become invalid! - for (size_t i = 0; i < blending_config_num; ++i) { + result.mBlendingConfigsForColorAttachments.reserve(blendingConfigNum); // Important! Otherwise the vector might realloc and .data() will become invalid! + for (size_t i = 0; i < blendingConfigNum; ++i) { // Do we have a specific blending config for color attachment i? #if defined(_MSC_VER) && _MSC_VER < 1930 auto configForI = aConfig.mColorBlendingPerAttachment @@ -4755,7 +4759,7 @@ namespace avk // TODO: Can the settings be inferred from the renderpass' color attachments (as they are right now)? If they can't, how to handle this situation? { /////////////////// TODO: FIX this section (after renderpass refactoring) vk::SampleCountFlagBits numSamples = vk::SampleCountFlagBits::e1; - if(!dynamic_rendering_enabled) + if(!dynamicRenderingEnabled) { numSamples = result.mRenderPass.value()->num_samples_for_subpass(result.subpass_id().value()); } else { @@ -4865,19 +4869,19 @@ namespace avk .setPPushConstantRanges(result.mPushConstantRanges.data()); // 15. Set Rendering info if dynamic rendering is enabled - if(dynamic_rendering_enabled) + if(dynamicRenderingEnabled) { std::vector depth_attachments; std::vector stencil_attachments; - for(const auto & dynamic_rendering_attachment : aConfig.mDynamicRenderingAttachments.value()) + for(const auto & dynamicRenderingAttachment : aConfig.mDynamicRenderingAttachments.value()) { - if(is_depth_format(dynamic_rendering_attachment.format())) + if(is_depth_format(dynamicRenderingAttachment.format())) { - depth_attachments.push_back(dynamic_rendering_attachment.format()); - } else if (is_stencil_format(dynamic_rendering_attachment.format())) { - stencil_attachments.push_back(dynamic_rendering_attachment.format()); + depth_attachments.push_back(dynamicRenderingAttachment.format()); + } else if (is_stencil_format(dynamicRenderingAttachment.format())) { + stencil_attachments.push_back(dynamicRenderingAttachment.format()); } else { - result.mDynamicRenderingColorFormats.push_back(dynamic_rendering_attachment.format()); + result.mDynamicRenderingColorFormats.push_back(dynamicRenderingAttachment.format()); } } if(depth_attachments.size() > 1) { throw avk::runtime_error("Provided multiple depth attachments! Only one is supported!"); } @@ -4895,7 +4899,7 @@ namespace avk aAlterConfigBeforeCreation(result); } - assert (aConfig.mRenderPassSubpass.has_value() || dynamic_rendering_enabled); + assert (aConfig.mRenderPassSubpass.has_value() || dynamicRenderingEnabled); rewire_config_and_create_graphics_pipeline(result); return result; } From 98400d1d541c6a72fd63242b53055c0945a6bda9 Mon Sep 17 00:00:00 2001 From: MatejSakmary Date: Sat, 23 Mar 2024 01:02:56 +0100 Subject: [PATCH 07/18] PR proposed fixes (mostly cosmetic) + inital draft of MSAA support (needs to be discussed further) --- include/avk/attachment.hpp | 13 ++++---- include/avk/graphics_pipeline.hpp | 6 ++-- src/avk.cpp | 51 +++++++++++++++++-------------- 3 files changed, 37 insertions(+), 33 deletions(-) diff --git a/include/avk/attachment.hpp b/include/avk/attachment.hpp index 71e9d3e..1985d59 100644 --- a/include/avk/attachment.hpp +++ b/include/avk/attachment.hpp @@ -61,25 +61,26 @@ namespace avk static attachment declare_for(const image_view_t& aImageView, attachment_load_config aLoadOp, subpass_usages aUsageInSubpasses, attachment_store_config aStoreOp); /** Declare multisampled format of an attachment for a dynamic rendering pipeline. This attachment can only be used with pipeline that has dynamic rendering enabled. - * It has fewever parameters than regular attachment since some of its values (load/store ops etc...) are set when starting the dynamic render pass + * It has fewer parameters than regular attachment since some of its values (load/store ops etc...) are set when starting the dynamic render pass * as opposed to being declared beforehand.. * @param aFormatAndSamples Multisampled format definition: A tuple with the format of the attachment in its first element, and with the number of samples in its second element. */ - static attachment declare_dynamic(std::tuple aFormatAndSamples); + static attachment declare_dynamic(std::tuple aFormatAndSamples, subpass_usage_type aUsage); /** Declare multisampled format of an attachment for a dynamic rendering pipeline. This attachment can only be used with pipeline that has dynamic rendering enabled. - * It has fewever parameters than regular attachment since some of its values (load/store ops etc...) are set when starting the dynamic render pass + * It has fewer parameters than regular attachment since some of its values (load/store ops etc...) are set when starting the dynamic render pass * as opposed to being declared beforehand.. * @param aFormat The format of the attachment */ - static attachment declare_dynamic(vk::Format aFormat); + static attachment declare_dynamic(vk::Format aFormat, subpass_usage_type aUsage); /** Declare multisampled format of an attachment for a dynamic rendering pipeline. This attachment can only be used with pipeline that has dynamic rendering enabled. - * It has fewever parameters than regular attachment since some of its values (load/store ops etc...) are set when starting the dynamic render pass + * It has fewer parameters than regular attachment since some of its values (load/store ops etc...) are set when starting the dynamic render pass * as opposed to being declared beforehand.. * @param aImageView The format of the attachment is copied from the given image view. */ - static attachment declare_dynamic_for(const image_view_t& aImageView); + static attachment declare_dynamic_for(const image_view_t& aImageView, subpass_usage_type aUsage); + attachment& set_clear_color(std::array aColor) { mColorClearValue = aColor; return *this; } attachment& set_depth_clear_value(float aDepthClear) { mDepthClearValue = aDepthClear; return *this; } diff --git a/include/avk/graphics_pipeline.hpp b/include/avk/graphics_pipeline.hpp index d9a97d7..7d4a817 100644 --- a/include/avk/graphics_pipeline.hpp +++ b/include/avk/graphics_pipeline.hpp @@ -23,8 +23,7 @@ namespace avk if(mRenderPass.has_value()) { return std::cref(mRenderPass.value().get()); } else { return std::nullopt; } } - // TODO(msakmary) Perhaps I just return std::optional here? It would probably be more readable then declval - auto renderpass_handle() const -> std::optional().handle())> + auto renderpass_handle() const -> std::optional { if(mRenderPass.has_value()) {return mRenderPass.value()->handle();} else {return std::nullopt;} @@ -32,8 +31,7 @@ namespace avk auto subpass_id() const -> std::optional { if(mRenderPass.has_value()) {return mSubpassIndex;} - // TODO(msakmary) change subpass index to int and make -1 invalid value or perhaps add on optional here? - else {return -1;} + else {return std::nullopt;} }; auto& vertex_input_binding_descriptions() { return mOrderedVertexInputBindingDescriptions; } auto& vertex_input_attribute_descriptions() { return mVertexInputAttributeDescriptions; } diff --git a/src/avk.cpp b/src/avk.cpp index fa1dd91..6bbf48d 100644 --- a/src/avk.cpp +++ b/src/avk.cpp @@ -1448,26 +1448,27 @@ namespace avk return result; } - attachment attachment::declare_dynamic(std::tuple aFormatAndSamples) + attachment attachment::declare_dynamic(std::tuple aFormatAndSamples, subpass_usage_type aUsage) { return attachment{ .mFormat = std::get(aFormatAndSamples), .mSampleCount = std::get(aFormatAndSamples), - .mSubpassUsages = subpass_usages(subpass_usage_type::create_unused()), + .mSubpassUsages = subpass_usages(aUsage), .mDynamicRenderingAttachment = true }; } - attachment attachment::declare_dynamic(vk::Format aFormat) + attachment attachment::declare_dynamic(vk::Format aFormat, subpass_usage_type aUsage) { - return declare_dynamic({aFormat, vk::SampleCountFlagBits::e1}); + return declare_dynamic({aFormat, vk::SampleCountFlagBits::e1}, aUsage); } - attachment attachment::declare_dynamic_for(const image_view_t& aImageView) + attachment attachment::declare_dynamic_for(const image_view_t& aImageView, subpass_usage_type aUsage) { const auto& imageConfig = aImageView.get_image().create_info(); const auto format = imageConfig.format; - return declare_dynamic(format); + const auto samples = imageConfig.samples; + return declare_dynamic({format, samples}, aUsage); } #pragma endregion @@ -4763,18 +4764,18 @@ namespace avk { numSamples = result.mRenderPass.value()->num_samples_for_subpass(result.subpass_id().value()); } else { - const auto & dynamicRenderingAttachments = aConfig.mDynamicRenderingAttachments.value(); - numSamples = dynamicRenderingAttachments.at(0).sample_count(); -#if defined(_DEBUG) - for(int attachment_idx = 1; attachment_idx < dynamicRenderingAttachments.size(); attachment_idx++) + for(const auto & attachment : aConfig.mDynamicRenderingAttachments.value()) { - if(numSamples != dynamicRenderingAttachments.at(attachment_idx).sample_count()) + if(attachment.is_multisampled()) { - //TODO(msakmary) This may be possible with some extension I'm not 100% sure... - throw avk::runtime_error("Cannot have different sample counts for attachments in the same renderpass"); + if(numSamples != vk::SampleCountFlagBits::e1 && numSamples != attachment.sample_count()) + { + //NOTE(msakmary) This may be possible with some extension I'm not 100% sure... + throw avk::runtime_error("Cannot have different sample counts for attachments in the same renderpass"); + } + numSamples = attachment.sample_count(); } } -#endif } // Evaluate and set the PER SAMPLE shading configuration: @@ -8382,9 +8383,9 @@ namespace avk uint32_t aLayerCount) { #ifdef _DEBUG - if (aAttachments.size() != aImageViews.size()) { - throw avk::runtime_error("Incomplete config for begin dynamic rendering: number of attachments (" + std::to_string(aAttachments.size()) + ") does not equal the number of image views (" + std::to_string(aImageViews.size()) + ")"); - } + // if (aAttachments.size() != aImageViews.size()) { + // throw avk::runtime_error("Incomplete config for begin dynamic rendering: number of attachments (" + std::to_string(aAttachments.size()) + ") does not equal the number of image views (" + std::to_string(aImageViews.size()) + ")"); + // } auto n = aAttachments.size(); for (size_t i = 0; i < n; ++i) { auto& a = aAttachments[i]; @@ -8392,6 +8393,10 @@ namespace avk if ((is_depth_format(v->get_image().format()) || has_stencil_component(v->get_image().format())) && !a.is_used_as_depth_stencil_attachment()) { AVK_LOG_WARNING("Possibly misconfigured framebuffer: image[" + std::to_string(i) + "] is a depth/stencil format, but it is never indicated to be used as such in the attachment-description[" + std::to_string(i) + "]."); } + if(!a.is_for_dynamic_rendering()) + { + AVK_LOG_WARNING("Provided attachment which was not created compatible with dynamic rendering. Please provide an attachment created with one of the declare_dynamic_* functions"); + } } #endif //_DEBUG const bool detectExtent = !aRenderAreaExtent.has_value(); @@ -8427,14 +8432,15 @@ namespace avk #endif //_DEBUG if(currAttachment.is_used_as_color_attachment()) { + const auto & usage = currAttachment.mSubpassUsages.get_subpass_usage(0); colorAttachments.push_back( vk::RenderingAttachmentInfoKHR{} .setImageView(currImageView->handle()) .setImageLayout(vk::ImageLayout::eColorAttachmentOptimal) - // TODO(msakmary) add support for resolve and MSAA - // .setResolveMode() - // .setResolveImageView() - // .setResolveImageLayout() + .setResolveMode(usage.mResolve ? vk::ResolveModeFlagBits::eAverage : vk::ResolveModeFlagBits::eNone) + .setResolveImageView(usage.mResolve ? aImageViews.at(usage.mResolveAttachmentIndex)->handle() : VK_NULL_HANDLE) + // TODO(msakmary) What here?? + .setResolveImageLayout(vk::ImageLayout::eColorAttachmentOptimal) .setLoadOp(to_vk_load_op(currAttachment.mLoadOperation.mLoadBehavior)) .setStoreOp(to_vk_store_op(currAttachment.mStoreOperation.mStoreBehavior)) .setClearValue(vk::ClearColorValue(currAttachment.clear_color())) @@ -8442,7 +8448,7 @@ namespace avk } else // currAttachment is either used as depth or as stencil { - // TODO(msakmary): This will brake if we want depth image and stencil both D24S8 but separate images (so two D24S8 images + // NOTE(msakmary): This will brake if we want depth image and stencil both D24S8 but separate images (so two D24S8 images // one used as depth one as stencil) probably should have this info in a custom attachment type. // I think something like begin_rendering_attachment should be added which would have an explicit field // which would denote how to use the attachment - use this attachment as stencil, depth or color @@ -8524,7 +8530,6 @@ namespace avk { return action_type_command { - // TODO(msakmary) I'm copying end renderpass here but I'm not sure this is correct? avk::sync::sync_hint { {{ // What previous commands must synchronize with: vk::PipelineStageFlagBits2KHR::eAllCommands, // eAllGraphics does not include new stages or ext-stages. Therefore, eAllCommands! From e58f0ad0f0a48e5873d61d77e73ed68b57a0f710 Mon Sep 17 00:00:00 2001 From: MatejSakmary Date: Thu, 28 Mar 2024 14:34:40 +0100 Subject: [PATCH 08/18] Modified dynamic rendering attachments to take in subpass_usages and modified the dynamic functionality to conform to these usages --- include/avk/attachment.hpp | 13 +++++-- src/avk.cpp | 78 +++++++++++++++++++++++--------------- 2 files changed, 57 insertions(+), 34 deletions(-) diff --git a/include/avk/attachment.hpp b/include/avk/attachment.hpp index 1985d59..6bf62a1 100644 --- a/include/avk/attachment.hpp +++ b/include/avk/attachment.hpp @@ -64,22 +64,29 @@ namespace avk * It has fewer parameters than regular attachment since some of its values (load/store ops etc...) are set when starting the dynamic render pass * as opposed to being declared beforehand.. * @param aFormatAndSamples Multisampled format definition: A tuple with the format of the attachment in its first element, and with the number of samples in its second element. + * @param aUsage How is this attachment being used in the renderpass? In contrast to non-dynamic attachments, this usage can only contain a single subpass as such + * Possible values in namespace avk::usage:: + * Usages for different subpasses can be defined by concatenating them using operator>>. + * Example 1: avk::usage::color(0) // Indicates that this attachment is used as color attachment at location=0 in the renderpass + * Example 2: avk::usage::color(2) + usage::resolve_to(3) // Indicates that this attachment is used as color attachment at location=2 in the renderpass + * // Additionally, at the end of renderpass, its contents are resolved into the attachment at index 3. + * Example 3: usage::unused // Indicates that this attachment is unused in the renderpass (it will only be used as a resolve target for example) */ - static attachment declare_dynamic(std::tuple aFormatAndSamples, subpass_usage_type aUsage); + static attachment declare_dynamic(std::tuple aFormatAndSamples, subpass_usages aUsage); /** Declare multisampled format of an attachment for a dynamic rendering pipeline. This attachment can only be used with pipeline that has dynamic rendering enabled. * It has fewer parameters than regular attachment since some of its values (load/store ops etc...) are set when starting the dynamic render pass * as opposed to being declared beforehand.. * @param aFormat The format of the attachment */ - static attachment declare_dynamic(vk::Format aFormat, subpass_usage_type aUsage); + static attachment declare_dynamic(vk::Format aFormat, subpass_usages aUsage); /** Declare multisampled format of an attachment for a dynamic rendering pipeline. This attachment can only be used with pipeline that has dynamic rendering enabled. * It has fewer parameters than regular attachment since some of its values (load/store ops etc...) are set when starting the dynamic render pass * as opposed to being declared beforehand.. * @param aImageView The format of the attachment is copied from the given image view. */ - static attachment declare_dynamic_for(const image_view_t& aImageView, subpass_usage_type aUsage); + static attachment declare_dynamic_for(const image_view_t& aImageView, subpass_usages aUsage); attachment& set_clear_color(std::array aColor) { mColorClearValue = aColor; return *this; } diff --git a/src/avk.cpp b/src/avk.cpp index 6bbf48d..327a8bf 100644 --- a/src/avk.cpp +++ b/src/avk.cpp @@ -1448,8 +1448,12 @@ namespace avk return result; } - attachment attachment::declare_dynamic(std::tuple aFormatAndSamples, subpass_usage_type aUsage) + attachment attachment::declare_dynamic(std::tuple aFormatAndSamples, subpass_usages aUsage) { + if(aUsage.num_subpasses() != 1) + { + throw avk::runtime_error("Dynamic rendering does not support multiple subpasses, please only provide usage with a single subpass"); + } return attachment{ .mFormat = std::get(aFormatAndSamples), .mSampleCount = std::get(aFormatAndSamples), @@ -1458,12 +1462,12 @@ namespace avk }; } - attachment attachment::declare_dynamic(vk::Format aFormat, subpass_usage_type aUsage) + attachment attachment::declare_dynamic(vk::Format aFormat, subpass_usages aUsage) { return declare_dynamic({aFormat, vk::SampleCountFlagBits::e1}, aUsage); } - attachment attachment::declare_dynamic_for(const image_view_t& aImageView, subpass_usage_type aUsage) + attachment attachment::declare_dynamic_for(const image_view_t& aImageView, subpass_usages aUsage) { const auto& imageConfig = aImageView.get_image().create_info(); const auto format = imageConfig.format; @@ -4705,7 +4709,7 @@ namespace avk for(const auto & dynRenderingAttachment : aConfig.mDynamicRenderingAttachments.value()) { - if(!is_depth_format(dynRenderingAttachment.format())) + if(dynRenderingAttachment.mSubpassUsages.contains_color()) { blendingConfigNum++; } @@ -4876,12 +4880,11 @@ namespace avk std::vector stencil_attachments; for(const auto & dynamicRenderingAttachment : aConfig.mDynamicRenderingAttachments.value()) { - if(is_depth_format(dynamicRenderingAttachment.format())) - { + if(is_depth_format(dynamicRenderingAttachment.format())) { depth_attachments.push_back(dynamicRenderingAttachment.format()); } else if (is_stencil_format(dynamicRenderingAttachment.format())) { stencil_attachments.push_back(dynamicRenderingAttachment.format()); - } else { + } else if (!dynamicRenderingAttachment.mSubpassUsages.get_subpass_usage(0).as_color()) { result.mDynamicRenderingColorFormats.push_back(dynamicRenderingAttachment.format()); } } @@ -8383,9 +8386,9 @@ namespace avk uint32_t aLayerCount) { #ifdef _DEBUG - // if (aAttachments.size() != aImageViews.size()) { - // throw avk::runtime_error("Incomplete config for begin dynamic rendering: number of attachments (" + std::to_string(aAttachments.size()) + ") does not equal the number of image views (" + std::to_string(aImageViews.size()) + ")"); - // } + if (aAttachments.size() != aImageViews.size()) { + throw avk::runtime_error("Incomplete config for begin dynamic rendering: number of attachments (" + std::to_string(aAttachments.size()) + ") does not equal the number of image views (" + std::to_string(aImageViews.size()) + ")"); + } auto n = aAttachments.size(); for (size_t i = 0; i < n; ++i) { auto& a = aAttachments[i]; @@ -8400,13 +8403,16 @@ namespace avk } #endif //_DEBUG const bool detectExtent = !aRenderAreaExtent.has_value(); - std::vector colorAttachments = {}; + std::vector> unsortedColorAttachments = {}; std::optional depthAttachment = {}; std::optional stencilAttachment = {}; // First parse all the attachments into vulkan structs for(uint32_t attachmentIndex = 0; attachmentIndex < aAttachments.size(); attachmentIndex++) { const auto & currAttachment = aAttachments.at(attachmentIndex); + // Unused attachments should not contribute to any rendering + if(currAttachment.mSubpassUsages.contains_unused()) { continue; } + const auto & currImageView = aImageViews.at(attachmentIndex); if(detectExtent && !aRenderAreaExtent.has_value()) { @@ -8432,18 +8438,20 @@ namespace avk #endif //_DEBUG if(currAttachment.is_used_as_color_attachment()) { - const auto & usage = currAttachment.mSubpassUsages.get_subpass_usage(0); - colorAttachments.push_back( - vk::RenderingAttachmentInfoKHR{} - .setImageView(currImageView->handle()) - .setImageLayout(vk::ImageLayout::eColorAttachmentOptimal) - .setResolveMode(usage.mResolve ? vk::ResolveModeFlagBits::eAverage : vk::ResolveModeFlagBits::eNone) - .setResolveImageView(usage.mResolve ? aImageViews.at(usage.mResolveAttachmentIndex)->handle() : VK_NULL_HANDLE) - // TODO(msakmary) What here?? - .setResolveImageLayout(vk::ImageLayout::eColorAttachmentOptimal) - .setLoadOp(to_vk_load_op(currAttachment.mLoadOperation.mLoadBehavior)) - .setStoreOp(to_vk_store_op(currAttachment.mStoreOperation.mStoreBehavior)) - .setClearValue(vk::ClearColorValue(currAttachment.clear_color())) + const auto usage = currAttachment.mSubpassUsages.get_subpass_usage(0); + const bool shouldResolve = currAttachment.is_to_be_resolved(); + unsortedColorAttachments.push_back({ + vk::RenderingAttachmentInfoKHR{} + .setImageView(currImageView->handle()) + .setImageLayout(vk::ImageLayout::eColorAttachmentOptimal) + .setResolveMode(shouldResolve ? vk::ResolveModeFlagBits::eAverage : vk::ResolveModeFlagBits::eNone) + .setResolveImageView(shouldResolve ? aImageViews.at(usage.mResolveAttachmentIndex)->handle() : VK_NULL_HANDLE) + .setResolveImageLayout(vk::ImageLayout::eColorAttachmentOptimal) + .setLoadOp(to_vk_load_op(currAttachment.mLoadOperation.mLoadBehavior)) + .setStoreOp(to_vk_store_op(currAttachment.mStoreOperation.mStoreBehavior)) + .setClearValue(vk::ClearColorValue(currAttachment.clear_color())), + usage.color_location() + } ); } else // currAttachment is either used as depth or as stencil @@ -8458,13 +8466,14 @@ namespace avk { throw avk::runtime_error("Multiple depth attachments provided! Please provide only a single depth attachment"); } + const auto usage = currAttachment.mSubpassUsages.get_subpass_usage(0); + const bool shouldResolve = currAttachment.is_to_be_resolved(); depthAttachment = vk::RenderingAttachmentInfoKHR{} .setImageView(currImageView->handle()) .setImageLayout(vk::ImageLayout::eAttachmentOptimal) - // TODO(msakmary) add support for resolve and MSAA - // .setResolveMode() - // .setResolveImageView() - // .setResolveImageLayout() + .setResolveMode(shouldResolve ? static_cast(static_cast(usage.mResolveModeDepth)) : vk::ResolveModeFlagBits::eNone) + .setResolveImageView(shouldResolve ? aImageViews.at(usage.mResolveAttachmentIndex)->handle() : VK_NULL_HANDLE) + .setResolveImageLayout(vk::ImageLayout::eAttachmentOptimal) .setLoadOp(to_vk_load_op(currAttachment.mLoadOperation.mLoadBehavior)) .setStoreOp(to_vk_store_op(currAttachment.mStoreOperation.mStoreBehavior)) .setClearValue(vk::ClearDepthStencilValue( @@ -8477,13 +8486,14 @@ namespace avk { throw avk::runtime_error("Multiple stencil attachments provided! Please provide only a single stencil attachment"); } + const auto usage = currAttachment.mSubpassUsages.get_subpass_usage(0); + const bool shouldResolve = currAttachment.is_to_be_resolved(); stencilAttachment = vk::RenderingAttachmentInfoKHR{} .setImageView(currImageView->handle()) .setImageLayout(vk::ImageLayout::eAttachmentOptimal) - // TODO(msakmary) add support for resolve and MSAA - // .setResolveMode() - // .setResolveImageView() - // .setResolveImageLayout() + .setResolveMode(shouldResolve ? static_cast(static_cast(usage.mResolveModeStencil)) : vk::ResolveModeFlagBits::eNone) + .setResolveImageView(shouldResolve ? aImageViews.at(usage.mResolveAttachmentIndex)->handle() : VK_NULL_HANDLE) + .setResolveImageLayout(vk::ImageLayout::eAttachmentOptimal) .setLoadOp(to_vk_load_op(currAttachment.mLoadOperation.mLoadBehavior)) .setStoreOp(to_vk_store_op(currAttachment.mStoreOperation.mStoreBehavior)) .setClearValue(vk::ClearDepthStencilValue( @@ -8492,6 +8502,12 @@ namespace avk } } } + std::sort(unsortedColorAttachments.begin(), unsortedColorAttachments.end(), + [](const auto & a, const auto & b) -> bool { return a.second < b.second; } + ); + std::vector colorAttachments = {}; + colorAttachments.reserve(unsortedColorAttachments.size()); + for(const auto & attachmentPair : unsortedColorAttachments) { colorAttachments.push_back(attachmentPair.first); } return action_type_command{ avk::sync::sync_hint { From f34f844a3f2d1dff3c38f08e6e8d88ca73e85f2e Mon Sep 17 00:00:00 2001 From: MatejSakmary Date: Thu, 28 Mar 2024 14:42:35 +0100 Subject: [PATCH 09/18] Added View mask to begin dynamic rendering parameters --- include/avk/commands.hpp | 2 +- src/avk.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/include/avk/commands.hpp b/include/avk/commands.hpp index 035ea3e..0d85fab 100644 --- a/include/avk/commands.hpp +++ b/include/avk/commands.hpp @@ -514,7 +514,7 @@ namespace avk * @param aRenderAreaExtent Render area extent (default is full extent inferred from images passed in aImageViews) * @param aLayerCount number of layers that will be used for rendering (default is 1) */ - extern action_type_command begin_dynamic_rendering(std::vector aAttachments, std::vector aImageViews, vk::Offset2D aRenderAreaOffset = {0, 0}, std::optional aRenderAreaExtent = {}, uint32_t aLayerCount = 1); + extern action_type_command begin_dynamic_rendering(std::vector aAttachments, std::vector aImageViews, vk::Offset2D aRenderAreaOffset = {0, 0}, std::optional aRenderAreaExtent = {}, uint32_t aLayerCount = 1, uint32_t aViewMask = 0); /** Ends dynamic rendering scope */ diff --git a/src/avk.cpp b/src/avk.cpp index 327a8bf..1e65838 100644 --- a/src/avk.cpp +++ b/src/avk.cpp @@ -8383,7 +8383,8 @@ namespace avk std::vector aImageViews, vk::Offset2D aRenderAreaOffset, std::optional aRenderAreaExtent, - uint32_t aLayerCount) + uint32_t aLayerCount, + uint32_t aViewMask) { #ifdef _DEBUG if (aAttachments.size() != aImageViews.size()) { @@ -8526,13 +8527,14 @@ namespace avk depthAttachment, stencilAttachment, aLayerCount, + aViewMask, aRenderAreaOffset, aRenderAreaExtent ](avk::command_buffer_t& cb) { auto const renderingInfo = vk::RenderingInfoKHR{} .setRenderArea(vk::Rect2D(aRenderAreaOffset, aRenderAreaExtent.value())) .setLayerCount(aLayerCount) - .setViewMask(0) //TODO(msakmary) this is for multiview - do we want to support it? + .setViewMask(aViewMask) .setColorAttachmentCount(static_cast(colorAttachments.size())) .setPColorAttachments(colorAttachments.data()) .setPDepthAttachment(depthAttachment.has_value() ? &depthAttachment.value() : nullptr) From b09a32611f7650c8a5c9ace7ff1e2f7eca5ca0ba Mon Sep 17 00:00:00 2001 From: Johannes Unterguggenberger Date: Fri, 12 Apr 2024 11:24:17 +0200 Subject: [PATCH 10/18] Trying to fix GitHub workflows --- .github/workflows/build.yml | 38 ++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 23a690f..ab12c4c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -28,19 +28,19 @@ jobs: #} - { name: "linux: gcc", - cc: "gcc-10", - cxx: "g++-10" + cc: "gcc-13", + cxx: "g++-13" } # note: if a specific vulkan version (e.g. 1.1.x, or < 1.2.135) needs testing, you can add it here: # (not that ubuntu-latest (20.04) only supports >= v1.2.148 via apt) - vulkan-sdk: ["latest", "1.2.176"] + vulkan-sdk: ["latest", "1.3.216"] vma: ["ON", "OFF"] exclude: # exclude combinations that are known to fail - vulkan-sdk: "1.2.176" vma: "ON" steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Create Build Environment shell: bash @@ -55,13 +55,18 @@ jobs: sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-${{ matrix.vulkan-sdk }}-focal.list https://packages.lunarg.com/vulkan/${{ matrix.vulkan-sdk }}/lunarg-vulkan-${{ matrix.vulkan-sdk }}-focal.list fi + # For GCC-13 + sudo add-apt-repository -y ppa:ubuntu-toolchain-r/ppa + # Update package lists sudo apt-get update -qq # Install dependencies sudo apt-get install -y \ vulkan-sdk - + g++-13 \ + gcc-13 + # clang does not yet (<= 12) support "Down with typename" (P0634R3), which is used in libstdc++ >= 11 in the ranges-header if [ "${{ matrix.config.cc }}" = "clang" ]; then sudo apt remove libgcc-11-dev gcc-11 @@ -89,7 +94,7 @@ jobs: run: cmake --build . windows: - name: ${{ matrix.config.name }}, VulkanSDK ${{ matrix.vulkan-sdk }}, VMA=${{ matrix.vma }} + name: ${{ matrix.config.name }}, windows-2019, VulkanSDK ${{ matrix.vulkan-sdk }}, VMA=${{ matrix.vma }} runs-on: windows-2019 env: vulkan_sdk: "$GITHUB_WORKSPACE/vulkan_sdk/" @@ -102,7 +107,7 @@ jobs: cc: "cl", cxx: "cl" } - # note: if a specific vulkan version (e.g. 1.1.x, or < 1.2.135) needs testing, you can add it here: + # note: if a specific vulkan version needs testing, you can add it here: vulkan-sdk: ["latest", "1.3.216.0", "1.2.198.1"] vma: ["ON", "OFF"] exclude: # exclude combinations that are known to fail @@ -110,8 +115,8 @@ jobs: vma: "ON" steps: - # apparently checkout@v2 pulls to Auto-Vk/Auto-Vk on windows - - uses: actions/checkout@v2 + # apparently checkout@v3 pulls to Auto-Vk/Auto-Vk on windows + - uses: actions/checkout@v3 - name: Create Build Environment # apparently checkout@v2 pulls to Auto-Vk/Auto-Vk on windows @@ -158,7 +163,7 @@ jobs: run: cmake --build . windows-latest: - name: ${{ matrix.config.name }}, VulkanSDK ${{ matrix.vulkan-sdk }}, VMA=${{ matrix.vma }} + name: ${{ matrix.config.name }}, windows-latest, VulkanSDK ${{ matrix.vulkan-sdk }}, VMA=${{ matrix.vma }} runs-on: windows-latest env: vulkan_sdk: "$GITHUB_WORKSPACE/vulkan_sdk/" @@ -179,11 +184,11 @@ jobs: vma: "ON" steps: - # apparently checkout@v2 pulls to Auto-Vk/Auto-Vk on windows - - uses: actions/checkout@v2 + # apparently checkout@v3 pulls to Auto-Vk/Auto-Vk on windows + - uses: actions/checkout@v3 - name: Create Build Environment - # apparently checkout@v2 pulls to Auto-Vk/Auto-Vk on windows + # apparently checkout@v3 pulls to Auto-Vk/Auto-Vk on windows working-directory: ${{ runner.workspace }}/${{ github.event.repository.name }} shell: pwsh # Some projects don't allow in-source building, so create a separate build directory @@ -199,7 +204,7 @@ jobs: mkdir "${{ env.vulkan_sdk }}Include/vma/" curl -LS -o "${{ env.vulkan_sdk }}Include/vma/vk_mem_alloc.h" https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator/blob/master/include/vk_mem_alloc.h?raw=true - # apparently checkout@v2 pulls to Auto-Vk/Auto-Vk on windows + # apparently checkout@v3 pulls to Auto-Vk/Auto-Vk on windows cmake -E make_directory ${{ runner.workspace }}/${{ github.event.repository.name }}/build - name: Configure CMake @@ -214,6 +219,9 @@ jobs: run: | $env:CC="${{ matrix.config.cc }}" $env:CXX="${{ matrix.config.cxx }}" + $env:VULKAN_SDK="${{ env.vulkan_sdk }}" + $env:Vulkan_LIBRARY="${{ env.vulkan_sdk }}/Bin" + $env:Vulkan_INCLUDE_DIR="${{ env.vulkan_sdk }}/Include" $env:Path += ";${{ env.vulkan_sdk }}\;${{ env.vulkan_sdk }}\Bin\" # apparently checkout@v2 pulls to Auto-Vk/Auto-Vk on windows @@ -221,7 +229,7 @@ jobs: - name: Build shell: bash - # apparently checkout@v2 pulls to Auto-Vk/Auto-Vk on windows + # apparently checkout@v3 pulls to Auto-Vk/Auto-Vk on windows working-directory: ${{ runner.workspace }}/${{ github.event.repository.name }}/build # Execute the build. You can specify a specific target with "--target " run: cmake --build . From 081f9e856d6ad2bcb62f9c1cfa0bb3c7a6348822 Mon Sep 17 00:00:00 2001 From: Johannes Unterguggenberger Date: Fri, 12 Apr 2024 12:44:31 +0200 Subject: [PATCH 11/18] Trying to fix GitHub workflows --- .github/workflows/build.yml | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c336e46..77a97f0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -63,7 +63,7 @@ jobs: # Install dependencies sudo apt-get install -y \ - vulkan-sdk + vulkan-sdk \ g++-13 \ gcc-13 @@ -91,7 +91,7 @@ jobs: shell: bash working-directory: ${{ runner.workspace }}/build # Execute the build. You can specify a specific target with "--target " - run: cmake --build . --config $BUILD_TYPE + run: cmake --build . windows: name: ${{ matrix.config.name }}, windows-2019, VulkanSDK ${{ matrix.vulkan-sdk }}, VMA=${{ matrix.vma }} @@ -119,7 +119,7 @@ jobs: - uses: actions/checkout@v3 - name: Create Build Environment - # apparently checkout@v2 pulls to Auto-Vk/Auto-Vk on windows + # apparently checkout@v3 pulls to Auto-Vk/Auto-Vk on windows working-directory: ${{ runner.workspace }}/${{ github.event.repository.name }} shell: pwsh # Some projects don't allow in-source building, so create a separate build directory @@ -160,10 +160,10 @@ jobs: - name: Build shell: bash - # apparently checkout@v2 pulls to Auto-Vk/Auto-Vk on windows + # apparently checkout@v3 pulls to Auto-Vk/Auto-Vk on windows working-directory: ${{ runner.workspace }}/${{ github.event.repository.name }}/build # Execute the build. You can specify a specific target with "--target " - run: cmake --build . --config $BUILD_TYPE + run: VULKAN_SDK=${{ env.vulkan_sdk }} cmake --build . --config $BUILD_TYPE windows-latest: name: ${{ matrix.config.name }}, windows-latest, VulkanSDK ${{ matrix.vulkan-sdk }}, VMA=${{ matrix.vma }} @@ -226,11 +226,6 @@ jobs: $env:Vulkan_LIBRARY="${{ env.vulkan_sdk }}/Bin" $env:Vulkan_INCLUDE_DIR="${{ env.vulkan_sdk }}/Include" $env:Path += ";${{ env.vulkan_sdk }}\;${{ env.vulkan_sdk }}\Bin\" - $env:VULKAN_SDK="${{ env.vulkan_sdk }}" - $env:Vulkan_LIBRARY="${{ env.vulkan_sdk }}/Bin" - $env:Vulkan_INCLUDE_DIR="${{ env.vulkan_sdk }}/Include" - - # apparently checkout@v2 pulls to Auto-Vk/Auto-Vk on windows cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -Davk_LibraryType=STATIC ${{ runner.workspace }}/${{ github.event.repository.name }} -Davk_UseVMA=${{ matrix.vma }} -G "Visual Studio 17 2022" -A x64 - name: Build From 5cda69238e7c19d26a65990ebff06d6142eff1f7 Mon Sep 17 00:00:00 2001 From: Johannes Unterguggenberger Date: Fri, 12 Apr 2024 13:10:55 +0200 Subject: [PATCH 12/18] Using Invoke-WebRequest instead of curl --- .github/workflows/build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 77a97f0..0b1f35f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -127,13 +127,13 @@ jobs: run: | If ('${{ matrix.vulkan-sdk }}' -eq 'latest') { # the download URL for the latest SDK version changes sometimes (every four months or so?)... - curl -LS -o vulkan-sdk.exe https://sdk.lunarg.com/sdk/download/latest/windows/vulkan-sdk.exe + Invoke-WebRequest -Uri https://sdk.lunarg.com/sdk/download/latest/windows/vulkan-sdk.exe -OutFile vulkan-sdk.exe } Else { - curl -LS -o vulkan-sdk.exe https://sdk.lunarg.com/sdk/download/${{ matrix.vulkan-sdk }}/windows/VulkanSDK-${{ matrix.vulkan-sdk }}-Installer.exe + Invoke-WebRequest -Uri https://sdk.lunarg.com/sdk/download/${{ matrix.vulkan-sdk }}/windows/VulkanSDK-${{ matrix.vulkan-sdk }}-Installer.exe -OutFile vulkan-sdk.exe } 7z x vulkan-sdk.exe -o"${{ env.vulkan_sdk }}" mkdir "${{ env.vulkan_sdk }}Include/vma/" - curl -LS -o "${{ env.vulkan_sdk }}Include/vma/vk_mem_alloc.h" https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator/blob/master/include/vk_mem_alloc.h?raw=true + Invoke-WebRequest -Uri https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator/blob/master/include/vk_mem_alloc.h?raw=true -OutFile "${{ env.vulkan_sdk }}Include/vma/vk_mem_alloc.h" # apparently checkout@v2 pulls to Auto-Vk/Auto-Vk on windows cmake -E make_directory ${{ runner.workspace }}/${{ github.event.repository.name }}/build From d31008004e85c9458a1e8c771efbbf5faec72465 Mon Sep 17 00:00:00 2001 From: Johannes Unterguggenberger Date: Fri, 12 Apr 2024 13:14:57 +0200 Subject: [PATCH 13/18] Reverted the last change --- .github/workflows/build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0b1f35f..77a97f0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -127,13 +127,13 @@ jobs: run: | If ('${{ matrix.vulkan-sdk }}' -eq 'latest') { # the download URL for the latest SDK version changes sometimes (every four months or so?)... - Invoke-WebRequest -Uri https://sdk.lunarg.com/sdk/download/latest/windows/vulkan-sdk.exe -OutFile vulkan-sdk.exe + curl -LS -o vulkan-sdk.exe https://sdk.lunarg.com/sdk/download/latest/windows/vulkan-sdk.exe } Else { - Invoke-WebRequest -Uri https://sdk.lunarg.com/sdk/download/${{ matrix.vulkan-sdk }}/windows/VulkanSDK-${{ matrix.vulkan-sdk }}-Installer.exe -OutFile vulkan-sdk.exe + curl -LS -o vulkan-sdk.exe https://sdk.lunarg.com/sdk/download/${{ matrix.vulkan-sdk }}/windows/VulkanSDK-${{ matrix.vulkan-sdk }}-Installer.exe } 7z x vulkan-sdk.exe -o"${{ env.vulkan_sdk }}" mkdir "${{ env.vulkan_sdk }}Include/vma/" - Invoke-WebRequest -Uri https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator/blob/master/include/vk_mem_alloc.h?raw=true -OutFile "${{ env.vulkan_sdk }}Include/vma/vk_mem_alloc.h" + curl -LS -o "${{ env.vulkan_sdk }}Include/vma/vk_mem_alloc.h" https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator/blob/master/include/vk_mem_alloc.h?raw=true # apparently checkout@v2 pulls to Auto-Vk/Auto-Vk on windows cmake -E make_directory ${{ runner.workspace }}/${{ github.event.repository.name }}/build From 4aaeb37ea15493b1a69f505721ae0ae9a897321d Mon Sep 17 00:00:00 2001 From: Johannes Unterguggenberger Date: Fri, 12 Apr 2024 13:17:07 +0200 Subject: [PATCH 14/18] I have no idea what I'm doing --- CMakeLists.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 47e22ef..486e151 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,9 @@ -cmake_minimum_required(VERSION 3.13) +cmake_minimum_required(VERSION 3.16) project(avk) if (MSVC) # support requires /std:c++latest on MSVC - set(CMAKE_CXX_STANDARD 23) - add_compile_options(/bigobj) + set(CMAKE_CXX_STANDARD 20) else (MSVC) set(CMAKE_CXX_STANDARD 20) endif (MSVC) From d06ff392caf44ae998d343c019022ab452fedcb7 Mon Sep 17 00:00:00 2001 From: Johannes Unterguggenberger Date: Fri, 12 Apr 2024 13:24:03 +0200 Subject: [PATCH 15/18] Moving two vulkan-hpp includes a bit down, namely: #include #include --- src/avk.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/avk.cpp b/src/avk.cpp index 9f8a942..534de92 100644 --- a/src/avk.cpp +++ b/src/avk.cpp @@ -1,5 +1,3 @@ -#include -#include #define NOMINMAX #include #include "avk/avk.hpp" @@ -13,6 +11,9 @@ #endif #endif +#include +#include + namespace avk { #pragma region root definitions From 48136de91b9ac77fbd6f772860eb5794e83a2996 Mon Sep 17 00:00:00 2001 From: Johannes Unterguggenberger Date: Fri, 12 Apr 2024 13:26:57 +0200 Subject: [PATCH 16/18] Testing ["latest", "1.3.216.0", "1.2.198.1"] also in windows-latest --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 77a97f0..ffb259e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -180,7 +180,7 @@ jobs: cxx: "cl" } # note: if a specific vulkan version needs testing, you can add it here: - vulkan-sdk: ["latest", "1.3.204.1", "1.3.216.0"] + vulkan-sdk: ["latest", "1.3.216.0", "1.2.198.1"] vma: ["ON", "OFF"] exclude: # exclude combinations that are known to fail - vulkan-sdk: "1.2.198" From 44bfd85359026c7589d01fd5f612dc2b921442bd Mon Sep 17 00:00:00 2001 From: Johannes Unterguggenberger Date: Fri, 12 Apr 2024 13:45:53 +0200 Subject: [PATCH 17/18] Using vk::ImageLayout::eDepthStencilAttachmentOptimal instead of vk::ImageLayout::eAttachmentOptimal --- src/avk.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/avk.cpp b/src/avk.cpp index 534de92..59c35f4 100644 --- a/src/avk.cpp +++ b/src/avk.cpp @@ -8475,10 +8475,10 @@ namespace avk const bool shouldResolve = currAttachment.is_to_be_resolved(); depthAttachment = vk::RenderingAttachmentInfoKHR{} .setImageView(currImageView->handle()) - .setImageLayout(vk::ImageLayout::eAttachmentOptimal) + .setImageLayout(vk::ImageLayout::eDepthStencilAttachmentOptimal) .setResolveMode(shouldResolve ? static_cast(static_cast(usage.mResolveModeDepth)) : vk::ResolveModeFlagBits::eNone) .setResolveImageView(shouldResolve ? aImageViews.at(usage.mResolveAttachmentIndex)->handle() : VK_NULL_HANDLE) - .setResolveImageLayout(vk::ImageLayout::eAttachmentOptimal) + .setResolveImageLayout(vk::ImageLayout::eDepthStencilAttachmentOptimal) .setLoadOp(to_vk_load_op(currAttachment.mLoadOperation.mLoadBehavior)) .setStoreOp(to_vk_store_op(currAttachment.mStoreOperation.mStoreBehavior)) .setClearValue(vk::ClearDepthStencilValue( @@ -8495,10 +8495,10 @@ namespace avk const bool shouldResolve = currAttachment.is_to_be_resolved(); stencilAttachment = vk::RenderingAttachmentInfoKHR{} .setImageView(currImageView->handle()) - .setImageLayout(vk::ImageLayout::eAttachmentOptimal) + .setImageLayout(vk::ImageLayout::eDepthStencilAttachmentOptimal) .setResolveMode(shouldResolve ? static_cast(static_cast(usage.mResolveModeStencil)) : vk::ResolveModeFlagBits::eNone) .setResolveImageView(shouldResolve ? aImageViews.at(usage.mResolveAttachmentIndex)->handle() : VK_NULL_HANDLE) - .setResolveImageLayout(vk::ImageLayout::eAttachmentOptimal) + .setResolveImageLayout(vk::ImageLayout::eDepthStencilAttachmentOptimal) .setLoadOp(to_vk_load_op(currAttachment.mLoadOperation.mLoadBehavior)) .setStoreOp(to_vk_store_op(currAttachment.mStoreOperation.mStoreBehavior)) .setClearValue(vk::ClearDepthStencilValue( From 40fbdf5484d8f91eaa9bf3f5fa10f2ce58bc31b6 Mon Sep 17 00:00:00 2001 From: Johannes Unterguggenberger Date: Fri, 12 Apr 2024 13:51:58 +0200 Subject: [PATCH 18/18] Disable VMA=ON on Linux with 1.2 SDK --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ffb259e..fd1c4b7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -36,7 +36,7 @@ jobs: vulkan-sdk: ["latest", "1.3.216", "1.2.198"] vma: ["ON", "OFF"] exclude: # exclude combinations that are known to fail - - vulkan-sdk: "1.3.204" + - vulkan-sdk: "1.2.198" vma: "ON" steps: