mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-17 09:22:43 +00:00
While the base of a memory object was aligned when calculating the memory block size, the top end was not, which could result in the memory block not getting enough bytes allocated to satisfy alignment requirements (eg, for flushing). While fixing that, I noticed the offsets of objects were not being aligned when binding, so that is fixed as well. Fixes Mr Fixit on my VersaPro.
299 lines
8.3 KiB
C
299 lines
8.3 KiB
C
/*
|
|
resource.c
|
|
|
|
Vulkan resource functions
|
|
|
|
Copyright (C) 2022 Bill Currie <bill@taniwha.org>
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to:
|
|
|
|
Free Software Foundation, Inc.
|
|
59 Temple Place - Suite 330
|
|
Boston, MA 02111-1307, USA
|
|
|
|
*/
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#include "QF/va.h"
|
|
|
|
#include "QF/Vulkan/buffer.h"
|
|
#include "QF/Vulkan/debug.h"
|
|
#include "QF/Vulkan/device.h"
|
|
#include "QF/Vulkan/image.h"
|
|
#include "QF/Vulkan/instance.h"
|
|
#include "QF/Vulkan/resource.h"
|
|
|
|
int
|
|
QFV_CreateResource (qfv_device_t *device, qfv_resource_t *resource)
|
|
{
|
|
qfv_devfuncs_t *dfunc = device->funcs;
|
|
qfv_physdev_t *physdev = device->physDev;
|
|
VkPhysicalDeviceMemoryProperties *memprops = &physdev->memory_properties;
|
|
VkMemoryRequirements req;
|
|
VkDeviceSize size = 0;
|
|
|
|
for (unsigned i = 0; i < resource->num_objects; i++) {
|
|
__auto_type obj = &resource->objects[i];
|
|
switch (obj->type) {
|
|
case qfv_res_buffer:
|
|
{
|
|
__auto_type buffer = &obj->buffer;
|
|
buffer->buffer = QFV_CreateBuffer (device,
|
|
buffer->size,
|
|
buffer->usage);
|
|
QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER,
|
|
buffer->buffer,
|
|
va (resource->va_ctx, "buffer:%s:%s",
|
|
resource->name, obj->name));
|
|
dfunc->vkGetBufferMemoryRequirements (device->dev,
|
|
buffer->buffer, &req);
|
|
}
|
|
break;
|
|
case qfv_res_buffer_view:
|
|
{
|
|
__auto_type buffview = &obj->buffer_view;
|
|
__auto_type buffobj = &resource->objects[buffview->buffer];
|
|
if (buffview->buffer >= resource->num_objects
|
|
|| buffobj->type != qfv_res_buffer) {
|
|
Sys_Error ("%s:%s invalid buffer for view",
|
|
resource->name, obj->name);
|
|
}
|
|
}
|
|
break;
|
|
case qfv_res_image:
|
|
{
|
|
__auto_type image = &obj->image;
|
|
image->image = QFV_CreateImage (device,
|
|
image->cubemap,
|
|
image->type,
|
|
image->format,
|
|
image->extent,
|
|
image->num_mipmaps,
|
|
image->num_layers,
|
|
image->samples,
|
|
image->usage);
|
|
QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE,
|
|
image->image,
|
|
va (resource->va_ctx, "image:%s:%s",
|
|
resource->name, obj->name));
|
|
dfunc->vkGetImageMemoryRequirements (device->dev,
|
|
image->image, &req);
|
|
}
|
|
break;
|
|
case qfv_res_image_view:
|
|
{
|
|
__auto_type imgview = &obj->image_view;
|
|
__auto_type imgobj = &resource->objects[imgview->image];
|
|
if (imgview->image >= resource->num_objects
|
|
|| imgobj->type != qfv_res_image) {
|
|
Sys_Error ("%s:%s invalid image for view",
|
|
resource->name, obj->name);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
Sys_Error ("%s:%s invalid resource type %d",
|
|
resource->name, obj->name, obj->type);
|
|
}
|
|
size = QFV_NextOffset (size, &req);
|
|
size += QFV_NextOffset (req.size, &req);
|
|
}
|
|
VkMemoryPropertyFlags properties = resource->memory_properties;
|
|
for (uint32_t type = 0; type < memprops->memoryTypeCount; type++) {
|
|
if ((req.memoryTypeBits & (1 << type))
|
|
&& ((memprops->memoryTypes[type].propertyFlags & properties)
|
|
== properties)) {
|
|
VkMemoryAllocateInfo allocate_info = {
|
|
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
|
.allocationSize = size,
|
|
.memoryTypeIndex = type,
|
|
};
|
|
VkResult res = dfunc->vkAllocateMemory (device->dev, &allocate_info,
|
|
0, &resource->memory);
|
|
if (res == VK_SUCCESS) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY,
|
|
resource->memory, va (resource->va_ctx, "memory:%s",
|
|
resource->name));
|
|
|
|
VkDeviceSize offset = 0;
|
|
for (unsigned i = 0; i < resource->num_objects; i++) {
|
|
__auto_type obj = &resource->objects[i];
|
|
switch (obj->type) {
|
|
case qfv_res_buffer:
|
|
{
|
|
__auto_type buffer = &obj->buffer;
|
|
dfunc->vkGetBufferMemoryRequirements (device->dev,
|
|
buffer->buffer, &req);
|
|
}
|
|
break;
|
|
case qfv_res_image:
|
|
{
|
|
__auto_type image = &obj->image;
|
|
dfunc->vkGetImageMemoryRequirements (device->dev,
|
|
image->image, &req);
|
|
}
|
|
break;
|
|
case qfv_res_buffer_view:
|
|
case qfv_res_image_view:
|
|
break;
|
|
}
|
|
|
|
offset = QFV_NextOffset (offset, &req);
|
|
switch (obj->type) {
|
|
case qfv_res_buffer:
|
|
{
|
|
__auto_type buffer = &obj->buffer;
|
|
QFV_BindBufferMemory (device, buffer->buffer,
|
|
resource->memory, offset);
|
|
buffer->offset = offset;
|
|
}
|
|
break;
|
|
case qfv_res_image:
|
|
{
|
|
__auto_type image = &obj->image;
|
|
QFV_BindImageMemory (device, image->image,
|
|
resource->memory, offset);
|
|
image->offset = offset;
|
|
}
|
|
break;
|
|
case qfv_res_buffer_view:
|
|
case qfv_res_image_view:
|
|
break;
|
|
}
|
|
offset = QFV_NextOffset (offset, &req);
|
|
offset += QFV_NextOffset (req.size, &req);
|
|
}
|
|
|
|
for (unsigned i = 0; i < resource->num_objects; i++) {
|
|
__auto_type obj = &resource->objects[i];
|
|
switch (obj->type) {
|
|
case qfv_res_buffer:
|
|
case qfv_res_image:
|
|
break;
|
|
case qfv_res_buffer_view:
|
|
{
|
|
__auto_type buffview = &obj->buffer_view;
|
|
__auto_type buffobj = &resource->objects[buffview->buffer];
|
|
__auto_type buffer = &buffobj->buffer;
|
|
buffview->view = QFV_CreateBufferView (device,
|
|
buffer->buffer,
|
|
buffview->format,
|
|
buffview->offset,
|
|
buffview->size);
|
|
QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER_VIEW,
|
|
buffview->view,
|
|
va (resource->va_ctx, "bview:%s:%s",
|
|
resource->name, obj->name));
|
|
}
|
|
break;
|
|
case qfv_res_image_view:
|
|
{
|
|
__auto_type imgview = &obj->image_view;
|
|
__auto_type imgobj = &resource->objects[imgview->image];
|
|
__auto_type image = &imgobj->image;
|
|
imgview->view = QFV_CreateImageView (device,
|
|
image->image,
|
|
imgview->type,
|
|
imgview->format,
|
|
imgview->aspect);
|
|
QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE_VIEW,
|
|
imgview->view,
|
|
va (resource->va_ctx, "iview:%s:%s",
|
|
resource->name, obj->name));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
QFV_DestroyResource (qfv_device_t *device, qfv_resource_t *resource)
|
|
{
|
|
qfv_devfuncs_t *dfunc = device->funcs;
|
|
|
|
for (unsigned i = 0; i < resource->num_objects; i++) {
|
|
__auto_type obj = &resource->objects[i];
|
|
switch (obj->type) {
|
|
case qfv_res_buffer:
|
|
case qfv_res_image:
|
|
break;
|
|
case qfv_res_buffer_view:
|
|
{
|
|
__auto_type buffview = &obj->buffer_view;
|
|
dfunc->vkDestroyBufferView (device->dev, buffview->view, 0);
|
|
}
|
|
break;
|
|
case qfv_res_image_view:
|
|
{
|
|
__auto_type imgview = &obj->image_view;
|
|
dfunc->vkDestroyImageView (device->dev, imgview->view, 0);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
for (unsigned i = 0; i < resource->num_objects; i++) {
|
|
__auto_type obj = &resource->objects[i];
|
|
switch (obj->type) {
|
|
case qfv_res_buffer:
|
|
{
|
|
__auto_type buffer = &obj->buffer;
|
|
dfunc->vkDestroyBuffer (device->dev, buffer->buffer, 0);
|
|
}
|
|
break;
|
|
case qfv_res_image:
|
|
{
|
|
__auto_type image = &obj->image;
|
|
dfunc->vkDestroyImage (device->dev, image->image, 0);
|
|
}
|
|
break;
|
|
case qfv_res_buffer_view:
|
|
case qfv_res_image_view:
|
|
break;
|
|
}
|
|
}
|
|
dfunc->vkFreeMemory (device->dev, resource->memory, 0);
|
|
}
|
|
|
|
void
|
|
QFV_ResourceInitTexImage (qfv_resobj_t *image, const char *name,
|
|
int mips, const tex_t *tex)
|
|
{
|
|
*image = (qfv_resobj_t) {
|
|
.name = name,
|
|
.type = qfv_res_image,
|
|
.image = {
|
|
.type = VK_IMAGE_TYPE_2D,
|
|
.format = QFV_ImageFormat (tex->format, 0),
|
|
.extent = {
|
|
.width = tex->width,
|
|
.height = tex->height,
|
|
.depth = 1,
|
|
},
|
|
.num_mipmaps = mips ? QFV_MipLevels (tex->width, tex->height) : 1,
|
|
.num_layers = 1,
|
|
.samples = VK_SAMPLE_COUNT_1_BIT,
|
|
.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT
|
|
| VK_IMAGE_USAGE_TRANSFER_SRC_BIT
|
|
| VK_IMAGE_USAGE_SAMPLED_BIT,
|
|
},
|
|
};
|
|
}
|