Staging buffers resize.

This commit is contained in:
Denis Pauk 2020-05-09 10:52:00 +03:00 committed by Yamagi
parent 896346cf1a
commit 3ec8e65d34
9 changed files with 119 additions and 84 deletions

View file

@ -157,6 +157,7 @@ extern cvar_t *vk_particle_min_size;
extern cvar_t *vk_particle_max_size;
extern cvar_t *vk_point_particles;
extern cvar_t *vk_dynamic;
extern cvar_t *vk_msaa;
extern cvar_t *vk_showtris;
extern cvar_t *vk_lightmap;
extern cvar_t *vk_texturemode;

View file

@ -215,6 +215,9 @@ extern VkCommandPool vk_commandPool;
extern VkCommandPool vk_transferCommandPool;
// Vulkan descriptor pool
extern VkDescriptorPool vk_descriptorPool;
// viewport/scissor
extern VkViewport vk_viewport;
extern VkRect2D vk_scissor;
// Vulkan descriptor sets
extern VkDescriptorSetLayout vk_uboDescSetLayout;
@ -282,7 +285,7 @@ VkResult QVk_BeginCommand(const VkCommandBuffer *commandBuffer);
void QVk_SubmitCommand(const VkCommandBuffer *commandBuffer, const VkQueue *queue);
VkCommandBuffer QVk_CreateCommandBuffer(const VkCommandPool *commandPool, VkCommandBufferLevel level);
const char* QVk_GetError(VkResult errorCode);
VkResult QVk_BeginFrame(void);
VkResult QVk_BeginFrame(const VkViewport* viewport, const VkRect2D* scissor);
VkResult QVk_EndFrame(qboolean force);
void QVk_BeginRenderpass(qvkrenderpasstype_t rpType);
void QVk_FreeStagingBuffer(qvkstagingbuffer_t *buffer);

View file

@ -21,6 +21,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <vulkan/vulkan.h>
#define ROUNDUP(a, b) (((a) + ((b)-1)) & ~((b)-1))
typedef struct BufferResource_s {
VkBuffer buffer;
VkDeviceMemory memory;
@ -35,7 +37,6 @@ typedef struct ImageResource_s {
} ImageResource_t;
VkResult buffer_create(BufferResource_t *buf,
VkDeviceSize size,
VkBufferCreateInfo buf_create_info,
VkMemoryPropertyFlags mem_properties,
VkMemoryPropertyFlags mem_preferences);

View file

@ -98,7 +98,7 @@ QVk_CreateBuffer(VkDeviceSize size, qvkbuffer_t *dstBuffer,
}
dstBuffer->currentOffset = 0;
return buffer_create(&dstBuffer->resource, size, bcInfo,
return buffer_create(&dstBuffer->resource, bcInfo,
options.reqMemFlags, options.prefMemFlags);
}
@ -125,7 +125,7 @@ QVk_CreateStagingBuffer(VkDeviceSize size, qvkstagingbuffer_t *dstBuffer,
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = NULL,
.flags = 0,
.size = size,
.size = ROUNDUP(size, 1024),
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
@ -133,7 +133,7 @@ QVk_CreateStagingBuffer(VkDeviceSize size, qvkstagingbuffer_t *dstBuffer,
};
dstBuffer->currentOffset = 0;
return buffer_create(&dstBuffer->resource, size, bcInfo, reqMemFlags,
return buffer_create(&dstBuffer->resource, bcInfo, reqMemFlags,
prefMemFlags);
}

View file

@ -249,8 +249,6 @@ VkDescriptorSetLayout vk_uboDescSetLayout;
VkDescriptorSetLayout vk_samplerDescSetLayout;
VkDescriptorSetLayout vk_samplerLightmapDescSetLayout;
extern cvar_t *vk_msaa;
VkFormat QVk_FindDepthFormat()
{
VkFormat depthFormats[] = {
@ -274,7 +272,7 @@ VkFormat QVk_FindDepthFormat()
}
// internal helper
static VkSampleCountFlagBits GetSampleCount()
static VkSampleCountFlagBits GetSampleCount(int msaa)
{
static VkSampleCountFlagBits msaaModes[] = {
VK_SAMPLE_COUNT_1_BIT,
@ -284,7 +282,7 @@ static VkSampleCountFlagBits GetSampleCount()
VK_SAMPLE_COUNT_16_BIT
};
return msaaModes[(int)vk_msaa->value];
return msaaModes[msaa];
}
// internal helper
@ -1060,6 +1058,37 @@ static void RebuildTriangleFanIndexBuffer()
free(fanData);
}
static void CreateStagingBuffer(VkDeviceSize size, qvkstagingbuffer_t *dstBuffer, int i)
{
VkFenceCreateInfo fCreateInfo = {
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
.flags = 0
};
VK_VERIFY(QVk_CreateStagingBuffer(size,
dstBuffer,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
VK_MEMORY_PROPERTY_HOST_CACHED_BIT));
dstBuffer->pMappedData = buffer_map(&dstBuffer->resource);
dstBuffer->submitted = false;
VK_VERIFY(vkCreateFence(vk_device.logical, &fCreateInfo,
NULL, &dstBuffer->fence));
dstBuffer->cmdBuffer = QVk_CreateCommandBuffer(&vk_stagingCommandPool,
VK_COMMAND_BUFFER_LEVEL_PRIMARY);
VK_VERIFY(QVk_BeginCommand(&dstBuffer->cmdBuffer));
QVk_DebugSetObjectName((uint64_t)dstBuffer->fence,
VK_OBJECT_TYPE_FENCE, va("Fence: Staging Buffer #%d", i));
QVk_DebugSetObjectName((uint64_t)dstBuffer->resource.buffer,
VK_OBJECT_TYPE_BUFFER, va("Staging Buffer #%d", i));
QVk_DebugSetObjectName((uint64_t)dstBuffer->resource.memory,
VK_OBJECT_TYPE_DEVICE_MEMORY, va("Memory: Staging Buffer #%d", i));
QVk_DebugSetObjectName((uint64_t)dstBuffer->cmdBuffer,
VK_OBJECT_TYPE_COMMAND_BUFFER, va("Command Buffer: Staging Buffer #%d", i));
}
// internal helper
static void CreateStagingBuffers()
{
@ -1068,41 +1097,21 @@ static void CreateStagingBuffers()
QVk_DebugSetObjectName((uint64_t)vk_stagingCommandPool,
VK_OBJECT_TYPE_COMMAND_POOL, "Command Pool: Staging Buffers");
VkFenceCreateInfo fCreateInfo = {
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
.flags = 0
};
for (int i = 0; i < NUM_DYNBUFFERS; ++i)
{
VK_VERIFY(QVk_CreateStagingBuffer(STAGING_BUFFER_MAXSIZE,
&vk_stagingBuffers[i],
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
VK_MEMORY_PROPERTY_HOST_CACHED_BIT));
vk_stagingBuffers[i].pMappedData = buffer_map(&vk_stagingBuffers[i].resource);
vk_stagingBuffers[i].submitted = false;
VK_VERIFY(vkCreateFence(vk_device.logical, &fCreateInfo,
NULL, &vk_stagingBuffers[i].fence));
vk_stagingBuffers[i].cmdBuffer = QVk_CreateCommandBuffer(&vk_stagingCommandPool,
VK_COMMAND_BUFFER_LEVEL_PRIMARY);
VK_VERIFY(QVk_BeginCommand(&vk_stagingBuffers[i].cmdBuffer));
QVk_DebugSetObjectName((uint64_t)vk_stagingBuffers[i].fence,
VK_OBJECT_TYPE_FENCE, va("Fence: Staging Buffer #%d", i));
QVk_DebugSetObjectName((uint64_t)vk_stagingBuffers[i].resource.buffer,
VK_OBJECT_TYPE_BUFFER, va("Staging Buffer #%d", i));
QVk_DebugSetObjectName((uint64_t)vk_stagingBuffers[i].resource.memory,
VK_OBJECT_TYPE_DEVICE_MEMORY, va("Memory: Staging Buffer #%d", i));
QVk_DebugSetObjectName((uint64_t)vk_stagingBuffers[i].cmdBuffer,
VK_OBJECT_TYPE_COMMAND_BUFFER, va("Command Buffer: Staging Buffer #%d", i));
CreateStagingBuffer(STAGING_BUFFER_MAXSIZE, &vk_stagingBuffers[i], i);
}
}
// internal helper
static void SubmitStagingBuffer(int index)
{
if (vk_stagingBuffers[index].submitted)
{
// buffer is alredy submitted
return;
}
VkMemoryBarrier memBarrier = {
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
.pNext = NULL,
@ -1415,6 +1424,23 @@ static void CreatePipelines()
vkDestroyShaderModule(vk_device.logical, shaders[1].module, NULL);
}
static void DestroyStagingBuffer(qvkstagingbuffer_t *dstBuffer)
{
if (dstBuffer->resource.buffer != VK_NULL_HANDLE)
{
// wait only if something is submitted
if (dstBuffer->submitted)
{
VK_VERIFY(vkWaitForFences(vk_device.logical, 1, &dstBuffer->fence,
VK_TRUE, UINT64_MAX));
}
buffer_unmap(&dstBuffer->resource);
QVk_FreeStagingBuffer(dstBuffer);
vkDestroyFence(vk_device.logical, dstBuffer->fence, NULL);
}
}
/*
** QVk_Shutdown
**
@ -1472,12 +1498,7 @@ void QVk_Shutdown( void )
buffer_unmap(&vk_dynVertexBuffers[i].resource);
QVk_FreeBuffer(&vk_dynVertexBuffers[i]);
}
if (vk_stagingBuffers[i].resource.buffer != VK_NULL_HANDLE)
{
buffer_unmap(&vk_stagingBuffers[i].resource);
QVk_FreeStagingBuffer(&vk_stagingBuffers[i]);
vkDestroyFence(vk_device.logical, vk_stagingBuffers[i].fence, NULL);
}
DestroyStagingBuffer(&vk_stagingBuffers[i]);
}
if (vk_descriptorPool != VK_NULL_HANDLE)
vkDestroyDescriptorPool(vk_device.logical, vk_descriptorPool, NULL);
@ -1752,7 +1773,7 @@ qboolean QVk_Init(SDL_Window *window)
vk_renderpasses[i].colorLoadOp = r_clear->value ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_DONT_CARE;
}
VkSampleCountFlagBits msaaMode = GetSampleCount();
VkSampleCountFlagBits msaaMode = GetSampleCount((int)vk_msaa->value);
VkSampleCountFlagBits supportedMsaa = vk_device.properties.limits.framebufferColorSampleCounts;
if (!(supportedMsaa & msaaMode))
{
@ -1873,7 +1894,7 @@ qboolean QVk_Init(SDL_Window *window)
return true;
}
VkResult QVk_BeginFrame()
VkResult QVk_BeginFrame(const VkViewport* viewport, const VkRect2D* scissor)
{
// reset tracking variables
vk_state.current_pipeline = VK_NULL_HANDLE;
@ -1922,8 +1943,8 @@ VkResult QVk_BeginFrame()
VK_VERIFY(vkBeginCommandBuffer(vk_commandbuffers[vk_activeBufferIdx], &beginInfo));
vkCmdSetViewport(vk_commandbuffers[vk_activeBufferIdx], 0, 1, &vk_viewport);
vkCmdSetScissor(vk_commandbuffers[vk_activeBufferIdx], 0, 1, &vk_scissor);
vkCmdSetViewport(vk_commandbuffers[vk_activeBufferIdx], 0, 1, viewport);
vkCmdSetScissor(vk_commandbuffers[vk_activeBufferIdx], 0, 1, scissor);
vk_frameStarted = true;
return VK_SUCCESS;
@ -2114,8 +2135,7 @@ uint8_t *QVk_GetVertexBuffer(VkDeviceSize size, VkBuffer *dstBuffer, VkDeviceSiz
static uint8_t *QVk_GetIndexBuffer(VkDeviceSize size, VkDeviceSize *dstOffset)
{
// align to 4 bytes, so that we can reuse the buffer for both VK_INDEX_TYPE_UINT16 and VK_INDEX_TYPE_UINT32
const int align_mod = size % 4;
const uint32_t aligned_size = ((size % 4) == 0) ? size : (size + 4 - align_mod);
const uint32_t aligned_size = ROUNDUP(size, 4);
if (vk_dynIndexBuffers[vk_activeDynBufferIdx].currentOffset + aligned_size > vk_config.index_buffer_size)
{
@ -2159,8 +2179,7 @@ static uint8_t *QVk_GetIndexBuffer(VkDeviceSize size, VkDeviceSize *dstOffset)
uint8_t *QVk_GetUniformBuffer(VkDeviceSize size, uint32_t *dstOffset, VkDescriptorSet *dstUboDescriptorSet)
{
// 0x100 alignment is required by Vulkan spec
const int align_mod = size % 256;
const uint32_t aligned_size = ((size % 256) == 0) ? size : (size + 256 - align_mod);
const uint32_t aligned_size = ROUNDUP(size, 256);
if (vk_dynUniformBuffers[vk_activeDynBufferIdx].currentOffset + UNIFORM_ALLOC_SIZE > vk_config.uniform_buffer_size)
{
@ -2217,33 +2236,39 @@ uint8_t *QVk_GetUniformBuffer(VkDeviceSize size, uint32_t *dstOffset, VkDescript
uint8_t *QVk_GetStagingBuffer(VkDeviceSize size, int alignment, VkCommandBuffer *cmdBuffer, VkBuffer *buffer, uint32_t *dstOffset)
{
qvkstagingbuffer_t * stagingBuffer = &vk_stagingBuffers[vk_activeStagingBuffer];
const int align_mod = stagingBuffer->currentOffset % alignment;
stagingBuffer->currentOffset = ((stagingBuffer->currentOffset % alignment) == 0)
? stagingBuffer->currentOffset : (stagingBuffer->currentOffset + alignment - align_mod);
stagingBuffer->currentOffset = ROUNDUP(stagingBuffer->currentOffset, alignment);
if (size > STAGING_BUFFER_MAXSIZE)
Sys_Error("QVk_GetStagingBuffer(): Cannot allocate staging buffer space!");
if ((stagingBuffer->currentOffset + size) >= STAGING_BUFFER_MAXSIZE && !stagingBuffer->submitted)
if (((stagingBuffer->currentOffset + size) >= stagingBuffer->resource.size) && !stagingBuffer->submitted)
SubmitStagingBuffer(vk_activeStagingBuffer);
stagingBuffer = &vk_stagingBuffers[vk_activeStagingBuffer];
if (stagingBuffer->submitted)
if (size > stagingBuffer->resource.size)
{
VK_VERIFY(vkWaitForFences(vk_device.logical, 1, &stagingBuffer->fence, VK_TRUE, UINT64_MAX));
VK_VERIFY(vkResetFences(vk_device.logical, 1, &stagingBuffer->fence));
R_Printf(PRINT_ALL, "%s: %d: Resize stanging buffer %ld -> %ld\n",
__func__, vk_activeStagingBuffer, stagingBuffer->resource.size, size);
stagingBuffer->currentOffset = 0;
stagingBuffer->submitted = false;
DestroyStagingBuffer(stagingBuffer);
CreateStagingBuffer(size, stagingBuffer, vk_activeStagingBuffer);
}
else
{
if (stagingBuffer->submitted)
{
VK_VERIFY(vkWaitForFences(vk_device.logical, 1, &stagingBuffer->fence, VK_TRUE, UINT64_MAX));
VK_VERIFY(vkResetFences(vk_device.logical, 1, &stagingBuffer->fence));
VkCommandBufferBeginInfo beginInfo = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
.pNext = NULL,
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
.pInheritanceInfo = NULL
};
stagingBuffer->currentOffset = 0;
stagingBuffer->submitted = false;
VK_VERIFY(vkBeginCommandBuffer(stagingBuffer->cmdBuffer, &beginInfo));
VkCommandBufferBeginInfo beginInfo = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
.pNext = NULL,
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
.pInheritanceInfo = NULL
};
VK_VERIFY(vkBeginCommandBuffer(stagingBuffer->cmdBuffer, &beginInfo));
}
}
if (cmdBuffer)

View file

@ -242,6 +242,9 @@ static void createTextureImage(qvktexture_t *dstTex, const unsigned char *data,
VkCommandBuffer command_buffer;
uint32_t staging_offset;
void *imgData = QVk_GetStagingBuffer(imageSize, 4, &command_buffer, &staging_buffer, &staging_offset);
if (!imgData)
Sys_Error("%s: Staging buffers is smaller than image: %d.\n", __func__, imageSize);
memcpy(imgData, data, (size_t)imageSize);
VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
@ -387,6 +390,9 @@ void QVk_UpdateTextureData(qvktexture_t *texture, const unsigned char *data, uin
VkCommandBuffer command_buffer;
uint32_t staging_offset;
void *imgData = QVk_GetStagingBuffer(imageSize, 4, &command_buffer, &staging_buffer, &staging_offset);
if (!imgData)
Sys_Error("%s: Staging buffers is smaller than image: %d.\n", __func__, imageSize);
memcpy(imgData, data, (size_t)imageSize);
transitionImageLayout(&command_buffer, &vk_device.transferQueue, texture, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
@ -463,7 +469,7 @@ void QVk_ReadPixels(uint8_t *dstBuffer, uint32_t width, uint32_t height)
.pQueueFamilyIndices = NULL,
};
VK_VERIFY(buffer_create(&buff, width * height * 4, bcInfo, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, VK_MEMORY_PROPERTY_HOST_CACHED_BIT));
VK_VERIFY(buffer_create(&buff, bcInfo, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, VK_MEMORY_PROPERTY_HOST_CACHED_BIT));
cmdBuffer = QVk_CreateCommandBuffer(&vk_commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
VK_VERIFY(QVk_BeginCommand(&cmdBuffer));

View file

@ -967,7 +967,7 @@ qboolean R_EndWorldRenderReady(void)
return true;
}
static void R_SetVulkan2D (void)
static void R_SetVulkan2D (const VkViewport* viewport, const VkRect2D* scissor)
{
// player configuration screen renders a model using the UI renderpass, so skip finishing RP_WORLD twice
if (!(r_newrefdef.rdflags & RDF_NOWORLDMODEL))
@ -975,10 +975,8 @@ static void R_SetVulkan2D (void)
// buffers is not initialized
return;
extern VkViewport vk_viewport;
extern VkRect2D vk_scissor;
vkCmdSetViewport(vk_activeCmdbuffer, 0, 1, &vk_viewport);
vkCmdSetScissor(vk_activeCmdbuffer, 0, 1, &vk_scissor);
vkCmdSetViewport(vk_activeCmdbuffer, 0, 1, viewport);
vkCmdSetScissor(vk_activeCmdbuffer, 0, 1, scissor);
// first, blit offscreen color buffer with warped/postprocessed world view
// skip this step if we're in player config screen since it uses RP_UI and draws directly to swapchain
@ -1040,7 +1038,7 @@ RE_RenderFrame (refdef_t *fd)
{
RE_RenderView( fd );
R_SetLightLevel ();
R_SetVulkan2D ();
R_SetVulkan2D (&vk_viewport, &vk_scissor);
}
@ -1321,7 +1319,7 @@ RE_BeginFrame( float camera_separation )
}
}
VkResult swapChainValid = QVk_BeginFrame();
VkResult swapChainValid = QVk_BeginFrame(&vk_viewport, &vk_scissor);
// if the swapchain is invalid, just recreate the video system and revert to safe windowed mode
if (swapChainValid != VK_SUCCESS)
{

View file

@ -140,7 +140,7 @@ void Vk_Strings_f(void)
VkPhysicalDevice *physicalDevices;
VkPhysicalDeviceProperties deviceProperties;
int preferredDevice = (int)vk_device_idx->value;
int msaa = (int)ri.Cvar_Get("vk_msaa", "0", CVAR_ARCHIVE)->value;
int msaa = (int)vk_msaa->value;
uint32_t driverMajor = VK_VERSION_MAJOR(vk_device.properties.driverVersion);
uint32_t driverMinor = VK_VERSION_MINOR(vk_device.properties.driverVersion);
uint32_t driverPatch = VK_VERSION_PATCH(vk_device.properties.driverVersion);
@ -238,22 +238,24 @@ void Vk_Strings_f(void)
vk_device.transferFamilyIndex);
R_Printf(PRINT_ALL, "Present mode: %s\n", vk_config.present_mode);
R_Printf(PRINT_ALL, "Swapchain image format: %d\n", vk_swapchain.format);
R_Printf(PRINT_ALL, "Supported present modes: ");
R_Printf(PRINT_ALL, "Supported present modes: ");
i = 0;
while(vk_config.supported_present_modes[i])
{
R_Printf(PRINT_ALL, "%s ", vk_config.supported_present_modes[i++]);
}
R_Printf(PRINT_ALL, "\nEnabled extensions: ");
R_Printf(PRINT_ALL, "\n");
R_Printf(PRINT_ALL, "Enabled extensions: ");
i = 0;
while(vk_config.extensions[i])
{
R_Printf(PRINT_ALL, "%s ", vk_config.extensions[i++]);
}
R_Printf(PRINT_ALL, "\nEnabled layers: ");
R_Printf(PRINT_ALL, "\n");
R_Printf(PRINT_ALL, "Enabled layers: ");
i = 0;
while(vk_config.layers[i])
{

View file

@ -35,17 +35,16 @@ get_memory_type(uint32_t mem_req_type_bits, VkMemoryPropertyFlags mem_prop)
VkResult
buffer_create(BufferResource_t *buf,
VkDeviceSize size,
VkBufferCreateInfo buf_create_info,
VkMemoryPropertyFlags mem_properties,
VkMemoryPropertyFlags mem_preferences)
{
assert(size > 0);
assert(buf_create_info.size > 0);
assert(buf);
VkResult result = VK_SUCCESS;
int memory_index;
buf->size = size;
buf->size = buf_create_info.size;
buf->is_mapped = 0;
result = vkCreateBuffer(vk_device.logical, &buf_create_info, NULL, &buf->buffer);