10 return m_window->getCurrentTarget()->targetImage();
15 return m_window->getCurrentTarget()->depthStencilBuffer();
49 std::vector<CommandBufferGraph::NodeRef> windowNodes;
51 for (
const auto& [imageName, imageNode] :
m_imageNodes) {
55 if (windowTargetNode && windowTargetNode->isValidWindowTarget()) {
56 window = windowTargetNode->getWindow();
61 if (windowDepthNode && windowDepthNode->isValidWindowDepthStencil()) {
62 window = windowDepthNode->getWindow();
67 bool alreadyAdded =
false;
68 for (
const auto& node : windowNodes) {
75 windowNodes.emplace_back(window);
97 *(it->second) |= texture;
98 return it->second.get();
100 auto node = std::make_unique<RenderGraphBufferNode>(texture);
111 *(it->second) |= target;
112 return it->second.get();
115 auto node = std::make_unique<RenderGraphWindowTargetNode>(target);
120 auto node = std::make_unique<RenderGraphBufferNode>(target);
133 return it->second.get();
136 auto node = std::make_unique<RenderGraphWindowDepthStencilNode>(
depthStencil);
141 auto node = std::make_unique<RenderGraphBufferNode>(
depthStencil);
154 auto edge = std::make_unique<TextureEdge>();
155 edge->size = texture.
size;
156 edge->fromImage = textureName;
157 edge->toPass = passName;
164 imageNodeIt->second->addOutgoingEdge(edgePtr);
166 pass.addIncomingEdge(edgePtr);
168 m_edges.push_back(std::move(edge));
175 auto edge = std::make_unique<TargetEdge>();
176 edge->fromPass = passName;
177 edge->toImage = targetName;
183 imageNodeIt->second->addIncomingEdge(edgePtr);
185 pass.addOutgoingEdge(edgePtr);
187 m_edges.push_back(std::move(edge));
195 auto edge = std::make_unique<DepthStencilEdge>();
196 edge->fromPass = passName;
197 edge->toImage = depthStencilName;
203 imageNodeIt->second->addIncomingEdge(edgePtr);
205 pass.addOutgoingEdge(edgePtr);
207 m_edges.push_back(std::move(edge));
215 pass.applyPassDesc(desc);
223 std::vector<RenderGraphImageNode*> renderTargetNodes;
225 for (
auto& target : desc.
targets)
228 renderTargetNodes.push_back(node);
235 renderTargetNodes.push_back(node);
239 if (renderTargetNodes.size() > 1) {
241 for (
size_t i = 1; i < renderTargetNodes.size(); ++i) {
242 firstNode->
unite(renderTargetNodes[i]);
255 std::vector<RenderGraphImageNode*> referenceNodes;
257 for (
auto* targetEdge : pass.getTargetOutgoingEdges()) {
258 auto imageNodeIt =
m_imageNodes.find(targetEdge->toImage);
260 referenceNodes.push_back(imageNodeIt->second.get());
264 for (
auto* depthStencilEdge : pass.getDepthStencilOutgoingEdges()) {
265 auto imageNodeIt =
m_imageNodes.find(depthStencilEdge->toImage);
267 referenceNodes.push_back(imageNodeIt->second.get());
271 if (referenceNodes.empty()) {
277 for (
auto* textureEdge : pass.getTextureIncomingEdges()) {
278 auto imageNodeIt =
m_imageNodes.find(textureEdge->fromImage);
292 FractionScale2D scale(textureEdge->size.relativeWidth, textureEdge->size.relativeHeight);
293 textureNode->
unite(referenceNode, scale);
301 for (
const auto& [passName, passNode] :
m_passNodes) {
305 for (
const auto& [passName, passNode] :
m_passNodes) {
306 for (
auto* textureEdge : passNode.getTextureIncomingEdges()) {
307 std::string imageName = textureEdge->fromImage;
316 for (
auto* targetEdge : passNode.getTargetOutgoingEdges()) {
319 passRenderTarget = targetIt->second.get();
324 if (!passRenderTarget) {
325 for (
auto* depthEdge : passNode.getDepthStencilOutgoingEdges()) {
328 passRenderTarget = depthIt->second.get();
334 if (passRenderTarget && imageNode->
isSameSize(passRenderTarget)) {
346 for (
const auto& [imageName, imageNode] :
m_imageNodes) {
347 std::vector<std::string> targetPasses;
348 std::vector<std::string> depthStencilPasses;
350 for (
auto* targetEdge : imageNode->getTargetIncomingEdges()) {
351 targetPasses.push_back(targetEdge->fromPass);
354 for (
auto* depthEdge : imageNode->getDepthStencilIncomingEdges()) {
355 depthStencilPasses.push_back(depthEdge->fromPass);
358 for (
size_t i = 1; i < targetPasses.size(); i++) {
362 for (
size_t i = 1; i < depthStencilPasses.size(); i++) {
363 m_passesUnions.unite(depthStencilPasses[0], depthStencilPasses[i]);
366 if (!targetPasses.empty() && !depthStencilPasses.empty()) {
377 imageNode->fillDefaultData();
380 if (!resourceManager) {
381 throw std::runtime_error(
"ResourceManager not available");
384 std::set<const SizeNode*> processedRoots;
388 if (!bufferNode || !bufferNode->isFilled()) {
394 if (root == bufferNode && processedRoots.find(root) == processedRoots.end()) {
395 processedRoots.insert(root);
397 uint32_t width, height;
398 bool hasFixedSize = bufferNode->getComputedSize(width, height);
402 targetDesc.
width =
static_cast<int>(width);
403 targetDesc.
height =
static_cast<int>(height);
404 targetDesc.
samples = bufferNode->getSamples();
405 targetDesc.
format = bufferNode->getFormat();
406 targetDesc.
usage = bufferNode->getUsage();
408 Image* allocatedImage = resourceManager->allocateTarget(name, targetDesc);
409 bufferNode->setAllocatedImage(allocatedImage);
412 throw std::runtime_error(
"Root node has no fixed size: " + name);
419 if (!bufferNode || !bufferNode->isFilled()) {
425 if (root != bufferNode) {
427 imageDesc.
format = bufferNode->getFormat();
428 imageDesc.
samples = bufferNode->getSamples();
429 imageDesc.
usage = bufferNode->getUsage();
431 Image* allocatedImage =
nullptr;
433 std::string dependencyName;
435 if (otherNode->getRoot() == root && otherNode->
getRoot() == otherNode.get()) {
436 dependencyName = otherName;
441 if (!dependencyName.empty()) {
447 if (windowTargetNode && windowTargetNode->isValidWindowTarget()) {
448 allocatedImage = resourceManager->allocateImage(
449 name, windowTargetNode->getWindow(), imageDesc);
450 }
else if (windowDepthNode && windowDepthNode->isValidWindowDepthStencil()) {
451 allocatedImage = resourceManager->allocateImage(
452 name, windowDepthNode->getWindow(), imageDesc);
454 allocatedImage = resourceManager->allocateImage(
455 name, dependencyName, imageDesc);
458 bufferNode->setAllocatedImage(allocatedImage);
461 throw std::runtime_error(
"Cannot determine dependency for image: " + name);
468 for (
const auto& [passName, passNode] :
m_passNodes) {
472 if (clearInfo.types) {
473 rhiPass->
enableClear(clearInfo.types, clearInfo.color, clearInfo.depth, clearInfo.stencil);
476 const auto& targetEdges = passNode.getTargetOutgoingEdges();
477 for (
size_t i = 0; i < targetEdges.size(); ++i) {
478 const auto& edge = targetEdges[i];
483 rhiPass->
bindTarget(
static_cast<int>(i), image);
488 const auto& depthStencilEdges = passNode.getDepthStencilOutgoingEdges();
489 for (
const auto& edge : depthStencilEdges) {
503 const std::string& groupLeader,
504 const std::vector<std::string>& groupMembers,
505 std::map<std::string, std::set<std::string>>& dependencies
507 if (dependencies.find(groupLeader) == dependencies.end()) {
508 dependencies[groupLeader] = std::set<std::string>();
511 for (
const std::string& passName : groupMembers) {
515 const auto& passNode = passNodeIt->second;
517 for (
const auto* textureEdge : passNode.getTextureIncomingEdges()) {
518 auto imageNodeIt =
m_imageNodes.find(textureEdge->fromImage);
521 const auto& imageNode = imageNodeIt->second;
523 for (
const auto* targetEdge : imageNode->getTargetIncomingEdges()) {
524 std::string producerPass = targetEdge->fromPass;
527 for (
const auto& [otherGroupLeader, otherGroupMembers] : allGroups) {
528 if (otherGroupLeader != groupLeader &&
529 std::find(otherGroupMembers.begin(), otherGroupMembers.end(), producerPass) != otherGroupMembers.end()) {
530 dependencies[groupLeader].insert(otherGroupLeader);
536 for (
const auto* depthEdge : imageNode->getDepthStencilIncomingEdges()) {
537 std::string producerPass = depthEdge->fromPass;
540 for (
const auto& [otherGroupLeader, otherGroupMembers] : allGroups) {
541 if (otherGroupLeader != groupLeader &&
542 std::find(otherGroupMembers.begin(), otherGroupMembers.end(), producerPass) != otherGroupMembers.end()) {
543 dependencies[groupLeader].insert(otherGroupLeader);
553 const std::map<std::string, std::set<std::string>>& dependencies
555 std::vector<std::string> result;
556 std::map<std::string, int> inDegree;
557 std::queue<std::string> queue;
559 for (
const auto& [node, deps] : dependencies) {
563 for (
const auto& [node, deps] : dependencies) {
564 for (
const std::string& dep : deps) {
565 if (inDegree.find(dep) != inDegree.end()) {
571 for (
const auto& [node, degree] : inDegree) {
577 while (!queue.empty()) {
578 std::string current = queue.front();
580 result.push_back(current);
582 for (
const auto& [node, deps] : dependencies) {
583 if (deps.find(current) != deps.end()) {
585 if (inDegree[node] == 0) {
592 if (result.size() != dependencies.size()) {
593 throw std::runtime_error(
"Circular dependency detected in PassGroups");
601 std::map<std::string, std::set<std::string>> dependencies;
603 for (
const auto& [groupLeader, groupMembers] : passGroups) {
616 for (
const auto& [groupLeader, groupMembers] : passGroups) {
619 std::vector<std::string> orderedPassNames;
621 for (
const std::string& passName : groupMembers) {
626 std::vector<RHI::PassNeighbors> predecessors;
627 std::vector<RHI::PassNeighbors> successors;
631 const auto& passNode = passNodeIt->second;
633 bool outputsToWindow =
false;
635 for (
const auto* targetEdge : passNode.getTargetOutgoingEdges()) {
636 auto imageNodeIt =
m_imageNodes.find(targetEdge->toImage);
639 imageNodeIt->second.get());
640 if (windowTargetNode && windowTargetNode->isValidWindowTarget()) {
641 outputsToWindow =
true;
647 if (!outputsToWindow) {
648 for (
const auto* depthEdge : passNode.getDepthStencilOutgoingEdges()) {
649 auto imageNodeIt =
m_imageNodes.find(depthEdge->toImage);
652 imageNodeIt->second.get());
653 if (windowDepthNode && windowDepthNode->isValidWindowDepthStencil()) {
654 outputsToWindow =
true;
661 if (outputsToWindow) {
662 successors.emplace_back(
667 for (
const auto* textureEdge : passNode.getTextureIncomingEdges()) {
668 auto imageNodeIt =
m_imageNodes.find(textureEdge->fromImage);
670 const auto& imageNode = imageNodeIt->second;
673 for (
const auto* targetEdge : imageNode->getTargetIncomingEdges()) {
674 if (std::find(groupMembers.begin(), groupMembers.end(), targetEdge->fromPass) != groupMembers.end()) {
677 predecessors.emplace_back(
678 predecessorPassIt->second,
689 for (
const auto* depthEdge : imageNode->getDepthStencilIncomingEdges()) {
690 if (std::find(groupMembers.begin(), groupMembers.end(), depthEdge->fromPass) != groupMembers.end()) {
693 predecessors.emplace_back(
694 predecessorPassIt->second,
707 orderedPassNames.push_back(passName);
724 const std::string& groupLeader) {
731 const std::vector<std::string>& orderedPassNames = orderIt->second;
733 passGroup->beginSubmit(cmdBuffer);
735 for (
size_t i = 0; i < orderedPassNames.size(); ++i) {
736 const std::string& passName = orderedPassNames[i];
743 if (i < orderedPassNames.size() - 1) {
744 passGroup->nextPass(cmdBuffer);
748 passGroup->endSubmit(cmdBuffer);
752 std::unordered_map<Image*, ImageState> imageStates;
754 for (
const auto& [imageName, imageNode] :
m_imageNodes) {
762 auto groupIt = passGroups.find(groupLeader);
763 if (groupIt == passGroups.end())
continue;
765 const auto& groupMembers = groupIt->second;
769 if (!barriers.empty()) {
778 const std::string& groupLeader,
779 const std::vector<std::string>& groupMembers,
780 const std::unordered_map<Image*, ImageState>& imageStates) {
782 std::vector<BarrierInfo> barriers;
783 std::set<Image*> processedImages;
785 for (
const std::string& passName : groupMembers) {
789 const auto& passNode = passIt->second;
791 for (
const auto* textureEdge : passNode.getTextureIncomingEdges()) {
792 auto imageNodeIt =
m_imageNodes.find(textureEdge->fromImage);
796 if (!image || processedImages.
count(image))
continue;
798 auto stateIt = imageStates.find(image);
799 if (stateIt == imageStates.end())
continue;
801 const ImageState& currentState = stateIt->second;
807 bool needsBarrier =
false;
822 barrier.
image = image;
837 barriers.push_back(barrier);
838 processedImages.insert(image);
847 const std::string& groupLeader,
848 const std::vector<std::string>& groupMembers,
849 std::unordered_map<Image*, ImageState>& imageStates) {
851 for (
const std::string& passName : groupMembers) {
855 const auto& passNode = passIt->second;
857 for (
const auto* targetEdge : passNode.getTargetOutgoingEdges()) {
858 auto imageNodeIt =
m_imageNodes.find(targetEdge->toImage);
862 if (!image)
continue;
871 for (
const auto* depthEdge : passNode.getDepthStencilOutgoingEdges()) {
872 auto imageNodeIt =
m_imageNodes.find(depthEdge->toImage);
876 if (!image)
continue;
885 for (
const auto* textureEdge : passNode.getTextureIncomingEdges()) {
886 auto imageNodeIt =
m_imageNodes.find(textureEdge->fromImage);
890 if (!image)
continue;
914 for (
const auto& barrier : barriers) {
947 return imageNodeIt->second->getImage();
956 return passNodeIt->second.getTextureIncomingEdges();
void trigger(const Event &event)
virtual Image * getImage() const
virtual void barrier(FCT::Image *image, ImageLayout oldLayout, ImageLayout newLayout, PipelineStages srcStage, PipelineStages dstStage, AccessFlags srcAccess, AccessFlags dstAccess, ImageAspects aspectMask=ImageAspect::color)=0
void depthStencil(FCT::Image *depthStencil)
static constexpr Pass * present
void enableClear(ClearTypes type, Vec4 color, float depth=1.0f, uint8_t stencil=0)
void bindTarget(uint32_t index, FCT::Image *target)
void simulateExecutionAndAnalyzeBarriers()
void simulatePassGroupExecution(const std::string &groupLeader, const std::vector< std::string > &groupMembers, std::unordered_map< Image *, ImageState > &imageStates)
RenderGraph(Device *device, FlowControl *flowControl, CommandBufferGraph *commandBufferGraph, ResourceManager *resourceManager)
void createTextureEdge(const std::string &passName, const std::string &textureName, const Texture &texture)
std::unordered_map< std::string, Image * > m_allocatedImages
std::unordered_map< std::string, std::unique_ptr< RenderGraphImageNode > > m_imageNodes
void allocateCommandBuffer()
Device * m_resourceDevice
FlowControl * m_flowControl
std::vector< TextureEdge * > getTextureEdges(const std::string &passName) const
void computePassGroupExecutionOrder()
RenderGraphImageNode * getOrCreateImageNode(const std::string &name, const Texture &texture)
void addPass(const PassDesc &desc)
void submitPassGroup(RHI::CommandBuffer *cmdBuffer, const std::string &groupLeader)
RHI::Pass * getPass(const std::string &name) const
void executeBarriers(RHI::CommandBuffer *cmdBuffer, const std::vector< BarrierInfo > &barriers)
CommandBufferGraph * m_commandBufferGraph
Image * getImage(const std::string &name) const
std::unordered_map< std::string, RHI::PassGroup * > m_allocatedPassGroups
std::unordered_map< std::string, RenderGraphPassNode > m_passNodes
ResourceManager * m_resourceManager
std::vector< std::string > m_passGroupExecutionOrder
std::vector< std::unique_ptr< Edge > > m_edges
UnionFind< std::string, char > m_passesUnions
std::unordered_map< std::string, std::vector< BarrierInfo > > m_passGroupBarriers
void executeAllPassGroups(RHI::CommandBuffer *cmdBuffer)
PipelineStage convertShaderStageToPipelineStage(ShaderStage stage) const
std::vector< std::string > topologicalSort(const std::map< std::string, std::set< std::string > > &dependencies) const
std::vector< BarrierInfo > checkBarriersBeforePassGroup(const std::string &groupLeader, const std::vector< std::string > &groupMembers, const std::unordered_map< Image *, ImageState > &imageStates)
std::unordered_map< std::string, RHI::Pass * > m_allocatedPasses
void createDepthStencilEdge(const std::string &passName, const std::string &depthStencilName, const DepthStencil &depthStencil)
void analyzePassGroupDependencies(const std::string &groupLeader, const std::vector< std::string > &groupMembers, std::map< std::string, std::set< std::string > > &dependencies) const
void resolveTextureSizes()
void createTargetEdge(const std::string &passName, const std::string &targetName, const Target &target)
std::unordered_map< std::string, std::vector< std::string > > m_passGroupOrders
CommandBufferToken m_commandBufferToken
const std::vector< TargetEdge * > & getTargetIncomingEdges() const
const std::vector< DepthStencilEdge * > & getDepthStencilIncomingEdges() const
Image * getImage() const override
Image * getImage() const override
constexpr const char * RenderGraphSubmit
@ depthStencilAttachmentWrite
constexpr const char * SwapBufferSubmitTicker
@ depthStencilAttachmentOptimal
ShaderStage getEarliestStage(ShaderStages stages)
std::vector< Texture > textures
std::vector< Target > targets
std::vector< DepthStencil > depthStencils
RHI::CommandBuffer * cmdBuf
ImageLayout currentLayout
std::string lastWriterGroup
const SizeNode * getRoot() const noexcept
bool isSizeDetermined() const noexcept
bool isSameSize(const SizeNode *other) const noexcept
bool unite(SizeNode *other, const FractionScale2D &scale=FractionScale2D()) const noexcept