vk: fix texture corruption after a few changelevels
We were running out of descriptor sets, as they weren't being freed at all. Now there's a 1-1 table of texture-descset, and no way to run out of them. Better solution would be to move this descset management to vk_render, and allocate them dynamically from a smaller pool.
This commit is contained in:
parent
e1d478fa28
commit
fd97dc2c24
|
@ -2,7 +2,7 @@
|
|||
|
||||
#include "eiface.h" // ARRAYSIZE
|
||||
|
||||
descriptor_pool_t vk_desc;
|
||||
descriptor_pool_t vk_desc_fixme;
|
||||
|
||||
qboolean VK_DescriptorInit( void )
|
||||
{
|
||||
|
@ -14,7 +14,7 @@ qboolean VK_DescriptorInit( void )
|
|||
.descriptorCount = MAX_TEXTURES,
|
||||
}, {
|
||||
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
|
||||
.descriptorCount = ARRAYSIZE(vk_desc.ubo_sets),
|
||||
.descriptorCount = ARRAYSIZE(vk_desc_fixme.ubo_sets),
|
||||
/*
|
||||
}, {
|
||||
.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
|
@ -33,7 +33,7 @@ qboolean VK_DescriptorInit( void )
|
|||
|
||||
dpci.maxSets = max_desc_sets;
|
||||
|
||||
XVK_CHECK(vkCreateDescriptorPool(vk_core.device, &dpci, NULL, &vk_desc.pool));
|
||||
XVK_CHECK(vkCreateDescriptorPool(vk_core.device, &dpci, NULL, &vk_desc_fixme.pool));
|
||||
|
||||
{
|
||||
const int num_sets = MAX_TEXTURES;
|
||||
|
@ -53,21 +53,21 @@ qboolean VK_DescriptorInit( void )
|
|||
VkDescriptorSetLayout* tmp_layouts = Mem_Malloc(vk_core.pool, sizeof(VkDescriptorSetLayout) * num_sets);
|
||||
const VkDescriptorSetAllocateInfo dsai = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
||||
.descriptorPool = vk_desc.pool,
|
||||
.descriptorPool = vk_desc_fixme.pool,
|
||||
.descriptorSetCount = num_sets,
|
||||
.pSetLayouts = tmp_layouts,
|
||||
};
|
||||
XVK_CHECK(vkCreateDescriptorSetLayout(vk_core.device, &dslci, NULL, &vk_desc.one_texture_layout));
|
||||
XVK_CHECK(vkCreateDescriptorSetLayout(vk_core.device, &dslci, NULL, &vk_desc_fixme.one_texture_layout));
|
||||
for (int i = 0; i < num_sets; ++i)
|
||||
tmp_layouts[i] = vk_desc.one_texture_layout;
|
||||
tmp_layouts[i] = vk_desc_fixme.one_texture_layout;
|
||||
|
||||
XVK_CHECK(vkAllocateDescriptorSets(vk_core.device, &dsai, vk_desc.sets));
|
||||
XVK_CHECK(vkAllocateDescriptorSets(vk_core.device, &dsai, vk_desc_fixme.texture_sets));
|
||||
|
||||
Mem_Free(tmp_layouts);
|
||||
}
|
||||
|
||||
{
|
||||
const int num_sets = ARRAYSIZE(vk_desc.ubo_sets);
|
||||
const int num_sets = ARRAYSIZE(vk_desc_fixme.ubo_sets);
|
||||
// ... TODO find better place for this; this should be per-pipeline/shader
|
||||
VkDescriptorSetLayoutBinding bindings[] = { {
|
||||
.binding = 0,
|
||||
|
@ -84,15 +84,15 @@ qboolean VK_DescriptorInit( void )
|
|||
VkDescriptorSetLayout* tmp_layouts = Mem_Malloc(vk_core.pool, sizeof(VkDescriptorSetLayout) * num_sets);
|
||||
VkDescriptorSetAllocateInfo dsai = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
||||
.descriptorPool = vk_desc.pool,
|
||||
.descriptorPool = vk_desc_fixme.pool,
|
||||
.descriptorSetCount = num_sets,
|
||||
.pSetLayouts = tmp_layouts,
|
||||
};
|
||||
XVK_CHECK(vkCreateDescriptorSetLayout(vk_core.device, &dslci, NULL, &vk_desc.one_uniform_buffer_layout));
|
||||
XVK_CHECK(vkCreateDescriptorSetLayout(vk_core.device, &dslci, NULL, &vk_desc_fixme.one_uniform_buffer_layout));
|
||||
for (int i = 0; i < num_sets; ++i)
|
||||
tmp_layouts[i] = vk_desc.one_uniform_buffer_layout;
|
||||
tmp_layouts[i] = vk_desc_fixme.one_uniform_buffer_layout;
|
||||
|
||||
XVK_CHECK(vkAllocateDescriptorSets(vk_core.device, &dsai, vk_desc.ubo_sets));
|
||||
XVK_CHECK(vkAllocateDescriptorSets(vk_core.device, &dsai, vk_desc_fixme.ubo_sets));
|
||||
|
||||
Mem_Free(tmp_layouts);
|
||||
}
|
||||
|
@ -102,9 +102,9 @@ qboolean VK_DescriptorInit( void )
|
|||
|
||||
void VK_DescriptorShutdown( void )
|
||||
{
|
||||
vkDestroyDescriptorPool(vk_core.device, vk_desc.pool, NULL);
|
||||
vkDestroyDescriptorSetLayout(vk_core.device, vk_desc.one_texture_layout, NULL);
|
||||
vkDestroyDescriptorSetLayout(vk_core.device, vk_desc.one_uniform_buffer_layout, NULL);
|
||||
vkDestroyDescriptorPool(vk_core.device, vk_desc_fixme.pool, NULL);
|
||||
vkDestroyDescriptorSetLayout(vk_core.device, vk_desc_fixme.one_texture_layout, NULL);
|
||||
vkDestroyDescriptorSetLayout(vk_core.device, vk_desc_fixme.one_uniform_buffer_layout, NULL);
|
||||
}
|
||||
|
||||
void VK_DescriptorsCreate(vk_descriptors_t *desc)
|
||||
|
|
|
@ -4,16 +4,12 @@
|
|||
|
||||
#include "vk_const.h"
|
||||
|
||||
// Only used for traditional renderer
|
||||
typedef struct descriptor_pool_s
|
||||
{
|
||||
VkDescriptorPool pool;
|
||||
|
||||
// TODO don't expose this, make a function to alloc desc set with given layout instead
|
||||
int next_free;
|
||||
//uint32_t *free_set;
|
||||
|
||||
// * 2 because of unorm views for trad renderer
|
||||
VkDescriptorSet sets[MAX_TEXTURES * 2];
|
||||
VkDescriptorSet texture_sets[MAX_TEXTURES];
|
||||
VkDescriptorSetLayout one_texture_layout;
|
||||
|
||||
// FIXME HOW THE F
|
||||
|
@ -21,7 +17,8 @@ typedef struct descriptor_pool_s
|
|||
VkDescriptorSetLayout one_uniform_buffer_layout;
|
||||
} descriptor_pool_t;
|
||||
|
||||
extern descriptor_pool_t vk_desc;
|
||||
// FIXME: move to traditional renderer
|
||||
extern descriptor_pool_t vk_desc_fixme;
|
||||
|
||||
qboolean VK_DescriptorInit( void );
|
||||
void VK_DescriptorShutdown( void );
|
||||
|
|
|
@ -145,7 +145,7 @@ static qboolean createPipelines( void )
|
|||
/* }; */
|
||||
|
||||
VkDescriptorSetLayout descriptor_layouts[] = {
|
||||
vk_desc.one_texture_layout,
|
||||
vk_desc_fixme.one_texture_layout,
|
||||
};
|
||||
|
||||
VkPipelineLayoutCreateInfo plci = {
|
||||
|
|
|
@ -62,10 +62,10 @@ static qboolean createPipelines( void )
|
|||
/* }; */
|
||||
|
||||
VkDescriptorSetLayout descriptor_layouts[] = {
|
||||
vk_desc.one_uniform_buffer_layout,
|
||||
vk_desc.one_texture_layout,
|
||||
vk_desc.one_texture_layout,
|
||||
vk_desc.one_uniform_buffer_layout,
|
||||
vk_desc_fixme.one_uniform_buffer_layout,
|
||||
vk_desc_fixme.one_texture_layout,
|
||||
vk_desc_fixme.one_texture_layout,
|
||||
vk_desc_fixme.one_uniform_buffer_layout,
|
||||
};
|
||||
|
||||
VkPipelineLayoutCreateInfo plci = {
|
||||
|
@ -321,7 +321,7 @@ qboolean VK_RenderInit( void ) {
|
|||
.descriptorCount = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
|
||||
.pBufferInfo = &dbi_uniform_data,
|
||||
.dstSet = vk_desc.ubo_sets[0], // FIXME
|
||||
.dstSet = vk_desc_fixme.ubo_sets[0], // FIXME
|
||||
}, {
|
||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||
.dstBinding = 0,
|
||||
|
@ -329,7 +329,7 @@ qboolean VK_RenderInit( void ) {
|
|||
.descriptorCount = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
|
||||
.pBufferInfo = &dbi_uniform_lights,
|
||||
.dstSet = vk_desc.ubo_sets[1], // FIXME
|
||||
.dstSet = vk_desc_fixme.ubo_sets[1], // FIXME
|
||||
}};
|
||||
vkUpdateDescriptorSets(vk_core.device, ARRAYSIZE(wds), wds, 0, NULL);
|
||||
}
|
||||
|
@ -552,7 +552,7 @@ void VK_RenderEnd( VkCommandBuffer cmdbuf, qboolean draw )
|
|||
vkCmdBindIndexBuffer(cmdbuf, geom_buffer, 0, VK_INDEX_TYPE_UINT16);
|
||||
}
|
||||
|
||||
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, g_render.pipeline_layout, 3, 1, vk_desc.ubo_sets + 1, 1, &dlights_ubo_offset);
|
||||
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, g_render.pipeline_layout, 3, 1, vk_desc_fixme.ubo_sets + 1, 1, &dlights_ubo_offset);
|
||||
|
||||
for (int i = 0; i < g_render_state.num_draw_commands; ++i) {
|
||||
const draw_command_t *const draw = g_render_state.draw_commands + i;
|
||||
|
@ -579,7 +579,7 @@ void VK_RenderEnd( VkCommandBuffer cmdbuf, qboolean draw )
|
|||
if (ubo_offset != draw->draw.ubo_offset)
|
||||
{
|
||||
ubo_offset = draw->draw.ubo_offset;
|
||||
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, g_render.pipeline_layout, 0, 1, vk_desc.ubo_sets, 1, &ubo_offset);
|
||||
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, g_render.pipeline_layout, 0, 1, vk_desc_fixme.ubo_sets, 1, &ubo_offset);
|
||||
}
|
||||
|
||||
if (pipeline != draw->draw.pipeline_index) {
|
||||
|
|
|
@ -697,59 +697,52 @@ static VkSampler pickSamplerForFlags( texFlags_t flags ) {
|
|||
return tglob.default_sampler_fixme;
|
||||
}
|
||||
|
||||
static void prepDestriptorSets(vk_texture_t* const tex, colorspace_hint_e colorspace_hint) {
|
||||
static void setDescriptorSet(vk_texture_t* const tex, colorspace_hint_e colorspace_hint) {
|
||||
// FIXME detect skybox some other way
|
||||
if (tex->vk.image.layers > 1)
|
||||
return;
|
||||
|
||||
const int index = tex - vk_textures;
|
||||
ASSERT(index >= 0);
|
||||
ASSERT(index < MAX_TEXTURES);
|
||||
|
||||
const VkImageView view = tex->vk.image.view != VK_NULL_HANDLE ? tex->vk.image.view : vk_textures[tglob.defaultTexture].vk.image.view;
|
||||
|
||||
if (view == VK_NULL_HANDLE)
|
||||
return;
|
||||
|
||||
VkDescriptorImageInfo dii = {
|
||||
.imageView = view,
|
||||
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
.sampler = pickSamplerForFlags( tex->flags ),
|
||||
};
|
||||
|
||||
// Set descriptor for bindless/ray tracing
|
||||
tglob.dii_all_textures[index] = dii;
|
||||
|
||||
// Continue with setting unorm descriptor for traditional renderer
|
||||
|
||||
// TODO how should we approach this:
|
||||
// - per-texture desc sets can be inconvenient if texture is used in different incompatible contexts
|
||||
// - update descriptor sets in batch?
|
||||
if (vk_desc.next_free < MAX_TEXTURES-2) {
|
||||
const int index = tex - vk_textures;
|
||||
const VkDescriptorSet ds = vk_desc.sets[vk_desc.next_free++];
|
||||
const VkDescriptorSet ds_unorm =
|
||||
(colorspace_hint == kColorspaceGamma && tex->vk.image.view_unorm != VK_NULL_HANDLE)
|
||||
? vk_desc.sets[vk_desc.next_free++] : VK_NULL_HANDLE;
|
||||
|
||||
const VkDescriptorImageInfo dii = {
|
||||
.imageView = tex->vk.image.view,
|
||||
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
.sampler = pickSamplerForFlags( tex->flags ),
|
||||
};
|
||||
if (colorspace_hint == kColorspaceGamma && tex->vk.image.view_unorm != VK_NULL_HANDLE)
|
||||
dii.imageView = tex->vk.image.view_unorm;
|
||||
|
||||
const VkDescriptorImageInfo dii_unorm = {
|
||||
.imageView = tex->vk.image.view_unorm,
|
||||
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
.sampler = dii.sampler,
|
||||
};
|
||||
const VkDescriptorSet ds = vk_desc_fixme.texture_sets[index];
|
||||
VkWriteDescriptorSet wds[1] = { {
|
||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||
.dstBinding = 0,
|
||||
.dstArrayElement = 0,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.pImageInfo = &dii,
|
||||
.dstSet = ds,
|
||||
}};
|
||||
|
||||
VkWriteDescriptorSet wds[2] = { {
|
||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||
.dstBinding = 0,
|
||||
.dstArrayElement = 0,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.pImageInfo = &dii,
|
||||
.dstSet = ds,
|
||||
}, {
|
||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||
.dstBinding = 0,
|
||||
.dstArrayElement = 0,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.pImageInfo = &dii_unorm,
|
||||
.dstSet = ds_unorm,
|
||||
}};
|
||||
vkUpdateDescriptorSets(vk_core.device, ds_unorm != VK_NULL_HANDLE ? 2 : 1 , wds, 0, NULL);
|
||||
vkUpdateDescriptorSets(vk_core.device, COUNTOF(wds), wds, 0, NULL);
|
||||
|
||||
// FIXME detect skybox some other way
|
||||
if (tex->vk.image.layers == 1) {
|
||||
tglob.dii_all_textures[index] = dii;
|
||||
}
|
||||
|
||||
tex->vk.descriptor_unorm = ds_unorm != VK_NULL_HANDLE ? ds_unorm : ds;
|
||||
}
|
||||
else
|
||||
{
|
||||
tex->vk.descriptor_unorm = VK_NULL_HANDLE;
|
||||
}
|
||||
tex->vk.descriptor_unorm = ds;
|
||||
}
|
||||
|
||||
static qboolean uploadRawKtx2( vk_texture_t *tex, const rgbdata_t* pic ) {
|
||||
|
@ -835,34 +828,17 @@ static qboolean uploadRawKtx2( vk_texture_t *tex, const rgbdata_t* pic ) {
|
|||
R_VkImageUploadEnd(&tex->vk.image);
|
||||
}
|
||||
|
||||
// KTX2 textures are inaccessible from trad renderer (for now)
|
||||
tex->vk.descriptor_unorm = VK_NULL_HANDLE;
|
||||
{
|
||||
// KTX2 textures are inaccessible from trad renderer (for now)
|
||||
tex->vk.descriptor_unorm = VK_NULL_HANDLE;
|
||||
|
||||
// TODO how should we approach this:
|
||||
// - per-texture desc sets can be inconvenient if texture is used in different incompatible contexts
|
||||
// - update descriptor sets in batch?
|
||||
|
||||
if (vk_desc.next_free != MAX_TEXTURES) {
|
||||
const int num_layers = 1; // TODO cubemap
|
||||
const int index = tex - vk_textures;
|
||||
VkDescriptorImageInfo dii_tmp;
|
||||
// FIXME handle cubemaps properly w/o this garbage. they should be the same as regular textures.
|
||||
VkDescriptorImageInfo *const dii_tex = (num_layers == 1) ? tglob.dii_all_textures + index : &dii_tmp;
|
||||
*dii_tex = (VkDescriptorImageInfo){
|
||||
const VkDescriptorImageInfo dii = {
|
||||
.imageView = tex->vk.image.view,
|
||||
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
.sampler = pickSamplerForFlags( tex->flags ),
|
||||
};
|
||||
const VkWriteDescriptorSet wds[] = { {
|
||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||
.dstBinding = 0,
|
||||
.dstArrayElement = 0,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.pImageInfo = dii_tex,
|
||||
.dstSet = vk_desc.sets[vk_desc.next_free++],
|
||||
}};
|
||||
vkUpdateDescriptorSets(vk_core.device, ARRAYSIZE(wds), wds, 0, NULL);
|
||||
tglob.dii_all_textures[index] = dii;
|
||||
}
|
||||
|
||||
g_textures.stats.size_total += tex->total_size;
|
||||
|
@ -989,7 +965,7 @@ static qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *const *const layers,
|
|||
}
|
||||
}
|
||||
|
||||
prepDestriptorSets(tex, colorspace_hint);
|
||||
setDescriptorSet(tex, colorspace_hint);
|
||||
|
||||
g_textures.stats.size_total += tex->total_size;
|
||||
g_textures.stats.count++;
|
||||
|
@ -1143,11 +1119,8 @@ void R_FreeTexture( unsigned int texnum ) {
|
|||
g_textures.stats.count--;
|
||||
memset(tex, 0, sizeof(*tex));
|
||||
|
||||
tglob.dii_all_textures[texnum] = (VkDescriptorImageInfo){
|
||||
.imageView = vk_textures[tglob.defaultTexture].vk.image.view,
|
||||
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
.sampler = tglob.default_sampler_fixme,
|
||||
};
|
||||
// Reset descriptor sets to default texture
|
||||
setDescriptorSet(tex, kColorspaceNative);
|
||||
|
||||
end:
|
||||
APROF_SCOPE_END(free);
|
||||
|
|
Loading…
Reference in New Issue