diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 69662f309..67b6ba35e 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -365,6 +365,12 @@ void Graphics::setFrontFaceWinding(Winding winding) { flushBatchedDraws(); states.back().winding = winding; + + if (optionalDeviceFeatures.extendedDynamicState) { + extendedDynamicStateFunctions.vkCmdSetFrontFaceEXT( + commandBuffers.at(currentFrame), + Vulkan::getFrontFace(winding)); + } } void Graphics::setColorMask(ColorChannelMask mask) { @@ -514,6 +520,18 @@ void Graphics::setScissor() { void Graphics::setStencilMode(StencilAction action, CompareMode compare, int value, love::uint32 readmask, love::uint32 writemask) { flushBatchedDraws(); + vkCmdSetStencilWriteMask(commandBuffers.at(currentFrame), VK_STENCIL_FACE_FRONT_AND_BACK, writemask); + vkCmdSetStencilCompareMask(commandBuffers.at(currentFrame), VK_STENCIL_FACE_FRONT_AND_BACK, readmask); + vkCmdSetStencilReference(commandBuffers.at(currentFrame), VK_STENCIL_FACE_FRONT_AND_BACK, value); + + if (optionalDeviceFeatures.extendedDynamicState) { + extendedDynamicStateFunctions.vkCmdSetStencilOpEXT( + commandBuffers.at(currentFrame), + VK_STENCIL_FACE_FRONT_AND_BACK, + VK_STENCIL_OP_KEEP, Vulkan::getStencilOp(action), + VK_STENCIL_OP_KEEP, Vulkan::getCompareOp(compare)); + } + states.back().stencil.action = action; states.back().stencil.compare = compare; states.back().stencil.value = value; @@ -524,6 +542,14 @@ void Graphics::setStencilMode(StencilAction action, CompareMode compare, int val void Graphics::setDepthMode(CompareMode compare, bool write) { flushBatchedDraws(); + if (optionalDeviceFeatures.extendedDynamicState) { + extendedDynamicStateFunctions.vkCmdSetDepthCompareOpEXT( + commandBuffers.at(currentFrame), Vulkan::getCompareOp(compare)); + + extendedDynamicStateFunctions.vkCmdSetDepthWriteEnableEXT( + commandBuffers.at(currentFrame), Vulkan::getBool(write)); + } + states.back().depthTest = compare; states.back().depthWrite = write; } @@ -586,6 +612,37 @@ void Graphics::initDynamicState() { } else { setScissor(); } + + VkViewport viewport{}; + viewport.x = 0.0f; + viewport.y = 0.0f; + viewport.width = swapChainExtent.width; + viewport.height = swapChainExtent.height; + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + + vkCmdSetViewport(commandBuffers.at(currentFrame), 0, 1, &viewport); + + vkCmdSetStencilWriteMask(commandBuffers.at(currentFrame), VK_STENCIL_FACE_FRONT_AND_BACK, states.back().stencil.writeMask); + vkCmdSetStencilCompareMask(commandBuffers.at(currentFrame), VK_STENCIL_FACE_FRONT_AND_BACK, states.back().stencil.readMask); + vkCmdSetStencilReference(commandBuffers.at(currentFrame), VK_STENCIL_FACE_FRONT_AND_BACK, states.back().stencil.value); + + if (optionalDeviceFeatures.extendedDynamicState) { + extendedDynamicStateFunctions.vkCmdSetStencilOpEXT( + commandBuffers.at(currentFrame), + VK_STENCIL_FACE_FRONT_AND_BACK, + VK_STENCIL_OP_KEEP, Vulkan::getStencilOp(states.back().stencil.action), + VK_STENCIL_OP_KEEP, Vulkan::getCompareOp(states.back().stencil.compare)); + + extendedDynamicStateFunctions.vkCmdSetDepthCompareOpEXT( + commandBuffers.at(currentFrame), Vulkan::getCompareOp(states.back().depthTest)); + + extendedDynamicStateFunctions.vkCmdSetDepthWriteEnableEXT( + commandBuffers.at(currentFrame), Vulkan::getBool(states.back().depthWrite)); + + extendedDynamicStateFunctions.vkCmdSetFrontFaceEXT( + commandBuffers.at(currentFrame), Vulkan::getFrontFace(states.back().winding)); + } } void Graphics::startRecordingGraphicsCommands() { @@ -928,6 +985,20 @@ QueueFamilyIndices Graphics::findQueueFamilies(VkPhysicalDevice device) { return indices; } +static void findOptionalDeviceExtensions(VkPhysicalDevice physicalDevice, OptionalDeviceFeatures &optionalDeviceFeatures) { + uint32_t extensionCount; + vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extensionCount, nullptr); + + std::vector availableExtensions(extensionCount); + vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extensionCount, availableExtensions.data()); + + for (const auto& extension : availableExtensions) { + if (strcmp(extension.extensionName, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME) == 0) { + optionalDeviceFeatures.extendedDynamicState = true; + } + } +} + void Graphics::createLogicalDevice() { QueueFamilyIndices indices = findQueueFamilies(physicalDevice); @@ -944,6 +1015,8 @@ void Graphics::createLogicalDevice() { queueCreateInfos.push_back(queueCreateInfo); } + findOptionalDeviceExtensions(physicalDevice, optionalDeviceFeatures); + VkPhysicalDeviceFeatures deviceFeatures{}; deviceFeatures.samplerAnisotropy = VK_TRUE; deviceFeatures.fillModeNonSolid = VK_TRUE; @@ -954,8 +1027,14 @@ void Graphics::createLogicalDevice() { createInfo.pQueueCreateInfos = queueCreateInfos.data(); createInfo.pEnabledFeatures = &deviceFeatures; - createInfo.enabledExtensionCount = static_cast(deviceExtensions.size()); - createInfo.ppEnabledExtensionNames = deviceExtensions.data(); + std::vector enabledExtensions(deviceExtensions.begin(), deviceExtensions.end()); + + if (optionalDeviceFeatures.extendedDynamicState) { + enabledExtensions.push_back(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME); + } + + createInfo.enabledExtensionCount = static_cast(enabledExtensions.size()); + createInfo.ppEnabledExtensionNames = enabledExtensions.data(); // can this be removed? if (enableValidationLayers) { @@ -966,6 +1045,13 @@ void Graphics::createLogicalDevice() { createInfo.enabledLayerCount = 0; } + VkPhysicalDeviceExtendedDynamicStateFeaturesEXT extendedDynamicStateFeatures{}; + extendedDynamicStateFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT; + extendedDynamicStateFeatures.extendedDynamicState = Vulkan::getBool(optionalDeviceFeatures.extendedDynamicState); + extendedDynamicStateFeatures.pNext = nullptr; + + createInfo.pNext = &extendedDynamicStateFeatures; + if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS) { throw love::Exception("failed to create logical device"); } @@ -976,6 +1062,34 @@ void Graphics::createLogicalDevice() { vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0, &graphicsQueue); vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue); + + if (optionalDeviceFeatures.extendedDynamicState) { +#ifdef LOVE_ANDROID + extendedDynamicStateFunctions.vkCmdSetCullModeEXT = vkCmdSetCullModeEXT; + extendedDynamicStateFunctions.vkCmdSetDepthBoundsTestEnableEXT = vkCmdSetDepthBoundsTestEnableEXT; + extendedDynamicStateFunctions.vkCmdSetDepthBoundsTestEnableEXT = vkCmdSetCullModeEXT; + extendedDynamicStateFunctions.vkCmdSetDepthTestEnableEXT = vkCmdSetDepthTestEnableEXT; + extendedDynamicStateFunctions.vkCmdSetDepthWriteEnableEXT = vkCmdSetDepthWriteEnableEXT; + extendedDynamicStateFunctions.vkCmdSetFrontFaceEXT = vkCmdSetFrontFaceEXT; + extendedDynamicStateFunctions.vkCmdSetPrimitiveTopologyEXT = vkCmdSetPrimitiveTopologyEXT; + extendedDynamicStateFunctions.vkCmdSetScissorWithCountEXT = vkCmdSetScissorWithCountEXT; + extendedDynamicStateFunctions.vkCmdSetStencilOpEXT = vkCmdSetStencilOpEXT; + extendedDynamicStateFunctions.vkCmdSetStencilTestEnableEXT = vkCmdSetStencilTestEnableEXT; + extendedDynamicStateFunctions.vkCmdSetViewportWithCountEXT = vkCmdSetViewportWithCountEXT; +#else + extendedDynamicStateFunctions.vkCmdSetCullModeEXT = (PFN_vkCmdSetCullModeEXT)vkGetDeviceProcAddr(device, "vkCmdSetCullModeEXT"); + extendedDynamicStateFunctions.vkCmdSetDepthBoundsTestEnableEXT = (PFN_vkCmdSetDepthBoundsTestEnableEXT)vkGetDeviceProcAddr(device, "vkCmdSetDepthBoundsTestEnableEXT"); + extendedDynamicStateFunctions.vkCmdSetDepthCompareOpEXT = (PFN_vkCmdSetDepthCompareOpEXT)vkGetDeviceProcAddr(device, "vkCmdSetDepthCompareOpEXT"); + extendedDynamicStateFunctions.vkCmdSetDepthTestEnableEXT = (PFN_vkCmdSetDepthTestEnableEXT)vkGetDeviceProcAddr(device, "vkCmdSetDepthTestEnableEXT"); + extendedDynamicStateFunctions.vkCmdSetDepthWriteEnableEXT = (PFN_vkCmdSetDepthWriteEnableEXT)vkGetDeviceProcAddr(device, "vkCmdSetDepthWriteEnableEXT"); + extendedDynamicStateFunctions.vkCmdSetFrontFaceEXT = (PFN_vkCmdSetFrontFaceEXT)vkGetDeviceProcAddr(device, "vkCmdSetFrontFaceEXT"); + extendedDynamicStateFunctions.vkCmdSetPrimitiveTopologyEXT = (PFN_vkCmdSetPrimitiveTopologyEXT)vkGetDeviceProcAddr(device, "vkCmdSetPrimitiveTopologyEXT"); + extendedDynamicStateFunctions.vkCmdSetScissorWithCountEXT = (PFN_vkCmdSetScissorWithCountEXT)vkGetDeviceProcAddr(device, "vkCmdSetScissorWithCountEXT"); + extendedDynamicStateFunctions.vkCmdSetStencilOpEXT = (PFN_vkCmdSetStencilOpEXT)vkGetDeviceProcAddr(device, "vkCmdSetStencilOpEXT"); + extendedDynamicStateFunctions.vkCmdSetStencilTestEnableEXT = (PFN_vkCmdSetStencilTestEnableEXT)vkGetDeviceProcAddr(device, "vkCmdSetStencilTestEnableEXT"); + extendedDynamicStateFunctions.vkCmdSetViewportWithCountEXT = (PFN_vkCmdSetViewportWithCountEXT)vkGetDeviceProcAddr(device, "vkCmdSetViewportWithCountEXT"); +#endif + } } void Graphics::initVMA() { @@ -1497,23 +1611,28 @@ void Graphics::createVulkanVertexFormat( } void Graphics::prepareDraw(const VertexAttributes& attributes, const BufferBindings& buffers, graphics::Texture* texture, PrimitiveType primitiveType, CullMode cullmode) { - GraphicsPipelineConfiguration configuration; + GraphicsPipelineConfiguration configuration{}; + configuration.renderPass = currentRenderPass; configuration.vertexAttributes = attributes; configuration.shader = (Shader*)Shader::current; - configuration.primitiveType = primitiveType; configuration.wireFrame = states.back().wireframe; configuration.blendState = states.back().blend; configuration.colorChannelMask = states.back().colorMask; - configuration.winding = states.back().winding; - configuration.stencil = states.back().stencil; - configuration.depthState.compare = states.back().depthTest; - configuration.depthState.write = states.back().depthWrite; - configuration.cullmode = cullmode; - configuration.viewportWidth = currentViewportWidth; - configuration.viewportHeight = currentViewportHeight; configuration.msaaSamples = currentMsaaSamples; configuration.numColorAttachments = currentNumColorAttachments; + configuration.primitiveType = primitiveType; + + if (optionalDeviceFeatures.extendedDynamicState) { + extendedDynamicStateFunctions.vkCmdSetCullModeEXT(commandBuffers.at(currentFrame), Vulkan::getCullMode(cullmode)); + } else { + configuration.dynamicState.winding = states.back().winding; + configuration.dynamicState.depthState.compare = states.back().depthTest; + configuration.dynamicState.depthState.write = states.back().depthWrite; + configuration.dynamicState.stencilAction = states.back().stencil.action; + configuration.dynamicState.stencilCompare = states.back().stencil.compare; + configuration.dynamicState.cullmode = cullmode; + } std::vector bufferVector; std::vector offsets; @@ -1565,6 +1684,16 @@ void Graphics::startDefaultRenderPass() { } void Graphics::startRenderPass(const RenderTargets& rts, int pixelw, int pixelh, bool hasSRGBtexture) { + VkViewport viewport{}; + viewport.x = 0.0f; + viewport.y = 0.0f; + viewport.width = static_cast(pixelw); + viewport.height = static_cast(pixelh); + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + + vkCmdSetViewport(commandBuffers.at(currentFrame), 0, 1, &viewport); + auto currentCommandBuffer = commandBuffers.at(currentFrame); // fixme: hasSRGBtexture @@ -1695,6 +1824,9 @@ VkSampler Graphics::getCachedSampler(const SamplerState& samplerState) { } VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration configuration) { + VkGraphicsPipelineCreateInfo pipelineInfo{}; + pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + auto &shaderStages = configuration.shader->getShaderStages(); std::vector bindingDescriptions; @@ -1709,38 +1841,11 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration config vertexInputInfo.vertexAttributeDescriptionCount = static_cast(attributeDescriptions.size()); vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data(); - VkPipelineInputAssemblyStateCreateInfo inputAssembly{}; - inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - inputAssembly.topology = Vulkan::getPrimitiveTypeTopology(configuration.primitiveType); - inputAssembly.primitiveRestartEnable = VK_FALSE; - - VkViewport viewport{}; - viewport.x = 0.0f; - viewport.y = 0.0f; - viewport.width = configuration.viewportWidth; - viewport.height = configuration.viewportHeight; - viewport.minDepth = 0.0f; - viewport.maxDepth = 1.0f; - VkPipelineViewportStateCreateInfo viewportState{}; viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; viewportState.viewportCount = 1; - viewportState.pViewports = &viewport; viewportState.scissorCount = 1; - VkPipelineRasterizationStateCreateInfo rasterizer{}; - rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - rasterizer.depthClampEnable = VK_FALSE; - rasterizer.rasterizerDiscardEnable = VK_FALSE; - rasterizer.polygonMode = Vulkan::getPolygonMode(configuration.wireFrame); - rasterizer.lineWidth = 1.0f; - rasterizer.cullMode = Vulkan::getCullMode(configuration.cullmode); - rasterizer.frontFace = Vulkan::getFrontFace(configuration.winding); - rasterizer.depthBiasEnable = VK_FALSE; - rasterizer.depthBiasConstantFactor = 0.0f; - rasterizer.depthBiasClamp = 0.0f; - rasterizer.depthBiasSlopeFactor = 0.0f; - VkPipelineMultisampleStateCreateInfo multisampling{}; multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; multisampling.sampleShadingEnable = VK_FALSE; @@ -1750,31 +1855,53 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration config multisampling.alphaToCoverageEnable = VK_FALSE; // Optional multisampling.alphaToOneEnable = VK_FALSE; // Optional + VkPipelineRasterizationStateCreateInfo rasterizer{}; + rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterizer.depthClampEnable = VK_FALSE; + rasterizer.rasterizerDiscardEnable = VK_FALSE; + rasterizer.polygonMode = Vulkan::getPolygonMode(configuration.wireFrame); + rasterizer.lineWidth = 1.0f; + if (!optionalDeviceFeatures.extendedDynamicState) { + rasterizer.cullMode = Vulkan::getCullMode(configuration.dynamicState.cullmode); + rasterizer.frontFace = Vulkan::getFrontFace(configuration.dynamicState.winding); + } + + rasterizer.depthBiasEnable = VK_FALSE; + rasterizer.depthBiasConstantFactor = 0.0f; + rasterizer.depthBiasClamp = 0.0f; + rasterizer.depthBiasSlopeFactor = 0.0f; + + VkPipelineInputAssemblyStateCreateInfo inputAssembly{}; + inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + inputAssembly.topology = Vulkan::getPrimitiveTypeTopology(configuration.primitiveType); + inputAssembly.primitiveRestartEnable = VK_FALSE; + VkPipelineDepthStencilStateCreateInfo depthStencil{}; depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; depthStencil.depthTestEnable = VK_TRUE; - depthStencil.depthWriteEnable = Vulkan::getBool(configuration.depthState.write); - depthStencil.depthCompareOp = Vulkan::getCompareOp(configuration.depthState.compare); + if (!optionalDeviceFeatures.extendedDynamicState) { + depthStencil.depthWriteEnable = Vulkan::getBool(configuration.dynamicState.depthState.write); + depthStencil.depthCompareOp = Vulkan::getCompareOp(configuration.dynamicState.depthState.compare); + } depthStencil.depthBoundsTestEnable = VK_FALSE; depthStencil.minDepthBounds = 0.0f; depthStencil.maxDepthBounds = 1.0f; + depthStencil.stencilTestEnable = VK_TRUE; - depthStencil.front.failOp = VK_STENCIL_OP_KEEP; - depthStencil.front.passOp = Vulkan::getStencilOp(configuration.stencil.action); - depthStencil.front.depthFailOp = VK_STENCIL_OP_KEEP; - depthStencil.front.compareOp = Vulkan::getCompareOp(configuration.stencil.compare); - depthStencil.front.compareMask = configuration.stencil.readMask; - depthStencil.front.writeMask = configuration.stencil.writeMask; - depthStencil.front.reference = configuration.stencil.value; + if (!optionalDeviceFeatures.extendedDynamicState) { + depthStencil.front.failOp = VK_STENCIL_OP_KEEP; + depthStencil.front.passOp = Vulkan::getStencilOp(configuration.dynamicState.stencilAction); + depthStencil.front.depthFailOp = VK_STENCIL_OP_KEEP; + depthStencil.front.compareOp = Vulkan::getCompareOp(configuration.dynamicState.stencilCompare); - depthStencil.back.failOp = VK_STENCIL_OP_KEEP; - depthStencil.back.passOp = Vulkan::getStencilOp(configuration.stencil.action); - depthStencil.back.depthFailOp = VK_STENCIL_OP_KEEP; - depthStencil.back.compareOp = Vulkan::getCompareOp(configuration.stencil.compare); - depthStencil.back.compareMask = configuration.stencil.readMask; - depthStencil.back.writeMask = configuration.stencil.writeMask; - depthStencil.back.reference = static_cast(configuration.stencil.value); + depthStencil.back.failOp = VK_STENCIL_OP_KEEP; + depthStencil.back.passOp = Vulkan::getStencilOp(configuration.dynamicState.stencilAction); + depthStencil.back.depthFailOp = VK_STENCIL_OP_KEEP; + depthStencil.back.compareOp = Vulkan::getCompareOp(configuration.dynamicState.stencilCompare); + } + + pipelineInfo.pDepthStencilState = &depthStencil; VkPipelineColorBlendAttachmentState colorBlendAttachment{}; colorBlendAttachment.colorWriteMask = Vulkan::getColorMask(configuration.colorChannelMask); @@ -1799,17 +1926,36 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration config colorBlending.blendConstants[2] = 0.0f; colorBlending.blendConstants[3] = 0.0f; - std::array dynamicStates = { - VK_DYNAMIC_STATE_SCISSOR - }; + std::vector dynamicStates; + + if (optionalDeviceFeatures.extendedDynamicState) { + dynamicStates = { + VK_DYNAMIC_STATE_SCISSOR, + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_STENCIL_WRITE_MASK, + VK_DYNAMIC_STATE_STENCIL_REFERENCE, + + VK_DYNAMIC_STATE_CULL_MODE_EXT, + VK_DYNAMIC_STATE_FRONT_FACE_EXT, + VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT, + VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT, + VK_DYNAMIC_STATE_STENCIL_OP_EXT, + }; + } + else { + dynamicStates = { + VK_DYNAMIC_STATE_SCISSOR, + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_STENCIL_WRITE_MASK, + VK_DYNAMIC_STATE_STENCIL_REFERENCE, + }; + } VkPipelineDynamicStateCreateInfo dynamicState{}; dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; dynamicState.dynamicStateCount = static_cast(dynamicStates.size()); dynamicState.pDynamicStates = dynamicStates.data(); - VkGraphicsPipelineCreateInfo pipelineInfo{}; - pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; pipelineInfo.stageCount = static_cast(shaderStages.size()); pipelineInfo.pStages = shaderStages.data(); pipelineInfo.pVertexInputState = &vertexInputInfo; @@ -1817,7 +1963,6 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration config pipelineInfo.pViewportState = &viewportState; pipelineInfo.pRasterizationState = &rasterizer; pipelineInfo.pMultisampleState = &multisampling; - pipelineInfo.pDepthStencilState = &depthStencil; pipelineInfo.pColorBlendState = &colorBlending; pipelineInfo.pDynamicState = &dynamicState; pipelineInfo.layout = configuration.shader->getGraphicsPipelineLayout(); diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index 234ecf6b6..80eff97a3 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -79,22 +79,42 @@ struct FramebufferConfigurationHasher { } }; +struct OptionalDeviceFeatures { + bool extendedDynamicState = false; +}; + +struct ExtendedDynamicStateFunctions { + PFN_vkCmdSetCullModeEXT vkCmdSetCullModeEXT = nullptr; + PFN_vkCmdSetDepthBoundsTestEnableEXT vkCmdSetDepthBoundsTestEnableEXT = nullptr; + PFN_vkCmdSetDepthCompareOpEXT vkCmdSetDepthCompareOpEXT = nullptr; + PFN_vkCmdSetDepthTestEnableEXT vkCmdSetDepthTestEnableEXT = nullptr; + PFN_vkCmdSetDepthWriteEnableEXT vkCmdSetDepthWriteEnableEXT = nullptr; + PFN_vkCmdSetFrontFaceEXT vkCmdSetFrontFaceEXT = nullptr; + PFN_vkCmdSetPrimitiveTopologyEXT vkCmdSetPrimitiveTopologyEXT = nullptr; + PFN_vkCmdSetScissorWithCountEXT vkCmdSetScissorWithCountEXT = nullptr; + PFN_vkCmdSetStencilOpEXT vkCmdSetStencilOpEXT = nullptr; + PFN_vkCmdSetStencilTestEnableEXT vkCmdSetStencilTestEnableEXT = nullptr; + PFN_vkCmdSetViewportWithCountEXT vkCmdSetViewportWithCountEXT = nullptr; +}; + struct GraphicsPipelineConfiguration { VkRenderPass renderPass; VertexAttributes vertexAttributes; Shader* shader = nullptr; - PrimitiveType primitiveType = PRIMITIVE_MAX_ENUM; bool wireFrame; BlendState blendState; ColorChannelMask colorChannelMask; - Winding winding; - CullMode cullmode; - float viewportWidth; - float viewportHeight; - StencilState stencil; - DepthState depthState; VkSampleCountFlagBits msaaSamples; uint32_t numColorAttachments; + PrimitiveType primitiveType; + + struct DynamicState { + CullMode cullmode = CULL_NONE; + Winding winding = WINDING_MAX_ENUM; + StencilAction stencilAction = STENCIL_MAX_ENUM; + CompareMode stencilCompare = COMPARE_MAX_ENUM; + DepthState depthState{}; + } dynamicState; GraphicsPipelineConfiguration() { memset(this, 0, sizeof(GraphicsPipelineConfiguration)); @@ -281,6 +301,8 @@ private: int requestedMsaa = 0; int actualMsaa = 0; VkDevice device = VK_NULL_HANDLE; + OptionalDeviceFeatures optionalDeviceFeatures; + ExtendedDynamicStateFunctions extendedDynamicStateFunctions; VkQueue graphicsQueue = VK_NULL_HANDLE; VkQueue presentQueue = VK_NULL_HANDLE; VkSurfaceKHR surface = VK_NULL_HANDLE;