3700 FPS here we go

This commit is contained in:
Dynamitos
2021-04-13 23:09:16 +02:00
parent d5f0fe644f
commit 312ae2af9a
36 changed files with 401 additions and 231 deletions
+1 -1
View File
@@ -22,7 +22,7 @@ struct GraphicsInitializer
GraphicsInitializer()
: applicationName("SeeleEngine")
, engineName("SeeleEngine")
, layers{"VK_LAYER_KHRONOS_validation"}
, layers{"VK_LAYER_KHRONOS_validation", "VK_LAYER_LUNARG_monitor"}
, instanceExtensions{}
, deviceExtensions{"VK_KHR_swapchain"}
, windowHandle(nullptr)
+1 -1
View File
@@ -73,7 +73,7 @@ ShaderCollection& ShaderMap::createShaders(
collection.fragmentShader = graphics->createFragmentShader(createInfo);
}
ShaderPermutation permutation;
std::string materialName = material->getFileName(); //Filename is fine, because it just has to be unique
std::string materialName = material->getName();
std::string vertexInputName = vertexInput->getName();
permutation.passType = renderPass;
std::memcpy(permutation.materialName, materialName.c_str(), sizeof(permutation.materialName));
+1 -1
View File
@@ -486,7 +486,7 @@ class RenderCommand
public:
RenderCommand();
virtual ~RenderCommand();
virtual void begin() = 0;
virtual bool isReady() = 0;
virtual void setViewport(Gfx::PViewport viewport) = 0;
virtual void bindPipeline(Gfx::PGraphicsPipeline pipeline) = 0;
virtual void bindDescriptor(Gfx::PDescriptorSet set) = 0;
+1
View File
@@ -1,4 +1,5 @@
#include "Mesh.h"
#include "VertexShaderInput.h"
using namespace Seele;
+1 -13
View File
@@ -42,18 +42,7 @@ void BasePassMeshProcessor::addMeshBatch(
descriptorSet->writeChanges();
cachedPrimitiveSets.add(descriptorSet);
}
Gfx::PRenderCommand renderCommand;
if (cachedCommandBuffers.size() > 0)
{
renderCommand = cachedCommandBuffers.back();
cachedCommandBuffers.pop();
renderCommand->begin();
}
else
{
renderCommand = graphics->createRenderCommand();
renderCommand->begin();
}
Gfx::PRenderCommand renderCommand = graphics->createRenderCommand();
renderCommand->setViewport(target);
for(uint32 i = 0; i < batch.elements.size(); ++i)
{
@@ -84,7 +73,6 @@ Array<Gfx::PRenderCommand> BasePassMeshProcessor::getRenderCommands()
void BasePassMeshProcessor::clearCommands()
{
cachedCommandBuffers = renderCommands;
renderCommands.clear();
cachedPrimitiveSets.clear();
cachedPrimitiveIndex = 0;
@@ -22,7 +22,6 @@ public:
void clearCommands();
private:
Array<Gfx::PRenderCommand> renderCommands;
Array<Gfx::PRenderCommand> cachedCommandBuffers;
Array<Gfx::PDescriptorSet> cachedPrimitiveSets;
Gfx::PViewport target;
uint8 translucentBasePass;
@@ -11,6 +11,7 @@ target_sources(SeeleEngine
VulkanGraphics.cpp
VulkanGraphicsResources.h
VulkanGraphicsResources.cpp
VulkanDescriptorSets.h
VulkanDescriptorSets.cpp
VulkanGraphicsEnums.h
VulkanGraphicsEnums.cpp
@@ -91,12 +91,15 @@ void CmdBuffer::executeCommands(Array<Gfx::PRenderCommand> commands)
for (uint32 i = 0; i < commands.size(); ++i)
{
auto command = commands[i].cast<SecondaryCmdBuffer>();
// Cache array and size to save on pointer access
DescriptorSet** boundDescriptors = command->boundDescriptors.data();
size_t numDescriptors = command->boundDescriptors.size();
for(size_t i = 0; i < numDescriptors; ++i)
{
boundDescriptors[i]->currentlyBound = true;
}
command->end();
executingCommands.add(command);
for(PDescriptorSet set : command->boundDescriptors)
{
set->setCurrentlyBound(this);
}
cmdBuffers[i] = command->getHandle();
}
vkCmdExecuteCommands(handle, (uint32)cmdBuffers.size(), cmdBuffers.data());
@@ -114,14 +117,14 @@ void CmdBuffer::refreshFence()
{
if (fence->isSignaled())
{
state = State::ReadyBegin;
vkResetCommandBuffer(handle, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT);
fence->reset();
for(auto command : executingCommands)
{
command->reset();
}
executingCommands.clear();
fence->reset();
state = State::ReadyBegin;
}
}
else
@@ -142,6 +145,7 @@ PCommandBufferManager CmdBuffer::getManager()
SecondaryCmdBuffer::SecondaryCmdBuffer(PGraphics graphics, VkCommandPool cmdPool)
: CmdBufferBase(graphics, cmdPool)
, ready(true)
{
VkCommandBufferAllocateInfo allocInfo =
init::CommandBufferAllocateInfo(cmdPool,
@@ -157,6 +161,7 @@ SecondaryCmdBuffer::~SecondaryCmdBuffer()
void SecondaryCmdBuffer::begin(PCmdBuffer parent)
{
ready = false;
VkCommandBufferBeginInfo beginInfo =
init::CommandBufferBeginInfo();
VkCommandBufferInheritanceInfo inheritanceInfo =
@@ -176,15 +181,20 @@ void SecondaryCmdBuffer::end()
void SecondaryCmdBuffer::reset()
{
for(auto descriptor : boundDescriptors)
vkResetCommandBuffer(handle, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT);
size_t numBoundDescriptors = boundDescriptors.size();
DescriptorSet** boundDescriptorSets = boundDescriptors.data();
for(size_t i = 0; i < numBoundDescriptors; ++i)
{
descriptor->releaseFromCmd();
boundDescriptorSets[i]->currentlyBound = false;
}
boundDescriptors.clear();
ready = true;
}
void SecondaryCmdBuffer::begin()
bool SecondaryCmdBuffer::isReady()
{
begin(graphics->getGraphicsCommands()->getCommands());
return ready;
}
void SecondaryCmdBuffer::setViewport(Gfx::PViewport viewport)
@@ -203,7 +213,7 @@ void SecondaryCmdBuffer::bindPipeline(Gfx::PGraphicsPipeline gfxPipeline)
void SecondaryCmdBuffer::bindDescriptor(Gfx::PDescriptorSet descriptorSet)
{
auto descriptor = descriptorSet.cast<DescriptorSet>();
boundDescriptors.add(descriptor);
boundDescriptors.add(descriptor.getHandle());
VkDescriptorSet setHandle = descriptor->getHandle();
vkCmdBindDescriptorSets(handle, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->getLayout(), descriptorSet->getSetIndex(), 1, &setHandle, 0, nullptr);
}
@@ -213,7 +223,7 @@ void SecondaryCmdBuffer::bindDescriptor(const Array<Gfx::PDescriptorSet>& descri
for(uint32 i = 0; i < descriptorSets.size(); ++i)
{
auto descriptorSet = descriptorSets[i].cast<DescriptorSet>();
boundDescriptors.add(descriptorSet);
boundDescriptors.add(descriptorSet.getHandle());
sets[descriptorSet->getSetIndex()] = descriptorSet->getHandle();
}
vkCmdBindDescriptorSets(handle, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->getLayout(), 0, (uint32)descriptorSets.size(), sets, 0, nullptr);
@@ -271,7 +281,20 @@ PCmdBuffer CommandBufferManager::getCommands()
PSecondaryCmdBuffer CommandBufferManager::createSecondaryCmdBuffer()
{
return new SecondaryCmdBuffer(graphics, commandPool);
std::scoped_lock lck(allocatedSecondBufferLock);
for (uint32 i = 0; i < allocatedSecondBuffers.size(); ++i)
{
PSecondaryCmdBuffer cmdBuffer = allocatedSecondBuffers[i];
if (cmdBuffer->isReady())
{
cmdBuffer->begin(activeCmdBuffer);
return cmdBuffer;
}
}
PSecondaryCmdBuffer result = new SecondaryCmdBuffer(graphics, commandPool);
allocatedSecondBuffers.add(result);
result->begin(activeCmdBuffer);
return result;
}
void CommandBufferManager::submitCommands(PSemaphore signalSemaphore)
@@ -293,7 +316,7 @@ void CommandBufferManager::submitCommands(PSemaphore signalSemaphore)
queue->submitCommandBuffer(activeCmdBuffer);
}
}
std::lock_guard lock(allocatedBufferLock);
std::scoped_lock lock(allocatedBufferLock);
for (uint32 i = 0; i < allocatedBuffers.size(); ++i)
{
PCmdBuffer cmdBuffer = allocatedBuffers[i];
@@ -80,7 +80,7 @@ public:
void begin(PCmdBuffer parent);
void end();
void reset();
virtual void begin() override;
virtual bool isReady() override;
virtual void setViewport(Gfx::PViewport viewport) override;
virtual void bindPipeline(Gfx::PGraphicsPipeline pipeline) override;
virtual void bindDescriptor(Gfx::PDescriptorSet descriptorSet) override;
@@ -91,7 +91,8 @@ public:
private:
PGraphicsPipeline pipeline;
Array<PDescriptorSet> boundDescriptors;
Array<DescriptorSet*> boundDescriptors;
bool ready;
friend class CmdBuffer;
};
DEFINE_REF(SecondaryCmdBuffer)
@@ -118,6 +119,8 @@ private:
PCmdBuffer activeCmdBuffer;
std::mutex allocatedBufferLock;
Array<PCmdBuffer> allocatedBuffers;
std::mutex allocatedSecondBufferLock;
Array<PSecondaryCmdBuffer> allocatedSecondBuffers;
};
DEFINE_REF(CommandBufferManager)
} // namespace Vulkan
@@ -171,8 +171,10 @@ void DescriptorSet::updateTexture(uint32_t binding, Gfx::PTexture texture, Gfx::
TextureHandle* cachedTexture = reinterpret_cast<TextureHandle*>(cachedData[Gfx::currentFrameIndex][binding]);
if(vulkanTexture == cachedTexture)
{
std::cout << "Cached texture is same as new one, skipping update" << std::endl;
return;
}
std::cout << "Texture changed, updating" << std::endl;
//It is assumed that the image is in the correct layout
VkDescriptorImageInfo imageInfo =
init::DescriptorImageInfo(
@@ -201,15 +203,16 @@ bool DescriptorSet::operator<(Gfx::PDescriptorSet other)
return this < otherSet.getHandle();
}
uint32 DescriptorSet::getSetIndex() const
{
return owner->getLayout().getSetIndex();
}
void DescriptorSet::writeChanges()
{
if (writeDescriptors.size() > 0)
{
if(currentlyBound != nullptr)
{
currentlyBound->getManager()->waitForCommands(currentlyBound);
currentlyBound = nullptr;
}
assert(!isCurrentlyBound());
vkUpdateDescriptorSets(graphics->getDevice(), (uint32)writeDescriptors.size(), writeDescriptors.data(), 0, nullptr);
writeDescriptors.clear();
imageInfos.clear();
@@ -220,9 +223,11 @@ void DescriptorSet::writeChanges()
DescriptorAllocator::DescriptorAllocator(PGraphics graphics, DescriptorLayout &layout)
: graphics(graphics)
, layout(layout)
, currentCachedIndex(0)
{
std::memset(&cachedHandles, 0, sizeof(cachedHandles));
for(uint32 i = 0; i < cachedHandles.size(); ++i)
{
cachedHandles[i] = new DescriptorSet(graphics, this);
}
uint32 perTypeSizes[VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT]; // TODO: FIX ENUM
std::memset(perTypeSizes, 0, sizeof(perTypeSizes));
@@ -243,7 +248,7 @@ DescriptorAllocator::DescriptorAllocator(PGraphics graphics, DescriptorLayout &l
poolSizes.add(size);
}
}
VkDescriptorPoolCreateInfo createInfo = init::DescriptorPoolCreateInfo((uint32)poolSizes.size(), poolSizes.data(), maxSets);
VkDescriptorPoolCreateInfo createInfo = init::DescriptorPoolCreateInfo((uint32)poolSizes.size(), poolSizes.data(), maxSets * Gfx::numFramesBuffered);
VK_CHECK(vkCreateDescriptorPool(graphics->getDevice(), &createInfo, nullptr, &poolHandle));
}
@@ -255,30 +260,48 @@ DescriptorAllocator::~DescriptorAllocator()
void DescriptorAllocator::allocateDescriptorSet(Gfx::PDescriptorSet &descriptorSet)
{
descriptorSet = new DescriptorSet(graphics, this);
PDescriptorSet vulkanSet = descriptorSet.cast<DescriptorSet>();
VkDescriptorSetLayout layoutHandle = layout.getHandle();
VkDescriptorSetAllocateInfo allocInfo =
init::DescriptorSetAllocateInfo(poolHandle, &layoutHandle, 1);
for(uint32 i = 0; i < Gfx::numFramesBuffered; ++i)
VkDescriptorSetLayout layoutArray[Gfx::numFramesBuffered];
for (uint32 i = 0; i < Gfx::numFramesBuffered; i++)
{
if(cachedHandles[currentCachedIndex] != VK_NULL_HANDLE)
{
vulkanSet->setHandle[i] = cachedHandles[currentCachedIndex++];
}
else
{
VK_CHECK(vkAllocateDescriptorSets(graphics->getDevice(), &allocInfo, &vulkanSet->setHandle[i]));
cachedHandles[currentCachedIndex++] = vulkanSet->setHandle[i];
}
vulkanSet->cachedData[i].resize(layout.bindings.size());
// Not really pretty, but this way the set knows which ones are valid
std::memset(vulkanSet->cachedData[i].data(), 0, sizeof(void*) * vulkanSet->cachedData[i].size());
layoutArray[i] = layoutHandle;
}
VkDescriptorSetAllocateInfo allocInfo =
init::DescriptorSetAllocateInfo(poolHandle, layoutArray, Gfx::numFramesBuffered);
for(uint32 setIndex = 0; setIndex < cachedHandles.size(); ++setIndex)
{
if(cachedHandles[setIndex]->isCurrentlyBound() || cachedHandles[setIndex]->isCurrentlyInUse())
{
// Currently in use, skip
continue;
}
if(cachedHandles[setIndex]->getHandle() == VK_NULL_HANDLE)
{
//If it hasnt been initialized, allocate it
VK_CHECK(vkAllocateDescriptorSets(graphics->getDevice(), &allocInfo, cachedHandles[setIndex]->setHandle));
}
cachedHandles[setIndex]->currentlyInUse = true;
descriptorSet = cachedHandles[setIndex];
PDescriptorSet vulkanSet = descriptorSet.cast<DescriptorSet>();
for(uint32 frameIndex = 0; frameIndex < Gfx::numFramesBuffered; ++frameIndex)
{
vulkanSet->cachedData[frameIndex].resize(layout.bindings.size());
// Not really pretty, but this way the set knows which ones are valid
std::memset(vulkanSet->cachedData[frameIndex].data(), 0, sizeof(void*) * vulkanSet->cachedData[frameIndex].size());
}
//Found set, stop searching
return;
}
throw std::logic_error("Out of descriptor sets");
}
void DescriptorAllocator::reset()
{
currentCachedIndex = 0;
for(uint32 i = 0; i < cachedHandles.size(); ++i)
{
cachedHandles[i]->free();
}
}
@@ -54,6 +54,60 @@ private:
};
DEFINE_REF(PipelineLayout)
class DescriptorSet : public Gfx::DescriptorSet
{
public:
DescriptorSet(PGraphics graphics, PDescriptorAllocator owner)
: graphics(graphics), owner(owner), currentlyInUse(false), currentlyBound(nullptr)
{
std::memset(setHandle, 0, sizeof(setHandle));
}
virtual ~DescriptorSet();
virtual void writeChanges();
virtual void updateBuffer(uint32_t binding, Gfx::PUniformBuffer uniformBuffer);
virtual void updateBuffer(uint32_t binding, Gfx::PStructuredBuffer uniformBuffer);
virtual void updateSampler(uint32_t binding, Gfx::PSamplerState samplerState);
virtual void updateTexture(uint32_t binding, Gfx::PTexture texture, Gfx::PSamplerState sampler = nullptr);
virtual bool operator<(Gfx::PDescriptorSet other);
inline bool isCurrentlyBound() const
{
return currentlyBound;
}
inline bool isCurrentlyInUse() const
{
return currentlyInUse;
}
void free()
{
currentlyInUse = false;
}
inline VkDescriptorSet getHandle() const
{
return setHandle[Gfx::currentFrameIndex];
}
virtual uint32 getSetIndex() const;
private:
Array<VkDescriptorImageInfo> imageInfos;
Array<VkDescriptorBufferInfo> bufferInfos;
Array<VkWriteDescriptorSet> writeDescriptors;
// contains the previously bound resources at every binding
// since the layout is fixed, trying to bind a texture to a buffer
// would not work anyways, so casts should be safe
Array<void*> cachedData[Gfx::numFramesBuffered];
VkDescriptorSet setHandle[Gfx::numFramesBuffered];
PGraphics graphics;
PDescriptorAllocator owner;
bool currentlyBound;
bool currentlyInUse;
friend class DescriptorAllocator;
friend class CmdBuffer;
friend class SecondaryCmdBuffer;
};
DEFINE_REF(DescriptorSet)
class DescriptorAllocator : public Gfx::DescriptorAllocator
{
public:
@@ -74,59 +128,10 @@ public:
private:
PGraphics graphics;
DescriptorLayout &layout;
uint32 currentCachedIndex;
const static int maxSets = 512;
VkDescriptorSet cachedHandles[maxSets];
StaticArray<PDescriptorSet, maxSets> cachedHandles;
VkDescriptorPool poolHandle;
};
DEFINE_REF(DescriptorAllocator)
class DescriptorSet : public Gfx::DescriptorSet
{
public:
DescriptorSet(PGraphics graphics, PDescriptorAllocator owner)
: graphics(graphics), owner(owner)
{
}
virtual ~DescriptorSet();
virtual void writeChanges();
virtual void updateBuffer(uint32_t binding, Gfx::PUniformBuffer uniformBuffer);
virtual void updateBuffer(uint32_t binding, Gfx::PStructuredBuffer uniformBuffer);
virtual void updateSampler(uint32_t binding, Gfx::PSamplerState samplerState);
virtual void updateTexture(uint32_t binding, Gfx::PTexture texture, Gfx::PSamplerState sampler = nullptr);
virtual bool operator<(Gfx::PDescriptorSet other);
void setCurrentlyBound(PCmdBuffer boundBy)
{
currentlyBound = boundBy;
}
void releaseFromCmd()
{
currentlyBound = nullptr;
}
inline VkDescriptorSet getHandle() const
{
return setHandle[Gfx::currentFrameIndex];
}
virtual uint32 getSetIndex() const
{
return owner->getLayout().getSetIndex();
}
private:
Array<VkDescriptorImageInfo> imageInfos;
Array<VkDescriptorBufferInfo> bufferInfos;
Array<VkWriteDescriptorSet> writeDescriptors;
// contains the previously bound resources at every binding
// since the layout is fixed, trying to bind a texture to a buffer
// would not work anyways, so casts should be safe
Array<void*> cachedData[Gfx::numFramesBuffered];
VkDescriptorSet setHandle[Gfx::numFramesBuffered];
PGraphics graphics;
PDescriptorAllocator owner;
PCmdBuffer currentlyBound;
friend class DescriptorAllocator;
};
DEFINE_REF(DescriptorSet)
} // namespace Vulkan
} // namespace Seele
@@ -768,8 +768,15 @@ VkPipelineShaderStageCreateInfo init::PipelineShaderStageCreateInfo(VkShaderStag
#pragma warning(disable : 4100)
VkBool32 Seele::Vulkan::debugCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t obj, size_t location, int32_t code, const char *layerPrefix, const char *msg, void *userDataManager)
{
std::cerr << layerPrefix << ": " << msg << std::endl;
return VK_FALSE;
if(flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT)
{
return VK_FALSE;
}
else
{
std::cerr << layerPrefix << ": " << msg << std::endl;
return VK_FALSE;
}
}
#pragma warning(default : 4100)
+36 -35
View File
@@ -22,43 +22,44 @@ Queue::~Queue()
void Queue::submitCommandBuffer(PCmdBuffer cmdBuffer, uint32 numSignalSemaphores, VkSemaphore *signalSemaphores)
{
assert(cmdBuffer->state == CmdBuffer::State::Ended);
PFence fence = cmdBuffer->fence;
assert(!fence->isSignaled());
const VkCommandBuffer cmdBuffers[] = {cmdBuffer->handle};
VkSubmitInfo submitInfo =
init::SubmitInfo();
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = cmdBuffers;
submitInfo.signalSemaphoreCount = static_cast<uint32>(numSignalSemaphores);
submitInfo.pSignalSemaphores = signalSemaphores;
Array<VkSemaphore> waitSemaphores;
if (cmdBuffer->waitSemaphores.size() > 0)
{
for (PSemaphore semaphore : cmdBuffer->waitSemaphores)
std::scoped_lock lck(queueLock);
assert(cmdBuffer->state == CmdBuffer::State::Ended);
PFence fence = cmdBuffer->fence;
assert(!fence->isSignaled());
const VkCommandBuffer cmdBuffers[] = {cmdBuffer->handle};
VkSubmitInfo submitInfo =
init::SubmitInfo();
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = cmdBuffers;
submitInfo.signalSemaphoreCount = static_cast<uint32>(numSignalSemaphores);
submitInfo.pSignalSemaphores = signalSemaphores;
Array<VkSemaphore> waitSemaphores;
if (cmdBuffer->waitSemaphores.size() > 0)
{
waitSemaphores.add(semaphore->getHandle());
for (PSemaphore semaphore : cmdBuffer->waitSemaphores)
{
waitSemaphores.add(semaphore->getHandle());
}
submitInfo.waitSemaphoreCount = static_cast<uint32>(cmdBuffer->waitSemaphores.size());
submitInfo.pWaitSemaphores = waitSemaphores.data();
submitInfo.pWaitDstStageMask = cmdBuffer->waitFlags.data();
}
submitInfo.waitSemaphoreCount = static_cast<uint32>(cmdBuffer->waitSemaphores.size());
submitInfo.pWaitSemaphores = waitSemaphores.data();
submitInfo.pWaitDstStageMask = cmdBuffer->waitFlags.data();
VK_CHECK(vkQueueSubmit(queue, 1, &submitInfo, fence->getHandle()));
cmdBuffer->state = CmdBuffer::State::Submitted;
cmdBuffer->waitFlags.clear();
cmdBuffer->waitSemaphores.clear();
if (Gfx::waitIdleOnSubmit)
{
fence->wait(200 * 1000ull);
}
cmdBuffer->refreshFence();
graphics->getStagingManager()->clearPending();
}
VK_CHECK(vkQueueSubmit(queue, 1, &submitInfo, fence->getHandle()));
cmdBuffer->state = CmdBuffer::State::Submitted;
cmdBuffer->waitFlags.clear();
cmdBuffer->waitSemaphores.clear();
if (Gfx::waitIdleOnSubmit)
{
fence->wait(200 * 1000ull);
}
cmdBuffer->refreshFence();
graphics->getStagingManager()->clearPending();
}
+1
View File
@@ -27,6 +27,7 @@ public:
}
private:
std::mutex queueLock;
PGraphics graphics;
VkQueue queue;
uint32 familyIndex;