blob: 2965993e811c115527af09dadf5acfbfff08de5c [file] [log] [blame]
/*
* Copyright 2024 Rive
*/
#pragma once
#include "rive/renderer/gpu_resource.hpp"
#include "rive/renderer/vulkan/vkutil.hpp"
VK_DEFINE_HANDLE(VmaAllocator);
namespace rive::gpu
{
// Specifies the Vulkan API version and which relevant features have been
// enabled. The client should ensure the features get enabled if they are
// supported.
struct VulkanFeatures
{
uint32_t apiVersion = VK_API_VERSION_1_0;
// VkPhysicalDeviceFeatures.
bool independentBlend = false;
bool fillModeNonSolid = false;
bool fragmentStoresAndAtomics = false;
bool shaderClipDistance = false;
// EXT_rasterization_order_attachment_access.
bool rasterizationOrderColorAttachmentAccess = false;
// VK_EXT_fragment_shader_interlock.
bool fragmentShaderPixelInterlock = false;
// Indicates a nonconformant driver, like MoltenVK.
bool VK_KHR_portability_subset = false;
};
// Wraps a VkDevice, function dispatch table, and VMA library instance.
//
// Provides methods to allocate vkutil::RenderingResource objects, and manages
// their lifecycles via a "resource purgatory", which keeps resources alive
// until command buffers have finished using them.
//
// Provides minor helper utilities, but for the most part, the client is
// expected to make raw Vulkan calls via the provided function pointers.
class VulkanContext : public GPUResourceManager
{
public:
VulkanContext(VkInstance,
VkPhysicalDevice,
VkDevice,
const VulkanFeatures&,
PFN_vkGetInstanceProcAddr);
~VulkanContext();
const VkInstance instance;
const VkPhysicalDevice physicalDevice;
const VkDevice device;
const VulkanFeatures features;
#define RIVE_VULKAN_INSTANCE_COMMANDS(F) \
F(GetDeviceProcAddr) \
F(GetPhysicalDeviceFormatProperties) \
F(GetPhysicalDeviceProperties) \
F(SetDebugUtilsObjectNameEXT)
#define RIVE_VULKAN_DEVICE_COMMANDS(F) \
F(AllocateDescriptorSets) \
F(CmdBeginRenderPass) \
F(CmdBindDescriptorSets) \
F(CmdBindIndexBuffer) \
F(CmdBindPipeline) \
F(CmdBindVertexBuffers) \
F(CmdBlitImage) \
F(CmdClearColorImage) \
F(CmdCopyBufferToImage) \
F(CmdDraw) \
F(CmdDrawIndexed) \
F(CmdEndRenderPass) \
F(CmdFillBuffer) \
F(CmdNextSubpass) \
F(CmdPipelineBarrier) \
F(CmdSetScissor) \
F(CmdSetViewport) \
F(CreateDescriptorPool) \
F(CreateDescriptorSetLayout) \
F(CreateFramebuffer) \
F(CreateGraphicsPipelines) \
F(CreateImageView) \
F(CreatePipelineLayout) \
F(CreateRenderPass) \
F(CreateSampler) \
F(CreateShaderModule) \
F(DestroyDescriptorPool) \
F(DestroyDescriptorSetLayout) \
F(DestroyFramebuffer) \
F(DestroyImageView) \
F(DestroyPipeline) \
F(DestroyPipelineLayout) \
F(DestroyRenderPass) \
F(DestroySampler) \
F(DestroyShaderModule) \
F(ResetDescriptorPool) \
F(UpdateDescriptorSets)
#define DECLARE_VULKAN_COMMAND(CMD) const PFN_vk##CMD CMD;
RIVE_VULKAN_INSTANCE_COMMANDS(DECLARE_VULKAN_COMMAND)
RIVE_VULKAN_DEVICE_COMMANDS(DECLARE_VULKAN_COMMAND)
#undef DECLARE_VULKAN_COMMAND
VmaAllocator allocator() const { return m_vmaAllocator; }
const VkPhysicalDeviceProperties& physicalDeviceProperties() const
{
return m_physicalDeviceProperties;
}
bool isFormatSupportedWithFeatureFlags(VkFormat, VkFormatFeatureFlagBits);
bool supportsD24S8() const { return m_supportsD24S8; }
// Resource allocation.
rcp<vkutil::Buffer> makeBuffer(const VkBufferCreateInfo&,
vkutil::Mappability);
rcp<vkutil::Image> makeImage(const VkImageCreateInfo&, const char* name);
rcp<vkutil::ImageView> makeImageView(rcp<vkutil::Image>, const char* name);
rcp<vkutil::ImageView> makeImageView(rcp<vkutil::Image>,
const VkImageViewCreateInfo&,
const char* name);
rcp<vkutil::ImageView> makeExternalImageView(const VkImageViewCreateInfo&,
const char* name);
rcp<vkutil::Texture2D> makeTexture2D(const VkImageCreateInfo&,
const char* name);
rcp<vkutil::Framebuffer> makeFramebuffer(const VkFramebufferCreateInfo&);
// Helpers.
void updateImageDescriptorSets(
VkDescriptorSet,
VkWriteDescriptorSet,
std::initializer_list<VkDescriptorImageInfo>);
void updateBufferDescriptorSets(
VkDescriptorSet,
VkWriteDescriptorSet,
std::initializer_list<VkDescriptorBufferInfo>);
void memoryBarrier(VkCommandBuffer,
VkPipelineStageFlags srcStageMask,
VkPipelineStageFlags dstStageMask,
VkDependencyFlags,
VkMemoryBarrier);
void imageMemoryBarriers(VkCommandBuffer,
VkPipelineStageFlags srcStageMask,
VkPipelineStageFlags dstStageMask,
VkDependencyFlags,
uint32_t count,
VkImageMemoryBarrier*);
void imageMemoryBarrier(VkCommandBuffer commandBuffer,
VkPipelineStageFlags srcStageMask,
VkPipelineStageFlags dstStageMask,
VkDependencyFlags dependencyFlags,
VkImageMemoryBarrier imageMemoryBarrier)
{
imageMemoryBarriers(commandBuffer,
srcStageMask,
dstStageMask,
dependencyFlags,
1,
&imageMemoryBarrier);
}
const vkutil::ImageAccess& simpleImageMemoryBarrier(
VkCommandBuffer,
const vkutil::ImageAccess& srcAccess,
const vkutil::ImageAccess& dstAccess,
VkImage,
vkutil::ImageAccessAction = vkutil::ImageAccessAction::preserveContents,
VkDependencyFlags = 0);
void bufferMemoryBarrier(VkCommandBuffer,
VkPipelineStageFlags srcStageMask,
VkPipelineStageFlags dstStageMask,
VkDependencyFlags,
VkBufferMemoryBarrier);
void clearColorImage(VkCommandBuffer, ColorInt, VkImage, VkImageLayout);
void blitSubRect(VkCommandBuffer commandBuffer,
VkImage srcImage,
VkImageLayout srcImageLayout,
VkImage dstImage,
VkImageLayout dstImageLayout,
const IAABB&);
void setDebugNameIfEnabled(uint64_t handle,
VkObjectType objectType,
const char* name);
private:
const VmaAllocator m_vmaAllocator;
VkPhysicalDeviceProperties m_physicalDeviceProperties;
// Vulkan spec: must support one of D24S8 and D32S8.
bool m_supportsD24S8 = false;
};
} // namespace rive::gpu