From e7a8ad46148f42a95567fd4ce221f23184384ef8 Mon Sep 17 00:00:00 2001 From: Jake Turner Date: Sun, 24 Nov 2024 11:46:51 +0000 Subject: [PATCH] DXIL Control Flow Change FindUniformBlocks to ignore blocks in a loop --- .../driver/shaders/dxil/dxil_controlflow.cpp | 125 ++++++++++++++++-- 1 file changed, 112 insertions(+), 13 deletions(-) diff --git a/renderdoc/driver/shaders/dxil/dxil_controlflow.cpp b/renderdoc/driver/shaders/dxil/dxil_controlflow.cpp index 6eb0116a8..7dd82f64e 100644 --- a/renderdoc/driver/shaders/dxil/dxil_controlflow.cpp +++ b/renderdoc/driver/shaders/dxil/dxil_controlflow.cpp @@ -31,6 +31,7 @@ Inputs are links of blocks : from -> to (can be forwards or backwards links) Output is a list of uniform control flow blocks which all possible flows go through (not diverged) +and are not in a loop The algorithm is: @@ -46,8 +47,10 @@ already computed 3. Find Uniform Blocks * Generate a list of path indexes for each block in the paths - * uniform block is defined by any block which appears in all paths - * all paths includes walking any paths linked at the end node of the path being walked + * Generate a list of all paths blocks which are blocks which appear in all possible paths + * all paths includes walking any paths linked at the end node of the path being walked + * Generate a list of loop blocks which are blocks which appear in any path starting from the block + * uniform blocks are defined to be blocks which are all paths blocks minus loop blocks */ namespace DXIL @@ -62,7 +65,8 @@ private: typedef rdcarray BlockPath; bool TraceBlockFlow(const uint32_t from, BlockPath &path); - bool BlockInPath(uint32_t block, uint32_t pathIdx, uint32_t startIdx); + bool BlockInAllPaths(uint32_t block, uint32_t pathIdx, uint32_t startIdx); + bool BlockInAnyPath(uint32_t block, uint32_t pathIdx, uint32_t startIdx); const uint32_t PATH_END = ~0U; @@ -141,7 +145,50 @@ bool ControlFlow::TraceBlockFlow(const uint32_t from, BlockPath &path) return true; } -bool ControlFlow::BlockInPath(uint32_t block, uint32_t pathIdx, uint32_t startIdx) +bool ControlFlow::BlockInAnyPath(uint32_t block, uint32_t pathIdx, uint32_t startIdx) +{ + const rdcarray &path = m_Paths[pathIdx]; + if(path.size() == 0) + return false; + + // Check the current path + for(uint32_t i = startIdx; i < path.size(); ++i) + { + if(block == path[i]) + return true; + } + + uint32_t endNode = path[path.size() - 1]; + if(endNode == PATH_END) + return false; + + m_CheckedPaths.insert(endNode); + + // Check any paths linked to by the end node of the current path + const rdcarray &childPathsToCheck = m_BlockPathLinks[endNode]; + for(uint32_t childPathIdx : childPathsToCheck) + { + if(m_CheckedPaths.count(childPathIdx) != 0) + continue; + + m_CheckedPaths.insert(childPathIdx); + const rdcarray &childPath = m_Paths[childPathIdx]; + uint32_t childPartStartIdx = ~0U; + for(childPartStartIdx = 0; childPartStartIdx < childPath.size(); ++childPartStartIdx) + { + if(childPath[childPartStartIdx] == endNode) + break; + } + if(childPartStartIdx != ~0U) + { + if(BlockInAnyPath(block, childPathIdx, childPartStartIdx)) + return true; + } + } + return false; +} + +bool ControlFlow::BlockInAllPaths(uint32_t block, uint32_t pathIdx, uint32_t startIdx) { const rdcarray &path = m_Paths[pathIdx]; if(path.size() == 0) @@ -174,7 +221,7 @@ bool ControlFlow::BlockInPath(uint32_t block, uint32_t pathIdx, uint32_t startId if(childPath[childPartStartIdx] == endNode) break; } - if(!BlockInPath(block, childPathIdx, childPartStartIdx)) + if(!BlockInAllPaths(block, childPathIdx, childPartStartIdx)) return false; } return true; @@ -197,9 +244,37 @@ void ControlFlow::FindUniformBlocks(rdcarray &uniformBlocks) } } - uniformBlocks.clear(); + rdcarray loopBlocks; + // A loop block is defined by any block which appears in any path starting from the block + for(uint32_t block : m_Blocks) + { + bool loop = false; + for(uint32_t pathIdx = 0; pathIdx < m_Paths.size(); ++pathIdx) + { + m_CheckedPaths.clear(); + uint32_t startIdx = ~0U; + for(uint32_t i = 0; i < m_Paths[pathIdx].size() - 1; ++i) + { + if(m_Paths[pathIdx][i] == block) + { + startIdx = i; + break; + } + } + // BlockInAllPaths will also check all paths linked to from the end node of the path + if(startIdx != ~0U && BlockInAnyPath(block, pathIdx, startIdx + 1)) + { + loop = true; + break; + } + } + if(loop) + loopBlocks.push_back(block); + } - // A uniform block is defined by any block which appears in all paths + rdcarray allPathsBlocks; + + // An all paths block is defined by any block which appears in all paths // all paths includes walking any paths linked at the end node of the path being walked for(uint32_t block : m_Blocks) { @@ -207,14 +282,22 @@ void ControlFlow::FindUniformBlocks(rdcarray &uniformBlocks) for(uint32_t pathIdx = 0; pathIdx < m_Paths.size(); ++pathIdx) { m_CheckedPaths.clear(); - // BlockInPath will also check all paths linked to from the end node of the path - if(!BlockInPath(block, pathIdx, 0)) + // BlockInAllPaths will also check all paths linked to from the end node of the path + if(!BlockInAllPaths(block, pathIdx, 0)) { uniform = false; break; } } if(uniform) + allPathsBlocks.push_back(block); + } + + // A uniform block is defined as an all paths block which is not part of a loop + uniformBlocks.clear(); + for(uint32_t block : allPathsBlocks) + { + if(!loopBlocks.contains(block)) uniformBlocks.push_back(block); } } @@ -276,7 +359,7 @@ TEST_CASE("DXIL Control Flow", "[dxil]") } { - // Finite Loop (3 -> 4 -> 5 -> 3) + // Finite loop (3 -> 4 -> 5 -> 3) // 0 -> 1 -> 3 // 0 -> 2 -> 3 // 3 -> 4 -> 5 @@ -294,10 +377,26 @@ TEST_CASE("DXIL Control Flow", "[dxil]") inputs.push_back({5, 3}); inputs.push_back({5, 6}); DXIL::FindUniformBlocks(inputs, outputs); - REQUIRE(4 == outputs.count()); + REQUIRE(2 == outputs.count()); REQUIRE(outputs.contains(0U)); - REQUIRE(outputs.contains(3U)); - REQUIRE(outputs.contains(4U)); + REQUIRE(outputs.contains(6U)); + } + { + // Finite loop (3 -> 4 -> 5 -> 3) + rdcarray inputs; + inputs.push_back({0, 1}); + inputs.push_back({1, 2}); + inputs.push_back({0, 2}); + inputs.push_back({5, 3}); + inputs.push_back({2, 3}); + inputs.push_back({3, 4}); + inputs.push_back({4, 5}); + inputs.push_back({3, 5}); + inputs.push_back({5, 6}); + DXIL::FindUniformBlocks(inputs, outputs); + REQUIRE(3 == outputs.count()); + REQUIRE(outputs.contains(0U)); + REQUIRE(outputs.contains(2U)); REQUIRE(outputs.contains(6U)); }