mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-28 14:31:10 +00:00
840c72d74d
This was a tricky one to figure out, but it's pretty simple to understand (I hope!). So, this AMD card I'm using requires buffer memory sizes to be aligned to 16 bytes. Intel is aligned to 4 bytes I think, but AMD - or at least this AMD model in particular - uses 16 bytes for alignment. When creating a a particular texture (I did not determin which one specifically!) a buffer of size 1276 bytes is requested. 1276 / 16 = 79.75, which is clearly not aligned to the required 16 bytes. We request Vulkan to create a buffer of 1276 bytes for us, it figures out that it's not aligned, and creates a buffer of 1280 bytes, which is aligned. The extra 4 bytes are wasted, but that's okay. We immediately query this buffer for this exact information, using vkGetBufferMemoryRequirements(), and proceed to create actual memory to back this buffer up. The buffer tells us we must use 1280 bytes, so we pass 1280 bytes and everyone is happy, right? Of course not. We pass 1276 bytes, and Vulkan is subtly unhappy at us. Fix that by passing the value that Vulkan asks us to use, i.e., the size returned by vkGetBufferMemoryRequirements().
111 lines
3.2 KiB
C
111 lines
3.2 KiB
C
#include "config.h"
|
|
|
|
#include "gskvulkanbufferprivate.h"
|
|
#include "gskvulkanmemoryprivate.h"
|
|
#include "gskvulkanpipelineprivate.h"
|
|
|
|
struct _GskVulkanBuffer
|
|
{
|
|
GdkVulkanContext *vulkan;
|
|
|
|
gsize size;
|
|
|
|
VkBuffer vk_buffer;
|
|
|
|
GskVulkanMemory *memory;
|
|
};
|
|
|
|
static GskVulkanBuffer *
|
|
gsk_vulkan_buffer_new_internal (GdkVulkanContext *context,
|
|
gsize size,
|
|
VkBufferUsageFlags usage)
|
|
{
|
|
VkMemoryRequirements requirements;
|
|
GskVulkanBuffer *self;
|
|
|
|
self = g_new0 (GskVulkanBuffer, 1);
|
|
|
|
self->vulkan = g_object_ref (context);
|
|
self->size = size;
|
|
|
|
GSK_VK_CHECK (vkCreateBuffer, gdk_vulkan_context_get_device (context),
|
|
&(VkBufferCreateInfo) {
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
|
.size = size,
|
|
.flags = 0,
|
|
.usage = usage,
|
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE
|
|
},
|
|
NULL,
|
|
&self->vk_buffer);
|
|
|
|
vkGetBufferMemoryRequirements (gdk_vulkan_context_get_device (context),
|
|
self->vk_buffer,
|
|
&requirements);
|
|
|
|
self->memory = gsk_vulkan_memory_new (context,
|
|
requirements.memoryTypeBits,
|
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
|
requirements.size);
|
|
|
|
GSK_VK_CHECK (vkBindBufferMemory, gdk_vulkan_context_get_device (context),
|
|
self->vk_buffer,
|
|
gsk_vulkan_memory_get_device_memory (self->memory),
|
|
0);
|
|
return self;
|
|
}
|
|
|
|
GskVulkanBuffer *
|
|
gsk_vulkan_buffer_new (GdkVulkanContext *context,
|
|
gsize size)
|
|
{
|
|
return gsk_vulkan_buffer_new_internal (context, size,
|
|
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
|
|
| VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
|
|
}
|
|
|
|
GskVulkanBuffer *
|
|
gsk_vulkan_buffer_new_staging (GdkVulkanContext *context,
|
|
gsize size)
|
|
{
|
|
return gsk_vulkan_buffer_new_internal (context, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
|
|
}
|
|
|
|
GskVulkanBuffer *
|
|
gsk_vulkan_buffer_new_download (GdkVulkanContext *context,
|
|
gsize size)
|
|
{
|
|
return gsk_vulkan_buffer_new_internal (context, size, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
|
|
}
|
|
void
|
|
gsk_vulkan_buffer_free (GskVulkanBuffer *self)
|
|
{
|
|
vkDestroyBuffer (gdk_vulkan_context_get_device (self->vulkan),
|
|
self->vk_buffer,
|
|
NULL);
|
|
|
|
gsk_vulkan_memory_free (self->memory);
|
|
|
|
g_object_unref (self->vulkan);
|
|
|
|
g_free (self);
|
|
}
|
|
|
|
VkBuffer
|
|
gsk_vulkan_buffer_get_buffer (GskVulkanBuffer *self)
|
|
{
|
|
return self->vk_buffer;
|
|
}
|
|
|
|
guchar *
|
|
gsk_vulkan_buffer_map (GskVulkanBuffer *self)
|
|
{
|
|
return gsk_vulkan_memory_map (self->memory);
|
|
}
|
|
|
|
void
|
|
gsk_vulkan_buffer_unmap (GskVulkanBuffer *self)
|
|
{
|
|
gsk_vulkan_memory_unmap (self->memory);
|
|
}
|