| /* | |
| * Copyright 2025 Rive | |
| */ | |
| #include "draw_pipeline_layout_vulkan.hpp" | |
| #include "rive/renderer/stack_vector.hpp" | |
| #include "rive/renderer/vulkan/vulkan_context.hpp" | |
| #include "rive/renderer/vulkan/render_context_vulkan_impl.hpp" | |
| #include "shaders/constants.glsl" | |
| #include "pipeline_manager_vulkan.hpp" | |
| namespace rive::gpu | |
| { | |
| DrawPipelineLayoutVulkan::DrawPipelineLayoutVulkan( | |
| PipelineManagerVulkan* impl, | |
| gpu::InterlockMode interlockMode, | |
| DrawPipelineLayoutVulkan::Options options) : | |
| m_vk(ref_rcp(impl->vulkanContext())), | |
| m_interlockMode(interlockMode), | |
| m_options(options) | |
| { | |
| // PLS planes get bound per flush as input attachments or storage | |
| // textures. | |
| StackVector<VkDescriptorSetLayoutBinding, PLS_PLANE_COUNT> | |
| plsLayoutBindings; | |
| if (!(m_options & Options::fixedFunctionColorOutput)) | |
| { | |
| plsLayoutBindings.push_back({ | |
| .binding = COLOR_PLANE_IDX, | |
| .descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, | |
| .descriptorCount = 1, | |
| .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, | |
| }); | |
| } | |
| if (interlockMode == gpu::InterlockMode::rasterOrdering || | |
| interlockMode == gpu::InterlockMode::atomics) | |
| { | |
| plsLayoutBindings.push_back({ | |
| .binding = CLIP_PLANE_IDX, | |
| .descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, | |
| .descriptorCount = 1, | |
| .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, | |
| }); | |
| if (interlockMode == gpu::InterlockMode::rasterOrdering) | |
| { | |
| plsLayoutBindings.push_back({ | |
| .binding = SCRATCH_COLOR_PLANE_IDX, | |
| .descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, | |
| .descriptorCount = 1, | |
| .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, | |
| }); | |
| } | |
| plsLayoutBindings.push_back({ | |
| .binding = COVERAGE_PLANE_IDX, | |
| .descriptorType = m_interlockMode == gpu::InterlockMode::atomics | |
| ? VK_DESCRIPTOR_TYPE_STORAGE_IMAGE | |
| : VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, | |
| .descriptorCount = 1, | |
| .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, | |
| }); | |
| } | |
| else if (interlockMode == gpu::InterlockMode::msaa) | |
| { | |
| // TODO: pipeline layouts aren't currently keyed by loadAction, but if | |
| // they were, we could only include this binding with | |
| // preserveRenderTarget. | |
| plsLayoutBindings.push_back({ | |
| .binding = MSAA_COLOR_SEED_IDX, | |
| .descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, | |
| .descriptorCount = 1, | |
| .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, | |
| }); | |
| } | |
| if (plsLayoutBindings.size() > 0) | |
| { | |
| VkDescriptorSetLayoutCreateInfo plsLayoutInfo = { | |
| .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, | |
| .bindingCount = plsLayoutBindings.size(), | |
| .pBindings = plsLayoutBindings.data(), | |
| }; | |
| VK_CHECK( | |
| m_vk->CreateDescriptorSetLayout(m_vk->device, | |
| &plsLayoutInfo, | |
| nullptr, | |
| &m_plsTextureDescriptorSetLayout)); | |
| } | |
| VkDescriptorSetLayout pipelineDescriptorSetLayouts[] = { | |
| impl->perFlushDescriptorSetLayout(), | |
| impl->perDrawDescriptorSetLayout(), | |
| impl->immutableSamplerDescriptorSetLayout(), | |
| m_plsTextureDescriptorSetLayout, | |
| }; | |
| static_assert(COLOR_PLANE_IDX == 0); | |
| static_assert(CLIP_PLANE_IDX == 1); | |
| static_assert(SCRATCH_COLOR_PLANE_IDX == 2); | |
| static_assert(COVERAGE_PLANE_IDX == 3); | |
| static_assert(BINDINGS_SET_COUNT == 4); | |
| VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = { | |
| .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, | |
| .setLayoutCount = m_plsTextureDescriptorSetLayout != VK_NULL_HANDLE | |
| ? BINDINGS_SET_COUNT | |
| : BINDINGS_SET_COUNT - 1u, | |
| .pSetLayouts = pipelineDescriptorSetLayouts, | |
| }; | |
| VK_CHECK(m_vk->CreatePipelineLayout(m_vk->device, | |
| &pipelineLayoutCreateInfo, | |
| nullptr, | |
| &m_pipelineLayout)); | |
| } | |
| DrawPipelineLayoutVulkan::~DrawPipelineLayoutVulkan() | |
| { | |
| m_vk->DestroyDescriptorSetLayout(m_vk->device, | |
| m_plsTextureDescriptorSetLayout, | |
| nullptr); | |
| m_vk->DestroyPipelineLayout(m_vk->device, m_pipelineLayout, nullptr); | |
| } | |
| uint32_t DrawPipelineLayoutVulkan::colorAttachmentCount( | |
| uint32_t subpassIndex) const | |
| { | |
| switch (m_interlockMode) | |
| { | |
| case gpu::InterlockMode::rasterOrdering: | |
| assert(subpassIndex == 0); | |
| return 4; | |
| case gpu::InterlockMode::atomics: | |
| assert(subpassIndex <= 1); | |
| return 2u - subpassIndex; // Subpass 0 -> 2, subpass 1 -> 1. | |
| case gpu::InterlockMode::clockwiseAtomic: | |
| assert(subpassIndex == 0); | |
| return 1; | |
| case gpu::InterlockMode::msaa: | |
| assert(subpassIndex == 0 || subpassIndex == 1); | |
| return 1; | |
| } | |
| RIVE_UNREACHABLE(); | |
| } | |
| } // namespace rive::gpu |