mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-26 13:41:07 +00:00
30dddf2412
Instead of having renderer API to wait for any number of frames, just have gsk_gpu_frame_wait() to wait for a single frame. This unifies behavior on Vulkan and GL, because unlike Vulkan, GL does not allow waiting for multiple fences. To make up for it, we replace waiting for multiple frames with finding the frame with the earliest timestamp and waiting for that one. Also implement wait() for GL.
449 lines
16 KiB
C
449 lines
16 KiB
C
#include "config.h"
|
|
|
|
#include "gskvulkanframeprivate.h"
|
|
|
|
#include "gskgpuopprivate.h"
|
|
#include "gskvulkanbufferprivate.h"
|
|
#include "gskvulkandescriptorsprivate.h"
|
|
#include "gskvulkandeviceprivate.h"
|
|
#include "gskvulkanimageprivate.h"
|
|
#include "gskvulkanrealdescriptorsprivate.h"
|
|
#include "gskvulkansubdescriptorsprivate.h"
|
|
|
|
#include "gdk/gdkdisplayprivate.h"
|
|
#include "gdk/gdkdmabuftextureprivate.h"
|
|
|
|
#define GDK_ARRAY_NAME gsk_descriptors
|
|
#define GDK_ARRAY_TYPE_NAME GskDescriptors
|
|
#define GDK_ARRAY_ELEMENT_TYPE GskVulkanRealDescriptors *
|
|
#define GDK_ARRAY_FREE_FUNC g_object_unref
|
|
#define GDK_ARRAY_NO_MEMSET 1
|
|
#include "gdk/gdkarrayimpl.c"
|
|
|
|
#define GDK_ARRAY_NAME gsk_semaphores
|
|
#define GDK_ARRAY_TYPE_NAME GskSemaphores
|
|
#define GDK_ARRAY_ELEMENT_TYPE VkSemaphore
|
|
#define GDK_ARRAY_PREALLOC 16
|
|
#define GDK_ARRAY_NO_MEMSET 1
|
|
#include "gdk/gdkarrayimpl.c"
|
|
|
|
#define GDK_ARRAY_NAME gsk_pipeline_stages
|
|
#define GDK_ARRAY_TYPE_NAME GskPipelineStages
|
|
#define GDK_ARRAY_ELEMENT_TYPE VkPipelineStageFlags
|
|
#define GDK_ARRAY_PREALLOC 16
|
|
#define GDK_ARRAY_NO_MEMSET 1
|
|
#include "gdk/gdkarrayimpl.c"
|
|
|
|
struct _GskVulkanSemaphores
|
|
{
|
|
GskSemaphores wait_semaphores;
|
|
GskPipelineStages wait_stages;
|
|
GskSemaphores signal_semaphores;
|
|
};
|
|
|
|
struct _GskVulkanFrame
|
|
{
|
|
GskGpuFrame parent_instance;
|
|
|
|
VkFence vk_fence;
|
|
VkCommandBuffer vk_command_buffer;
|
|
VkDescriptorPool vk_descriptor_pool;
|
|
|
|
GskDescriptors descriptors;
|
|
|
|
gsize pool_n_sets;
|
|
gsize pool_n_images;
|
|
gsize pool_n_buffers;
|
|
};
|
|
|
|
struct _GskVulkanFrameClass
|
|
{
|
|
GskGpuFrameClass parent_class;
|
|
};
|
|
|
|
G_DEFINE_TYPE (GskVulkanFrame, gsk_vulkan_frame, GSK_TYPE_GPU_FRAME)
|
|
|
|
static gboolean
|
|
gsk_vulkan_frame_is_busy (GskGpuFrame *frame)
|
|
{
|
|
GskVulkanFrame *self = GSK_VULKAN_FRAME (frame);
|
|
VkDevice device;
|
|
|
|
device = gsk_vulkan_device_get_vk_device (GSK_VULKAN_DEVICE (gsk_gpu_frame_get_device (frame)));
|
|
|
|
return vkGetFenceStatus (device, self->vk_fence) == VK_NOT_READY;
|
|
}
|
|
|
|
static void
|
|
gsk_vulkan_frame_wait (GskGpuFrame *frame)
|
|
{
|
|
GskVulkanFrame *self = GSK_VULKAN_FRAME (frame);
|
|
VkDevice vk_device;
|
|
|
|
vk_device = gsk_vulkan_device_get_vk_device (GSK_VULKAN_DEVICE (gsk_gpu_frame_get_device (frame)));
|
|
|
|
GSK_VK_CHECK (vkWaitForFences, vk_device,
|
|
1,
|
|
&self->vk_fence,
|
|
VK_FALSE,
|
|
INT64_MAX);
|
|
}
|
|
|
|
static void
|
|
gsk_vulkan_frame_setup (GskGpuFrame *frame)
|
|
{
|
|
GskVulkanFrame *self = GSK_VULKAN_FRAME (frame);
|
|
GskVulkanDevice *device;
|
|
VkDevice vk_device;
|
|
VkCommandPool vk_command_pool;
|
|
|
|
device = GSK_VULKAN_DEVICE (gsk_gpu_frame_get_device (frame));
|
|
vk_device = gsk_vulkan_device_get_vk_device (device);
|
|
vk_command_pool = gsk_vulkan_device_get_vk_command_pool (device);
|
|
|
|
GSK_VK_CHECK (vkAllocateCommandBuffers, vk_device,
|
|
&(VkCommandBufferAllocateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
|
.commandPool = vk_command_pool,
|
|
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
|
.commandBufferCount = 1,
|
|
},
|
|
&self->vk_command_buffer);
|
|
|
|
GSK_VK_CHECK (vkCreateFence, vk_device,
|
|
&(VkFenceCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
|
|
.flags = VK_FENCE_CREATE_SIGNALED_BIT
|
|
},
|
|
NULL,
|
|
&self->vk_fence);
|
|
}
|
|
|
|
static void
|
|
gsk_vulkan_frame_cleanup (GskGpuFrame *frame)
|
|
{
|
|
GskVulkanFrame *self = GSK_VULKAN_FRAME (frame);
|
|
GskVulkanDevice *device;
|
|
VkDevice vk_device;
|
|
|
|
device = GSK_VULKAN_DEVICE (gsk_gpu_frame_get_device (frame));
|
|
vk_device = gsk_vulkan_device_get_vk_device (device);
|
|
|
|
GSK_VK_CHECK (vkWaitForFences, vk_device,
|
|
1,
|
|
&self->vk_fence,
|
|
VK_TRUE,
|
|
INT64_MAX);
|
|
|
|
GSK_VK_CHECK (vkResetFences, vk_device,
|
|
1,
|
|
&self->vk_fence);
|
|
|
|
GSK_VK_CHECK (vkResetCommandBuffer, self->vk_command_buffer,
|
|
0);
|
|
|
|
if (self->vk_descriptor_pool != VK_NULL_HANDLE)
|
|
{
|
|
GSK_VK_CHECK (vkResetDescriptorPool, vk_device,
|
|
self->vk_descriptor_pool,
|
|
0);
|
|
}
|
|
|
|
gsk_descriptors_set_size (&self->descriptors, 0);
|
|
|
|
GSK_GPU_FRAME_CLASS (gsk_vulkan_frame_parent_class)->cleanup (frame);
|
|
}
|
|
|
|
static GskGpuImage *
|
|
gsk_vulkan_frame_upload_texture (GskGpuFrame *frame,
|
|
gboolean with_mipmap,
|
|
GdkTexture *texture)
|
|
{
|
|
#ifdef HAVE_DMABUF
|
|
if (GDK_IS_DMABUF_TEXTURE (texture))
|
|
{
|
|
GskGpuImage *image = gsk_vulkan_image_new_for_dmabuf (GSK_VULKAN_DEVICE (gsk_gpu_frame_get_device (frame)),
|
|
texture);
|
|
if (image)
|
|
return image;
|
|
}
|
|
#endif
|
|
|
|
return GSK_GPU_FRAME_CLASS (gsk_vulkan_frame_parent_class)->upload_texture (frame, with_mipmap, texture);
|
|
}
|
|
|
|
static void
|
|
gsk_vulkan_frame_prepare_descriptors (GskVulkanFrame *self)
|
|
{
|
|
GskVulkanDevice *device;
|
|
VkDevice vk_device;
|
|
gsize i, n_images, n_buffers, n_sets;
|
|
|
|
device = GSK_VULKAN_DEVICE (gsk_gpu_frame_get_device (GSK_GPU_FRAME (self)));
|
|
vk_device = gsk_vulkan_device_get_vk_device (device);
|
|
|
|
n_images = 0;
|
|
n_buffers = 0;
|
|
n_sets = 2 * gsk_descriptors_get_size (&self->descriptors);
|
|
for (i = 0; i < gsk_descriptors_get_size (&self->descriptors); i++)
|
|
{
|
|
gsize n_desc_images, n_desc_buffers;
|
|
GskVulkanRealDescriptors *desc = gsk_descriptors_get (&self->descriptors, i);
|
|
gsk_vulkan_real_descriptors_prepare (desc, &n_desc_images, &n_desc_buffers);
|
|
n_images += n_desc_images;
|
|
n_buffers += n_desc_buffers;
|
|
}
|
|
|
|
if (n_sets > self->pool_n_sets ||
|
|
n_images > self->pool_n_images ||
|
|
n_buffers > self->pool_n_buffers)
|
|
{
|
|
if (self->vk_descriptor_pool != VK_NULL_HANDLE)
|
|
{
|
|
vkDestroyDescriptorPool (vk_device,
|
|
self->vk_descriptor_pool,
|
|
NULL);
|
|
self->vk_descriptor_pool = VK_NULL_HANDLE;
|
|
}
|
|
if (n_sets > self->pool_n_sets)
|
|
self->pool_n_sets = 4 << g_bit_nth_msf (n_sets - 1, -1);
|
|
if (n_images > self->pool_n_images)
|
|
self->pool_n_images = 2 << g_bit_nth_msf (n_images - 1, -1);
|
|
if (n_buffers > self->pool_n_buffers)
|
|
self->pool_n_buffers = 4 << g_bit_nth_msf (n_buffers - 1, -1);
|
|
}
|
|
|
|
if (self->vk_descriptor_pool == VK_NULL_HANDLE)
|
|
{
|
|
GSK_VK_CHECK (vkCreateDescriptorPool, vk_device,
|
|
&(VkDescriptorPoolCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
|
.flags = 0,
|
|
.maxSets = self->pool_n_sets,
|
|
.poolSizeCount = 2,
|
|
.pPoolSizes = (VkDescriptorPoolSize[2]) {
|
|
{
|
|
.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
|
.descriptorCount = self->pool_n_images,
|
|
},
|
|
{
|
|
.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
|
.descriptorCount = self->pool_n_buffers,
|
|
}
|
|
}
|
|
},
|
|
NULL,
|
|
&self->vk_descriptor_pool);
|
|
}
|
|
|
|
for (i = 0; i < gsk_descriptors_get_size (&self->descriptors); i++)
|
|
{
|
|
GskVulkanRealDescriptors *desc = gsk_descriptors_get (&self->descriptors, i);
|
|
|
|
gsk_vulkan_real_descriptors_update_sets (desc, self->vk_descriptor_pool);
|
|
}
|
|
}
|
|
|
|
static GskGpuDescriptors *
|
|
gsk_vulkan_frame_create_descriptors (GskGpuFrame *frame)
|
|
{
|
|
GskVulkanFrame *self = GSK_VULKAN_FRAME (frame);
|
|
|
|
if (gsk_vulkan_device_has_feature (GSK_VULKAN_DEVICE (gsk_gpu_frame_get_device (frame)), GDK_VULKAN_FEATURE_DESCRIPTOR_INDEXING))
|
|
{
|
|
GskVulkanRealDescriptors *parent;
|
|
|
|
if (gsk_descriptors_get_size (&self->descriptors) > 0)
|
|
{
|
|
parent = gsk_descriptors_get (&self->descriptors, gsk_descriptors_get_size (&self->descriptors) - 1);
|
|
if (gsk_vulkan_real_descriptors_is_full (parent))
|
|
parent = NULL;
|
|
}
|
|
else
|
|
parent = NULL;
|
|
|
|
if (parent == NULL)
|
|
{
|
|
parent = gsk_vulkan_real_descriptors_new (self);
|
|
gsk_descriptors_append (&self->descriptors, parent);
|
|
}
|
|
|
|
return GSK_GPU_DESCRIPTORS (gsk_vulkan_sub_descriptors_new (GSK_VULKAN_DESCRIPTORS (parent)));
|
|
}
|
|
else
|
|
{
|
|
GskVulkanRealDescriptors *desc;
|
|
|
|
desc = gsk_vulkan_real_descriptors_new (self);
|
|
gsk_descriptors_append (&self->descriptors, desc);
|
|
|
|
return GSK_GPU_DESCRIPTORS (g_object_ref (desc));
|
|
}
|
|
}
|
|
|
|
static GskGpuBuffer *
|
|
gsk_vulkan_frame_create_vertex_buffer (GskGpuFrame *frame,
|
|
gsize size)
|
|
{
|
|
return gsk_vulkan_buffer_new_vertex (GSK_VULKAN_DEVICE (gsk_gpu_frame_get_device (frame)), size);
|
|
}
|
|
|
|
static GskGpuBuffer *
|
|
gsk_vulkan_frame_create_storage_buffer (GskGpuFrame *frame,
|
|
gsize size)
|
|
{
|
|
return gsk_vulkan_buffer_new_storage (GSK_VULKAN_DEVICE (gsk_gpu_frame_get_device (frame)), size);
|
|
}
|
|
|
|
static void
|
|
gsk_vulkan_frame_submit (GskGpuFrame *frame,
|
|
GskGpuBuffer *vertex_buffer,
|
|
GskGpuOp *op)
|
|
{
|
|
GskVulkanFrame *self = GSK_VULKAN_FRAME (frame);
|
|
GskVulkanSemaphores semaphores;
|
|
GskVulkanCommandState state;
|
|
|
|
if (gsk_descriptors_get_size (&self->descriptors) == 0)
|
|
gsk_descriptors_append (&self->descriptors, gsk_vulkan_real_descriptors_new (self));
|
|
|
|
gsk_vulkan_frame_prepare_descriptors (self);
|
|
|
|
GSK_VK_CHECK (vkBeginCommandBuffer, self->vk_command_buffer,
|
|
&(VkCommandBufferBeginInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
|
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
|
|
});
|
|
|
|
if (vertex_buffer)
|
|
vkCmdBindVertexBuffers (self->vk_command_buffer,
|
|
0,
|
|
1,
|
|
(VkBuffer[1]) {
|
|
gsk_vulkan_buffer_get_vk_buffer (GSK_VULKAN_BUFFER (vertex_buffer))
|
|
},
|
|
(VkDeviceSize[1]) { 0 });
|
|
|
|
gsk_semaphores_init (&semaphores.wait_semaphores);
|
|
gsk_pipeline_stages_init (&semaphores.wait_stages);
|
|
gsk_semaphores_init (&semaphores.signal_semaphores);
|
|
|
|
state.vk_command_buffer = self->vk_command_buffer;
|
|
state.vk_render_pass = VK_NULL_HANDLE;
|
|
state.vk_format = VK_FORMAT_UNDEFINED;
|
|
state.blend = GSK_GPU_BLEND_OVER; /* should we have a BLEND_NONE? */
|
|
state.desc = GSK_VULKAN_DESCRIPTORS (gsk_descriptors_get (&self->descriptors, 0));
|
|
state.semaphores = &semaphores;
|
|
|
|
gsk_vulkan_descriptors_bind (GSK_VULKAN_DESCRIPTORS (gsk_descriptors_get (&self->descriptors, 0)),
|
|
NULL,
|
|
state.vk_command_buffer);
|
|
|
|
while (op)
|
|
{
|
|
op = gsk_gpu_op_vk_command (op, frame, &state);
|
|
}
|
|
|
|
GSK_VK_CHECK (vkEndCommandBuffer, self->vk_command_buffer);
|
|
|
|
GSK_VK_CHECK (vkQueueSubmit, gsk_vulkan_device_get_vk_queue (GSK_VULKAN_DEVICE (gsk_gpu_frame_get_device (frame))),
|
|
1,
|
|
&(VkSubmitInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
|
.commandBufferCount = 1,
|
|
.pCommandBuffers = &self->vk_command_buffer,
|
|
.pWaitSemaphores = gsk_semaphores_get_data (&semaphores.wait_semaphores),
|
|
.pWaitDstStageMask = gsk_pipeline_stages_get_data (&semaphores.wait_stages),
|
|
.waitSemaphoreCount = gsk_semaphores_get_size (&semaphores.wait_semaphores),
|
|
.pSignalSemaphores = gsk_semaphores_get_data (&semaphores.signal_semaphores),
|
|
.signalSemaphoreCount = gsk_semaphores_get_size (&semaphores.signal_semaphores),
|
|
},
|
|
self->vk_fence);
|
|
|
|
gsk_semaphores_clear (&semaphores.wait_semaphores);
|
|
gsk_pipeline_stages_clear (&semaphores.wait_stages);
|
|
gsk_semaphores_clear (&semaphores.signal_semaphores);
|
|
}
|
|
|
|
static void
|
|
gsk_vulkan_frame_finalize (GObject *object)
|
|
{
|
|
GskVulkanFrame *self = GSK_VULKAN_FRAME (object);
|
|
GskVulkanDevice *device;
|
|
VkDevice vk_device;
|
|
VkCommandPool vk_command_pool;
|
|
|
|
device = GSK_VULKAN_DEVICE (gsk_gpu_frame_get_device (GSK_GPU_FRAME (self)));
|
|
vk_device = gsk_vulkan_device_get_vk_device (device);
|
|
vk_command_pool = gsk_vulkan_device_get_vk_command_pool (device);
|
|
|
|
if (self->vk_descriptor_pool != VK_NULL_HANDLE)
|
|
{
|
|
vkDestroyDescriptorPool (vk_device,
|
|
self->vk_descriptor_pool,
|
|
NULL);
|
|
}
|
|
gsk_descriptors_clear (&self->descriptors);
|
|
|
|
vkFreeCommandBuffers (vk_device,
|
|
vk_command_pool,
|
|
1, &self->vk_command_buffer);
|
|
vkDestroyFence (vk_device,
|
|
self->vk_fence,
|
|
NULL);
|
|
|
|
G_OBJECT_CLASS (gsk_vulkan_frame_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
gsk_vulkan_frame_class_init (GskVulkanFrameClass *klass)
|
|
{
|
|
GskGpuFrameClass *gpu_frame_class = GSK_GPU_FRAME_CLASS (klass);
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
gpu_frame_class->is_busy = gsk_vulkan_frame_is_busy;
|
|
gpu_frame_class->wait = gsk_vulkan_frame_wait;
|
|
gpu_frame_class->setup = gsk_vulkan_frame_setup;
|
|
gpu_frame_class->cleanup = gsk_vulkan_frame_cleanup;
|
|
gpu_frame_class->upload_texture = gsk_vulkan_frame_upload_texture;
|
|
gpu_frame_class->create_descriptors = gsk_vulkan_frame_create_descriptors;
|
|
gpu_frame_class->create_vertex_buffer = gsk_vulkan_frame_create_vertex_buffer;
|
|
gpu_frame_class->create_storage_buffer = gsk_vulkan_frame_create_storage_buffer;
|
|
gpu_frame_class->submit = gsk_vulkan_frame_submit;
|
|
|
|
object_class->finalize = gsk_vulkan_frame_finalize;
|
|
}
|
|
|
|
static void
|
|
gsk_vulkan_frame_init (GskVulkanFrame *self)
|
|
{
|
|
gsk_descriptors_init (&self->descriptors);
|
|
|
|
self->pool_n_sets = 4;
|
|
self->pool_n_images = 8;
|
|
self->pool_n_buffers = 8;
|
|
}
|
|
|
|
VkFence
|
|
gsk_vulkan_frame_get_vk_fence (GskVulkanFrame *self)
|
|
{
|
|
return self->vk_fence;
|
|
}
|
|
|
|
void
|
|
gsk_vulkan_semaphores_add_wait (GskVulkanSemaphores *self,
|
|
VkSemaphore semaphore,
|
|
VkPipelineStageFlags stage)
|
|
{
|
|
gsk_semaphores_append (&self->wait_semaphores, semaphore);
|
|
gsk_pipeline_stages_append (&self->wait_stages, stage);
|
|
}
|
|
|
|
void
|
|
gsk_vulkan_semaphores_add_signal (GskVulkanSemaphores *self,
|
|
VkSemaphore semaphore)
|
|
{
|
|
gsk_semaphores_append (&self->signal_semaphores, semaphore);
|
|
}
|
|
|