void WriteBlockInstructions(ShaderBlock block, List <IShaderIR> instructions) { foreach (var ir in instructions) { WriteIR(ir); } }
public virtual void Visit(ShaderBlock shaderBlock) { foreach (var ir in shaderBlock.mOps) { Visit(ir); } }
public ShaderBlock CreateBlock(string debugBlockName) { var block = new ShaderBlock(); block.DebugInfo.Name = debugBlockName; return(block); }
public ShaderOp CreateOp(ShaderBlock block, OpInstructionType opType, ShaderType resultType, List <IShaderIR> arguments) { var resultOp = CreateOp(opType, resultType, arguments); block.mOps.Add(resultOp); return(resultOp); }
public ShaderOp CreateStoreOp(ShaderBlock block, IShaderIR variable, IShaderIR result) { var valueResult = GetOrGenerateValueTypeFromIR(block, result); return(CreateOp(block, OpInstructionType.OpStore, null, new List <IShaderIR> { variable, valueResult })); }
public void VisitMethod(CSharpSyntaxNode node, ShaderFunction shaderFunction) { var fnSymbol = mFrontEnd.mSemanticModel.GetDeclaredSymbol(node) as IMethodSymbol; // Handle intrinsics. If we have a resolver for a special handler then call that and return. if (SpecialResolvers.TryProcessIntrinsicMethod(mFrontEnd, fnSymbol)) { return; } // Add the current function as the active one and the parameter mContext.mCurrentFunction = shaderFunction; // Start writing out the parameters (so the parameter block is the active one) mContext.mCurrentBlock = shaderFunction.mParametersBlock; // Add the 'this' op if it exists if (!fnSymbol.IsStatic) { var selfType = mContext.mCurrentType; var thisType = selfType.FindPointerType(StorageClass.Function); var selfOp = CreateOp(mContext.mCurrentBlock, OpInstructionType.OpFunctionParameter, thisType, null); selfOp.DebugInfo.Name = "self"; mContext.mThisOp = selfOp; } // Add the function parameter ops foreach (var parameter in fnSymbol.Parameters) { var parameterType = FindParameterType(mFrontEnd.mCurrentLibrary.FindType(new TypeKey(parameter.Type)), parameter); var paramOp = CreateOp(mContext.mCurrentBlock, OpInstructionType.OpFunctionParameter, parameterType, null); // Extract the debug info. We can't get this from the node because the node isn't always a method with arguments. // // If this is a get/set then the arguments are implicit and there's no location to look at. if (parameter.Locations != null && parameter.Locations.Length != 0) { paramOp.DebugInfo.Location = parameter.Locations[0]; } paramOp.DebugInfo.Name = parameter.Name; // Also map parameter symbols in this scope to their ops so we can look them up later when visiting identifiers mContext.mSymbolToIRMap.Add(parameter, paramOp); } // Now set the body as the current scope and visit the function var firstBlock = new ShaderBlock(); shaderFunction.mBlocks.Add(firstBlock); mContext.mCurrentBlock = firstBlock; mCommonPass.Visit(node); // SpirV has some special rules about returns. Make sure to address these by fixing up missing terminators or removing extra functions. mFrontEnd.FixupBlockTerminators(shaderFunction); // Clear the function out of the current context mContext.mThisOp = null; mContext.mCurrentBlock = null; mContext.mCurrentFunction = null; }
void WriteDebugInstructions(ShaderBlock block) { WriteDebugName(block, block.DebugInfo.Name); foreach (var op in block.mLocalVariables) { WriteDebugName(op, op.DebugInfo.Name); } foreach (var op in block.mOps) { WriteDebugName(op, op.DebugInfo.Name); } }
void GenerateIds(ShaderBlock block) { GetId(block); foreach (var op in block.mLocalVariables) { GenerateIds(op); } foreach (var op in block.mOps) { GenerateIds(op); } }
public void GenerateLoopHeaderBlock(ShaderBlock headerBlock, ShaderBlock branchTarget, ShaderBlock mergeBlock, ShaderBlock continueBlock, FrontEndContext context) { // Mark the header block as a loop block (so we emit the LoopMerge instruction) headerBlock.mBlockType = BlockType.Loop; // Being a LoopMerge requires setting the merge and continue points headerBlock.mMergePoint = mergeBlock; headerBlock.mContinuePoint = continueBlock; var loopControlMask = mFrontEnd.CreateConstantLiteral <uint>((uint)Spv.LoopControlMask.LoopControlMaskNone); mFrontEnd.CreateOp(headerBlock, OpInstructionType.OpLoopMerge, null, new List <IShaderIR> { mergeBlock, continueBlock, loopControlMask }); // The header always jumps to the branch target (typically a continue) mFrontEnd.CreateOp(headerBlock, OpInstructionType.OpBranch, null, new List <IShaderIR> { branchTarget }); }
public void GenerateLoopStatements(StatementSyntax loopScopeNode, ShaderBlock loopBlock, ShaderBlock mergeBlock, ShaderBlock continueBlock, FrontEndContext context) { context.mCurrentBlock = loopBlock; // Set the continue and merge points for this block (mainly needed for nested loops) loopBlock.mContinuePoint = continueBlock; loopBlock.mMergePoint = mergeBlock; context.PushMergePoint(continueBlock, mergeBlock); // Iterate over all of the statements in the loop body Visit(loopScopeNode); // Write out a jump back to the continue block of the loop. Only write this to the active block // which will either be the end of the loop block or something like an after if if (context.mCurrentBlock.mTerminatorOp == null) { var currentBlockContinue = mFrontEnd.CreateOp(context.mCurrentBlock, OpInstructionType.OpBranch, null, new List <IShaderIR> { continueBlock }); } context.PopMergePoint(); }
public ShaderOp GetOrGenerateValueTypeFromIR(ShaderBlock block, IShaderIR ir) { var op = ir as ShaderOp; if (op == null) { return(null); } var opResultType = GetOpResultType(op); if (opResultType.mBaseType != OpType.Pointer) { return(op); } var opValueType = GetValueType(opResultType); var valueOp = CreateOp(block, OpInstructionType.OpLoad, opValueType, new List <IShaderIR> { op }); return(valueOp); }
public void GenerateLoopConditionBlock(SyntaxNode conditionalNode, ShaderBlock conditionBlock, ShaderBlock branchTrueBlock, ShaderBlock branchFalseBlock, FrontEndContext context) { // The condition builds the conditional and then jumps either to the body of the loop or to the end context.mCurrentBlock = conditionBlock; // If the conditional node exists if (conditionalNode != null) { //ExtractDebugInfo(conditionalNode->Condition, context->mDebugInfo); // Get the conditional value (must be a bool via how zilch works) IShaderIR conditional = WalkAndGetValueTypeResult(context.mCurrentBlock, conditionalNode); // Branch to either the true or false branch mFrontEnd.CreateOp(context.mCurrentBlock, OpInstructionType.OpBranchConditional, null, new List <IShaderIR> { conditional, branchTrueBlock, branchFalseBlock }); } // Otherwise there is no conditional (e.g. loop) so unconditionally branch to the true block else { mFrontEnd.CreateOp(context.mCurrentBlock, OpInstructionType.OpBranch, null, new List <IShaderIR> { branchTrueBlock }); } }
public IShaderIR WalkAndGetValueTypeResult(ShaderBlock block, SyntaxNode node) { var ir = WalkAndGetResult(node); return(mFrontEnd.GetOrGenerateValueTypeFromIR(block, ir)); }
public ShaderOp CreateOp(ShaderBlock block, OpInstructionType opType, ShaderType resultType, List <IShaderIR> arguments) { return(mFrontEnd.CreateOp(block, opType, resultType, arguments)); }
void WriteBlock(ShaderBlock block) { mWriter.WriteInstruction(2, Spv.Op.OpLabel, GetId(block)); WriteBlockInstructions(block, block.mLocalVariables); WriteBlockInstructions(block, block.mOps); }
public static void AddDecorationBlock(FrontEndTranslator translator, ShaderType shaderType, ShaderBlock decorationsBlock) { var decorationBlockLiteral = translator.CreateConstantLiteral((int)Spv.Decoration.DecorationBlock); translator.CreateOp(decorationsBlock, OpInstructionType.OpDecorate, null, new List <IShaderIR>() { shaderType, decorationBlockLiteral }); }
public static void AddDecorationLocations(FrontEndTranslator translator, ShaderType shaderType, ShaderInterfaceSet interfaceSet, LocationCallback locationCallback, ShaderBlock decorationsBlock) { int GetNextLocation(Dictionary <int, ShaderInterfaceField> usedLocations, int currLocation) { while (usedLocations.ContainsKey(currLocation)) { ++currLocation; } return(currLocation); }; var usedLocations = new Dictionary <int, ShaderInterfaceField>(); List <(ShaderInterfaceField Field, ShaderOp FieldOp)> unknownLocationFields = new List <(ShaderInterfaceField Field, ShaderOp FieldOp)>(); foreach (var field in interfaceSet) { var fieldOp = interfaceSet.GetFieldInstance(translator, field, null); int location = -1; int component = -1; locationCallback(field.ShaderField, out location, out component); if (location != -1) { Decorations.AddDecorationLocation(translator, fieldOp, location, decorationsBlock); usedLocations.Add(location, field); if (component != -1) { Decorations.AddDecorationComponent(translator, fieldOp, location, decorationsBlock); } } else { unknownLocationFields.Add((field, fieldOp)); } } var nextLocation = 0; foreach (var pair in unknownLocationFields) { nextLocation = GetNextLocation(usedLocations, nextLocation); Decorations.AddDecorationLocation(translator, pair.FieldOp, nextLocation, decorationsBlock); usedLocations.Add(nextLocation, pair.Field); } }
public static void AddDecorationMemberMatrixMajor(FrontEndTranslator translator, ShaderType shaderType, int fieldIndex, Spv.Decoration decoration, ShaderBlock decorationsBlock) { var decorationOffsetLiteral = translator.CreateConstantLiteral((int)decoration); var fieldIndexLiteral = translator.CreateConstantLiteral(fieldIndex); translator.CreateOp(decorationsBlock, OpInstructionType.OpMemberDecorate, null, new List <IShaderIR>() { shaderType, fieldIndexLiteral, decorationOffsetLiteral }); }
public static void AddDecorationBuiltIn(FrontEndTranslator translator, ShaderOp instanceOp, Spv.BuiltIn builtInType, ShaderBlock decorationsBlock) { var decorationBuiltInLiteral = translator.CreateConstantLiteral((int)Spv.Decoration.DecorationBuiltIn); var builtInTypeLiteral = translator.CreateConstantLiteral((int)builtInType); translator.CreateOp(decorationsBlock, OpInstructionType.OpDecorate, null, new List <IShaderIR>() { instanceOp, decorationBuiltInLiteral, builtInTypeLiteral }); }
public static void AddDecorationDescriptorSet(FrontEndTranslator translator, IShaderIR ir, int descriptorSetId, ShaderBlock decorationsBlock) { var decorationBindingLiteral = translator.CreateConstantLiteral((int)Spv.Decoration.DecorationDescriptorSet); var descriptorSetIdLiteral = translator.CreateConstantLiteral(descriptorSetId); translator.CreateOp(decorationsBlock, OpInstructionType.OpDecorate, null, new List <IShaderIR>() { ir, decorationBindingLiteral, descriptorSetIdLiteral }); }
public static void DecorateMatrixMajor(FrontEndTranslator translator, ShaderType shaderType, ShaderBlock decorationsBlock) { for (var fieldIndex = 0; fieldIndex < shaderType.mFields.Count; ++fieldIndex) { var field = shaderType.mFields[fieldIndex]; var fieldType = field.mType; // Recursively decorate structs if (fieldType.mBaseType == OpType.Struct) { DecorateMatrixMajor(translator, fieldType, decorationsBlock); } else if (fieldType.mBaseType == OpType.Matrix) { AddDecorationMemberColMajor(translator, shaderType, fieldIndex, decorationsBlock); } } }
public override void Visit(ShaderBlock shaderblock) { GetId(shaderblock); base.Visit(shaderblock); }
public void GenerateLoopContinueBlock(IEnumerable <SyntaxNode> iteratorNodes, ShaderBlock continueBlock, ShaderBlock headerBlock, FrontEndContext context) { // Mark the continue block as the active block context.mCurrentBlock = continueBlock; // If it exists, walk the iterator statement if (iteratorNodes != null) { foreach (var iteratorNode in iteratorNodes) { Visit(iteratorNode); } } // Always jump back to the header block mFrontEnd.CreateOp(continueBlock, OpInstructionType.OpBranch, null, new List <IShaderIR> { headerBlock }); }
public static void DecorateUniforms(FrontEndTranslator translator, ShaderOp instanceOp, ShaderBlock decorationsBlock) { var instanceType = instanceOp.mResultType.GetDereferenceType(); AddDecorationDescriptorSet(translator, instanceType, 0, decorationsBlock); AddDecorationBinding(translator, instanceType, 0, decorationsBlock); AddDecorationBlock(translator, instanceType, decorationsBlock); DecorateOffsets(translator, instanceType, decorationsBlock); }
public static void AddDecorationMemberColMajor(FrontEndTranslator translator, ShaderType shaderType, int fieldIndex, ShaderBlock decorationsBlock) { AddDecorationMemberMatrixMajor(translator, shaderType, fieldIndex, Spv.Decoration.DecorationColMajor, decorationsBlock); }
public static void AddDecorationLocation(FrontEndTranslator translator, ShaderOp instanceOp, int location, ShaderBlock decorationsBlock) { var decorationLocationLiteral = translator.CreateConstantLiteral((int)Spv.Decoration.DecorationLocation); var locationLiteral = translator.CreateConstantLiteral(location); translator.CreateOp(decorationsBlock, OpInstructionType.OpDecorate, null, new List <IShaderIR>() { instanceOp, decorationLocationLiteral, locationLiteral }); }
public static void DecorateOffsets(FrontEndTranslator translator, ShaderType shaderType, ShaderBlock decorationsBlock) { UInt32 currentByteOffset = 0; for (var fieldIndex = 0; fieldIndex < shaderType.mFields.Count; ++fieldIndex) { var field = shaderType.mFields[fieldIndex]; var fieldType = field.mType; // Recursively decorate structs if (fieldType.mBaseType == OpType.Struct) { DecorateOffsets(translator, fieldType, decorationsBlock); } var requiredAlignment = fieldType.ComputeByteAlignment(); var byteSize = fieldType.ComputeByteSize(); currentByteOffset = ShaderType.ComputeSizeAfterAlignment(currentByteOffset, requiredAlignment); AddDecorationMemberOffset(translator, shaderType, fieldIndex, currentByteOffset, decorationsBlock); currentByteOffset += byteSize; } }
public static void GenerateHardwareBuiltIns(FrontEndTranslator translator, ShaderInterfaceSet interfaceSet, StorageClass storageClass, ShaderBlock declarationBlock, ShaderBlock decorationsBlock) { foreach (var builtInInterfaceField in interfaceSet) { var pointerType = translator.FindOrCreatePointerType(builtInInterfaceField.ShaderField.mType, storageClass); var fieldInstanceOp = translator.CreateOp(OpInstructionType.OpVariable, pointerType, null); declarationBlock.mLocalVariables.Add(fieldInstanceOp); Decorations.AddDecorationBuiltIn(translator, fieldInstanceOp, builtInInterfaceField.BuiltInType, decorationsBlock); ShaderInterfaceField.InstanceAccessDelegate fieldInstanceGetFunction = (FrontEndTranslator translator, ShaderInterfaceField interfaceField, FrontEndContext context) => { return(fieldInstanceOp); }; builtInInterfaceField.GetInstance = fieldInstanceGetFunction; } }
public void Visit(ShaderBlock block) { Visit(block.mLocalVariables); Visit(block.mOps); }
public static void DecorateStrides(FrontEndTranslator translator, ShaderType shaderType, ShaderBlock decorationsBlock) { for (var fieldIndex = 0; fieldIndex < shaderType.mFields.Count; ++fieldIndex) { var field = shaderType.mFields[fieldIndex]; var fieldType = field.mType; // Recursively decorate structs if (fieldType.mBaseType == OpType.Struct) { DecorateStrides(translator, fieldType, decorationsBlock); } else if (fieldType.mBaseType == OpType.Matrix) { // Hardcode stride to size of a vec4 for performance reasons. // @JoshD: Maybe make a packing option for this later? int matrixStride = 16; AddDecorationMemberMatrixStride(translator, shaderType, fieldIndex, matrixStride, decorationsBlock); } } }