mirror of
https://github.com/ZDoom/gzdoom.git
synced 2025-02-16 17:21:10 +00:00
Add bindless texture support
This commit is contained in:
parent
adc9fb3421
commit
ebdef188ee
11 changed files with 114 additions and 7 deletions
|
@ -1852,6 +1852,7 @@ std::vector<VulkanCompatibleDevice> 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)
|
||||
|
|
|
@ -249,6 +249,9 @@ public:
|
|||
virtual void RenderTextureView(FCanvasTexture* tex, std::function<void(IntRect&)> 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();
|
||||
|
|
|
@ -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"
|
||||
|
@ -141,6 +142,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());
|
||||
|
|
|
@ -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 <zvulkan/vulkanswapchain.h>
|
||||
#include <zvulkan/vulkanbuilders.h>
|
||||
#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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "zvulkan/vulkanobjects.h"
|
||||
#include "zvulkan/vulkanbuilders.h"
|
||||
#include <list>
|
||||
#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<VulkanDescriptorSet> 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<VulkanDescriptorSet> AllocatePPDescriptorSet(VulkanDescriptorSetLayout* layout);
|
||||
|
@ -66,5 +73,12 @@ private:
|
|||
|
||||
std::list<VkMaterial*> Materials;
|
||||
|
||||
std::unique_ptr<VulkanDescriptorPool> BindlessDescriptorPool;
|
||||
std::unique_ptr<VulkanDescriptorSet> BindlessDescriptorSet;
|
||||
std::unique_ptr<VulkanDescriptorSetLayout> BindlessDescriptorSetLayout;
|
||||
WriteDescriptors WriteBindless;
|
||||
int NextBindlessIndex = 0;
|
||||
|
||||
static const int maxSets = 100;
|
||||
static const int MaxBindlessTextures = 16536;
|
||||
};
|
||||
|
|
|
@ -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<VkHardwareTexture*>(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<VkHardwareTexture*>(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)
|
||||
|
|
|
@ -71,21 +71,22 @@ public:
|
|||
std::list<VkMaterial*>::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<VulkanDescriptorSet> descriptor;
|
||||
int bindlessIndex;
|
||||
|
||||
DescriptorEntry(int cm, intptr_t f, std::unique_ptr<VulkanDescriptorSet>&& d)
|
||||
DescriptorEntry(int cm, intptr_t f, std::unique_ptr<VulkanDescriptorSet>&& 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<DescriptorEntry> mDescriptorSets;
|
||||
std::vector<std::vector<ThreadDescriptorEntry>> mThreadDescriptorSets;
|
||||
};
|
||||
|
|
|
@ -120,10 +120,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()
|
||||
|
@ -607,3 +617,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<VkMaterial*>(material)->GetBindlessIndex(materialState);
|
||||
}
|
|
@ -87,6 +87,8 @@ public:
|
|||
|
||||
void WaitForCommands(bool finish) override;
|
||||
|
||||
int GetBindlessTextureIndex(FMaterial* material, int clampmode, int translation) override;
|
||||
|
||||
void ResetRenderStateCache();
|
||||
|
||||
std::mutex ThreadMutex;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue