diff --git a/libraries/ZVulkan/src/vulkanbuilders.cpp b/libraries/ZVulkan/src/vulkanbuilders.cpp index 013c34c22..e6777075c 100644 --- a/libraries/ZVulkan/src/vulkanbuilders.cpp +++ b/libraries/ZVulkan/src/vulkanbuilders.cpp @@ -1853,6 +1853,7 @@ std::vector VulkanDeviceBuilder::FindDevices(const std:: enabledFeatures.DescriptorIndexing.descriptorBindingPartiallyBound = deviceFeatures.DescriptorIndexing.descriptorBindingPartiallyBound; enabledFeatures.DescriptorIndexing.descriptorBindingSampledImageUpdateAfterBind = deviceFeatures.DescriptorIndexing.descriptorBindingSampledImageUpdateAfterBind; enabledFeatures.DescriptorIndexing.descriptorBindingVariableDescriptorCount = deviceFeatures.DescriptorIndexing.descriptorBindingVariableDescriptorCount; + enabledFeatures.DescriptorIndexing.shaderSampledImageArrayNonUniformIndexing = deviceFeatures.DescriptorIndexing.shaderSampledImageArrayNonUniformIndexing; // Figure out which queue can present if (surface) diff --git a/src/common/rendering/v_video.h b/src/common/rendering/v_video.h index c6eafc1f6..44f676c10 100644 --- a/src/common/rendering/v_video.h +++ b/src/common/rendering/v_video.h @@ -249,6 +249,9 @@ public: virtual void RenderTextureView(FCanvasTexture* tex, std::function renderFunc) {} virtual void SetActiveRenderTarget() {} + // Get the array index for the material in the textures array accessible from shaders + virtual int GetBindlessTextureIndex(FMaterial* material, int clampmode, int translation) { return -1; } + // Screen wiping virtual FTexture *WipeStartScreen(); virtual FTexture *WipeEndScreen(); diff --git a/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp b/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp index 311196608..130f8709d 100644 --- a/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp +++ b/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp @@ -3,6 +3,7 @@ #include "vulkan/vk_renderdevice.h" #include "vulkan/textures/vk_texture.h" #include "vulkan/commands/vk_commandbuffer.h" +#include "vulkan/descriptorsets/vk_descriptorset.h" #include "vk_raytrace.h" #include "zvulkan/vulkanbuilders.h" #include "halffloat.h" @@ -140,6 +141,7 @@ void VkLightmap::RenderBakeImage() cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, raytrace.pipeline.get()); cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, raytrace.pipelineLayout.get(), 0, raytrace.descriptorSet0.get()); cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, raytrace.pipelineLayout.get(), 1, raytrace.descriptorSet1.get()); + cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, raytrace.pipelineLayout.get(), 2, fb->GetDescriptorSetManager()->GetBindlessDescriptorSet()); VkViewport viewport = {}; viewport.maxDepth = 1; @@ -498,6 +500,7 @@ void VkLightmap::CreateRaytracePipeline() raytrace.pipelineLayout = PipelineLayoutBuilder() .AddSetLayout(raytrace.descriptorSetLayout0.get()) .AddSetLayout(raytrace.descriptorSetLayout1.get()) + .AddSetLayout(fb->GetDescriptorSetManager()->GetBindlessSetLayout()) .AddPushConstantRange(VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(LightmapPushConstants)) .DebugName("raytrace.pipelineLayout") .Create(fb->GetDevice()); diff --git a/src/common/rendering/vulkan/commands/vk_commandbuffer.cpp b/src/common/rendering/vulkan/commands/vk_commandbuffer.cpp index 5fc527570..8dcf12ca4 100644 --- a/src/common/rendering/vulkan/commands/vk_commandbuffer.cpp +++ b/src/common/rendering/vulkan/commands/vk_commandbuffer.cpp @@ -25,6 +25,7 @@ #include "vulkan/vk_renderstate.h" #include "vulkan/vk_postprocess.h" #include "vulkan/framebuffers/vk_framebuffer.h" +#include "vulkan/descriptorsets/vk_descriptorset.h" #include #include #include "hw_clock.h" @@ -150,6 +151,8 @@ void VkCommandBufferManager::FlushCommands(VulkanCommandBuffer** commands, size_ void VkCommandBufferManager::FlushCommands(bool finish, bool lastsubmit, bool uploadOnly) { + fb->GetDescriptorSetManager()->UpdateBindlessDescriptorSet(); + if (!uploadOnly) fb->GetRenderState(0)->EndRenderPass(); diff --git a/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.cpp b/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.cpp index f38559075..1c99c3c3b 100644 --- a/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.cpp +++ b/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.cpp @@ -44,6 +44,7 @@ VkDescriptorSetManager::VkDescriptorSetManager(VulkanRenderDevice* fb) : fb(fb) CreateFixedSetLayout(); CreateRSBufferPool(); CreateFixedSetPool(); + CreateBindlessDescriptorSet(); } VkDescriptorSetManager::~VkDescriptorSetManager() @@ -126,6 +127,9 @@ void VkDescriptorSetManager::ResetHWTextureSets() TextureDescriptorPools.clear(); TextureDescriptorSetsLeft = 0; TextureDescriptorsLeft = 0; + + WriteBindless = WriteDescriptors(); + NextBindlessIndex = 0; } VulkanDescriptorSet* VkDescriptorSetManager::GetNullTextureDescriptorSet() @@ -306,3 +310,38 @@ void VkDescriptorSetManager::CreateFixedSetPool() poolbuilder.DebugName("VkDescriptorSetManager.FixedDescriptorPool"); FixedDescriptorPool = poolbuilder.Create(fb->GetDevice()); } + +void VkDescriptorSetManager::CreateBindlessDescriptorSet() +{ + BindlessDescriptorPool = DescriptorPoolBuilder() + .Flags(VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT) + .AddPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, MaxBindlessTextures) + .MaxSets(MaxBindlessTextures) + .DebugName("BindlessDescriptorPool") + .Create(fb->GetDevice()); + + BindlessDescriptorSetLayout = DescriptorSetLayoutBuilder() + .Flags(VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT) + .AddBinding( + 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + MaxBindlessTextures, + VK_SHADER_STAGE_FRAGMENT_BIT, + VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT | VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT | VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT) + .DebugName("BindlessDescriptorSetLayout") + .Create(fb->GetDevice()); + + BindlessDescriptorSet = BindlessDescriptorPool->allocate(BindlessDescriptorSetLayout.get(), MaxBindlessTextures); +} + +void VkDescriptorSetManager::UpdateBindlessDescriptorSet() +{ + WriteBindless.Execute(fb->GetDevice()); + WriteBindless = WriteDescriptors(); +} + +int VkDescriptorSetManager::AddBindlessTextureIndex(VulkanImageView* imageview, VulkanSampler* sampler) +{ + int index = NextBindlessIndex++; + WriteBindless.AddCombinedImageSampler(BindlessDescriptorSet.get(), 0, index, imageview, sampler, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + return index; +} diff --git a/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.h b/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.h index 04babd639..0265d566a 100644 --- a/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.h +++ b/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.h @@ -2,6 +2,7 @@ #pragma once #include "zvulkan/vulkanobjects.h" +#include "zvulkan/vulkanbuilders.h" #include #include "tarray.h" @@ -24,10 +25,12 @@ public: VulkanDescriptorSetLayout* GetRSBufferSetLayout() { return RSBufferSetLayout.get(); } VulkanDescriptorSetLayout* GetFixedSetLayout() { return FixedSetLayout.get(); } VulkanDescriptorSetLayout* GetTextureSetLayout(int numLayers); + VulkanDescriptorSetLayout* GetBindlessSetLayout() { return BindlessDescriptorSetLayout.get(); } VulkanDescriptorSet* GetRSBufferDescriptorSet(int threadIndex) { return RSBufferSets[threadIndex].get(); } VulkanDescriptorSet* GetFixedDescriptorSet() { return FixedSet.get(); } VulkanDescriptorSet* GetNullTextureDescriptorSet(); + VulkanDescriptorSet* GetBindlessDescriptorSet() { return BindlessDescriptorSet.get(); } std::unique_ptr AllocateTextureDescriptorSet(int numLayers); @@ -36,11 +39,15 @@ public: void AddMaterial(VkMaterial* texture); void RemoveMaterial(VkMaterial* texture); + void UpdateBindlessDescriptorSet(); + int AddBindlessTextureIndex(VulkanImageView* imageview, VulkanSampler* sampler); + private: void CreateRSBufferSetLayout(); void CreateFixedSetLayout(); void CreateRSBufferPool(); void CreateFixedSetPool(); + void CreateBindlessDescriptorSet(); void UpdateFixedSet(); std::unique_ptr AllocatePPDescriptorSet(VulkanDescriptorSetLayout* layout); @@ -66,5 +73,12 @@ private: std::list Materials; + std::unique_ptr BindlessDescriptorPool; + std::unique_ptr BindlessDescriptorSet; + std::unique_ptr BindlessDescriptorSetLayout; + WriteDescriptors WriteBindless; + int NextBindlessIndex = 0; + static const int maxSets = 100; + static const int MaxBindlessTextures = 16536; }; diff --git a/src/common/rendering/vulkan/textures/vk_hwtexture.cpp b/src/common/rendering/vulkan/textures/vk_hwtexture.cpp index 33fce2f45..0cc733520 100644 --- a/src/common/rendering/vulkan/textures/vk_hwtexture.cpp +++ b/src/common/rendering/vulkan/textures/vk_hwtexture.cpp @@ -331,6 +331,16 @@ void VkMaterial::DeleteDescriptors() } VulkanDescriptorSet* VkMaterial::GetDescriptorSet(const FMaterialState& state) +{ + return GetDescriptorEntry(state).descriptor.get(); +} + +int VkMaterial::GetBindlessIndex(const FMaterialState& state) +{ + return GetDescriptorEntry(state).bindlessIndex; +} + +VkMaterial::DescriptorEntry& VkMaterial::GetDescriptorEntry(const FMaterialState& state) { auto base = Source(); int clampmode = state.mClampMode; @@ -341,12 +351,13 @@ VulkanDescriptorSet* VkMaterial::GetDescriptorSet(const FMaterialState& state) for (auto& set : mDescriptorSets) { - if (set.descriptor && set.clampmode == clampmode && set.remap == translationp) return set.descriptor.get(); + if (set.descriptor && set.clampmode == clampmode && set.remap == translationp) return set; } int numLayers = NumLayers(); - auto descriptor = fb->GetDescriptorSetManager()->AllocateTextureDescriptorSet(max(numLayers, SHADER_MIN_REQUIRED_TEXTURE_LAYERS)); + auto descriptors = fb->GetDescriptorSetManager(); + auto descriptor = descriptors->AllocateTextureDescriptorSet(max(numLayers, SHADER_MIN_REQUIRED_TEXTURE_LAYERS)); descriptor->SetDebugName("VkHardwareTexture.mDescriptorSets"); @@ -358,6 +369,8 @@ VulkanDescriptorSet* VkMaterial::GetDescriptorSet(const FMaterialState& state) auto systeximage = systex->GetImage(layer->layerTexture, state.mTranslation, layer->scaleFlags); update.AddCombinedImageSampler(descriptor.get(), 0, systeximage->View.get(), fb->GetSamplerManager()->Get(GetLayerFilter(0), clampmode), systeximage->Layout); + int bindlessIndex = descriptors->AddBindlessTextureIndex(systeximage->View.get(), fb->GetSamplerManager()->Get(GetLayerFilter(0), clampmode)); + if (!(layer->scaleFlags & CTF_Indexed)) { for (int i = 1; i < numLayers; i++) @@ -365,6 +378,8 @@ VulkanDescriptorSet* VkMaterial::GetDescriptorSet(const FMaterialState& state) auto syslayer = static_cast(GetLayer(i, 0, &layer)); auto syslayerimage = syslayer->GetImage(layer->layerTexture, 0, layer->scaleFlags); update.AddCombinedImageSampler(descriptor.get(), i, syslayerimage->View.get(), fb->GetSamplerManager()->Get(GetLayerFilter(i), clampmode), syslayerimage->Layout); + + descriptors->AddBindlessTextureIndex(syslayerimage->View.get(), fb->GetSamplerManager()->Get(GetLayerFilter(i), clampmode)); } } else @@ -374,6 +389,8 @@ VulkanDescriptorSet* VkMaterial::GetDescriptorSet(const FMaterialState& state) auto syslayer = static_cast(GetLayer(i, translation, &layer)); auto syslayerimage = syslayer->GetImage(layer->layerTexture, 0, layer->scaleFlags); update.AddCombinedImageSampler(descriptor.get(), i, syslayerimage->View.get(), fb->GetSamplerManager()->Get(GetLayerFilter(i), clampmode), syslayerimage->Layout); + + descriptors->AddBindlessTextureIndex(syslayerimage->View.get(), fb->GetSamplerManager()->Get(GetLayerFilter(i), clampmode)); } numLayers = 3; } @@ -385,8 +402,8 @@ VulkanDescriptorSet* VkMaterial::GetDescriptorSet(const FMaterialState& state) } update.Execute(fb->GetDevice()); - mDescriptorSets.emplace_back(clampmode, translationp, std::move(descriptor)); - return mDescriptorSets.back().descriptor.get(); + mDescriptorSets.emplace_back(clampmode, translationp, std::move(descriptor), bindlessIndex); + return mDescriptorSets.back(); } VulkanDescriptorSet* VkMaterial::GetDescriptorSet(int threadIndex, const FMaterialState& state) diff --git a/src/common/rendering/vulkan/textures/vk_hwtexture.h b/src/common/rendering/vulkan/textures/vk_hwtexture.h index 99bcaa6a3..041eddeec 100644 --- a/src/common/rendering/vulkan/textures/vk_hwtexture.h +++ b/src/common/rendering/vulkan/textures/vk_hwtexture.h @@ -71,21 +71,22 @@ public: std::list::iterator it; VulkanDescriptorSet* GetDescriptorSet(int threadIndex, const FMaterialState& state); + int GetBindlessIndex(const FMaterialState& state); private: - VulkanDescriptorSet* GetDescriptorSet(const FMaterialState& state); - struct DescriptorEntry { int clampmode; intptr_t remap; std::unique_ptr descriptor; + int bindlessIndex; - DescriptorEntry(int cm, intptr_t f, std::unique_ptr&& d) + DescriptorEntry(int cm, intptr_t f, std::unique_ptr&& d, int index) { clampmode = cm; remap = f; descriptor = std::move(d); + bindlessIndex = index; } }; @@ -98,6 +99,9 @@ private: ThreadDescriptorEntry(int cm, intptr_t f, VulkanDescriptorSet* d) : clampmode(cm), remap(f), descriptor(d) { } }; + VulkanDescriptorSet* GetDescriptorSet(const FMaterialState& state); + DescriptorEntry& GetDescriptorEntry(const FMaterialState& state); + std::vector mDescriptorSets; std::vector> mThreadDescriptorSets; }; diff --git a/src/common/rendering/vulkan/vk_renderdevice.cpp b/src/common/rendering/vulkan/vk_renderdevice.cpp index f4a7f5ada..d841dae5c 100644 --- a/src/common/rendering/vulkan/vk_renderdevice.cpp +++ b/src/common/rendering/vulkan/vk_renderdevice.cpp @@ -119,10 +119,20 @@ VulkanRenderDevice::VulkanRenderDevice(void *hMonitor, bool fullscreen, std::sha { VulkanDeviceBuilder builder; builder.OptionalRayQuery(); + builder.RequireExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); builder.Surface(surface); builder.SelectDevice(vk_device); SupportedDevices = builder.FindDevices(surface->Instance); mDevice = builder.Create(surface->Instance); + + bool supportsBindless = + mDevice->EnabledFeatures.DescriptorIndexing.descriptorBindingPartiallyBound && + mDevice->EnabledFeatures.DescriptorIndexing.runtimeDescriptorArray && + mDevice->EnabledFeatures.DescriptorIndexing.shaderSampledImageArrayNonUniformIndexing; + if (!supportsBindless) + { + I_FatalError("This GPU does not support the minimum requirements of this application"); + } } VulkanRenderDevice::~VulkanRenderDevice() @@ -605,3 +615,12 @@ void VulkanRenderDevice::SetSceneRenderTarget(bool useSSAO) renderstate->SetRenderTarget(&GetBuffers()->SceneColor, GetBuffers()->SceneDepthStencil.View.get(), GetBuffers()->GetWidth(), GetBuffers()->GetHeight(), VK_FORMAT_R16G16B16A16_SFLOAT, GetBuffers()->GetSceneSamples()); } } + +int VulkanRenderDevice::GetBindlessTextureIndex(FMaterial* material, int clampmode, int translation) +{ + FMaterialState materialState; + materialState.mMaterial = material; + materialState.mClampMode = clampmode; + materialState.mTranslation = translation; + return static_cast(material)->GetBindlessIndex(materialState); +} \ No newline at end of file diff --git a/src/common/rendering/vulkan/vk_renderdevice.h b/src/common/rendering/vulkan/vk_renderdevice.h index 7b9ec03d3..f302680fe 100644 --- a/src/common/rendering/vulkan/vk_renderdevice.h +++ b/src/common/rendering/vulkan/vk_renderdevice.h @@ -87,6 +87,8 @@ public: void WaitForCommands(bool finish) override; + int GetBindlessTextureIndex(FMaterial* material, int clampmode, int translation) override; + void ResetRenderStateCache(); std::mutex ThreadMutex; diff --git a/wadsrc/static/shaders/lightmap/frag_raytrace.glsl b/wadsrc/static/shaders/lightmap/frag_raytrace.glsl index 4e0225ba3..80b44a323 100644 --- a/wadsrc/static/shaders/lightmap/frag_raytrace.glsl +++ b/wadsrc/static/shaders/lightmap/frag_raytrace.glsl @@ -68,6 +68,8 @@ layout(set = 0, binding = 2) buffer SurfaceBuffer { SurfaceInfo surfaces[]; }; layout(set = 0, binding = 3) buffer LightBuffer { LightInfo lights[]; }; layout(set = 0, binding = 4) buffer PortalBuffer { PortalInfo portals[]; }; +layout(set = 2, binding = 0) uniform sampler2D textures[]; + layout(push_constant) uniform PushConstants { uint LightStart;