Geometry Nodes: Rename Blur Attribute to a Blur Field #111542
5
AUTHORS
5
AUTHORS
@ -226,7 +226,7 @@ Geoffroy Krantz <kgeogeo@hotmail.com>
|
||||
George Vogiatzis <Gvgeo>
|
||||
Georgiy Markelov <georgiy.m.markelov@gmail.com>
|
||||
Germano Cavalcante <germano.costa@ig.com.br>
|
||||
Gilberto Rodrigues <gilberto_rodrigues>
|
||||
Gilberto Rodrigues <gilbertorodrigues@outlook.com>
|
||||
Glenn Tester <karmacop>
|
||||
Gottfried Hofmann <gottfried>
|
||||
Greg Neumiller <rlneumiller>
|
||||
@ -635,12 +635,13 @@ Victor-Louis De Gusseme <victorlouis>
|
||||
Viktoriia Safiullina <safiuvik>
|
||||
Ville Kivistö <vkivisto>
|
||||
Vincent Blankfield <vvv>
|
||||
Vitor Boschi da Silva <vitorboschi>
|
||||
Vitor Boschi <vitorboschi@gmail.com>
|
||||
Vuk Gardašević <lijenstina>
|
||||
Wael El Oraiby <wael.eloraiby@gmail.com>
|
||||
Walid Shouman <eng.walidshouman@gmail.com>
|
||||
Wannes Malfait <Wannes>
|
||||
Wayde Moss <wbmoss_dev@yahoo.com>
|
||||
Weikang Qiu <qiuweikang1999@gmail.com>
|
||||
Weizhen Huang <weizhen@blender.org>
|
||||
Welp <jtf515@gmail.com>
|
||||
William Leeson <william@blender.org>
|
||||
|
@ -256,7 +256,10 @@ extern GHOST_TSuccess GHOST_EndFullScreen(GHOST_SystemHandle systemhandle);
|
||||
extern bool GHOST_GetFullScreen(GHOST_SystemHandle systemhandle);
|
||||
|
||||
/**
|
||||
* Get the Window under the cursor.
|
||||
* Get the Window under the cursor. Although coordinates of the mouse are supplied, platform-
|
||||
* specific implementations are free to ignore these and query the mouse location themselves, due
|
||||
* to them possibly being incorrect under certain conditions, for example when using multiple
|
||||
* monitors that vary in scale and/or DPI.
|
||||
* \param x: The x-coordinate of the cursor.
|
||||
* \param y: The y-coordinate of the cursor.
|
||||
* \return The window under the cursor or nullptr in none.
|
||||
@ -1257,56 +1260,35 @@ void GHOST_GetVulkanHandles(GHOST_ContextHandle context,
|
||||
void *r_queue);
|
||||
|
||||
/**
|
||||
* Return Vulkan command buffer.
|
||||
* Set the pre and post callbacks for vulkan swap chain in the given context.
|
||||
*
|
||||
* Command buffers are different for each image in the swap chain.
|
||||
* At the start of each frame the correct command buffer should be
|
||||
* retrieved with this function.
|
||||
*
|
||||
* Should only be called when using a Vulkan context.
|
||||
* Other contexts will not return any handles and leave the
|
||||
* handles where the parameters are referring to unmodified.
|
||||
*
|
||||
* \param context: GHOST context handle to a vulkan context to get the
|
||||
* command queue from.
|
||||
* \param r_command_buffer: After calling this function the VkCommandBuffer
|
||||
* referenced by this parameter will contain the VKCommandBuffer handle
|
||||
* of the current back buffer (when swap chains are enabled) or
|
||||
* it will contain a general VkCommandQueue.
|
||||
* \param context: GHOST context handle of a vulkan context to
|
||||
* get the Vulkan handles from.
|
||||
* \param swap_buffers_pre_callback: Function pointer to be called at the beginning of swapBuffers.
|
||||
* Inside this callback the next swap chain image needs to be acquired and filled.
|
||||
* \param swap_buffers_post_callback: Function to be called at th end of swapBuffers. swapBuffers
|
||||
* can recreate the swap chain. When this is done the application should be informed by those
|
||||
* changes.
|
||||
*/
|
||||
void GHOST_GetVulkanCommandBuffer(GHOST_ContextHandle context, void *r_command_buffer);
|
||||
void GHOST_SetVulkanSwapBuffersCallbacks(
|
||||
GHOST_ContextHandle context,
|
||||
void (*swap_buffers_pre_callback)(const GHOST_VulkanSwapChainData *),
|
||||
void (*swap_buffers_post_callback)(void));
|
||||
|
||||
/**
|
||||
* Gets the Vulkan back-buffer related resource handles associated with the Vulkan context.
|
||||
* Needs to be called after each swap event as the back-buffer will change.
|
||||
*
|
||||
* Should only be called when using a Vulkan context with an active swap chain.
|
||||
* Other contexts will not return any handles and leave the
|
||||
* handles where the parameters are referring to unmodified.
|
||||
* Acquire the current swap chain format.
|
||||
*
|
||||
* \param windowhandle: GHOST window handle to a window to get the resource from.
|
||||
* \param r_image: After calling this function the VkImage
|
||||
* referenced by this parameter will contain the VKImage handle
|
||||
* of the current back buffer.
|
||||
* \param r_framebuffer: After calling this function the VkFramebuffer
|
||||
* referenced by this parameter will contain the VKFramebuffer handle
|
||||
* of the current back buffer.
|
||||
* \param r_render_pass: After calling this function the VkRenderPass
|
||||
* referenced by this parameter will contain the VKRenderPass handle
|
||||
* of the current back buffer.
|
||||
* \param r_surface_format: After calling this function the VkSurfaceFormatKHR
|
||||
* referenced by this parameter will contain the surface format of the
|
||||
* surface. The format is the same as the image returned in the r_image
|
||||
* parameter.
|
||||
* \param r_extent: After calling this function the VkExtent2D
|
||||
* referenced by this parameter will contain the size of the
|
||||
* frame buffer and image in pixels.
|
||||
* \param r_fb_id: After calling this function the uint32_t
|
||||
* referenced by this parameter will contain the id of the
|
||||
* framebuffer of the current back buffer.
|
||||
*/
|
||||
void GHOST_GetVulkanBackbuffer(GHOST_WindowHandle windowhandle,
|
||||
void *r_image,
|
||||
void *r_framebuffer,
|
||||
void *r_render_pass,
|
||||
void *r_extent,
|
||||
uint32_t *r_fb_id);
|
||||
void GHOST_GetVulkanSwapChainFormat(GHOST_WindowHandle windowhandle,
|
||||
GHOST_VulkanSwapChainData *r_swap_chain_data);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -9,6 +9,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "GHOST_Types.h"
|
||||
|
||||
/**
|
||||
@ -38,7 +40,9 @@ class GHOST_IContext {
|
||||
virtual GHOST_TSuccess releaseDrawingContext() = 0;
|
||||
|
||||
virtual unsigned int getDefaultFramebuffer() = 0;
|
||||
virtual GHOST_TSuccess swapBuffers() = 0;
|
||||
|
||||
#ifdef WITH_VULKAN_BACKEND
|
||||
/**
|
||||
* Get Vulkan handles for the given context.
|
||||
*
|
||||
@ -47,6 +51,8 @@ class GHOST_IContext {
|
||||
* Other contexts will not return any handles and leave the
|
||||
* handles where the parameters are referring to unmodified.
|
||||
*
|
||||
* \param context: GHOST context handle of a vulkan context to
|
||||
* get the Vulkan handles from.
|
||||
* \param r_instance: After calling this function the VkInstance
|
||||
* referenced by this parameter will contain the VKInstance handle
|
||||
* of the context associated with the `context` parameter.
|
||||
@ -62,9 +68,6 @@ class GHOST_IContext {
|
||||
* \param r_queue: After calling this function the VkQueue
|
||||
* referenced by this parameter will contain the VKQueue handle
|
||||
* of the context associated with the `context` parameter.
|
||||
* \returns GHOST_kFailure when context isn't a Vulkan context.
|
||||
* GHOST_kSuccess when the context is a Vulkan context and the
|
||||
* handles have been set.
|
||||
*/
|
||||
virtual GHOST_TSuccess getVulkanHandles(void *r_instance,
|
||||
void *r_physical_device,
|
||||
@ -73,52 +76,35 @@ class GHOST_IContext {
|
||||
void *r_queue) = 0;
|
||||
|
||||
/**
|
||||
* Return Vulkan command buffer.
|
||||
* Acquire the current swap chain format.
|
||||
*
|
||||
* Command buffers are different for each image in the swap chain.
|
||||
* At the start of each frame the correct command buffer should be
|
||||
* retrieved with this function.
|
||||
*
|
||||
* \param r_command_buffer: After calling this function the VkCommandBuffer
|
||||
* referenced by this parameter will contain the VKCommandBuffer handle
|
||||
* of the current back buffer (when swap chains are enabled) or
|
||||
* it will contain a general VkCommandQueue.
|
||||
* \returns GHOST_kFailure when context isn't a Vulkan context.
|
||||
* GHOST_kSuccess when the context is a Vulkan context and the
|
||||
* handles have been set.
|
||||
*/
|
||||
virtual GHOST_TSuccess getVulkanCommandBuffer(void *r_command_buffer) = 0;
|
||||
|
||||
/**
|
||||
* Gets the Vulkan back-buffer related resource handles associated with the Vulkan context.
|
||||
* Needs to be called after each swap event as the back-buffer will change.
|
||||
*
|
||||
* \param r_image: After calling this function the VkImage
|
||||
* referenced by this parameter will contain the VKImage handle
|
||||
* of the current back buffer.
|
||||
* \param r_framebuffer: After calling this function the VkFramebuffer
|
||||
* referenced by this parameter will contain the VKFramebuffer handle
|
||||
* of the current back buffer.
|
||||
* \param r_render_pass: After calling this function the VkRenderPass
|
||||
* referenced by this parameter will contain the VKRenderPass handle
|
||||
* of the current back buffer.
|
||||
* \param windowhandle: GHOST window handle to a window to get the resource from.
|
||||
* \param r_surface_format: After calling this function the VkSurfaceFormatKHR
|
||||
* referenced by this parameter will contain the surface format of the
|
||||
* surface. The format is the same as the image returned in the r_image
|
||||
* parameter.
|
||||
* \param r_extent: After calling this function the VkExtent2D
|
||||
* referenced by this parameter will contain the size of the
|
||||
* frame buffer and image in pixels.
|
||||
* \param r_fb_id: After calling this function the uint32_t
|
||||
* referenced by this parameter will contain the id of the
|
||||
* framebuffer of the current back buffer.
|
||||
* \returns GHOST_kFailure when context isn't a Vulkan context.
|
||||
* GHOST_kSuccess when the context is a Vulkan context and the
|
||||
* handles have been set.
|
||||
*/
|
||||
virtual GHOST_TSuccess getVulkanBackbuffer(void *r_image,
|
||||
void *r_framebuffer,
|
||||
void *r_render_pass,
|
||||
void *r_extent,
|
||||
uint32_t *r_fb_id) = 0;
|
||||
virtual GHOST_TSuccess getVulkanSwapChainFormat(
|
||||
GHOST_VulkanSwapChainData *r_swap_chain_data) = 0;
|
||||
|
||||
virtual GHOST_TSuccess swapBuffers() = 0;
|
||||
/**
|
||||
* Set the pre and post callbacks for vulkan swap chain in the given context.
|
||||
*
|
||||
* \param context: GHOST context handle of a vulkan context to
|
||||
* get the Vulkan handles from.
|
||||
* \param swap_buffers_pre_callback: Function pointer to be called at the beginning of
|
||||
* swapBuffers. Inside this callback the next swap chain image needs to be acquired and filled.
|
||||
* \param swap_buffers_post_callback: Function to be called at th end of swapBuffers. swapBuffers
|
||||
* can recreate the swap chain. When this is done the application should be informed by those
|
||||
* changes.
|
||||
*/
|
||||
virtual GHOST_TSuccess setVulkanSwapBuffersCallbacks(
|
||||
std::function<void(const GHOST_VulkanSwapChainData *)> swap_buffers_pre_callback,
|
||||
std::function<void(void)> swap_buffers_post_callback) = 0;
|
||||
#endif
|
||||
|
||||
#ifdef WITH_CXX_GUARDEDALLOC
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("GHOST:GHOST_IContext")
|
||||
|
@ -332,7 +332,10 @@ class GHOST_ISystem {
|
||||
virtual void setAutoFocus(const bool auto_focus) = 0;
|
||||
|
||||
/**
|
||||
* Get the Window under the cursor.
|
||||
* Get the Window under the cursor. Although coordinates of the mouse are supplied, platform-
|
||||
* specific implementations are free to ignore these and query the mouse location themselves, due
|
||||
* to them possibly being incorrect under certain conditions, for example when using multiple
|
||||
* monitors that vary in scale and/or DPI.
|
||||
* \param x: The x-coordinate of the cursor.
|
||||
* \param y: The y-coordinate of the cursor.
|
||||
* \return The window under the cursor or nullptr if none.
|
||||
|
@ -209,13 +209,10 @@ class GHOST_IWindow {
|
||||
*/
|
||||
virtual unsigned int getDefaultFramebuffer() = 0;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
virtual GHOST_TSuccess getVulkanBackbuffer(
|
||||
void *image, void *framebuffer, void *render_pass, void *extent, uint32_t *fb_id) = 0;
|
||||
#ifdef WITH_VULKAN_BACKEND
|
||||
virtual GHOST_TSuccess getVulkanSwapChainFormat(
|
||||
GHOST_VulkanSwapChainData *r_swap_chain_data) = 0;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Invalidates the contents of this window.
|
||||
|
@ -10,6 +10,14 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef WITH_VULKAN_BACKEND
|
||||
# ifdef __APPLE__
|
||||
# include <MoltenVK/vk_mvk_moltenvk.h>
|
||||
# else
|
||||
# include <vulkan/vulkan.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* This is used by `GHOST_C-api.h` too, cannot use C++ conventions. */
|
||||
// NOLINTBEGIN: modernize-use-using
|
||||
|
||||
@ -691,6 +699,17 @@ typedef struct {
|
||||
GHOST_TDrawingContextType context_type;
|
||||
} GHOST_GPUSettings;
|
||||
|
||||
#ifdef WITH_VULKAN_BACKEND
|
||||
typedef struct {
|
||||
/** Image handle to the image that will be presented to the user. */
|
||||
VkImage image;
|
||||
/** Format of the image. */
|
||||
VkFormat format;
|
||||
/** Resolution of the image. */
|
||||
VkExtent2D extent;
|
||||
} GHOST_VulkanSwapChainData;
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
/** Axis that cursor grab will wrap. */
|
||||
GHOST_kDebugDefault = (1 << 1),
|
||||
|
@ -1237,21 +1237,20 @@ void GHOST_GetVulkanHandles(GHOST_ContextHandle contexthandle,
|
||||
r_instance, r_physical_device, r_device, r_graphic_queue_family, r_queue);
|
||||
}
|
||||
|
||||
void GHOST_GetVulkanCommandBuffer(GHOST_ContextHandle contexthandle, void *r_command_buffer)
|
||||
void GHOST_SetVulkanSwapBuffersCallbacks(
|
||||
GHOST_ContextHandle contexthandle,
|
||||
void (*swap_buffers_pre_callback)(const GHOST_VulkanSwapChainData *),
|
||||
void (*swap_buffers_post_callback)(void))
|
||||
{
|
||||
GHOST_IContext *context = (GHOST_IContext *)contexthandle;
|
||||
context->getVulkanCommandBuffer(r_command_buffer);
|
||||
context->setVulkanSwapBuffersCallbacks(swap_buffers_pre_callback, swap_buffers_post_callback);
|
||||
}
|
||||
|
||||
void GHOST_GetVulkanBackbuffer(GHOST_WindowHandle windowhandle,
|
||||
void *image,
|
||||
void *framebuffer,
|
||||
void *render_pass,
|
||||
void *extent,
|
||||
uint32_t *fb_id)
|
||||
void GHOST_GetVulkanSwapChainFormat(GHOST_WindowHandle windowhandle,
|
||||
GHOST_VulkanSwapChainData *r_swap_chain_data)
|
||||
{
|
||||
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
|
||||
window->getVulkanBackbuffer(image, framebuffer, render_pass, extent, fb_id);
|
||||
window->getVulkanSwapChainFormat(r_swap_chain_data);
|
||||
}
|
||||
|
||||
#endif /* WITH_VULKAN_BACKEND */
|
||||
|
@ -130,6 +130,7 @@ class GHOST_Context : public GHOST_IContext {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef WITH_VULKAN_BACKEND
|
||||
/**
|
||||
* Get Vulkan handles for the given context.
|
||||
*
|
||||
@ -166,58 +167,20 @@ class GHOST_Context : public GHOST_IContext {
|
||||
return GHOST_kFailure;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return Vulkan command buffer.
|
||||
*
|
||||
* Command buffers are different for each image in the swap chain.
|
||||
* At the start of each frame the correct command buffer should be
|
||||
* retrieved with this function.
|
||||
*
|
||||
* \param r_command_buffer: After calling this function the VkCommandBuffer
|
||||
* referenced by this parameter will contain the VKCommandBuffer handle
|
||||
* of the current back buffer (when swap chains are enabled) or
|
||||
* it will contain a general VkCommandQueue.
|
||||
* \returns GHOST_kFailure when context isn't a Vulkan context.
|
||||
* GHOST_kSuccess when the context is a Vulkan context and the
|
||||
* handles have been set.
|
||||
*/
|
||||
virtual GHOST_TSuccess getVulkanCommandBuffer(void * /*r_command_buffer*/) override
|
||||
{
|
||||
return GHOST_kFailure;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the Vulkan back-buffer related resource handles associated with the Vulkan context.
|
||||
* Needs to be called after each swap event as the back-buffer will change.
|
||||
*
|
||||
* \param r_image: After calling this function the VkImage
|
||||
* referenced by this parameter will contain the VKImage handle
|
||||
* of the current back buffer.
|
||||
* \param r_framebuffer: After calling this function the VkFramebuffer
|
||||
* referenced by this parameter will contain the VKFramebuffer handle
|
||||
* of the current back buffer.
|
||||
* \param r_render_pass: After calling this function the VkRenderPass
|
||||
* referenced by this parameter will contain the VKRenderPass handle
|
||||
* of the current back buffer.
|
||||
* \param r_extent: After calling this function the VkExtent2D
|
||||
* referenced by this parameter will contain the size of the
|
||||
* frame buffer and image in pixels.
|
||||
* \param r_fb_id: After calling this function the uint32_t
|
||||
* referenced by this parameter will contain the id of the
|
||||
* framebuffer of the current back buffer.
|
||||
* \returns GHOST_kFailure when context isn't a Vulkan context.
|
||||
* GHOST_kSuccess when the context is a Vulkan context and the
|
||||
* handles have been set.
|
||||
*/
|
||||
virtual GHOST_TSuccess getVulkanBackbuffer(void * /*r_image*/,
|
||||
void * /*r_framebuffer*/,
|
||||
void * /*r_render_pass*/,
|
||||
void * /*r_extent*/,
|
||||
uint32_t * /*fb_id*/) override
|
||||
virtual GHOST_TSuccess getVulkanSwapChainFormat(
|
||||
GHOST_VulkanSwapChainData * /*r_swap_chain_data */) override
|
||||
{
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
virtual GHOST_TSuccess setVulkanSwapBuffersCallbacks(
|
||||
std::function<void(const GHOST_VulkanSwapChainData *)> /*swap_buffers_pre_callback*/,
|
||||
std::function<void(void)> /*swap_buffers_post_callback*/) override
|
||||
{
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
bool m_stereoVisual;
|
||||
|
||||
|
@ -222,7 +222,12 @@ class GHOST_DeviceVK {
|
||||
device_features.multiViewport = VK_TRUE;
|
||||
#endif
|
||||
|
||||
VkPhysicalDeviceMaintenance4FeaturesKHR maintenance_4 = {};
|
||||
maintenance_4.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES_KHR;
|
||||
maintenance_4.maintenance4 = VK_TRUE;
|
||||
|
||||
VkDeviceCreateInfo device_create_info = {};
|
||||
device_create_info.pNext = &maintenance_4;
|
||||
device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||
device_create_info.queueCreateInfoCount = static_cast<uint32_t>(queue_create_infos.size());
|
||||
device_create_info.pQueueCreateInfos = queue_create_infos.data();
|
||||
@ -390,9 +395,10 @@ GHOST_ContextVK::GHOST_ContextVK(bool stereoVisual,
|
||||
m_context_minor_version(contextMinorVersion),
|
||||
m_debug(debug),
|
||||
m_command_pool(VK_NULL_HANDLE),
|
||||
m_command_buffer(VK_NULL_HANDLE),
|
||||
m_surface(VK_NULL_HANDLE),
|
||||
m_swapchain(VK_NULL_HANDLE),
|
||||
m_render_pass(VK_NULL_HANDLE)
|
||||
m_fence(VK_NULL_HANDLE)
|
||||
{
|
||||
}
|
||||
|
||||
@ -404,6 +410,10 @@ GHOST_ContextVK::~GHOST_ContextVK()
|
||||
|
||||
destroySwapchain();
|
||||
|
||||
if (m_command_buffer != VK_NULL_HANDLE) {
|
||||
vkFreeCommandBuffers(device_vk.device, m_command_pool, 1, &m_command_buffer);
|
||||
m_command_buffer = VK_NULL_HANDLE;
|
||||
}
|
||||
if (m_command_pool != VK_NULL_HANDLE) {
|
||||
vkDestroyCommandPool(device_vk.device, m_command_pool, nullptr);
|
||||
}
|
||||
@ -423,30 +433,13 @@ GHOST_TSuccess GHOST_ContextVK::destroySwapchain()
|
||||
assert(vulkan_device.has_value() && vulkan_device->device != VK_NULL_HANDLE);
|
||||
VkDevice device = vulkan_device->device;
|
||||
|
||||
for (auto semaphore : m_image_available_semaphores) {
|
||||
vkDestroySemaphore(device, semaphore, nullptr);
|
||||
}
|
||||
for (auto semaphore : m_render_finished_semaphores) {
|
||||
vkDestroySemaphore(device, semaphore, nullptr);
|
||||
}
|
||||
for (auto fence : m_in_flight_fences) {
|
||||
vkDestroyFence(device, fence, nullptr);
|
||||
}
|
||||
for (auto framebuffer : m_swapchain_framebuffers) {
|
||||
vkDestroyFramebuffer(device, framebuffer, nullptr);
|
||||
}
|
||||
if (m_render_pass != VK_NULL_HANDLE) {
|
||||
vkDestroyRenderPass(device, m_render_pass, nullptr);
|
||||
}
|
||||
for (auto command_buffer : m_command_buffers) {
|
||||
vkFreeCommandBuffers(device, m_command_pool, 1, &command_buffer);
|
||||
}
|
||||
for (auto imageView : m_swapchain_image_views) {
|
||||
vkDestroyImageView(device, imageView, nullptr);
|
||||
}
|
||||
if (m_swapchain != VK_NULL_HANDLE) {
|
||||
vkDestroySwapchainKHR(device, m_swapchain, nullptr);
|
||||
}
|
||||
if (m_fence != VK_NULL_HANDLE) {
|
||||
vkDestroyFence(device, m_fence, nullptr);
|
||||
m_fence = VK_NULL_HANDLE;
|
||||
}
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
@ -456,109 +449,65 @@ GHOST_TSuccess GHOST_ContextVK::swapBuffers()
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
if (m_lastFrame != m_currentFrame) {
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
VkPipelineStageFlags wait_stages[] = {VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT};
|
||||
|
||||
/* Image should be in present src layout before presenting to screen. */
|
||||
VkCommandBufferBeginInfo begin_info = {};
|
||||
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
VK_CHECK(vkBeginCommandBuffer(m_command_buffers[m_currentImage], &begin_info));
|
||||
VkImageMemoryBarrier barrier{};
|
||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
barrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
barrier.image = m_swapchain_images[m_currentImage];
|
||||
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
|
||||
barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
|
||||
vkCmdPipelineBarrier(m_command_buffers[m_currentImage],
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_DEPENDENCY_BY_REGION_BIT,
|
||||
0,
|
||||
nullptr,
|
||||
0,
|
||||
nullptr,
|
||||
1,
|
||||
&barrier);
|
||||
VK_CHECK(vkEndCommandBuffer(m_command_buffers[m_currentImage]));
|
||||
|
||||
VkSubmitInfo submit_info = {};
|
||||
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submit_info.pWaitDstStageMask = wait_stages;
|
||||
submit_info.commandBufferCount = 1;
|
||||
submit_info.pCommandBuffers = &m_command_buffers[m_currentImage];
|
||||
submit_info.signalSemaphoreCount = 1;
|
||||
submit_info.pSignalSemaphores = &m_render_finished_semaphores[m_currentFrame];
|
||||
|
||||
assert(vulkan_device.has_value() && vulkan_device->device != VK_NULL_HANDLE);
|
||||
VkDevice device = vulkan_device->device;
|
||||
vkAcquireNextImageKHR(device, m_swapchain, UINT64_MAX, VK_NULL_HANDLE, m_fence, &m_currentImage);
|
||||
VK_CHECK(vkWaitForFences(device, 1, &m_fence, VK_TRUE, UINT64_MAX));
|
||||
VK_CHECK(vkResetFences(device, 1, &m_fence));
|
||||
|
||||
VkResult result;
|
||||
VK_CHECK(vkQueueSubmit(m_graphic_queue, 1, &submit_info, m_in_flight_fences[m_currentFrame]));
|
||||
do {
|
||||
result = vkWaitForFences(device, 1, &m_in_flight_fences[m_currentFrame], VK_TRUE, 10000);
|
||||
} while (result == VK_TIMEOUT);
|
||||
GHOST_VulkanSwapChainData swap_chain_data;
|
||||
swap_chain_data.image = m_swapchain_images[m_currentImage];
|
||||
swap_chain_data.format = m_surface_format.format;
|
||||
swap_chain_data.extent = m_render_extent;
|
||||
|
||||
VK_CHECK(vkQueueWaitIdle(m_graphic_queue));
|
||||
if (swap_buffers_pre_callback_) {
|
||||
swap_buffers_pre_callback_(&swap_chain_data);
|
||||
}
|
||||
|
||||
VkPresentInfoKHR present_info = {};
|
||||
present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
||||
present_info.waitSemaphoreCount = 1;
|
||||
present_info.pWaitSemaphores = &m_render_finished_semaphores[m_currentFrame];
|
||||
present_info.waitSemaphoreCount = 0;
|
||||
present_info.pWaitSemaphores = nullptr;
|
||||
present_info.swapchainCount = 1;
|
||||
present_info.pSwapchains = &m_swapchain;
|
||||
present_info.pImageIndices = &m_currentImage;
|
||||
present_info.pResults = nullptr;
|
||||
|
||||
result = vkQueuePresentKHR(m_present_queue, &present_info);
|
||||
|
||||
VkResult result = vkQueuePresentKHR(m_present_queue, &present_info);
|
||||
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) {
|
||||
/* Swap-chain is out of date. Recreate swap-chain and skip this frame. */
|
||||
destroySwapchain();
|
||||
createSwapchain();
|
||||
if (swap_buffers_post_callback_) {
|
||||
swap_buffers_post_callback_();
|
||||
}
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
else if (result != VK_SUCCESS) {
|
||||
fprintf(stderr,
|
||||
"Error: Failed to present swap chain image : %s\n",
|
||||
vulkan_error_as_string(result));
|
||||
if (swap_buffers_post_callback_) {
|
||||
swap_buffers_post_callback_();
|
||||
}
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
m_currentFrame = (m_currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
|
||||
vkResetFences(device, 1, &m_in_flight_fences[m_currentFrame]);
|
||||
|
||||
if (swap_buffers_post_callback_) {
|
||||
swap_buffers_post_callback_();
|
||||
}
|
||||
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_ContextVK::getVulkanBackbuffer(
|
||||
void *image, void *framebuffer, void *render_pass, void *extent, uint32_t *fb_id)
|
||||
GHOST_TSuccess GHOST_ContextVK::getVulkanSwapChainFormat(
|
||||
GHOST_VulkanSwapChainData *r_swap_chain_data)
|
||||
{
|
||||
if (m_swapchain == VK_NULL_HANDLE) {
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
if (m_currentFrame != m_lastFrame) {
|
||||
assert(vulkan_device.has_value() && vulkan_device->device != VK_NULL_HANDLE);
|
||||
VkDevice device = vulkan_device->device;
|
||||
vkAcquireNextImageKHR(device,
|
||||
m_swapchain,
|
||||
UINT64_MAX,
|
||||
m_image_available_semaphores[m_currentFrame],
|
||||
VK_NULL_HANDLE,
|
||||
&m_currentImage);
|
||||
|
||||
m_lastFrame = m_currentFrame;
|
||||
}
|
||||
|
||||
*((VkImage *)image) = m_swapchain_images[m_currentImage];
|
||||
*((VkFramebuffer *)framebuffer) = m_swapchain_framebuffers[m_currentImage];
|
||||
*((VkRenderPass *)render_pass) = m_render_pass;
|
||||
*((VkExtent2D *)extent) = m_render_extent;
|
||||
*fb_id = m_swapchain_id * 10 + m_currentFrame;
|
||||
r_swap_chain_data->image = VK_NULL_HANDLE;
|
||||
r_swap_chain_data->format = m_surface_format.format;
|
||||
r_swap_chain_data->extent = m_render_extent;
|
||||
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
@ -585,19 +534,12 @@ GHOST_TSuccess GHOST_ContextVK::getVulkanHandles(void *r_instance,
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_ContextVK::getVulkanCommandBuffer(void *r_command_buffer)
|
||||
GHOST_TSuccess GHOST_ContextVK::setVulkanSwapBuffersCallbacks(
|
||||
std::function<void(const GHOST_VulkanSwapChainData *)> swap_buffers_pre_callback,
|
||||
std::function<void(void)> swap_buffers_post_callback)
|
||||
{
|
||||
if (m_command_buffers.empty()) {
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
if (m_swapchain == VK_NULL_HANDLE) {
|
||||
*((VkCommandBuffer *)r_command_buffer) = m_command_buffers[0];
|
||||
}
|
||||
else {
|
||||
*((VkCommandBuffer *)r_command_buffer) = m_command_buffers[m_currentImage];
|
||||
}
|
||||
|
||||
swap_buffers_pre_callback_ = swap_buffers_pre_callback;
|
||||
swap_buffers_post_callback_ = swap_buffers_post_callback;
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
@ -703,41 +645,6 @@ static void enableLayer(vector<VkLayerProperties> &layers_available,
|
||||
#undef PUSH_VKLAYER
|
||||
}
|
||||
|
||||
static GHOST_TSuccess create_render_pass(VkDevice device,
|
||||
VkFormat format,
|
||||
VkRenderPass *r_renderPass)
|
||||
{
|
||||
VkAttachmentDescription colorAttachment = {};
|
||||
colorAttachment.format = format;
|
||||
colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
|
||||
VkAttachmentReference colorAttachmentRef = {};
|
||||
colorAttachmentRef.attachment = 0;
|
||||
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
|
||||
VkSubpassDescription subpass = {};
|
||||
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||
subpass.colorAttachmentCount = 1;
|
||||
subpass.pColorAttachments = &colorAttachmentRef;
|
||||
|
||||
VkRenderPassCreateInfo renderPassInfo = {};
|
||||
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||
renderPassInfo.attachmentCount = 1;
|
||||
renderPassInfo.pAttachments = &colorAttachment;
|
||||
renderPassInfo.subpassCount = 1;
|
||||
renderPassInfo.pSubpasses = &subpass;
|
||||
|
||||
VK_CHECK(vkCreateRenderPass(device, &renderPassInfo, nullptr, r_renderPass));
|
||||
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
static GHOST_TSuccess selectPresentMode(VkPhysicalDevice device,
|
||||
VkSurfaceKHR surface,
|
||||
VkPresentModeKHR *r_presentMode)
|
||||
@ -783,31 +690,14 @@ GHOST_TSuccess GHOST_ContextVK::createGraphicsCommandBuffer()
|
||||
{
|
||||
assert(vulkan_device.has_value() && vulkan_device->device != VK_NULL_HANDLE);
|
||||
assert(m_command_pool != VK_NULL_HANDLE);
|
||||
assert(m_command_buffers.size() == 0);
|
||||
m_command_buffers.resize(1);
|
||||
assert(m_command_buffer == VK_NULL_HANDLE);
|
||||
VkCommandBufferAllocateInfo alloc_info = {};
|
||||
alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
alloc_info.commandPool = m_command_pool;
|
||||
alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
alloc_info.commandBufferCount = static_cast<uint32_t>(m_command_buffers.size());
|
||||
alloc_info.commandBufferCount = 1;
|
||||
|
||||
VK_CHECK(vkAllocateCommandBuffers(vulkan_device->device, &alloc_info, m_command_buffers.data()));
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_ContextVK::createGraphicsCommandBuffers()
|
||||
{
|
||||
assert(vulkan_device.has_value() && vulkan_device->device != VK_NULL_HANDLE);
|
||||
assert(m_command_pool != VK_NULL_HANDLE);
|
||||
m_command_buffers.resize(m_swapchain_image_views.size());
|
||||
|
||||
VkCommandBufferAllocateInfo alloc_info = {};
|
||||
alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
alloc_info.commandPool = m_command_pool;
|
||||
alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
alloc_info.commandBufferCount = static_cast<uint32_t>(m_command_buffers.size());
|
||||
|
||||
VK_CHECK(vkAllocateCommandBuffers(vulkan_device->device, &alloc_info, m_command_buffers.data()));
|
||||
VK_CHECK(vkAllocateCommandBuffers(vulkan_device->device, &alloc_info, &m_command_buffer));
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
@ -857,17 +747,16 @@ static bool selectSurfaceFormat(const VkPhysicalDevice physical_device,
|
||||
GHOST_TSuccess GHOST_ContextVK::createSwapchain()
|
||||
{
|
||||
assert(vulkan_device.has_value() && vulkan_device->device != VK_NULL_HANDLE);
|
||||
m_swapchain_id++;
|
||||
|
||||
VkPhysicalDevice physical_device = vulkan_device->physical_device;
|
||||
|
||||
VkSurfaceFormatKHR format = {};
|
||||
m_surface_format = {};
|
||||
#if SELECT_COMPATIBLE_SURFACES_ONLY
|
||||
if (!selectSurfaceFormat(physical_device, m_surface, format)) {
|
||||
if (!selectSurfaceFormat(physical_device, m_surface, m_surface_format)) {
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
#else
|
||||
selectSurfaceFormat(physical_device, m_surface, format);
|
||||
selectSurfaceFormat(physical_device, m_surface, m_surface_format);
|
||||
#endif
|
||||
|
||||
VkPresentModeKHR present_mode;
|
||||
@ -903,8 +792,8 @@ GHOST_TSuccess GHOST_ContextVK::createSwapchain()
|
||||
create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
||||
create_info.surface = m_surface;
|
||||
create_info.minImageCount = image_count;
|
||||
create_info.imageFormat = format.format;
|
||||
create_info.imageColorSpace = format.colorSpace;
|
||||
create_info.imageFormat = m_surface_format.format;
|
||||
create_info.imageColorSpace = m_surface_format.colorSpace;
|
||||
create_info.imageExtent = m_render_extent;
|
||||
create_info.imageArrayLayers = 1;
|
||||
create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||
@ -920,70 +809,56 @@ GHOST_TSuccess GHOST_ContextVK::createSwapchain()
|
||||
VkDevice device = vulkan_device->device;
|
||||
VK_CHECK(vkCreateSwapchainKHR(device, &create_info, nullptr, &m_swapchain));
|
||||
|
||||
create_render_pass(device, format.format, &m_render_pass);
|
||||
|
||||
/* image_count may not be what we requested! Getter for final value. */
|
||||
vkGetSwapchainImagesKHR(device, m_swapchain, &image_count, nullptr);
|
||||
m_swapchain_images.resize(image_count);
|
||||
vkGetSwapchainImagesKHR(device, m_swapchain, &image_count, m_swapchain_images.data());
|
||||
|
||||
m_swapchain_image_views.resize(image_count);
|
||||
m_swapchain_framebuffers.resize(image_count);
|
||||
for (int i = 0; i < image_count; i++) {
|
||||
VkImageViewCreateInfo view_create_info = {};
|
||||
view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
view_create_info.image = m_swapchain_images[i];
|
||||
view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
view_create_info.format = format.format;
|
||||
view_create_info.components = {
|
||||
VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
};
|
||||
view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
view_create_info.subresourceRange.baseMipLevel = 0;
|
||||
view_create_info.subresourceRange.levelCount = 1;
|
||||
view_create_info.subresourceRange.baseArrayLayer = 0;
|
||||
view_create_info.subresourceRange.layerCount = 1;
|
||||
|
||||
VK_CHECK(vkCreateImageView(device, &view_create_info, nullptr, &m_swapchain_image_views[i]));
|
||||
|
||||
VkImageView attachments[] = {m_swapchain_image_views[i]};
|
||||
|
||||
VkFramebufferCreateInfo fb_create_info = {};
|
||||
fb_create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||
fb_create_info.renderPass = m_render_pass;
|
||||
fb_create_info.attachmentCount = 1;
|
||||
fb_create_info.pAttachments = attachments;
|
||||
fb_create_info.width = m_render_extent.width;
|
||||
fb_create_info.height = m_render_extent.height;
|
||||
fb_create_info.layers = 1;
|
||||
|
||||
VK_CHECK(vkCreateFramebuffer(device, &fb_create_info, nullptr, &m_swapchain_framebuffers[i]));
|
||||
}
|
||||
|
||||
m_image_available_semaphores.resize(MAX_FRAMES_IN_FLIGHT);
|
||||
m_render_finished_semaphores.resize(MAX_FRAMES_IN_FLIGHT);
|
||||
m_in_flight_fences.resize(MAX_FRAMES_IN_FLIGHT);
|
||||
|
||||
VkSemaphoreCreateInfo semaphore_info = {};
|
||||
semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||
VkFenceCreateInfo fence_info = {};
|
||||
fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||
fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||
VK_CHECK(vkCreateFence(device, &fence_info, nullptr, &m_fence));
|
||||
|
||||
for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
|
||||
/* Change image layout from VK_IMAGE_LAYOUT_UNDEFINED to VK_IMAGE_LAYOUT_PRESENT_SRC_KHR. */
|
||||
VkCommandBufferBeginInfo begin_info = {};
|
||||
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
VK_CHECK(vkBeginCommandBuffer(m_command_buffer, &begin_info));
|
||||
VkImageMemoryBarrier *barriers = new VkImageMemoryBarrier[image_count];
|
||||
for (int i = 0; i < image_count; i++) {
|
||||
VkImageMemoryBarrier &barrier = barriers[i];
|
||||
barrier = {};
|
||||
|
||||
VK_CHECK(
|
||||
vkCreateSemaphore(device, &semaphore_info, nullptr, &m_image_available_semaphores[i]));
|
||||
VK_CHECK(
|
||||
vkCreateSemaphore(device, &semaphore_info, nullptr, &m_render_finished_semaphores[i]));
|
||||
|
||||
VK_CHECK(vkCreateFence(device, &fence_info, nullptr, &m_in_flight_fences[i]));
|
||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
barrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
barrier.image = m_swapchain_images[i];
|
||||
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
|
||||
barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
|
||||
}
|
||||
vkCmdPipelineBarrier(m_command_buffer,
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_DEPENDENCY_BY_REGION_BIT,
|
||||
0,
|
||||
nullptr,
|
||||
0,
|
||||
nullptr,
|
||||
image_count,
|
||||
barriers);
|
||||
VK_CHECK(vkEndCommandBuffer(m_command_buffer));
|
||||
|
||||
createGraphicsCommandBuffers();
|
||||
VkPipelineStageFlags wait_stages[] = {VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT};
|
||||
VkSubmitInfo submit_info = {};
|
||||
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submit_info.pWaitDstStageMask = wait_stages;
|
||||
submit_info.commandBufferCount = 1;
|
||||
submit_info.pCommandBuffers = &m_command_buffer;
|
||||
submit_info.signalSemaphoreCount = 0;
|
||||
submit_info.pSignalSemaphores = nullptr;
|
||||
VK_CHECK(vkQueueSubmit(m_graphic_queue, 1, &submit_info, nullptr));
|
||||
VK_CHECK(vkQueueWaitIdle(m_graphic_queue));
|
||||
|
||||
delete barriers;
|
||||
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
@ -1051,6 +926,8 @@ GHOST_TSuccess GHOST_ContextVK::initializeDrawingContext()
|
||||
}
|
||||
extensions_device.push_back("VK_KHR_dedicated_allocation");
|
||||
extensions_device.push_back("VK_KHR_get_memory_requirements2");
|
||||
/* Allow relaxed interface matching between shader stages.*/
|
||||
extensions_device.push_back("VK_KHR_maintenance4");
|
||||
/* Enable MoltenVK required instance extensions. */
|
||||
#ifdef VK_MVK_MOLTENVK_EXTENSION_NAME
|
||||
requireExtension(
|
||||
@ -1138,14 +1015,13 @@ GHOST_TSuccess GHOST_ContextVK::initializeDrawingContext()
|
||||
vulkan_device->device, vulkan_device->generic_queue_family, 0, &m_graphic_queue);
|
||||
|
||||
createCommandPools();
|
||||
createGraphicsCommandBuffer();
|
||||
if (use_window_surface) {
|
||||
vkGetDeviceQueue(
|
||||
vulkan_device->device, vulkan_device->generic_queue_family, 0, &m_present_queue);
|
||||
createSwapchain();
|
||||
}
|
||||
else {
|
||||
createGraphicsCommandBuffer();
|
||||
}
|
||||
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
|
@ -26,12 +26,6 @@
|
||||
|
||||
#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
|
||||
@ -117,15 +111,12 @@ class GHOST_ContextVK : public GHOST_Context {
|
||||
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);
|
||||
GHOST_TSuccess getVulkanSwapChainFormat(GHOST_VulkanSwapChainData *r_swap_chain_data) override;
|
||||
|
||||
GHOST_TSuccess setVulkanSwapBuffersCallbacks(
|
||||
std::function<void(const GHOST_VulkanSwapChainData *)> swap_buffers_pre_callback,
|
||||
std::function<void(void)> swap_buffers_post_callback) override;
|
||||
|
||||
/**
|
||||
* Sets the swap interval for `swapBuffers`.
|
||||
@ -167,6 +158,7 @@ class GHOST_ContextVK : public GHOST_Context {
|
||||
const int m_debug;
|
||||
|
||||
VkCommandPool m_command_pool;
|
||||
VkCommandBuffer m_command_buffer;
|
||||
|
||||
VkQueue m_graphic_queue;
|
||||
VkQueue m_present_queue;
|
||||
@ -175,29 +167,18 @@ class GHOST_ContextVK : public GHOST_Context {
|
||||
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;
|
||||
VkSurfaceFormatKHR m_surface_format;
|
||||
VkFence m_fence;
|
||||
|
||||
/** 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;
|
||||
|
||||
std::function<void(const GHOST_VulkanSwapChainData *)> swap_buffers_pre_callback_;
|
||||
std::function<void(void)> swap_buffers_post_callback_;
|
||||
|
||||
const char *getPlatformSpecificSurfaceExtension() const;
|
||||
GHOST_TSuccess createSwapchain();
|
||||
|
@ -105,7 +105,7 @@ GHOST_TSuccess GHOST_ISystem::createSystem(bool verbose, [[maybe_unused]] bool b
|
||||
try {
|
||||
m_system = new GHOST_SystemWayland(background);
|
||||
}
|
||||
catch (const std::runtime_error &const e) {
|
||||
catch (const std::runtime_error &e) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "GHOST: %s\n", e.what());
|
||||
}
|
||||
|
@ -473,6 +473,23 @@ GHOST_TSuccess GHOST_SystemWin32::getPixelAtCursor(float r_color[3]) const
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
GHOST_IWindow *GHOST_SystemWin32::getWindowUnderCursor(int32_t /*x*/, int32_t /*y*/)
|
||||
{
|
||||
/* Get cursor position from the OS. Do not use the supplied positions as those
|
||||
* could be incorrect, especially if using multiple windows of differing OS scale. */
|
||||
POINT point;
|
||||
if (!GetCursorPos(&point)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HWND win = WindowFromPoint(point);
|
||||
if (win == NULL) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return m_windowManager->getWindowAssociatedWithOSWindow((void *)win);
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_SystemWin32::getModifierKeys(GHOST_ModifierKeys &keys) const
|
||||
{
|
||||
/* `GetAsyncKeyState` returns the current interrupt-level state of the hardware, which is needed
|
||||
|
@ -151,6 +151,12 @@ class GHOST_SystemWin32 : public GHOST_System {
|
||||
*/
|
||||
static GHOST_TSuccess disposeContextD3D(GHOST_ContextD3D *context);
|
||||
|
||||
/**
|
||||
* Get the Window under the mouse cursor. Location obtained from the OS.
|
||||
* \return The window under the cursor or nullptr if none.
|
||||
*/
|
||||
GHOST_IWindow *getWindowUnderCursor(int32_t /*x*/, int32_t /*y*/);
|
||||
|
||||
/***************************************************************************************
|
||||
** Event management functionality
|
||||
***************************************************************************************/
|
||||
|
@ -1526,6 +1526,45 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
|
||||
}
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_SystemX11::getPixelAtCursor(float r_color[3]) const
|
||||
{
|
||||
/* NOTE: There are known issues/limitations at the moment:
|
||||
*
|
||||
* - Blender has no control of the cursor outside of its window, so it is
|
||||
* not going to be the eyedropper icon.
|
||||
* - GHOST does not report click events from outside of the window, so the
|
||||
* user needs to press Enter instead.
|
||||
*
|
||||
* Ref #111303. */
|
||||
|
||||
XColor c;
|
||||
int32_t x, y;
|
||||
|
||||
if (getCursorPosition(x, y) == GHOST_kFailure) {
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
XImage *image = XGetImage(m_display,
|
||||
XRootWindow(m_display, XDefaultScreen(m_display)),
|
||||
x,
|
||||
y,
|
||||
1,
|
||||
1,
|
||||
AllPlanes,
|
||||
XYPixmap);
|
||||
if (image == nullptr) {
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
c.pixel = XGetPixel(image, 0, 0);
|
||||
XFree(image);
|
||||
XQueryColor(m_display, XDefaultColormap(m_display, XDefaultScreen(m_display)), &c);
|
||||
|
||||
/* X11 returns colors in the [0, 65535] range, so we need to scale back to [0, 1]. */
|
||||
r_color[0] = c.red / 65535.0f;
|
||||
r_color[1] = c.green / 65535.0f;
|
||||
r_color[2] = c.blue / 65535.0f;
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_SystemX11::getModifierKeys(GHOST_ModifierKeys &keys) const
|
||||
{
|
||||
|
||||
|
@ -154,6 +154,13 @@ class GHOST_SystemX11 : public GHOST_System {
|
||||
|
||||
GHOST_TSuccess setCursorPosition(int32_t x, int32_t y) override;
|
||||
|
||||
/**
|
||||
* Get the color of the pixel at the current mouse cursor location
|
||||
* \param r_color: returned sRGB float colors
|
||||
* \return Success value (true == successful and supported by platform)
|
||||
*/
|
||||
GHOST_TSuccess getPixelAtCursor(float r_color[3]) const override;
|
||||
|
||||
/**
|
||||
* Returns the state of all modifier keys.
|
||||
* \param keys: The state of all modifier keys (true == pressed).
|
||||
|
@ -107,11 +107,12 @@ uint GHOST_Window::getDefaultFramebuffer()
|
||||
return (m_context) ? m_context->getDefaultFramebuffer() : 0;
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_Window::getVulkanBackbuffer(
|
||||
void *image, void *framebuffer, void *render_pass, void *extent, uint32_t *fb_id)
|
||||
#ifdef WITH_VULKAN_BACKEND
|
||||
GHOST_TSuccess GHOST_Window::getVulkanSwapChainFormat(GHOST_VulkanSwapChainData *r_swap_chain_data)
|
||||
{
|
||||
return m_context->getVulkanBackbuffer(image, framebuffer, render_pass, extent, fb_id);
|
||||
return m_context->getVulkanSwapChainFormat(r_swap_chain_data);
|
||||
}
|
||||
#endif
|
||||
|
||||
GHOST_TSuccess GHOST_Window::activateDrawingContext()
|
||||
{
|
||||
|
@ -270,13 +270,10 @@ class GHOST_Window : public GHOST_IWindow {
|
||||
*/
|
||||
virtual unsigned int getDefaultFramebuffer() override;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
virtual GHOST_TSuccess getVulkanBackbuffer(
|
||||
void *image, void *framebuffer, void *render_pass, void *extent, uint32_t *fb_id) override;
|
||||
#ifdef WITH_VULKAN_BACKEND
|
||||
virtual GHOST_TSuccess getVulkanSwapChainFormat(
|
||||
GHOST_VulkanSwapChainData *r_swap_chain_data) override;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Returns the window user data.
|
||||
|
@ -361,6 +361,11 @@ HWND GHOST_WindowWin32::getHWND() const
|
||||
return m_hWnd;
|
||||
}
|
||||
|
||||
void *GHOST_WindowWin32::getOSWindow() const
|
||||
{
|
||||
return (void *)m_hWnd;
|
||||
}
|
||||
|
||||
void GHOST_WindowWin32::setTitle(const char *title)
|
||||
{
|
||||
wchar_t *title_16 = alloc_utf16_from_8((char *)title, 0);
|
||||
|
@ -107,6 +107,12 @@ class GHOST_WindowWin32 : public GHOST_Window {
|
||||
*/
|
||||
HWND getHWND() const;
|
||||
|
||||
/**
|
||||
* Returns the handle of the window.
|
||||
* \return The handle of the window.
|
||||
*/
|
||||
void *getOSWindow() const;
|
||||
|
||||
/**
|
||||
* Sets the title displayed in the title bar.
|
||||
* \param title: The title to display in the title bar.
|
||||
|