blob: 81f511f59b7b87bfe80340c5c09052da5c18e947 [file] [log] [blame]
/*
* 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