//// - Copyright (c) 2023, Mobica Limited - - SPDX-License-Identifier: Apache-2.0 - - Licensed under the Apache License, Version 2.0 the "License"; - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - //// = Logic operations dynamic state ifdef::site-gen-antora[] TIP: The source for this sample can be found in the https://github.com/KhronosGroup/Vulkan-Samples/tree/main/samples/extensions/logic_op_dynamic_state[Khronos Vulkan samples github repository]. endif::[] image::./images/logic_op_dynamic_state_screenshot.png[Sample] == Overview The https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_extended_dynamic_state2.html[VK_EXT_extended_dynamic_state2] extension allows to use dynamic states e.g. the VK_DYNAMIC_STATE_LOGIC_OP_EXT. This may help an application to change a logical operation used without creating a new pipeline. The sample demonstrates usage of this extension with dynamically changed logical operations applied to blending. == Surface format setting Logical operations are applied only for https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#framebuffer-logicop[signed and unsigned integer and normalized integer framebuffers]. In the sample the surface format is changed to `VK_FORMAT_B8G8R8A8_UNORM` by overriding the virtual method `create_render_context` (derived from `ApiVulkanSample` class). [,C++] ---- auto surface_priority_list = std::vector{ {VK_FORMAT_B8G8R8A8_UNORM, VK_COLORSPACE_SRGB_NONLINEAR_KHR}, }; render_context = platform.create_render_context(*device.get(), surface, surface_priority_list); ---- == Enabling logical operations in pipeline creation In the sample two pipelines are created: * a pipeline for a background model (the background pipeline); * a pipeline for a cube model (the baseline pipeline). The cube model is used to present blending effect achieved using the dynamic logical operations. The `logicOpEnable` member of the `VkPipelineColorBlendStateCreateInfo` structure https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineColorBlendStateCreateInfo.html[controls if logical operations should be applied]. The `logicOpEnable` member is set to `VK_TRUE` during creation of the baseline pipeline in the `create_pipeline` method. [,C++] ---- VkPipelineColorBlendStateCreateInfo color_blend_state = vkb::initializers::pipeline_color_blend_state_create_info(1, &blend_attachment_state); /* Enable logic operations */ color_blend_state.logicOpEnable = VK_TRUE; ---- In the same method `VK_DYNAMIC_STATE_LOGIC_OP_EXT` is added to the vector of `VkDynamicState` (used to define pipeline dynamic state in https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineDynamicStateCreateInfo.html[`VkPipelineDynamicStateCreateInfo`]). [,C++] ---- std::vector dynamic_state_enables = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR, VK_DYNAMIC_STATE_LOGIC_OP_EXT, }; VkPipelineDynamicStateCreateInfo dynamic_state = vkb::initializers::pipeline_dynamic_state_create_info( dynamic_state_enables.data(), static_cast(dynamic_state_enables.size()), 0); ---- Both structures: `color_blend_state` and `dynamic_state` are used to define https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkGraphicsPipelineCreateInfo.html[`VkGraphicsPipelineCreateInfo`] needed to create the graphics pipeline. [,C++] ---- VkGraphicsPipelineCreateInfo graphics_create{VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO}; graphics_create.pColorBlendState = &color_blend_state; graphics_create.pDynamicState = &dynamic_state; ... VK_CHECK(vkCreateGraphicsPipelines(get_device().get_handle(), pipeline_cache, 1, &graphics_create, VK_NULL_HANDLE, &pipeline.baseline)); ---- Logical operations are not enabled in the background pipeline. [,C++] ---- std::vector dynamic_state_enables_background = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR, }; /* Disable logic operations in background pipeline */ color_blend_state.logicOpEnable = VK_FALSE; ---- == Logical operation dynamic setting in command buffer creation Calling https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkCmdSetLogicOpEXT.html[`vkCmdSetLogicOpEXT`] allows to set the logic operation dynamically. In the sample it is called before drawing the model in the `build_command_buffers` method using a value provided by the GUI. Available logical operations are defined by the `VkLogicOp` enumeration (check the Vulkan specification for details of https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VkLogicOp[the logical operations]). The background model is drawn before the cube model (with logical operations enabled) to observe blending results on the cube model. [,C++] ---- VK_CHECK(vkBeginCommandBuffer(draw_cmd_buffer, &command_begin)); ... /* Drawing background */ draw_model(background_model, draw_cmd_buffer); ... /* Set logic operation chosen in GUI for the cube model */ vkCmdSetLogicOpEXT(draw_cmd_buffer, static_cast(gui_settings.selected_operation)); /* Draw model */ draw_created_model(draw_cmd_buffer); ... VK_CHECK(vkEndCommandBuffer(draw_cmd_buffer)); ---- == Enabling the required extensions The extended dynamic state 2 API requires Vulkan 1.0 and the appropriate headers / SDK is required. This extension has been https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_extended_dynamic_state2.html#_promotion_to_vulkan_1_3[partially] promoted to Vulkan 1.3. The device extension `VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME` requires `VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME` instance extension to be enabled. [,C++] ---- add_instance_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); add_device_extension(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME); ---- Enabling extension features is done using `VkPhysicalDeviceExtendedDynamicState2FeaturesEXT` and `VkPhysicalDeviceExtendedDynamicStateFeaturesEXT` structures. [,C++] ---- typedef struct VkPhysicalDeviceExtendedDynamicState2FeaturesEXT { VkStructureType sType; void* pNext; VkBool32 extendedDynamicState2; VkBool32 extendedDynamicState2LogicOp; VkBool32 extendedDynamicState2PatchControlPoints; } VkPhysicalD typedef struct VkPhysicalDeviceExtendedDynamicStateFeaturesEXT { VkStructureType sType; void* pNext; VkBool32 extendedDynamicState; } VkPhysicalDeviceExtendedDynamicStateFeaturesEXT; ---- In the sample it is implemented in the `request_gpu_features` method. [,C++] ---- auto &requested_extended_dynamic_state2_features = gpu.request_extension_features(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT); requested_extended_dynamic_state2_features.extendedDynamicState2 = VK_TRUE; requested_extended_dynamic_state2_features.extendedDynamicState2LogicOp = VK_TRUE; auto &requested_extended_dynamic_state_feature = gpu.request_extension_features(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT); requested_extended_dynamic_state_feature.extendedDynamicState = VK_TRUE; ----