| /* |
| * Copyright 2025 Rive |
| */ |
| |
| #include "offscreen_render_target.hpp" |
| |
| #ifndef RIVE_VULKAN |
| |
| namespace rive_tests |
| { |
| rive::rcp<OffscreenRenderTarget> OffscreenRenderTarget::MakeVulkan( |
| rive::gpu::VulkanContext*, |
| uint32_t width, |
| uint32_t height, |
| bool riveRenderable) |
| { |
| return nullptr; |
| } |
| } // namespace rive_tests |
| |
| #else |
| |
| #include "rive/renderer/rive_render_image.hpp" |
| #include "rive/renderer/vulkan/vulkan_context.hpp" |
| #include "rive/renderer/vulkan/render_target_vulkan.hpp" |
| #include "shaders/constants.glsl" |
| |
| namespace rive_tests |
| { |
| class OffscreenRenderTargetVulkan : public OffscreenRenderTarget |
| { |
| public: |
| OffscreenRenderTargetVulkan(rive::rcp<rive::gpu::VulkanContext> vk, |
| uint32_t width, |
| uint32_t height, |
| bool riveRenderable) : |
| m_textureTarget(rive::make_rcp<TextureTarget>(std::move(vk), |
| width, |
| height, |
| riveRenderable)) |
| {} |
| |
| rive::RenderImage* asRenderImage() override |
| { |
| return m_textureTarget->renderImage(); |
| } |
| |
| rive::gpu::RenderTarget* asRenderTarget() override |
| { |
| return m_textureTarget.get(); |
| } |
| |
| private: |
| class TextureTarget : public rive::gpu::RenderTargetVulkan |
| { |
| public: |
| TextureTarget(rive::rcp<rive::gpu::VulkanContext> vk, |
| uint32_t width, |
| uint32_t height, |
| bool riveRenderable) : |
| RenderTargetVulkan( |
| vk, |
| width, |
| height, |
| // BGRA is not riveRenderable when using storage textures for |
| // PLS (like in clockwise mode) because storage textures have to |
| // be RGBA8. Let's test both formats, but make sure to use RGBA |
| // for the riveRenderable case. |
| // Also don't test BGRA on Qualcomm. Various Adreno 6 devices |
| // can get the RGB order wrong when resolving BGRA multisampled |
| // data. |
| (riveRenderable || vk->physicalDeviceProperties().vendorID == |
| VULKAN_VENDOR_QUALCOMM) |
| ? VK_FORMAT_R8G8B8A8_UNORM |
| : VK_FORMAT_B8G8R8A8_UNORM, |
| VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | |
| VK_IMAGE_USAGE_SAMPLED_BIT | |
| // Rendering scenarios that use an offscreen color buffer |
| // sometimes require "transfer" usages for copying the |
| // contents back and forth from the main render target. |
| VK_IMAGE_USAGE_TRANSFER_SRC_BIT | |
| VK_IMAGE_USAGE_TRANSFER_DST_BIT | |
| (riveRenderable ? VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | |
| VK_IMAGE_USAGE_STORAGE_BIT |
| : VK_IMAGE_USAGE_TRANSFER_DST_BIT)), |
| m_renderImage( |
| rive::make_rcp<rive::RiveRenderImage>(m_vk->makeTexture2D( |
| { |
| .format = framebufferFormat(), |
| .extent = {width, height}, |
| .usage = targetUsageFlags(), |
| }, |
| "OffscreenRenderTargetVulkan::TextureTarget"))) |
| {} |
| |
| rive::RiveRenderImage* renderImage() const |
| { |
| return m_renderImage.get(); |
| } |
| |
| VkImage accessTargetImage( |
| VkCommandBuffer commandBuffer, |
| const rive::gpu::vkutil::ImageAccess& dstAccess, |
| rive::gpu::vkutil::ImageAccessAction accessAction = |
| rive::gpu::vkutil::ImageAccessAction::preserveContents) override |
| { |
| texture()->barrier(commandBuffer, dstAccess, accessAction); |
| return texture()->vkImage(); |
| } |
| |
| VkImageView accessTargetImageView( |
| VkCommandBuffer commandBuffer, |
| const rive::gpu::vkutil::ImageAccess& dstAccess, |
| rive::gpu::vkutil::ImageAccessAction accessAction = |
| rive::gpu::vkutil::ImageAccessAction::preserveContents) override |
| { |
| texture()->barrier(commandBuffer, dstAccess, accessAction); |
| return texture()->vkImageView(); |
| } |
| |
| private: |
| rive::gpu::vkutil::Texture2D* texture() |
| { |
| return static_cast<rive::gpu::vkutil::Texture2D*>( |
| m_renderImage->getTexture()); |
| } |
| |
| rive::rcp<rive::RiveRenderImage> m_renderImage; |
| }; |
| |
| rive::rcp<TextureTarget> m_textureTarget; |
| }; |
| |
| rive::rcp<OffscreenRenderTarget> OffscreenRenderTarget::MakeVulkan( |
| rive::gpu::VulkanContext* vk, |
| uint32_t width, |
| uint32_t height, |
| bool riveRenderable) |
| { |
| return rive::make_rcp<OffscreenRenderTargetVulkan>(ref_rcp(vk), |
| width, |
| height, |
| riveRenderable); |
| } |
| }; // namespace rive_tests |
| |
| #endif |