| 1752 | } |
| 1753 | |
| 1754 | bool AutoAssignRegistersForNode( ParserState& state, ASTNode* functionHeader, const FileLocation& messageLocation ) |
| 1755 | { |
| 1756 | /* |
| 1757 | |
| 1758 | This function assigns "registers" i.e. Metal input attributes [[buffer(###)]] or [[texture(###)]] to the shader arguments. |
| 1759 | Metal partitions the set off all inputs into "buffers" and "textures", which is somewhat different from DirectX that partitions |
| 1760 | the inputs into "constant buffers", SRVs and UAVs. Since Trinity uses DirectX partitioning for inputs we need to adapt Metal |
| 1761 | to that. This puts some extra limitations on the allocation of registers. For metal we use a single set or "registers" (up to |
| 1762 | 31 registers - the limit for min supported macOS): all SRV/UAV buffers and textures go into this set of "registers". Constant |
| 1763 | buffers are in a separate set. We map these to sets to "buffers" and "textures" for Metal. |
| 1764 | |
| 1765 | Firstly, we reserve 4 first slots in [[buffer(###)]] metal set for IA buffers |
| 1766 | Secondly, we reserve space in [[buffer(###)]] metal set for all constant buffers as they have an explicit register binding. We map |
| 1767 | them with an offset of 4, so for example the Globals constant buffer (cb0) would be mapped to [[buffer(4)]]. |
| 1768 | Then we allocate any unused [[buffer(###)]] indices for SRV/UAV buffer inputs. For example, if [[buffer(5)]] is not assigned, the |
| 1769 | next SRV/UAV buffer gets assigned to that slot and also recieves SRV register #5 as if it was declared register(t5) in HLSL. |
| 1770 | Lastly we allocate SRV/UAV texture registers, making sure we don't put them into the same SRV "register" as a previously allocated |
| 1771 | SRV/UAV buffer. |
| 1772 | |
| 1773 | */ |
| 1774 | |
| 1775 | auto GetAssignedSymbolNames = []( const std::vector<Symbol*>& symbols ) { |
| 1776 | std::string result; |
| 1777 | for( auto symbol : symbols ) |
| 1778 | { |
| 1779 | if( !result.empty() ) |
| 1780 | { |
| 1781 | result += ", "; |
| 1782 | } |
| 1783 | result += ToString( symbol->name ); |
| 1784 | } |
| 1785 | return result; |
| 1786 | }; |
| 1787 | |
| 1788 | auto RecordRegister = [&state]( int index, std::vector<Symbol*>& registers, ASTNode* node ) { |
| 1789 | Symbol* symbol = node->GetSymbol(); |
| 1790 | |
| 1791 | if( index < 0 || index >= int( registers.size() ) ) |
| 1792 | { |
| 1793 | state.ShowMessage( |
| 1794 | node->GetLocation(), |
| 1795 | EC_CUSTOM_ERROR, |
| 1796 | "Couldn't allocate a register for %s. Reason: Invalid register index.", |
| 1797 | ToString( symbol->name ).c_str() ); |
| 1798 | return false; |
| 1799 | } |
| 1800 | |
| 1801 | if( !registers[index] ) |
| 1802 | { |
| 1803 | registers[index] = symbol; |
| 1804 | return true; |
| 1805 | } |
| 1806 | else |
| 1807 | { |
| 1808 | state.ShowMessage( |
| 1809 | node->GetLocation(), |
| 1810 | EC_CUSTOM_ERROR, |
| 1811 | "Couldn't allocate a register for %s. Reason: register %d already assigned to %s.", |
no test coverage detected