| /* | |
| * Copyright 2023 Rive | |
| */ | |
| #include "rive/renderer/vulkan/render_target_vulkan.hpp" | |
| #include "rive/renderer/vulkan/render_context_vulkan_impl.hpp" | |
| namespace rive::gpu | |
| { | |
| RenderTargetVulkan::RenderTargetVulkan(rcp<VulkanContext> vk, | |
| uint32_t width, | |
| uint32_t height, | |
| VkFormat framebufferFormat, | |
| VkImageUsageFlags targetUsageFlags) : | |
| RenderTarget(width, height), | |
| m_vk(std::move(vk)), | |
| m_framebufferFormat(framebufferFormat), | |
| m_targetUsageFlags(targetUsageFlags) | |
| { | |
| #ifndef NDEBUG | |
| // In order to implement blend modes, the target texture needs to either | |
| // support input attachment usage (ideal), or else transfers. | |
| constexpr static VkImageUsageFlags TRANSFER_SRC_AND_DST = | |
| VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; | |
| assert((m_targetUsageFlags & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) || | |
| (m_targetUsageFlags & TRANSFER_SRC_AND_DST) == TRANSFER_SRC_AND_DST); | |
| #endif | |
| } | |
| VkImage RenderTargetVulkanImpl::accessTargetImage( | |
| VkCommandBuffer commandBuffer, | |
| const vkutil::ImageAccess& dstAccess, | |
| vkutil::ImageAccessAction imageAccessAction) | |
| { | |
| m_targetLastAccess = m_vk->simpleImageMemoryBarrier(commandBuffer, | |
| m_targetLastAccess, | |
| dstAccess, | |
| m_targetImage, | |
| imageAccessAction); | |
| return m_targetImage; | |
| } | |
| VkImageView RenderTargetVulkanImpl::accessTargetImageView( | |
| VkCommandBuffer commandBuffer, | |
| const vkutil::ImageAccess& dstAccess, | |
| vkutil::ImageAccessAction imageAccessAction) | |
| { | |
| accessTargetImage(commandBuffer, dstAccess, imageAccessAction); | |
| return m_targetImageView; | |
| } | |
| vkutil::Texture2D* RenderTargetVulkan::accessOffscreenColorTexture( | |
| VkCommandBuffer commandBuffer, | |
| const vkutil::ImageAccess& dstAccess, | |
| vkutil::ImageAccessAction imageAccessAction) | |
| { | |
| if (m_offscreenColorTexture == nullptr) | |
| { | |
| m_offscreenColorTexture = m_vk->makeTexture2D({ | |
| .format = m_framebufferFormat, | |
| .extent = {width(), height()}, | |
| .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | | |
| VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | | |
| VK_IMAGE_USAGE_TRANSFER_SRC_BIT | | |
| VK_IMAGE_USAGE_TRANSFER_DST_BIT, | |
| }); | |
| } | |
| m_offscreenColorTexture->barrier(commandBuffer, | |
| dstAccess, | |
| imageAccessAction); | |
| return m_offscreenColorTexture.get(); | |
| } | |
| vkutil::Texture2D* RenderTargetVulkan::copyTargetImageToOffscreenColorTexture( | |
| VkCommandBuffer commandBuffer, | |
| const vkutil::ImageAccess& dstAccess, | |
| const IAABB& copyBounds) | |
| { | |
| m_vk->blitSubRect( | |
| commandBuffer, | |
| accessTargetImage(commandBuffer, | |
| { | |
| .pipelineStages = VK_PIPELINE_STAGE_TRANSFER_BIT, | |
| .accessMask = VK_ACCESS_TRANSFER_READ_BIT, | |
| .layout = VK_IMAGE_LAYOUT_GENERAL, | |
| }), | |
| VK_IMAGE_LAYOUT_GENERAL, | |
| accessOffscreenColorTexture( | |
| commandBuffer, | |
| { | |
| .pipelineStages = VK_PIPELINE_STAGE_TRANSFER_BIT, | |
| .accessMask = VK_ACCESS_TRANSFER_WRITE_BIT, | |
| .layout = VK_IMAGE_LAYOUT_GENERAL, | |
| }, | |
| vkutil::ImageAccessAction::invalidateContents) | |
| ->vkImage(), | |
| VK_IMAGE_LAYOUT_GENERAL, | |
| copyBounds); | |
| return accessOffscreenColorTexture(commandBuffer, dstAccess); | |
| } | |
| vkutil::Texture2D* RenderTargetVulkan::clipTextureR32UI() | |
| { | |
| if (m_clipTextureR32UI == nullptr) | |
| { | |
| m_clipTextureR32UI = m_vk->makeTexture2D({ | |
| .format = VK_FORMAT_R32_UINT, | |
| .extent = {width(), height()}, | |
| .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | | |
| VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | | |
| VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, | |
| }); | |
| } | |
| return m_clipTextureR32UI.get(); | |
| } | |
| vkutil::Texture2D* RenderTargetVulkan::scratchColorTexture() | |
| { | |
| if (m_scratchColorTexture == nullptr) | |
| { | |
| m_scratchColorTexture = m_vk->makeTexture2D({ | |
| .format = m_framebufferFormat, | |
| .extent = {width(), height()}, | |
| .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | | |
| VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | | |
| VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, | |
| }); | |
| } | |
| return m_scratchColorTexture.get(); | |
| } | |
| vkutil::Texture2D* RenderTargetVulkan::coverageTexture() | |
| { | |
| if (m_coverageTexture == nullptr) | |
| { | |
| m_coverageTexture = m_vk->makeTexture2D({ | |
| .format = VK_FORMAT_R32_UINT, | |
| .extent = {width(), height()}, | |
| .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | | |
| VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | | |
| VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, | |
| }); | |
| } | |
| return m_coverageTexture.get(); | |
| } | |
| vkutil::Texture2D* RenderTargetVulkan::clipTextureRGBA8() | |
| { | |
| if (m_clipTextureRGBA8 == nullptr) | |
| { | |
| m_clipTextureRGBA8 = m_vk->makeTexture2D({ | |
| .format = VK_FORMAT_R8G8B8A8_UNORM, | |
| .extent = {width(), height()}, | |
| .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | | |
| VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | | |
| VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, | |
| }); | |
| } | |
| return m_clipTextureRGBA8.get(); | |
| } | |
| vkutil::Texture2D* RenderTargetVulkan::coverageAtomicTexture() | |
| { | |
| if (m_coverageAtomicTexture == nullptr) | |
| { | |
| m_coverageAtomicTexture = m_vk->makeTexture2D({ | |
| .format = VK_FORMAT_R32_UINT, | |
| .extent = {width(), height()}, | |
| .usage = | |
| VK_IMAGE_USAGE_STORAGE_BIT | | |
| VK_IMAGE_USAGE_TRANSFER_DST_BIT, // For vkCmdClearColorImage | |
| }); | |
| } | |
| return m_coverageAtomicTexture.get(); | |
| } | |
| vkutil::Texture2D* RenderTargetVulkan::msaaColorTexture() | |
| { | |
| if (m_msaaColorTexture == nullptr) | |
| { | |
| m_msaaColorTexture = m_vk->makeTexture2D({ | |
| .format = m_framebufferFormat, | |
| .extent = {width(), height(), 1}, | |
| .samples = VK_SAMPLE_COUNT_4_BIT, | |
| .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | | |
| VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, | |
| }); | |
| } | |
| return m_msaaColorTexture.get(); | |
| } | |
| vkutil::Texture2D* RenderTargetVulkan::msaaDepthStencilTexture() | |
| { | |
| if (m_msaaDepthStencilTexture == nullptr) | |
| { | |
| m_msaaDepthStencilTexture = m_vk->makeTexture2D({ | |
| .format = vkutil::get_preferred_depth_stencil_format( | |
| m_vk->supportsD24S8()), | |
| .extent = {width(), height(), 1}, | |
| .samples = VK_SAMPLE_COUNT_4_BIT, | |
| .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, | |
| }); | |
| } | |
| return m_msaaDepthStencilTexture.get(); | |
| } | |
| rcp<RenderTargetVulkanImpl> RenderContextVulkanImpl::makeRenderTarget( | |
| uint32_t width, | |
| uint32_t height, | |
| VkFormat framebufferFormat, | |
| VkImageUsageFlags targetUsageFlags) | |
| { | |
| return rcp(new RenderTargetVulkanImpl(m_vk, | |
| width, | |
| height, | |
| framebufferFormat, | |
| targetUsageFlags)); | |
| } | |
| } // namespace rive::gpu |