Geometry Nodes: Rename Blur Attribute to a Blur Field #111542

Closed
Iliya Katushenock wants to merge 3 commits from mod_moder:tmp_rename_blur_attribute into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
512 changed files with 27815 additions and 23472 deletions
Showing only changes of commit ac0967cd55 - Show all commits

View File

@ -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>

View File

@ -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

View File

@ -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")

View File

@ -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.

View File

@ -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.

View File

@ -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),

View File

@ -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 */

View File

@ -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;

View File

@ -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;
}

View File

@ -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();

View File

@ -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());
}

View File

@ -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

View File

@ -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
***************************************************************************************/

View File

@ -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
{

View File

@ -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).

View File

@ -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()
{

View File

@ -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.

View File

@ -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);

View File

@ -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.