Files
test/intern/ghost/intern/GHOST_ContextVK.hh
Jeroen Bakker 6a20b0022c Vulkan: Swap Chain
This PR replaces the previous implementation of the swap chain.
The previous implementation was based on a gaming loop where
inside a single function an image is requested, the drawing occurs
and the requested image is presented on screen.

In blender the drawing isn't controlled in a single function and
this approach lead to freezes, missing frames and other
artifacts.

This approach is not be the final approach but a step into a
direction where the acquiring of the next image in the swap chain
is separated from the swapping.

Pull Request: https://projects.blender.org/blender/blender/pulls/107740
2023-05-11 12:51:05 +02:00

208 lines
5.9 KiB
C++

/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup GHOST
*/
#pragma once
#include "GHOST_Context.hh"
#ifdef _WIN32
# include "GHOST_SystemWin32.hh"
#elif defined(__APPLE__)
# include "GHOST_SystemCocoa.hh"
#else
# include "GHOST_SystemX11.hh"
# ifdef WITH_GHOST_WAYLAND
# include "GHOST_SystemWayland.hh"
# else
# define wl_surface void
# define wl_display void
# endif
#endif
#include <vector>
#ifdef __APPLE__
# include <MoltenVK/vk_mvk_moltenvk.h>
#else
# include <vulkan/vulkan.h>
#endif
#ifndef GHOST_OPENGL_VK_CONTEXT_FLAGS
/* leave as convenience define for the future */
# define GHOST_OPENGL_VK_CONTEXT_FLAGS 0
#endif
#ifndef GHOST_OPENGL_VK_RESET_NOTIFICATION_STRATEGY
# define GHOST_OPENGL_VK_RESET_NOTIFICATION_STRATEGY 0
#endif
typedef enum {
GHOST_kVulkanPlatformX11 = 0,
#ifdef WITH_GHOST_WAYLAND
GHOST_kVulkanPlatformWayland,
#endif
} GHOST_TVulkanPlatformType;
class GHOST_ContextVK : public GHOST_Context {
public:
/**
* Constructor.
*/
GHOST_ContextVK(bool stereoVisual,
#ifdef _WIN32
HWND hwnd,
#elif defined(__APPLE__)
/* FIXME CAMetalLayer but have issue with linking. */
void *metal_layer,
#else
GHOST_TVulkanPlatformType platform,
/* X11 */
Window window,
Display *display,
/* Wayland */
wl_surface *wayland_surface,
wl_display *wayland_display,
#endif
int contextMajorVersion,
int contextMinorVersion,
int m_debug);
/**
* Destructor.
*/
~GHOST_ContextVK();
/**
* Swaps front and back buffers of a window.
* \return A boolean success indicator.
*/
GHOST_TSuccess swapBuffers();
/**
* Activates the drawing context of this window.
* \return A boolean success indicator.
*/
GHOST_TSuccess activateDrawingContext();
/**
* Release the drawing context of the calling thread.
* \return A boolean success indicator.
*/
GHOST_TSuccess releaseDrawingContext();
/**
* Call immediately after new to initialize. If this fails then immediately delete the object.
* \return Indication as to whether initialization has succeeded.
*/
GHOST_TSuccess initializeDrawingContext();
/**
* Removes references to native handles from this context and then returns
* \return GHOST_kSuccess if it is OK for the parent to release the handles and
* GHOST_kFailure if releasing the handles will interfere with sharing
*/
GHOST_TSuccess releaseNativeHandles();
/**
* Gets the Vulkan context related resource handles.
* \return A boolean success indicator.
*/
GHOST_TSuccess getVulkanHandles(void *r_instance,
void *r_physical_device,
void *r_device,
uint32_t *r_graphic_queue_family,
void *r_queue);
GHOST_TSuccess getVulkanCommandBuffer(void *r_command_buffer);
/**
* Gets the Vulkan framebuffer related resource handles associated with the Vulkan context.
* Needs to be called after each swap events as the framebuffer will change.
* \return A boolean success indicator.
*/
GHOST_TSuccess getVulkanBackbuffer(
void *image, void *framebuffer, void *render_pass, void *extent, uint32_t *fb_id);
/**
* Sets the swap interval for `swapBuffers`.
* \param interval: The swap interval to use.
* \return A boolean success indicator.
*/
GHOST_TSuccess setSwapInterval(int /* interval */)
{
return GHOST_kFailure;
}
/**
* Gets the current swap interval for swapBuffers.
* \param intervalOut: Variable to store the swap interval if it can be read.
* \return Whether the swap interval can be read.
*/
GHOST_TSuccess getSwapInterval(int &)
{
return GHOST_kFailure;
};
private:
#ifdef _WIN32
HWND m_hwnd;
#elif defined(__APPLE__)
CAMetalLayer *m_metal_layer;
#else /* Linux */
GHOST_TVulkanPlatformType m_platform;
/* X11 */
Display *m_display;
Window m_window;
/* Wayland */
wl_surface *m_wayland_surface;
wl_display *m_wayland_display;
#endif
const int m_context_major_version;
const int m_context_minor_version;
const int m_debug;
VkCommandPool m_command_pool;
VkQueue m_graphic_queue;
VkQueue m_present_queue;
/* For display only. */
VkSurfaceKHR m_surface;
VkSwapchainKHR m_swapchain;
std::vector<VkImage> m_swapchain_images;
std::vector<VkImageView> m_swapchain_image_views;
std::vector<VkFramebuffer> m_swapchain_framebuffers;
std::vector<VkCommandBuffer> m_command_buffers;
VkRenderPass m_render_pass;
VkExtent2D m_render_extent;
std::vector<VkSemaphore> m_image_available_semaphores;
std::vector<VkSemaphore> m_render_finished_semaphores;
std::vector<VkFence> m_in_flight_fences;
/** frame modulo swapchain_len. Used as index for sync objects. */
int m_currentFrame = 0;
/**
* Last frame where the vulkan handles where retrieved from. This attribute is used to determine
* if a new image from the swap chain needs to be acquired.
*
* In a regular vulkan application this is done in the same method, but due to GHOST API this
* isn't possible. Swap chains are triggered by the window manager and the GPUBackend isn't
* informed about these changes.
*/
int m_lastFrame = -1;
/** Image index in the swapchain. Used as index for render objects. */
uint32_t m_currentImage = 0;
/** Used to unique framebuffer ids to return when swapchain is recreated. */
uint32_t m_swapchain_id = 0;
const char *getPlatformSpecificSurfaceExtension() const;
GHOST_TSuccess createSwapchain();
GHOST_TSuccess destroySwapchain();
GHOST_TSuccess createCommandPools();
GHOST_TSuccess createGraphicsCommandBuffers();
GHOST_TSuccess createGraphicsCommandBuffer();
GHOST_TSuccess recordCommandBuffers();
};