aboutsummaryrefslogtreecommitdiff
path: root/include/render/vulkan.h
diff options
context:
space:
mode:
authornyorain <nyorain@gmail.com>2021-02-21 18:30:12 +0100
committerSimon Ser <contact@emersion.fr>2021-10-18 11:51:13 +0200
commit8e346922508aa3eaccd6e12f2917f6574f349843 (patch)
tree550742b8a086287b6d478db1ade14b2cc4a21294 /include/render/vulkan.h
parent2edf468aeb7d4703aa211cea3b58f04cbc73298c (diff)
render/vulkan: add Vulkan renderer
This new renderer is implemented with the existing wlr_renderer API (which is known to be sub-optimal for some operations). It's not used by default, but users can opt-in by setting WLR_RENDERER=vulkan. The renderer depends on VK_EXT_image_drm_format_modifier and VK_EXT_physical_device_drm. Co-authored-by: Simon Ser <contact@emersion.fr> Co-authored-by: Jan Beich <jbeich@FreeBSD.org>
Diffstat (limited to 'include/render/vulkan.h')
-rw-r--r--include/render/vulkan.h312
1 files changed, 312 insertions, 0 deletions
diff --git a/include/render/vulkan.h b/include/render/vulkan.h
new file mode 100644
index 00000000..aa40198c
--- /dev/null
+++ b/include/render/vulkan.h
@@ -0,0 +1,312 @@
+#ifndef RENDER_VULKAN_H
+#define RENDER_VULKAN_H
+
+#include <stdint.h>
+#include <string.h>
+#include <stdbool.h>
+#include <vulkan/vulkan.h>
+#include <wlr/render/wlr_renderer.h>
+#include <wlr/render/wlr_texture.h>
+#include <wlr/render/drm_format_set.h>
+#include <wlr/render/interface.h>
+
+struct wlr_vk_descriptor_pool;
+
+// Central vulkan state that should only be needed once per compositor.
+struct wlr_vk_instance {
+ VkInstance instance;
+ VkDebugUtilsMessengerEXT messenger;
+
+ // enabled extensions
+ size_t extension_count;
+ const char **extensions;
+
+ struct {
+ PFN_vkCreateDebugUtilsMessengerEXT createDebugUtilsMessengerEXT;
+ PFN_vkDestroyDebugUtilsMessengerEXT destroyDebugUtilsMessengerEXT;
+ } api;
+};
+
+// Creates and initializes a vulkan instance.
+// Will try to enable the given extensions but not fail if they are not
+// available which can later be checked by the caller.
+// The debug parameter determines if validation layers are enabled and a
+// debug messenger created.
+// `compositor_name` and `compositor_version` are passed to the vulkan driver.
+struct wlr_vk_instance *vulkan_instance_create(size_t ext_count,
+ const char **exts, bool debug);
+void vulkan_instance_destroy(struct wlr_vk_instance *ini);
+
+// Logical vulkan device state.
+// Ownership can be shared by multiple renderers, reference counted
+// with `renderers`.
+struct wlr_vk_device {
+ struct wlr_vk_instance *instance;
+
+ VkPhysicalDevice phdev;
+ VkDevice dev;
+
+ int drm_fd;
+
+ // enabled extensions
+ size_t extension_count;
+ const char **extensions;
+
+ // we only ever need one queue for rendering and transfer commands
+ uint32_t queue_family;
+ VkQueue queue;
+
+ struct {
+ PFN_vkGetMemoryFdPropertiesKHR getMemoryFdPropertiesKHR;
+ } api;
+
+ uint32_t format_prop_count;
+ struct wlr_vk_format_props *format_props;
+ struct wlr_drm_format_set dmabuf_render_formats;
+ struct wlr_drm_format_set dmabuf_texture_formats;
+
+ // supported formats for textures (contains only those formats
+ // that support everything we need for textures)
+ uint32_t shm_format_count;
+ uint32_t *shm_formats; // to implement vulkan_get_shm_texture_formats
+};
+
+// Tries to find the VkPhysicalDevice for the given drm fd.
+// Might find none and return VK_NULL_HANDLE.
+VkPhysicalDevice vulkan_find_drm_phdev(struct wlr_vk_instance *ini, int drm_fd);
+
+// Creates a device for the given instance and physical device.
+// Will try to enable the given extensions but not fail if they are not
+// available which can later be checked by the caller.
+struct wlr_vk_device *vulkan_device_create(struct wlr_vk_instance *ini,
+ VkPhysicalDevice phdev, size_t ext_count, const char **exts);
+void vulkan_device_destroy(struct wlr_vk_device *dev);
+
+// Tries to find any memory bit for the given vulkan device that
+// supports the given flags and is set in req_bits (e.g. if memory
+// type 2 is ok, (req_bits & (1 << 2)) must not be 0.
+// Set req_bits to 0xFFFFFFFF to allow all types.
+int vulkan_find_mem_type(struct wlr_vk_device *device,
+ VkMemoryPropertyFlags flags, uint32_t req_bits);
+
+struct wlr_vk_format {
+ uint32_t drm_format;
+ VkFormat vk_format;
+};
+
+// Returns all known format mappings.
+// Might not be supported for gpu/usecase.
+const struct wlr_vk_format *vulkan_get_format_list(size_t *len);
+const struct wlr_vk_format *vulkan_get_format_from_drm(uint32_t drm_format);
+
+struct wlr_vk_format_modifier_props {
+ VkDrmFormatModifierPropertiesEXT props;
+ VkExternalMemoryFeatureFlags dmabuf_flags;
+ VkExtent2D max_extent;
+ bool export_imported;
+};
+
+struct wlr_vk_format_props {
+ struct wlr_vk_format format;
+ VkExtent2D max_extent; // relevant if not created as dma_buf
+ VkFormatFeatureFlags features; // relevant if not created as dma_buf
+
+ uint32_t render_mod_count;
+ struct wlr_vk_format_modifier_props *render_mods;
+
+ uint32_t texture_mod_count;
+ struct wlr_vk_format_modifier_props *texture_mods;
+};
+
+void vulkan_format_props_query(struct wlr_vk_device *dev,
+ const struct wlr_vk_format *format);
+struct wlr_vk_format_modifier_props *vulkan_format_props_find_modifier(
+ struct wlr_vk_format_props *props, uint64_t mod, bool render);
+void vulkan_format_props_finish(struct wlr_vk_format_props *props);
+
+// For each format we want to render, we need a separate renderpass
+// and therefore also separate pipelines.
+struct wlr_vk_render_format_setup {
+ struct wl_list link;
+ VkFormat render_format; // used in renderpass
+ VkRenderPass render_pass;
+
+ VkPipeline tex_pipe;
+ VkPipeline quad_pipe;
+};
+
+// Renderer-internal represenation of an wlr_buffer imported for rendering.
+struct wlr_vk_render_buffer {
+ struct wlr_buffer *wlr_buffer;
+ struct wlr_vk_renderer *renderer;
+ struct wlr_vk_render_format_setup *render_setup;
+ struct wl_list link; // wlr_vk_renderer.buffers
+
+ VkImage image;
+ VkImageView image_view;
+ VkFramebuffer framebuffer;
+ uint32_t mem_count;
+ VkDeviceMemory memories[WLR_DMABUF_MAX_PLANES];
+ bool transitioned;
+
+ struct wl_listener buffer_destroy;
+};
+
+// Vulkan wlr_renderer implementation on top of a wlr_vk_device.
+struct wlr_vk_renderer {
+ struct wlr_renderer wlr_renderer;
+ struct wlr_backend *backend;
+ struct wlr_vk_device *dev;
+
+ VkCommandPool command_pool;
+
+ VkShaderModule vert_module;
+ VkShaderModule tex_frag_module;
+ VkShaderModule quad_frag_module;
+
+ VkDescriptorSetLayout ds_layout;
+ VkPipelineLayout pipe_layout;
+ VkSampler sampler;
+
+ VkFence fence;
+
+ struct wlr_vk_render_buffer *current_render_buffer;
+
+ // current frame id. Used in wlr_vk_texture.last_used
+ // Increased every time a frame is ended for the renderer
+ uint32_t frame;
+ VkRect2D scissor; // needed for clearing
+
+ VkCommandBuffer cb;
+ VkPipeline bound_pipe;
+
+ uint32_t render_width;
+ uint32_t render_height;
+ float projection[9];
+
+ size_t last_pool_size;
+ struct wl_list descriptor_pools; // type wlr_vk_descriptor_pool
+ struct wl_list render_format_setups;
+
+ struct wl_list textures; // wlr_gles2_texture.link
+ struct wl_list destroy_textures; // wlr_vk_texture to destroy after frame
+ struct wl_list foreign_textures; // wlr_vk_texture to return to foreign queue
+
+ struct wl_list render_buffers; // wlr_vk_render_buffer
+
+ struct {
+ VkCommandBuffer cb;
+ bool recording;
+ struct wl_list buffers; // type wlr_vk_shared_buffer
+ } stage;
+};
+
+// Creates a vulkan renderer for the given device.
+struct wlr_renderer *vulkan_renderer_create_for_device(struct wlr_vk_device *dev);
+
+// stage utility - for uploading/retrieving data
+// Gets an command buffer in recording state which is guaranteed to be
+// executed before the next frame.
+VkCommandBuffer vulkan_record_stage_cb(struct wlr_vk_renderer *renderer);
+
+// Submits the current stage command buffer and waits until it has
+// finished execution.
+bool vulkan_submit_stage_wait(struct wlr_vk_renderer *renderer);
+
+// Suballocates a buffer span with the given size that can be mapped
+// and used as staging buffer. The allocation is implicitly released when the
+// stage cb has finished execution.
+struct wlr_vk_buffer_span vulkan_get_stage_span(
+ struct wlr_vk_renderer *renderer, VkDeviceSize size);
+
+// Tries to allocate a texture descriptor set. Will additionally
+// return the pool it was allocated from when successful (for freeing it later).
+struct wlr_vk_descriptor_pool *vulkan_alloc_texture_ds(
+ struct wlr_vk_renderer *renderer, VkDescriptorSet *ds);
+
+// Frees the given descriptor set from the pool its pool.
+void vulkan_free_ds(struct wlr_vk_renderer *renderer,
+ struct wlr_vk_descriptor_pool *pool, VkDescriptorSet ds);
+struct wlr_vk_format_props *vulkan_format_props_from_drm(
+ struct wlr_vk_device *dev, uint32_t drm_format);
+struct wlr_vk_renderer *vulkan_get_renderer(struct wlr_renderer *r);
+
+// State (e.g. image texture) associated with a surface.
+struct wlr_vk_texture {
+ struct wlr_texture wlr_texture;
+ struct wlr_vk_renderer *renderer;
+ uint32_t mem_count;
+ VkDeviceMemory memories[WLR_DMABUF_MAX_PLANES];
+ VkImage image;
+ VkImageView image_view;
+ const struct wlr_vk_format *format;
+ VkDescriptorSet ds;
+ struct wlr_vk_descriptor_pool *ds_pool;
+ uint32_t last_used; // to track when it can be destroyed
+ bool dmabuf_imported;
+ bool owned; // if dmabuf_imported: whether we have ownership of the image
+ bool transitioned; // if dma_imported: whether we transitioned it away from preinit
+ bool invert_y; // if dma_imported: whether we must flip y
+ struct wl_list foreign_link;
+ struct wl_list destroy_link;
+ struct wl_list link; // wlr_gles2_renderer.textures
+
+ // If imported from a wlr_buffer
+ struct wlr_buffer *buffer;
+ struct wl_listener buffer_destroy;
+};
+
+struct wlr_vk_texture *vulkan_get_texture(struct wlr_texture *wlr_texture);
+VkImage vulkan_import_dmabuf(struct wlr_vk_renderer *renderer,
+ const struct wlr_dmabuf_attributes *attribs,
+ VkDeviceMemory mems[static WLR_DMABUF_MAX_PLANES], uint32_t *n_mems,
+ bool for_render);
+struct wlr_texture *vulkan_texture_from_buffer(
+ struct wlr_renderer *wlr_renderer, struct wlr_buffer *buffer);
+void vulkan_texture_destroy(struct wlr_vk_texture *texture);
+
+struct wlr_vk_descriptor_pool {
+ VkDescriptorPool pool;
+ uint32_t free; // number of textures that can be allocated
+ struct wl_list link;
+};
+
+struct wlr_vk_allocation {
+ VkDeviceSize start;
+ VkDeviceSize size;
+};
+
+// List of suballocated staging buffers.
+// Used to upload to/read from device local images.
+struct wlr_vk_shared_buffer {
+ struct wl_list link;
+ VkBuffer buffer;
+ VkDeviceMemory memory;
+ VkDeviceSize buf_size;
+
+ size_t allocs_size;
+ size_t allocs_capacity;
+ struct wlr_vk_allocation *allocs;
+};
+
+// Suballocated range on a buffer.
+struct wlr_vk_buffer_span {
+ struct wlr_vk_shared_buffer *buffer;
+ struct wlr_vk_allocation alloc;
+};
+
+// util
+bool vulkan_has_extension(size_t count, const char **exts, const char *find);
+const char *vulkan_strerror(VkResult err);
+void vulkan_change_layout(VkCommandBuffer cb, VkImage img,
+ VkImageLayout ol, VkPipelineStageFlags srcs, VkAccessFlags srca,
+ VkImageLayout nl, VkPipelineStageFlags dsts, VkAccessFlags dsta);
+void vulkan_change_layout_queue(VkCommandBuffer cb, VkImage img,
+ VkImageLayout ol, VkPipelineStageFlags srcs, VkAccessFlags srca,
+ VkImageLayout nl, VkPipelineStageFlags dsts, VkAccessFlags dsta,
+ uint32_t src_family, uint32_t dst_family);
+
+#define wlr_vk_error(fmt, res, ...) wlr_log(WLR_ERROR, fmt ": %s (%d)", \
+ vulkan_strerror(res), res, ##__VA_ARGS__)
+
+#endif // RENDER_VULKAN_H