mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-28 06:21:14 +00:00
c29237c75d
This adds GSK_GPU_IMAGE_CAN_MIPMAP and GSK_GPU_IMAGE_MIPMAP flags and support to ensure_image() and image creation functions for creating a mipmapped image. Mipmaps are created using the new mipmap op that uses glGenerateMipmap() on GL and equivalent blit ops on Vulkan. This is then used to ensure the image is mipmapped when rendering it with a texture-scale node.
462 lines
19 KiB
C
462 lines
19 KiB
C
#include "config.h"
|
|
|
|
#include "gskvulkanframeprivate.h"
|
|
|
|
#include "gskgpuopprivate.h"
|
|
#include "gskvulkanbufferprivate.h"
|
|
#include "gskvulkandescriptorsprivate.h"
|
|
#include "gskvulkandeviceprivate.h"
|
|
#include "gskvulkanimageprivate.h"
|
|
|
|
#include "gdk/gdkdisplayprivate.h"
|
|
#include "gdk/gdkdmabuftextureprivate.h"
|
|
|
|
#define GDK_ARRAY_NAME gsk_descriptor_image_infos
|
|
#define GDK_ARRAY_TYPE_NAME GskDescriptorImageInfos
|
|
#define GDK_ARRAY_ELEMENT_TYPE VkDescriptorImageInfo
|
|
#define GDK_ARRAY_BY_VALUE 1
|
|
#define GDK_ARRAY_PREALLOC 128
|
|
#define GDK_ARRAY_NO_MEMSET 1
|
|
#include "gdk/gdkarrayimpl.c"
|
|
|
|
#define GDK_ARRAY_NAME gsk_descriptor_buffer_infos
|
|
#define GDK_ARRAY_TYPE_NAME GskDescriptorBufferInfos
|
|
#define GDK_ARRAY_ELEMENT_TYPE VkDescriptorBufferInfo
|
|
#define GDK_ARRAY_BY_VALUE 1
|
|
#define GDK_ARRAY_PREALLOC 32
|
|
#define GDK_ARRAY_NO_MEMSET 1
|
|
#include "gdk/gdkarrayimpl.c"
|
|
|
|
#define GDK_ARRAY_NAME gsk_samplers
|
|
#define GDK_ARRAY_TYPE_NAME GskSamplers
|
|
#define GDK_ARRAY_ELEMENT_TYPE VkSampler
|
|
#define GDK_ARRAY_NULL_TERMINATED 1
|
|
#define GDK_ARRAY_PREALLOC 31
|
|
#define GDK_ARRAY_NO_MEMSET 1
|
|
#include "gdk/gdkarrayimpl.c"
|
|
|
|
struct _GskVulkanFrame
|
|
{
|
|
GskGpuFrame parent_instance;
|
|
|
|
GskVulkanPipelineLayout *pipeline_layout;
|
|
GskSamplers immutable_samplers;
|
|
GskDescriptorImageInfos descriptor_immutable_images;
|
|
GskDescriptorImageInfos descriptor_images;
|
|
GskDescriptorBufferInfos descriptor_buffers;
|
|
|
|
VkFence vk_fence;
|
|
VkCommandBuffer vk_command_buffer;
|
|
VkDescriptorPool vk_descriptor_pool;
|
|
};
|
|
|
|
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_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);
|
|
|
|
GSK_VK_CHECK (vkCreateDescriptorPool, vk_device,
|
|
&(VkDescriptorPoolCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
|
.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT,
|
|
.maxSets = GSK_VULKAN_N_DESCRIPTOR_SETS,
|
|
.poolSizeCount = GSK_VULKAN_N_DESCRIPTOR_SETS,
|
|
.pPoolSizes = (VkDescriptorPoolSize[GSK_VULKAN_N_DESCRIPTOR_SETS]) {
|
|
{
|
|
.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
|
.descriptorCount = gsk_vulkan_device_get_max_descriptors (device),
|
|
},
|
|
{
|
|
.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
|
.descriptorCount = gsk_vulkan_device_get_max_descriptors (device),
|
|
}
|
|
}
|
|
},
|
|
NULL,
|
|
&self->vk_descriptor_pool);
|
|
|
|
}
|
|
|
|
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);
|
|
|
|
GSK_VK_CHECK (vkResetDescriptorPool, vk_device,
|
|
self->vk_descriptor_pool,
|
|
0);
|
|
gsk_samplers_set_size (&self->immutable_samplers, 0);
|
|
gsk_descriptor_image_infos_set_size (&self->descriptor_immutable_images, 0);
|
|
gsk_descriptor_image_infos_set_size (&self->descriptor_images, 0);
|
|
gsk_descriptor_buffer_infos_set_size (&self->descriptor_buffers, 0);
|
|
|
|
gsk_vulkan_device_release_pipeline_layout (device, self->pipeline_layout);
|
|
self->pipeline_layout = NULL;
|
|
|
|
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);
|
|
}
|
|
|
|
guint32
|
|
gsk_vulkan_frame_add_image (GskVulkanFrame *self,
|
|
GskGpuImage *image,
|
|
GskGpuSampler sampler)
|
|
{
|
|
GskVulkanImage *vulkan_image = GSK_VULKAN_IMAGE (image);
|
|
GskVulkanDevice *device;
|
|
VkSampler vk_sampler;
|
|
guint32 result;
|
|
|
|
device = GSK_VULKAN_DEVICE (gsk_gpu_frame_get_device (GSK_GPU_FRAME (self)));
|
|
vk_sampler = gsk_vulkan_image_get_vk_sampler (vulkan_image);
|
|
|
|
if (vk_sampler)
|
|
{
|
|
result = gsk_descriptor_image_infos_get_size (&self->descriptor_immutable_images) << 1 | 1;
|
|
|
|
gsk_samplers_append (&self->immutable_samplers, vk_sampler);
|
|
gsk_descriptor_image_infos_append (&self->descriptor_immutable_images,
|
|
&(VkDescriptorImageInfo) {
|
|
.imageView = gsk_vulkan_image_get_vk_image_view (vulkan_image),
|
|
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
|
|
});
|
|
}
|
|
else
|
|
{
|
|
result = gsk_descriptor_image_infos_get_size (&self->descriptor_images);
|
|
g_assert (result < gsk_vulkan_device_get_max_descriptors (device));
|
|
result = result << 1;
|
|
|
|
gsk_descriptor_image_infos_append (&self->descriptor_images,
|
|
&(VkDescriptorImageInfo) {
|
|
.sampler = gsk_vulkan_device_get_vk_sampler (device, sampler),
|
|
.imageView = gsk_vulkan_image_get_vk_image_view (vulkan_image),
|
|
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
|
|
});
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static guint32
|
|
gsk_vulkan_frame_get_buffer_descriptor (GskVulkanFrame *self,
|
|
GskGpuBuffer *buffer)
|
|
{
|
|
guint32 result;
|
|
|
|
result = gsk_descriptor_buffer_infos_get_size (&self->descriptor_buffers);
|
|
gsk_descriptor_buffer_infos_append (&self->descriptor_buffers,
|
|
&(VkDescriptorBufferInfo) {
|
|
.buffer = gsk_vulkan_buffer_get_vk_buffer (GSK_VULKAN_BUFFER (buffer)),
|
|
.offset = 0,
|
|
.range = VK_WHOLE_SIZE
|
|
});
|
|
|
|
return result;
|
|
}
|
|
|
|
static void
|
|
gsk_vulkan_frame_prepare_descriptor_sets (GskVulkanFrame *self)
|
|
{
|
|
GskVulkanDevice *device;
|
|
VkDevice vk_device;
|
|
VkWriteDescriptorSet write_descriptor_sets[GSK_VULKAN_N_DESCRIPTOR_SETS + 1];
|
|
gsize n_descriptor_sets;
|
|
VkDescriptorSet descriptor_sets[GSK_VULKAN_N_DESCRIPTOR_SETS];
|
|
|
|
device = GSK_VULKAN_DEVICE (gsk_gpu_frame_get_device (GSK_GPU_FRAME (self)));
|
|
vk_device = gsk_vulkan_device_get_vk_device (device);
|
|
|
|
GSK_VK_CHECK (vkAllocateDescriptorSets, vk_device,
|
|
&(VkDescriptorSetAllocateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
|
.descriptorPool = self->vk_descriptor_pool,
|
|
.descriptorSetCount = GSK_VULKAN_N_DESCRIPTOR_SETS,
|
|
.pSetLayouts = (VkDescriptorSetLayout[GSK_VULKAN_N_DESCRIPTOR_SETS]) {
|
|
gsk_vulkan_device_get_vk_image_set_layout (device, self->pipeline_layout),
|
|
gsk_vulkan_device_get_vk_buffer_set_layout (device),
|
|
},
|
|
.pNext = &(VkDescriptorSetVariableDescriptorCountAllocateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO,
|
|
.descriptorSetCount = GSK_VULKAN_N_DESCRIPTOR_SETS,
|
|
.pDescriptorCounts = (uint32_t[GSK_VULKAN_N_DESCRIPTOR_SETS]) {
|
|
MAX (1, gsk_descriptor_image_infos_get_size (&self->descriptor_immutable_images) +
|
|
gsk_descriptor_image_infos_get_size (&self->descriptor_images)),
|
|
MAX (1, gsk_descriptor_buffer_infos_get_size (&self->descriptor_buffers))
|
|
}
|
|
}
|
|
},
|
|
descriptor_sets);
|
|
|
|
n_descriptor_sets = 0;
|
|
if (gsk_descriptor_image_infos_get_size (&self->descriptor_immutable_images) > 0)
|
|
{
|
|
write_descriptor_sets[n_descriptor_sets++] = (VkWriteDescriptorSet) {
|
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
|
.dstSet = descriptor_sets[GSK_VULKAN_IMAGE_SET_LAYOUT],
|
|
.dstBinding = 0,
|
|
.dstArrayElement = 0,
|
|
.descriptorCount = gsk_descriptor_image_infos_get_size (&self->descriptor_immutable_images),
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
|
.pImageInfo = gsk_descriptor_image_infos_get_data (&self->descriptor_immutable_images)
|
|
};
|
|
}
|
|
if (gsk_descriptor_image_infos_get_size (&self->descriptor_images) > 0)
|
|
{
|
|
write_descriptor_sets[n_descriptor_sets++] = (VkWriteDescriptorSet) {
|
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
|
.dstSet = descriptor_sets[GSK_VULKAN_IMAGE_SET_LAYOUT],
|
|
.dstBinding = 1,
|
|
.dstArrayElement = 0,
|
|
.descriptorCount = gsk_descriptor_image_infos_get_size (&self->descriptor_images),
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
|
.pImageInfo = gsk_descriptor_image_infos_get_data (&self->descriptor_images)
|
|
};
|
|
}
|
|
if (gsk_descriptor_buffer_infos_get_size (&self->descriptor_buffers) > 0)
|
|
{
|
|
write_descriptor_sets[n_descriptor_sets++] = (VkWriteDescriptorSet) {
|
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
|
.dstSet = descriptor_sets[GSK_VULKAN_BUFFER_SET_LAYOUT],
|
|
.dstBinding = 0,
|
|
.dstArrayElement = 0,
|
|
.descriptorCount = gsk_descriptor_buffer_infos_get_size (&self->descriptor_buffers),
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
|
.pBufferInfo = gsk_descriptor_buffer_infos_get_data (&self->descriptor_buffers)
|
|
};
|
|
}
|
|
|
|
vkUpdateDescriptorSets (vk_device,
|
|
n_descriptor_sets,
|
|
write_descriptor_sets,
|
|
0, NULL);
|
|
|
|
vkCmdBindDescriptorSets (self->vk_command_buffer,
|
|
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
gsk_vulkan_device_get_vk_pipeline_layout (device, self->pipeline_layout),
|
|
0,
|
|
GSK_VULKAN_N_DESCRIPTOR_SETS,
|
|
descriptor_sets,
|
|
0,
|
|
NULL);
|
|
}
|
|
|
|
static GskGpuDescriptors *
|
|
gsk_vulkan_frame_create_descriptors (GskGpuFrame *frame)
|
|
{
|
|
return GSK_GPU_DESCRIPTORS (gsk_vulkan_descriptors_new (GSK_VULKAN_FRAME (frame)));
|
|
}
|
|
|
|
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,
|
|
GskGpuBuffer *storage_buffer,
|
|
GskGpuOp *op)
|
|
{
|
|
GskVulkanFrame *self = GSK_VULKAN_FRAME (frame);
|
|
|
|
if (storage_buffer)
|
|
{
|
|
G_GNUC_UNUSED guint32 descriptor;
|
|
descriptor = gsk_vulkan_frame_get_buffer_descriptor (self, storage_buffer);
|
|
g_assert (descriptor == 0);
|
|
}
|
|
|
|
self->pipeline_layout = gsk_vulkan_device_acquire_pipeline_layout (GSK_VULKAN_DEVICE (gsk_gpu_frame_get_device (frame)),
|
|
gsk_samplers_get_data (&self->immutable_samplers),
|
|
gsk_samplers_get_size (&self->immutable_samplers));
|
|
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,
|
|
});
|
|
|
|
gsk_vulkan_frame_prepare_descriptor_sets (self);
|
|
|
|
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 });
|
|
|
|
while (op)
|
|
{
|
|
op = gsk_gpu_op_vk_command (op, frame, VK_NULL_HANDLE, VK_FORMAT_UNDEFINED, self->vk_command_buffer);
|
|
}
|
|
|
|
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,
|
|
},
|
|
self->vk_fence);
|
|
}
|
|
|
|
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);
|
|
|
|
vkDestroyDescriptorPool (vk_device,
|
|
self->vk_descriptor_pool,
|
|
NULL);
|
|
gsk_samplers_clear (&self->immutable_samplers);
|
|
gsk_descriptor_image_infos_clear (&self->descriptor_immutable_images);
|
|
gsk_descriptor_image_infos_clear (&self->descriptor_images);
|
|
gsk_descriptor_buffer_infos_clear (&self->descriptor_buffers);
|
|
|
|
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->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_samplers_init (&self->immutable_samplers);
|
|
gsk_descriptor_image_infos_init (&self->descriptor_immutable_images);
|
|
gsk_descriptor_image_infos_init (&self->descriptor_images);
|
|
gsk_descriptor_buffer_infos_init (&self->descriptor_buffers);
|
|
}
|
|
|
|
VkFence
|
|
gsk_vulkan_frame_get_vk_fence (GskVulkanFrame *self)
|
|
{
|
|
return self->vk_fence;
|
|
}
|
|
|
|
GskVulkanPipelineLayout *
|
|
gsk_vulkan_frame_get_pipeline_layout (GskVulkanFrame *self)
|
|
{
|
|
return self->pipeline_layout;
|
|
}
|
|
|