From 2e6368e6c21b96bf5aab0a9c736f528d26515d59 Mon Sep 17 00:00:00 2001 From: Jake Turner Date: Fri, 6 Dec 2024 08:14:21 +0000 Subject: [PATCH] DXIL ControlFlow optimisations, new APIs Use rdcarray instead of unordered_map, unordered_set for hot containers Made struct public and added new APIs rdcarray GetUniformBlocks(); rdcarray GetLoopBlocks(); uint32_t GetNextUniformBlock(uint32_t from); --- .../driver/shaders/dxil/dxil_controlflow.cpp | 677 ++++++++++++------ .../driver/shaders/dxil/dxil_controlflow.h | 32 +- renderdoc/driver/shaders/dxil/dxil_debug.cpp | 5 +- 3 files changed, 502 insertions(+), 212 deletions(-) diff --git a/renderdoc/driver/shaders/dxil/dxil_controlflow.cpp b/renderdoc/driver/shaders/dxil/dxil_controlflow.cpp index c31270626..86bfa0564 100644 --- a/renderdoc/driver/shaders/dxil/dxil_controlflow.cpp +++ b/renderdoc/driver/shaders/dxil/dxil_controlflow.cpp @@ -22,12 +22,9 @@ * THE SOFTWARE. ******************************************************************************/ -#include -#include - +#include "dxil_controlflow.h" #include "common/formatting.h" #include "core/settings.h" -#include "dxil_controlflow.h" RDOC_EXTERN_CONFIG(bool, D3D12_DXILShaderDebugger_Logging); @@ -59,41 +56,150 @@ already computed namespace DXIL { -struct ControlFlow +bool ControlFlow::TraceBlockFlow(const uint32_t from, BlockPath &path) { -public: - ControlFlow(const rdcarray> &links); - void FindUniformBlocks(rdcarray &uniformBlocks); + if(from == PATH_END) + { + m_Paths.push_back(path); + return true; + } + if(m_BlockLinks[from].empty()) + { + m_Paths.push_back(path); + return true; + } + if(m_TracedBlocks[from]) + { + m_Paths.push_back(path); + return true; + } + m_TracedBlocks[from] = true; + BlockPath newPath = path; + const rdcarray &gotos = m_BlockLinks.at(from); + for(uint32_t to : gotos) + { + newPath.push_back(to); + if(TraceBlockFlow(to, newPath)) + newPath = path; + } + return true; +} -private: - typedef rdcarray BlockPath; - - bool TraceBlockFlow(const uint32_t from, BlockPath &path); - 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; - - std::unordered_set m_Blocks; - std::unordered_map m_BlockLinks; - - std::unordered_map> m_BlockPathLinks; - std::unordered_set m_TracedBlocks; - std::unordered_set m_CheckedPaths; - rdcarray m_Paths; -}; - -ControlFlow::ControlFlow(const rdcarray> &links) +int32_t ControlFlow::BlockInAnyPath(uint32_t block, uint32_t pathIdx, int32_t startIdx, + int32_t steps) const { + const BlockPath &path = m_Paths[pathIdx]; + if(path.size() == 0) + return -1; + + // Check the current path + for(uint32_t i = startIdx; i < path.size(); ++i) + { + if(block == path[i]) + return steps; + ++steps; + } + + uint32_t endNode = path[path.size() - 1]; + if(endNode == PATH_END) + return -1; + + m_CheckedPaths[pathIdx] = true; + + // Check any paths linked to by the end node of the current path + const rdcarray &childPathsToCheck = m_BlockPathLinks.at(endNode); + for(uint32_t childPathIdx : childPathsToCheck) + { + if(m_CheckedPaths[childPathIdx]) + continue; + + m_CheckedPaths[childPathIdx] = true; + const BlockPath &childPath = m_Paths[childPathIdx]; + int32_t childPartStartIdx = -1; + int32_t newSteps = steps; + for(uint32_t i = 0; i < childPath.size(); ++i) + { + if(childPath[i] == endNode) + { + childPartStartIdx = i; + break; + } + ++newSteps; + } + if(childPartStartIdx != -1) + { + newSteps = BlockInAnyPath(block, childPathIdx, childPartStartIdx, newSteps); + if(newSteps != -1) + return newSteps; + } + } + return -1; +} + +bool ControlFlow::BlockInAllPaths(uint32_t block, uint32_t pathIdx, int32_t startIdx) const +{ + const BlockPath &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; + } + + m_CheckedPaths[pathIdx] = true; + uint32_t endNode = path[path.size() - 1]; + if(endNode == PATH_END) + return false; + + // Check any paths linked to by the end node of the current path + const rdcarray &childPathsToCheck = m_BlockPathLinks.at(endNode); + for(uint32_t childPathIdx : childPathsToCheck) + { + if(m_CheckedPaths[childPathIdx]) + continue; + + m_CheckedPaths[childPathIdx] = true; + int32_t childPartStartIdx = m_Paths[childPathIdx].indexOf(endNode); + RDCASSERTNOTEQUAL(childPartStartIdx, -1); + if(!BlockInAllPaths(block, childPathIdx, childPartStartIdx)) + return false; + } + return true; +} + +void ControlFlow::Construct(const rdcarray> &links) +{ + m_Blocks.clear(); + m_BlockLinks.clear(); + m_BlockPathLinks.clear(); + m_TracedBlocks.clear(); + m_CheckedPaths.clear(); + m_Paths.clear(); + + m_UniformBlocks.clear(); + m_LoopBlocks.clear(); + // 1. Setup // Compute all possible known blocks + uint32_t maxBlockIndex = 0; for(const auto &link : links) { uint32_t from = link.first; uint32_t to = link.second; m_Blocks.insert(from); m_Blocks.insert(to); + maxBlockIndex = RDCMAX(maxBlockIndex, from); + maxBlockIndex = RDCMAX(maxBlockIndex, to); } + ++maxBlockIndex; + m_TracedBlocks.resize(maxBlockIndex); + for(size_t i = 0; i < maxBlockIndex; ++i) + m_TracedBlocks[i] = false; + m_BlockLinks.resize(maxBlockIndex); + m_BlockPathLinks.resize(maxBlockIndex); // For each block a list of "to" blocks for(const auto &link : links) @@ -106,7 +212,7 @@ ControlFlow::ControlFlow(const rdcarray> &links) // Any block without links in the input are set to link to the end sentinel (PATH_END) for(uint32_t b : m_Blocks) { - if(m_BlockLinks.count(b) == 0) + if(m_BlockLinks[b].empty()) m_BlockLinks[b].push_back(PATH_END); } @@ -114,132 +220,18 @@ ControlFlow::ControlFlow(const rdcarray> &links) // Paths can terminate at the end block (PATH_END) // Paths can also terminate at a block before the end, if that block has had all its possible paths already computed - for(const auto &it : m_BlockLinks) + for(size_t i = 0; i < m_BlockLinks.size(); ++i) { - uint32_t from = it.first; - if(m_TracedBlocks.count(from) != 0) + uint32_t from = (uint32_t)i; + if(m_BlockLinks[i].empty()) + continue; + if(m_TracedBlocks[from]) continue; BlockPath path; path.push_back(from); TraceBlockFlow(from, path); } -} -bool ControlFlow::TraceBlockFlow(const uint32_t from, BlockPath &path) -{ - if(m_BlockLinks.count(from) == 0) - { - m_Paths.push_back(path); - return true; - } - if(m_TracedBlocks.count(from) != 0) - { - m_Paths.push_back(path); - return true; - } - m_TracedBlocks.insert(from); - BlockPath newPath = path; - const rdcarray &gotos = m_BlockLinks.at(from); - for(uint32_t to : gotos) - { - newPath.push_back(to); - if(TraceBlockFlow(to, newPath)) - newPath = path; - } - return true; -} - -bool ControlFlow::BlockInAnyPath(uint32_t block, uint32_t pathIdx, uint32_t startIdx) -{ - const BlockPath &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 BlockPath &childPath = m_Paths[childPathIdx]; - uint32_t childPartStartIdx = ~0U; - for(uint32_t i = 0; i < childPath.size(); ++i) - { - if(childPath[i] == endNode) - { - childPartStartIdx = i; - 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 BlockPath &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; - } - - m_CheckedPaths.insert(pathIdx); - uint32_t endNode = path[path.size() - 1]; - if(endNode == PATH_END) - return false; - - // 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 BlockPath &childPath = m_Paths[childPathIdx]; - uint32_t childPartStartIdx = ~0U; - for(uint32_t i = 0; i < childPath.size(); ++i) - { - if(childPath[i] == endNode) - { - childPartStartIdx = i; - break; - } - } - RDCASSERTNOTEQUAL(childPartStartIdx, ~0U); - if(!BlockInAllPaths(block, childPathIdx, childPartStartIdx)) - return false; - } - return true; -} - -void ControlFlow::FindUniformBlocks(rdcarray &uniformBlocks) -{ // 3. Find Uniform Blocks for(uint32_t b : m_Blocks) m_BlockPathLinks[b].clear(); @@ -275,7 +267,6 @@ void ControlFlow::FindUniformBlocks(rdcarray &uniformBlocks) } } - 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) { @@ -283,7 +274,10 @@ void ControlFlow::FindUniformBlocks(rdcarray &uniformBlocks) for(uint32_t pathIdx = 0; pathIdx < m_Paths.size(); ++pathIdx) { m_CheckedPaths.clear(); - uint32_t startIdx = ~0U; + m_CheckedPaths.resize(m_Paths.size()); + for(size_t i = 0; i < m_CheckedPaths.size(); ++i) + m_CheckedPaths[i] = false; + int32_t startIdx = -1; for(uint32_t i = 0; i < m_Paths[pathIdx].size() - 1; ++i) { if(m_Paths[pathIdx][i] == block) @@ -292,15 +286,15 @@ void ControlFlow::FindUniformBlocks(rdcarray &uniformBlocks) break; } } - // BlockInAllPaths will also check all paths linked to from the end node of the path - if(startIdx != ~0U && BlockInAnyPath(block, pathIdx, startIdx + 1)) + // BlockInAnyPath will also check all paths linked to from the end node of the path + if(startIdx != -1 && (BlockInAnyPath(block, pathIdx, startIdx + 1, 0) != -1)) { loop = true; break; } } if(loop) - loopBlocks.push_back(block); + m_LoopBlocks.push_back(block); } rdcarray allPathsBlocks; @@ -313,6 +307,9 @@ void ControlFlow::FindUniformBlocks(rdcarray &uniformBlocks) for(uint32_t pathIdx = 0; pathIdx < m_Paths.size(); ++pathIdx) { m_CheckedPaths.clear(); + m_CheckedPaths.resize(m_Paths.size()); + for(size_t i = 0; i < m_CheckedPaths.size(); ++i) + m_CheckedPaths[i] = false; // BlockInAllPaths will also check all paths linked to from the end node of the path if(!BlockInAllPaths(block, pathIdx, 0)) { @@ -325,20 +322,21 @@ void ControlFlow::FindUniformBlocks(rdcarray &uniformBlocks) } // 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); + if(!m_LoopBlocks.contains(block)) + m_UniformBlocks.push_back(block); } if(D3D12_DXILShaderDebugger_Logging()) { RDCLOG("Block Links:"); - for(auto it = m_BlockLinks.begin(); it != m_BlockLinks.end(); ++it) + for(size_t i = 0; i < m_BlockLinks.size(); ++i) { - uint32_t from = it->first; - for(uint32_t to : it->second) + uint32_t from = (uint32_t)i; + if(m_BlockLinks[i].empty()) + continue; + for(uint32_t to : m_BlockLinks[i]) RDCLOG("Block:%d->Block:%d", from, to); } @@ -367,7 +365,7 @@ void ControlFlow::FindUniformBlocks(rdcarray &uniformBlocks) output = ""; bool needComma = false; - for(uint32_t block : loopBlocks) + for(uint32_t block : m_LoopBlocks) { if(needComma) output += ", "; @@ -389,7 +387,7 @@ void ControlFlow::FindUniformBlocks(rdcarray &uniformBlocks) output = ""; needComma = false; - for(uint32_t block : uniformBlocks) + for(uint32_t block : m_UniformBlocks) { if(needComma) output += ", "; @@ -398,15 +396,43 @@ void ControlFlow::FindUniformBlocks(rdcarray &uniformBlocks) } RDCLOG("Uniform Blocks: %s", output.c_str()); } + + // Clear temporary data + m_TracedBlocks.clear(); + m_CheckedPaths.clear(); } -void FindUniformBlocks(const rdcarray &links, rdcarray &uniformBlocks) +uint32_t ControlFlow::GetNextUniformBlock(uint32_t from) const { - ControlFlow controlFlow(links); - - controlFlow.FindUniformBlocks(uniformBlocks); + // find the closest uniform block when walking the path starting at the from block + int32_t minSteps = INT_MAX; + uint32_t bestBlock = from; + for(uint32_t uniform : m_UniformBlocks) + { + for(uint32_t pathIdx = 0; pathIdx < m_Paths.size(); ++pathIdx) + { + m_CheckedPaths.clear(); + m_CheckedPaths.resize(m_Paths.size()); + for(size_t i = 0; i < m_CheckedPaths.size(); ++i) + m_CheckedPaths[i] = false; + int32_t startIdx = m_Paths[pathIdx].indexOf(from); + // BlockInAnyPath will also check all paths linked to from the end node of the path + if(startIdx != -1) + { + int32_t steps = BlockInAnyPath(uniform, pathIdx, startIdx + 1, 0); + if(steps != -1) + { + if(steps < minSteps) + { + minSteps = steps; + bestBlock = uniform; + } + } + } + } + } + return bestBlock; } - }; // namespace DXIL #if ENABLED(ENABLE_UNIT_TESTS) @@ -420,22 +446,30 @@ TEST_CASE("DXIL Control Flow", "[dxil]") { SECTION("FindUniformBlocks") { - rdcarray outputs; + ControlFlow controlFlow; + rdcarray uniformBlocks; + rdcarray loopBlocks; { // Degenerate case rdcarray inputs; - DXIL::FindUniformBlocks(inputs, outputs); - REQUIRE(0 == outputs.count()); + controlFlow.Construct(inputs); + uniformBlocks = controlFlow.GetUniformBlocks(); + REQUIRE(0 == uniformBlocks.count()); + loopBlocks = controlFlow.GetLoopBlocks(); + REQUIRE(0 == loopBlocks.count()); } { // Only uniform flow is the start and end // 0 -> 1 rdcarray inputs; inputs.push_back({0, 1}); - DXIL::FindUniformBlocks(inputs, outputs); - REQUIRE(2 == outputs.count()); - REQUIRE(outputs.contains(0U)); - REQUIRE(outputs.contains(1U)); + controlFlow.Construct(inputs); + uniformBlocks = controlFlow.GetUniformBlocks(); + REQUIRE(2 == uniformBlocks.count()); + REQUIRE(uniformBlocks.contains(0U)); + REQUIRE(uniformBlocks.contains(1U)); + loopBlocks = controlFlow.GetLoopBlocks(); + REQUIRE(0 == loopBlocks.count()); } { @@ -449,11 +483,14 @@ TEST_CASE("DXIL Control Flow", "[dxil]") inputs.push_back({0, 2}); inputs.push_back({2, 3}); inputs.push_back({3, 4}); - DXIL::FindUniformBlocks(inputs, outputs); - REQUIRE(3 == outputs.count()); - REQUIRE(outputs.contains(0U)); - REQUIRE(outputs.contains(3U)); - REQUIRE(outputs.contains(4U)); + controlFlow.Construct(inputs); + uniformBlocks = controlFlow.GetUniformBlocks(); + REQUIRE(3 == uniformBlocks.count()); + REQUIRE(uniformBlocks.contains(0U)); + REQUIRE(uniformBlocks.contains(3U)); + REQUIRE(uniformBlocks.contains(4U)); + loopBlocks = controlFlow.GetLoopBlocks(); + REQUIRE(0 == loopBlocks.count()); } { @@ -471,11 +508,14 @@ TEST_CASE("DXIL Control Flow", "[dxil]") inputs.push_back({2, 3}); inputs.push_back({2, 4}); inputs.push_back({3, 4}); - DXIL::FindUniformBlocks(inputs, outputs); - REQUIRE(3 == outputs.count()); - REQUIRE(outputs.contains(0U)); - REQUIRE(outputs.contains(2U)); - REQUIRE(outputs.contains(4U)); + controlFlow.Construct(inputs); + uniformBlocks = controlFlow.GetUniformBlocks(); + REQUIRE(3 == uniformBlocks.count()); + REQUIRE(uniformBlocks.contains(0U)); + REQUIRE(uniformBlocks.contains(2U)); + REQUIRE(uniformBlocks.contains(4U)); + loopBlocks = controlFlow.GetLoopBlocks(); + REQUIRE(0 == loopBlocks.count()); } { // Finite loop (3 -> 4 -> 5 -> 3) @@ -495,28 +535,45 @@ TEST_CASE("DXIL Control Flow", "[dxil]") inputs.push_back({4, 6}); inputs.push_back({5, 3}); inputs.push_back({5, 6}); - DXIL::FindUniformBlocks(inputs, outputs); - REQUIRE(2 == outputs.count()); - REQUIRE(outputs.contains(0U)); - REQUIRE(outputs.contains(6U)); + controlFlow.Construct(inputs); + uniformBlocks = controlFlow.GetUniformBlocks(); + REQUIRE(2 == uniformBlocks.count()); + REQUIRE(uniformBlocks.contains(0U)); + REQUIRE(uniformBlocks.contains(6U)); + loopBlocks = controlFlow.GetLoopBlocks(); + REQUIRE(3 == loopBlocks.count()); + REQUIRE(loopBlocks.contains(3U)); + REQUIRE(loopBlocks.contains(4U)); + REQUIRE(loopBlocks.contains(5U)); } { // Finite loop (3 -> 4 -> 5 -> 3) + // 0 -> 1 -> 2 + // 0 -> 2 + // 2 -> 3 + // 3 -> 4 -> 5 -> 6 + // 3 -> 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)); + inputs.push_back({3, 5}); + inputs.push_back({5, 3}); + controlFlow.Construct(inputs); + uniformBlocks = controlFlow.GetUniformBlocks(); + REQUIRE(3 == uniformBlocks.count()); + REQUIRE(uniformBlocks.contains(0U)); + REQUIRE(uniformBlocks.contains(2U)); + REQUIRE(uniformBlocks.contains(6U)); + loopBlocks = controlFlow.GetLoopBlocks(); + REQUIRE(3 == loopBlocks.count()); + REQUIRE(loopBlocks.contains(3U)); + REQUIRE(loopBlocks.contains(4U)); + REQUIRE(loopBlocks.contains(5U)); } { @@ -536,14 +593,34 @@ TEST_CASE("DXIL Control Flow", "[dxil]") inputs.push_back({4, 3}); inputs.push_back({1, 6}); inputs.push_back({2, 6}); - DXIL::FindUniformBlocks(inputs, outputs); - REQUIRE(2 == outputs.count()); - REQUIRE(outputs.contains(0U)); - REQUIRE(outputs.contains(6U)); + controlFlow.Construct(inputs); + uniformBlocks = controlFlow.GetUniformBlocks(); + REQUIRE(2 == uniformBlocks.count()); + REQUIRE(uniformBlocks.contains(0U)); + REQUIRE(uniformBlocks.contains(6U)); + loopBlocks = controlFlow.GetLoopBlocks(); + REQUIRE(2 == loopBlocks.count()); + REQUIRE(loopBlocks.contains(3U)); + REQUIRE(loopBlocks.contains(4U)); } { - // Complex case with multiple loops + // Complex case with two loops + // Loop: 7 -> 9 -> 7, 13 -> 15 -> 13 + // 0 -> 1 -> 3 + // 0 -> 2 -> 3 + // 3 -> 4 -> 5 + // 3 -> 5 + // 5 -> 6 -> 7 + // 5 -> 11 + // 7 -> 8 -> 11 + // 7 -> 9 -> 7 + // 9 -> 10 -> 11 -> 12 -> 13 -> 14 -> 17 -> 18 -> 19 -> 20 -> 21 -> 22 -> 23 -> 26 + // 13 -> 15 -> 13 + // 15 -> 16 -> 17 -> 19 -> 21 -> 26 + // 11 -> 17 + // 22 -> 24 -> 25 -> 26 + // 24 -> 26 rdcarray inputs; inputs.push_back({0, 1}); inputs.push_back({0, 2}); @@ -584,18 +661,200 @@ TEST_CASE("DXIL Control Flow", "[dxil]") inputs.push_back({24, 26}); inputs.push_back({23, 26}); inputs.push_back({21, 26}); - DXIL::FindUniformBlocks(inputs, outputs); - REQUIRE(8 == outputs.count()); - REQUIRE(outputs.contains(0U)); - REQUIRE(outputs.contains(3U)); - REQUIRE(outputs.contains(5U)); - REQUIRE(outputs.contains(11U)); - REQUIRE(outputs.contains(17U)); - REQUIRE(outputs.contains(19U)); - REQUIRE(outputs.contains(21U)); - REQUIRE(outputs.contains(26U)); + controlFlow.Construct(inputs); + uniformBlocks = controlFlow.GetUniformBlocks(); + REQUIRE(8 == uniformBlocks.count()); + REQUIRE(uniformBlocks.contains(0U)); + REQUIRE(uniformBlocks.contains(3U)); + REQUIRE(uniformBlocks.contains(5U)); + REQUIRE(uniformBlocks.contains(11U)); + REQUIRE(uniformBlocks.contains(17U)); + REQUIRE(uniformBlocks.contains(19U)); + REQUIRE(uniformBlocks.contains(21U)); + REQUIRE(uniformBlocks.contains(26U)); + loopBlocks = controlFlow.GetLoopBlocks(); + REQUIRE(4 == loopBlocks.count()); + REQUIRE(loopBlocks.contains(7U)); + REQUIRE(loopBlocks.contains(9U)); + REQUIRE(loopBlocks.contains(13U)); + REQUIRE(loopBlocks.contains(15U)); + } + { + // Complex case with multiple loops: 4 -> 5 -> 6 -> 4, 10 -> 11 -> 12 -> 10, 68 + // 0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 4 + // 0 -> 2 -> 8 -> 9 -> 10 -> 11 -> 12 -> 10 + // 4 -> 6 -> 7 -> 8 -> 14 -> 15 -> 19 -> 20 -> 24 -> 25 -> 29 -> 31 -> 32 -> 33 + // 10 -> 12 -> 13 -> 14 -> 16 -> 17 -> 19 + // 16 -> 18 -> 19 -> 21 -> 22 -> 23 -> 24 -> 26 -> 27 -> 29 -> 30 -> 33 -> 35 -> 37 + // 22 -> 24 + // 26 -> 28 -> 29 + + // 31 -> 33 -> 34 -> 37 -> 39 -> 40 -> 41 -> 42 -> 43 -> 44 -> 45 -> 47 -> 49 -> 51 -> 52 -> + // 53 -> 54 -> 55 -> 57 -> 58 -> 59 -> 60 -> 61 -> 62 -> 63 -> 64 -> 65 -> 66 -> 68 -> 67 -> + // 69 -> 70 -> 71 -> 72 -> 73 -> 74 -> 75 -> 76 -> 77 -> 78 -> 79 -> END + + // 35 -> 36 -> 37 -> 38 -> 41 39 -> 41 -> 43 -> 45 -> 46 -> 47 -> 48 -> 49 -> 50 -> 51 + // 51 -> 53 -> 55 -> 56 -> 57 -> 59 -> 61 -> 63 -> 65 -> 69 -> 71 -> 73 -> 75 -> 77 -> 79 + // 68 -> 68 + rdcarray inputs; + inputs.push_back({8, 9}); + inputs.push_back({8, 14}); + inputs.push_back({64, 65}); + inputs.push_back({0, 1}); + inputs.push_back({0, 2}); + inputs.push_back({1, 2}); + inputs.push_back({2, 3}); + inputs.push_back({2, 8}); + inputs.push_back({6, 4}); + inputs.push_back({6, 7}); + inputs.push_back({3, 4}); + inputs.push_back({4, 5}); + inputs.push_back({4, 6}); + inputs.push_back({5, 6}); + inputs.push_back({7, 8}); + inputs.push_back({12, 10}); + inputs.push_back({12, 13}); + inputs.push_back({9, 10}); + inputs.push_back({10, 11}); + inputs.push_back({10, 12}); + inputs.push_back({11, 12}); + inputs.push_back({13, 14}); + inputs.push_back({14, 15}); + inputs.push_back({14, 16}); + inputs.push_back({16, 17}); + inputs.push_back({16, 18}); + inputs.push_back({18, 19}); + inputs.push_back({17, 19}); + inputs.push_back({15, 19}); + inputs.push_back({19, 20}); + inputs.push_back({19, 21}); + inputs.push_back({21, 22}); + inputs.push_back({21, 23}); + inputs.push_back({23, 24}); + inputs.push_back({22, 24}); + inputs.push_back({20, 24}); + inputs.push_back({24, 25}); + inputs.push_back({24, 26}); + inputs.push_back({26, 27}); + inputs.push_back({26, 28}); + inputs.push_back({28, 29}); + inputs.push_back({27, 29}); + inputs.push_back({25, 29}); + inputs.push_back({29, 30}); + inputs.push_back({29, 31}); + inputs.push_back({31, 32}); + inputs.push_back({31, 33}); + inputs.push_back({32, 33}); + inputs.push_back({30, 33}); + inputs.push_back({33, 34}); + inputs.push_back({33, 35}); + inputs.push_back({35, 37}); + inputs.push_back({35, 36}); + inputs.push_back({36, 37}); + inputs.push_back({34, 37}); + inputs.push_back({37, 38}); + inputs.push_back({37, 39}); + inputs.push_back({39, 40}); + inputs.push_back({39, 41}); + inputs.push_back({40, 41}); + inputs.push_back({38, 41}); + inputs.push_back({41, 42}); + inputs.push_back({41, 43}); + inputs.push_back({42, 43}); + inputs.push_back({43, 44}); + inputs.push_back({43, 45}); + inputs.push_back({44, 45}); + inputs.push_back({45, 46}); + inputs.push_back({45, 47}); + inputs.push_back({46, 47}); + inputs.push_back({47, 48}); + inputs.push_back({47, 49}); + inputs.push_back({48, 49}); + inputs.push_back({49, 50}); + inputs.push_back({49, 51}); + inputs.push_back({50, 51}); + inputs.push_back({51, 52}); + inputs.push_back({51, 53}); + inputs.push_back({52, 53}); + inputs.push_back({53, 54}); + inputs.push_back({53, 55}); + inputs.push_back({54, 55}); + inputs.push_back({55, 56}); + inputs.push_back({55, 57}); + inputs.push_back({56, 57}); + inputs.push_back({57, 58}); + inputs.push_back({57, 59}); + inputs.push_back({58, 59}); + inputs.push_back({59, 60}); + inputs.push_back({59, 61}); + inputs.push_back({60, 61}); + inputs.push_back({61, 62}); + inputs.push_back({61, 63}); + inputs.push_back({62, 63}); + inputs.push_back({63, 64}); + inputs.push_back({63, 65}); + inputs.push_back({65, 66}); + inputs.push_back({65, 69}); + inputs.push_back({68, 67}); + inputs.push_back({68, 68}); + inputs.push_back({66, 68}); + inputs.push_back({67, 69}); + inputs.push_back({69, 70}); + inputs.push_back({69, 71}); + inputs.push_back({70, 71}); + inputs.push_back({71, 72}); + inputs.push_back({71, 73}); + inputs.push_back({72, 73}); + inputs.push_back({73, 74}); + inputs.push_back({73, 75}); + inputs.push_back({74, 75}); + inputs.push_back({75, 76}); + inputs.push_back({75, 77}); + inputs.push_back({76, 77}); + inputs.push_back({77, 78}); + inputs.push_back({77, 79}); + inputs.push_back({78, 79}); + controlFlow.Construct(inputs); + uniformBlocks = controlFlow.GetUniformBlocks(); + REQUIRE(28 == uniformBlocks.count()); + REQUIRE(uniformBlocks.contains(0U)); + REQUIRE(uniformBlocks.contains(2U)); + REQUIRE(uniformBlocks.contains(8U)); + REQUIRE(uniformBlocks.contains(14U)); + REQUIRE(uniformBlocks.contains(19U)); + REQUIRE(uniformBlocks.contains(24U)); + REQUIRE(uniformBlocks.contains(29U)); + REQUIRE(uniformBlocks.contains(33U)); + REQUIRE(uniformBlocks.contains(37U)); + REQUIRE(uniformBlocks.contains(41U)); + REQUIRE(uniformBlocks.contains(43U)); + REQUIRE(uniformBlocks.contains(45U)); + REQUIRE(uniformBlocks.contains(47U)); + REQUIRE(uniformBlocks.contains(49U)); + REQUIRE(uniformBlocks.contains(51U)); + REQUIRE(uniformBlocks.contains(53U)); + REQUIRE(uniformBlocks.contains(55U)); + REQUIRE(uniformBlocks.contains(57U)); + REQUIRE(uniformBlocks.contains(59U)); + REQUIRE(uniformBlocks.contains(61U)); + REQUIRE(uniformBlocks.contains(63U)); + REQUIRE(uniformBlocks.contains(65U)); + REQUIRE(uniformBlocks.contains(69U)); + REQUIRE(uniformBlocks.contains(71U)); + REQUIRE(uniformBlocks.contains(73U)); + REQUIRE(uniformBlocks.contains(75U)); + REQUIRE(uniformBlocks.contains(77U)); + REQUIRE(uniformBlocks.contains(79U)); + loopBlocks = controlFlow.GetLoopBlocks(); + REQUIRE(7 == loopBlocks.count()); + REQUIRE(loopBlocks.contains(4U)); + REQUIRE(loopBlocks.contains(5U)); + REQUIRE(loopBlocks.contains(6U)); + REQUIRE(loopBlocks.contains(10U)); + REQUIRE(loopBlocks.contains(11U)); + REQUIRE(loopBlocks.contains(12U)); + REQUIRE(loopBlocks.contains(68U)); } }; }; - #endif // ENABLED(ENABLE_UNIT_TESTS) diff --git a/renderdoc/driver/shaders/dxil/dxil_controlflow.h b/renderdoc/driver/shaders/dxil/dxil_controlflow.h index cb6108a1a..55acfa40f 100644 --- a/renderdoc/driver/shaders/dxil/dxil_controlflow.h +++ b/renderdoc/driver/shaders/dxil/dxil_controlflow.h @@ -24,10 +24,40 @@ #pragma once +#include + namespace DXIL { typedef rdcpair BlockLink; -void FindUniformBlocks(const rdcarray &links, rdcarray &uniformBlocks); +struct ControlFlow +{ +public: + ControlFlow() = default; + ControlFlow(const rdcarray> &links) { Construct(links); } + void Construct(const rdcarray> &links); + rdcarray GetUniformBlocks() const { return m_UniformBlocks; } + rdcarray GetLoopBlocks() const { return m_LoopBlocks; } + uint32_t GetNextUniformBlock(uint32_t from) const; +private: + typedef rdcarray BlockPath; + + bool TraceBlockFlow(const uint32_t from, BlockPath &path); + bool BlockInAllPaths(uint32_t block, uint32_t pathIdx, int32_t startIdx) const; + int32_t BlockInAnyPath(uint32_t block, uint32_t pathIdx, int32_t startIdx, int32_t steps) const; + + const uint32_t PATH_END = ~0U; + + std::unordered_set m_Blocks; + rdcarray m_BlockLinks; + + rdcarray> m_BlockPathLinks; + mutable rdcarray m_TracedBlocks; + mutable rdcarray m_CheckedPaths; + rdcarray m_Paths; + + rdcarray m_UniformBlocks; + rdcarray m_LoopBlocks; +}; }; // namespace DXIL diff --git a/renderdoc/driver/shaders/dxil/dxil_debug.cpp b/renderdoc/driver/shaders/dxil/dxil_debug.cpp index 8f3fc479b..c72b3352a 100644 --- a/renderdoc/driver/shaders/dxil/dxil_debug.cpp +++ b/renderdoc/driver/shaders/dxil/dxil_debug.cpp @@ -6489,8 +6489,9 @@ ShaderDebugTrace *Debugger::BeginDebug(uint32_t eventId, const DXBC::DXBCContain } } } - DXIL::FindUniformBlocks(links, info.uniformBlocks); - // Handle de-generate case when a single block + ControlFlow controlFlow(links); + info.uniformBlocks = controlFlow.GetUniformBlocks(); + // Handle de-generate case when a single block if(info.uniformBlocks.empty()) { RDCASSERTEQUAL(f->blocks.size(), 1);