diff --git a/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.cpp b/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.cpp index d2fdef02a..e5426499f 100644 --- a/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.cpp +++ b/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.cpp @@ -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 { diff --git a/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.h b/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.h index 76a7ea912..62197163d 100644 --- a/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.h +++ b/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.h @@ -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 Layout; @@ -96,7 +104,9 @@ private: std::unique_ptr Set; std::unique_ptr Layout; WriteDescriptors Writer; - int NextIndex = 0; + int NextIndex = FixedBindlessSlots + MaxLightmaps; + std::vector AllocSizes; + std::vector> FreeSlots; } Bindless; struct @@ -128,9 +138,4 @@ private: std::list Materials; std::vector Colormaps; std::vector LightProbes; - - static const int MaxFixedSets = 100; - static const int MaxBindlessTextures = 16536; - static const int LightmapsStart = 3; - static const int MaxLightmaps = 128; }; diff --git a/src/common/rendering/vulkan/textures/vk_hwtexture.cpp b/src/common/rendering/vulkan/textures/vk_hwtexture.cpp index 0c4082d6d..978667046 100644 --- a/src/common/rendering/vulkan/textures/vk_hwtexture.cpp +++ b/src/common/rendering/vulkan/textures/vk_hwtexture.cpp @@ -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(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(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(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(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(); }