Add support for allocating and freeing slots in the bindless texture set

This commit is contained in:
Magnus Norddahl 2025-07-18 16:37:02 +02:00
commit 6abe93a020
3 changed files with 111 additions and 38 deletions

View file

@ -169,25 +169,23 @@ void VkDescriptorSetManager::ResetHWTextureSets()
mat->DeleteDescriptors();
for (FSWColormap* colormap : Colormaps)
colormap->Renderdev.bindIndex = -1;
{
if (colormap->Renderdev.bindIndex != -1)
{
FreeBindlessSlot(colormap->Renderdev.bindIndex);
colormap->Renderdev.bindIndex = -1;
}
}
Colormaps.clear();
for (int index : LightProbes)
FreeBindlessSlot(index);
LightProbes.clear();
Bindless.Writer = WriteDescriptors();
Bindless.NextIndex = 0;
// Slot zero always needs to be the null texture
AddBindlessTextureIndex(fb->GetTextureManager()->GetNullTextureView(), fb->GetSamplerManager()->Get(CLAMP_XY_NOMIP));
// And slot 1 is always our BRDF LUT texture
AddBindlessTextureIndex(fb->GetTextureManager()->GetBrdfLutTextureView(), fb->GetSamplerManager()->Get(CLAMP_XY_NOMIP));
// Slot 2 is always our game palette texture
AddBindlessTextureIndex(fb->GetTextureManager()->GetGamePaletteView(), fb->GetSamplerManager()->Get(CLAMP_XY_NOMIP));
// Lightmap textures follow
Bindless.NextIndex = LightmapsStart + MaxLightmaps;
// Fixed indexes the shaders can always access
SetBindlessTexture(0, fb->GetTextureManager()->GetNullTextureView(), fb->GetSamplerManager()->Get(CLAMP_XY_NOMIP));
SetBindlessTexture(1, fb->GetTextureManager()->GetBrdfLutTextureView(), fb->GetSamplerManager()->Get(CLAMP_XY_NOMIP));
SetBindlessTexture(2, fb->GetTextureManager()->GetGamePaletteView(), fb->GetSamplerManager()->Get(CLAMP_XY_NOMIP));
}
void VkDescriptorSetManager::AddMaterial(VkMaterial* texture)
@ -406,7 +404,7 @@ void VkDescriptorSetManager::CreateBindlessSet()
void VkDescriptorSetManager::UpdateBindlessDescriptorSet()
{
auto sampler = fb->GetSamplerManager()->LightmapSampler.get();
int index = LightmapsStart;
int index = FixedBindlessSlots;
for (auto& lightmap : fb->GetTextureManager()->Lightmaps)
{
Bindless.Writer.AddCombinedImageSampler(Bindless.Set.get(), 0, index, lightmap.View.get(), sampler, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
@ -417,11 +415,47 @@ void VkDescriptorSetManager::UpdateBindlessDescriptorSet()
Bindless.Writer = WriteDescriptors();
}
int VkDescriptorSetManager::AddBindlessTextureIndex(VulkanImageView* imageview, VulkanSampler* sampler)
int VkDescriptorSetManager::AllocBindlessSlot(int count)
{
if (count <= 0)
return 0;
int bucket = count - 1;
if (Bindless.FreeSlots.size() <= (size_t)bucket)
Bindless.FreeSlots.resize(bucket + 1);
if (!Bindless.FreeSlots[bucket].empty())
{
int index = Bindless.FreeSlots[bucket].back();
Bindless.FreeSlots[bucket].pop_back();
return index;
}
else
{
if (Bindless.NextIndex + count > MaxBindlessTextures)
I_FatalError("Out of bindless texture slots!");
int index = Bindless.NextIndex;
if (Bindless.AllocSizes.size() < index + count)
Bindless.AllocSizes.resize(index + count, 0);
Bindless.AllocSizes[index] = count;
Bindless.NextIndex += count;
return index;
}
}
void VkDescriptorSetManager::FreeBindlessSlot(int index)
{
if (index <= 0)
return;
int bucket = Bindless.AllocSizes[index] - 1;
Bindless.FreeSlots[bucket].push_back(index);
}
void VkDescriptorSetManager::SetBindlessTexture(int index, VulkanImageView* imageview, VulkanSampler* sampler)
{
int index = Bindless.NextIndex++;
Bindless.Writer.AddCombinedImageSampler(Bindless.Set.get(), 0, index, imageview, sampler, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
return index;
}
int VkDescriptorSetManager::GetSWColormapTextureIndex(FSWColormap* colormap)
@ -429,7 +463,8 @@ int VkDescriptorSetManager::GetSWColormapTextureIndex(FSWColormap* colormap)
if (colormap->Renderdev.bindIndex != -1)
return colormap->Renderdev.bindIndex;
colormap->Renderdev.bindIndex = AddBindlessTextureIndex(fb->GetTextureManager()->GetSWColormapView(colormap), fb->GetSamplerManager()->Get(CLAMP_XY_NOMIP));
colormap->Renderdev.bindIndex = AllocBindlessSlot(1);
SetBindlessTexture(colormap->Renderdev.bindIndex, fb->GetTextureManager()->GetSWColormapView(colormap), fb->GetSamplerManager()->Get(CLAMP_XY_NOMIP));
Colormaps.push_back(colormap);
return colormap->Renderdev.bindIndex;
}
@ -447,8 +482,10 @@ int VkDescriptorSetManager::GetLightProbeTextureIndex(int probeIndex)
if (textures->Irradiancemaps.size() > (size_t)probeIndex && textures->Irradiancemaps[probeIndex].View &&
textures->Prefiltermaps.size() > (size_t)probeIndex && textures->Prefiltermaps[probeIndex].View)
{
LightProbes[probeIndex] = AddBindlessTextureIndex(textures->Irradiancemaps[probeIndex].View.get(), fb->GetSamplerManager()->IrradiancemapSampler.get());
AddBindlessTextureIndex(textures->Prefiltermaps[probeIndex].View.get(), fb->GetSamplerManager()->PrefiltermapSampler.get());
int bindIndex = AllocBindlessSlot(2);
LightProbes[probeIndex] = bindIndex;
SetBindlessTexture(bindIndex, textures->Irradiancemaps[probeIndex].View.get(), fb->GetSamplerManager()->IrradiancemapSampler.get());
SetBindlessTexture(bindIndex + 1, textures->Prefiltermaps[probeIndex].View.get(), fb->GetSamplerManager()->PrefiltermapSampler.get());
}
else
{

View file

@ -43,11 +43,14 @@ public:
void RemoveMaterial(VkMaterial* texture);
void UpdateBindlessDescriptorSet();
int AddBindlessTextureIndex(VulkanImageView* imageview, VulkanSampler* sampler);
void SetBindlessTexture(int index, VulkanImageView* imageview, VulkanSampler* sampler);
int GetSWColormapTextureIndex(FSWColormap* colormap);
int GetLightProbeTextureIndex(int probeIndex);
int AllocBindlessSlot(int count);
void FreeBindlessSlot(int index);
private:
void CreateLevelMeshLayout();
void CreateRSBufferLayout();
@ -69,6 +72,11 @@ private:
VulkanRenderDevice* fb = nullptr;
static const int MaxFixedSets = 100;
static const int MaxBindlessTextures = 16536;
static const int FixedBindlessSlots = 3;
static const int MaxLightmaps = 128;
struct
{
std::unique_ptr<VulkanDescriptorSetLayout> Layout;
@ -96,7 +104,9 @@ private:
std::unique_ptr<VulkanDescriptorSet> Set;
std::unique_ptr<VulkanDescriptorSetLayout> Layout;
WriteDescriptors Writer;
int NextIndex = 0;
int NextIndex = FixedBindlessSlots + MaxLightmaps;
std::vector<int> AllocSizes;
std::vector<std::vector<int>> FreeSlots;
} Bindless;
struct
@ -128,9 +138,4 @@ private:
std::list<VkMaterial*> Materials;
std::vector<FSWColormap*> Colormaps;
std::vector<int> LightProbes;
static const int MaxFixedSets = 100;
static const int MaxBindlessTextures = 16536;
static const int LightmapsStart = 3;
static const int MaxLightmaps = 128;
};

View file

@ -399,6 +399,11 @@ VkMaterial::~VkMaterial()
void VkMaterial::DeleteDescriptors()
{
auto descriptors = fb->GetDescriptorSetManager();
for (auto& set : mDescriptorSets)
{
descriptors->FreeBindlessSlot(set.bindlessIndex);
}
mDescriptorSets.clear();
}
@ -432,15 +437,38 @@ VkMaterial::DescriptorEntry& VkMaterial::GetDescriptorEntry(const FMaterialState
if (set.clampmode == clampmode && set.remap == translationp && set.globalShaderAddr == globalShaderAddr && set.indexed == state.mPaletteMode) return set;
}
auto globalshader = GetGlobalShader(globalShaderAddr);
int numLayersMat = *globalshader ? NumNonMaterialLayers() : NumLayers();
const GlobalShaderDesc& globalshader = *GetGlobalShader(globalShaderAddr);
int numLayersMat = globalshader ? NumNonMaterialLayers() : NumLayers();
auto descriptors = fb->GetDescriptorSetManager();
auto* sampler = fb->GetSamplerManager()->Get(clampmode);
MaterialLayerInfo *layer;
MaterialLayerInfo *layer = nullptr;
auto systex = static_cast<VkHardwareTexture*>(GetLayer(0, state.mTranslation, &layer));
// How many textures do we need?
int textureCount;
if (!(layer->scaleFlags & CTF_Indexed))
{
textureCount = numLayersMat;
if (globalshader)
{
for (auto& texture : globalshader.CustomShaderTextures)
{
if (texture != nullptr)
textureCount++;
}
}
}
else
{
textureCount = 3;
}
int bindlessIndex = descriptors->AllocBindlessSlot(textureCount);
int texIndex = bindlessIndex;
auto systeximage = systex->GetImage(layer->layerTexture, state.mTranslation, layer->scaleFlags | paletteFlags);
int bindlessIndex = descriptors->AddBindlessTextureIndex(systeximage->View.get(), fb->GetSamplerManager()->Get(GetLayerFilter(0), clampmode));
descriptors->SetBindlessTexture(texIndex++, systeximage->View.get(), fb->GetSamplerManager()->Get(GetLayerFilter(0), clampmode));
if (!(layer->scaleFlags & CTF_Indexed))
{
@ -448,19 +476,19 @@ VkMaterial::DescriptorEntry& VkMaterial::GetDescriptorEntry(const FMaterialState
{
auto syslayer = static_cast<VkHardwareTexture*>(GetLayer(i, 0, &layer));
auto syslayerimage = syslayer->GetImage(layer->layerTexture, 0, layer->scaleFlags | paletteFlags);
descriptors->AddBindlessTextureIndex(syslayerimage->View.get(), fb->GetSamplerManager()->Get(GetLayerFilter(i), clampmode));
descriptors->SetBindlessTexture(texIndex++, syslayerimage->View.get(), fb->GetSamplerManager()->Get(GetLayerFilter(i), clampmode));
}
if(*globalshader)
if(globalshader)
{
size_t i = 0;
for (auto& texture : globalshader->CustomShaderTextures)
for (auto& texture : globalshader.CustomShaderTextures)
{
if (texture != nullptr)
{
VkHardwareTexture *tex = static_cast<VkHardwareTexture*>(texture.get()->GetHardwareTexture(0, 0));
VkTextureImage *img = tex->GetImage(texture.get(), 0, paletteFlags);
descriptors->AddBindlessTextureIndex(img->View.get(), fb->GetSamplerManager()->Get(globalshader->CustomShaderTextureSampling[i], clampmode));
descriptors->SetBindlessTexture(texIndex++, img->View.get(), fb->GetSamplerManager()->Get(globalshader.CustomShaderTextureSampling[i], clampmode));
}
i++;
}
@ -472,10 +500,13 @@ VkMaterial::DescriptorEntry& VkMaterial::GetDescriptorEntry(const FMaterialState
{
auto syslayer = static_cast<VkHardwareTexture*>(GetLayer(i, translation, &layer));
auto syslayerimage = syslayer->GetImage(layer->layerTexture, 0, layer->scaleFlags | paletteFlags);
descriptors->AddBindlessTextureIndex(syslayerimage->View.get(), fb->GetSamplerManager()->Get(GetLayerFilter(i), clampmode));
descriptors->SetBindlessTexture(texIndex++, syslayerimage->View.get(), fb->GetSamplerManager()->Get(GetLayerFilter(i), clampmode));
}
}
if (texIndex != bindlessIndex + textureCount)
I_FatalError("VkMaterial.GetDescriptorEntry: texIndex != bindlessIndex + textureCount");
mDescriptorSets.emplace_back(clampmode, translationp, bindlessIndex, globalShaderAddr, state.mPaletteMode);
return mDescriptorSets.back();
}