예제 #1
0
        /// <summary>
        /// Does a simple intrinsic (one where all ops are value types).
        /// </summary>
        static void SimpleValueTypeIntrinsic(FrontEndTranslator translator, FrontEndContext context, OpInstructionType opType, ShaderType returnType, List <IShaderIR> arguments)
        {
            var valueOps = new List <IShaderIR>();

            foreach (var argument in arguments)
            {
                valueOps.Add(translator.GetOrGenerateValueTypeFromIR(context.mCurrentBlock, argument));
            }
            var op = translator.CreateOp(context.mCurrentBlock, opType, returnType, valueOps);

            context.Push(op);
        }
예제 #2
0
        public void Translate(FrontEndTranslator translator, CSharpCompilation compilation, List <SyntaxTree> trees)
        {
            FrontEndContext context = new FrontEndContext();

            context.mFrontEnd = translator;
            foreach (var pass in mPasses)
            {
                pass.Visit(translator, compilation, trees, context);
            }

            // Validation passes
        }
예제 #3
0
        public static ShaderEntryPointInfo GeneratePixel(FrontEndTranslator translator, ShaderType shaderType, ShaderFunction function)
        {
            var entryPoint = new ShaderEntryPointInfo();
            var context    = new FrontEndContext();

            context.mCurrentType = shaderType;

            var interfaceInfo = new EntryPointInterfaceInfo();

            EntryPointGenerationShared.CollectInterface(translator, shaderType, interfaceInfo);

            // Build inputs block
            EntryPointGenerationShared.GenerateHardwareBuiltIns(translator, interfaceInfo.HardwareBuiltInInputs, StorageClass.Input, entryPoint.mInterfaceVariables, entryPoint.mDecorations);
            InputDeclarations.GenerateInputStruct(translator, shaderType, interfaceInfo.StageInputs, entryPoint.mInterfaceVariables, entryPoint.mDecorations);
            EntryPointGenerationShared.GenerateHardwareBuiltIns(translator, interfaceInfo.HardwareBuiltInOutputs, StorageClass.Output, entryPoint.mInterfaceVariables, entryPoint.mDecorations);
            OutputDeclarations.GenerateOutputFields(translator, shaderType, interfaceInfo.StageOutputs, entryPoint.mInterfaceVariables, entryPoint.mDecorations);
            UniformDeclarations.DeclareUniformBuffers(translator, interfaceInfo.UniformBuffers, entryPoint.mInterfaceVariables, entryPoint.mDecorations);
            UniformDeclarations.DeclareUniformConstants(translator, interfaceInfo.ConstantUniforms, entryPoint.mDecorations);

            // Create the functions required to run an entry point
            string entryPointName = EntryPointGenerationShared.GenerateEntryPointFunctionName(translator, shaderType, function);

            CreateGlobalVariableInitializeFunction(translator, shaderType, entryPoint, interfaceInfo, context);
            InputDeclarations.GenerateCopyInputsFunction(translator, shaderType, entryPoint, interfaceInfo);
            OutputDeclarations.GenerateCopyOutputsFunction(translator, shaderType, entryPoint, interfaceInfo);
            var entryPointFunction = GenerateSpirVEntryPointFunction(translator, shaderType, entryPointName);

            // Generate the entry point function body
            translator.TryGenerateFunctionCall(entryPoint.mGlobalsInitializationFunction, null, null, entryPointFunction.Context);
            EntryPointGenerationShared.ConstructShaderType(translator, shaderType, entryPointFunction.Context);

            var entryPointThisOp = entryPointFunction.Context.mThisOp;

            translator.TryGenerateFunctionCall(interfaceInfo.CopyInputsFunction.ShaderFunction, entryPointThisOp, null, entryPointFunction.Context);
            translator.TryGenerateFunctionCall(function, entryPointThisOp, null, entryPointFunction.Context);
            translator.TryGenerateFunctionCall(interfaceInfo.CopyOutputsFunction.ShaderFunction, entryPointThisOp, null, entryPointFunction.Context);
            translator.FixupBlockTerminators(entryPointFunction.ShaderFunction);

            // Make sure all global variables are added to the interface of the entry point
            AddGlobalVariables(translator, entryPoint, interfaceInfo);

            entryPoint.mEntryPointFunction = entryPointFunction.ShaderFunction;
            entryPoint.mStageType          = shaderType.mFragmentType;
            shaderType.mEntryPoints.Add(entryPoint);

            EntryPointGenerationShared.AddExecutionMode(translator, entryPoint, entryPoint.mEntryPointFunction, Spv.ExecutionMode.ExecutionModeOriginUpperLeft);
            return(entryPoint);
        }
예제 #4
0
        public static EntryPointFunction GenerateEntryPointCopyFunction(FrontEndTranslator translator, ShaderType shaderType, string functionName)
        {
            ShaderOp thisOp         = null;
            var      shaderFunction = GenerateFunction_ShaderTypeParam(translator, shaderType, functionName, out thisOp);
            var      context        = new FrontEndContext();

            context.mCurrentBlock    = shaderFunction.mBlocks[0];
            context.mCurrentFunction = shaderFunction;

            var entryPointFunction = new EntryPointFunction();

            entryPointFunction.Context              = context;
            entryPointFunction.ShaderFunction       = shaderFunction;
            entryPointFunction.ShaderTypeInstanceOp = thisOp;
            return(entryPointFunction);
        }
예제 #5
0
        /// <summary>
        /// Does a simple extension intrinsic (one where all ops are value types).
        /// </summary>
        static void ResolveSimpleExtensionIntrinsic(FrontEndTranslator translator, FrontEndContext context, string extensionName, int extOpType, ShaderType returnType, List <IShaderIR> arguments)
        {
            var extensionImportOp = translator.mCurrentLibrary.GetOrCreateExtensionLibraryImport(extensionName);
            var extOpTypeOp       = translator.CreateConstantLiteral(extOpType);

            var valueOps = new List <IShaderIR>();

            valueOps.Add(extensionImportOp);
            valueOps.Add(extOpTypeOp);
            foreach (var argument in arguments)
            {
                valueOps.Add(translator.GetOrGenerateValueTypeFromIR(context.mCurrentBlock, argument));
            }
            var op = translator.CreateOp(context.mCurrentBlock, OpInstructionType.OpExtInst, returnType, valueOps);

            context.Push(op);
        }
예제 #6
0
        public ShaderOp GenerateCompositeExtract(IShaderIR selfIR, string fieldName, FrontEndContext context)
        {
            var         selfOp   = selfIR as ShaderOp;
            var         selfType = selfOp.mResultType.GetDereferenceType();
            ShaderField shaderField;
            int         fieldIndex;

            FindField(selfType, fieldName, out shaderField, out fieldIndex);

            var resultType       = shaderField.mType.GetDereferenceType();
            var constantLiteral  = CreateConstantLiteral <uint>((uint)fieldIndex);
            var memberVariableOp = CreateOp(context.mCurrentBlock, OpInstructionType.OpCompositeExtract, resultType, new List <IShaderIR> {
                selfOp, constantLiteral
            });

            return(memberVariableOp);
        }
예제 #7
0
        public ShaderOp ConstructAndInitializeOpVariable(ShaderType shaderType, FrontEndContext context)
        {
            // Create the variable
            var voidType = mCurrentLibrary.FindType(new TypeKey(typeof(void)));
            var varOp    = CreateOpVariable(shaderType, context);

            // Either call the constructor or implicitly construct the type if needed.
            if (shaderType.mImplicitConstructor != null)
            {
                var fnParamOps = new List <IShaderIR>();
                fnParamOps.Add(shaderType.mImplicitConstructor);
                fnParamOps.Add(varOp);
                CreateOp(context.mCurrentBlock, OpInstructionType.OpFunctionCall, voidType, fnParamOps);
            }
            else if (shaderType.mPreConstructor != null)
            {
                var fnParamOps = new List <IShaderIR>();
                fnParamOps.Add(shaderType.mPreConstructor);
                fnParamOps.Add(varOp);
                CreateOp(context.mCurrentBlock, OpInstructionType.OpFunctionCall, voidType, fnParamOps);
            }
            return(varOp);
        }
        public void CreateDummyEntryPoint(TypeDependencyCollector typeCollector, ShaderLibrary library, FrontEndTranslator frontEnd, ShaderType shaderType)
        {
            var context = new FrontEndContext();

            context.mCurrentType = shaderType;

            if (shaderType.mEntryPoints.Count != 0)
            {
                return;
            }

            ShaderEntryPointInfo entryPoint = null;

            if (shaderType.mFragmentType == FragmentType.Pixel || shaderType.mFragmentType == FragmentType.None)
            {
                entryPoint = EntryPointGeneration.GeneratePixel(frontEnd, shaderType, null);
            }
            else if (shaderType.mFragmentType == FragmentType.Vertex)
            {
                entryPoint = EntryPointGeneration.GenerateVertex(frontEnd, shaderType, null);
            }

            typeCollector.Visit(entryPoint);
        }
예제 #9
0
 public virtual void Visit(FrontEndTranslator translator, CSharpCompilation compilation, List <SyntaxTree> trees, FrontEndContext context)
 {
     mFrontEnd             = translator;
     mContext              = context;
     mContext.mCurrentPass = this;
     VisitTrees(compilation, trees);
 }
예제 #10
0
 public ShaderOp CastUnsignedConvert(ShaderType resultType, IShaderIR expressionOp, FrontEndContext context)
 {
     return(SimpleCast(resultType, OpInstructionType.OpUConvert, expressionOp, context));
 }
예제 #11
0
        static void ProcessCompositeConstructIntrinsic(FrontEndTranslator translator, ShaderType returnType, List <IShaderIR> arguments, FrontEndContext context)
        {
            // Extract how many elements this composite is made up of
            var compositeCountLiteral = returnType.mParameters[1] as ShaderConstantLiteral;
            var compositeCount        = (uint)compositeCountLiteral.mValue;

            var valueOps = new List <IShaderIR>();

            // If this is a splat constructor (only 1 arg) then splat the argument for each composite element
            if (arguments.Count == 1)
            {
                var splatArgument = translator.GetOrGenerateValueTypeFromIR(context.mCurrentBlock, arguments[0]);
                for (uint i = 0; i < compositeCount; ++i)
                {
                    valueOps.Add(splatArgument);
                }
            }
            // Otherwise, just copy all args over (@JoshD: Needs validation)
            else
            {
                foreach (var argument in arguments)
                {
                    valueOps.Add(translator.GetOrGenerateValueTypeFromIR(context.mCurrentBlock, argument));
                }
            }
            var op = translator.CreateOp(context.mCurrentBlock, OpInstructionType.OpCompositeConstruct, returnType, valueOps);

            context.Push(op);
        }
예제 #12
0
 public ShaderOp CastUIntToInt(ShaderType resultType, IShaderIR expressionOp, FrontEndContext context)
 {
     return(SimpleCast(resultType, OpInstructionType.OpBitcast, expressionOp, context));
 }
예제 #13
0
        public static void CopyInterfaceFields(FrontEndTranslator translator, ShaderOp thisOp, ShaderInterfaceSet interfaceSet, InterfaceFieldCopyMode copyMode, FrontEndContext context)
        {
            foreach (var interfaceField in interfaceSet)
            {
                var interfaceInstance = interfaceSet.GetFieldInstance(translator, interfaceField, context);
                if (interfaceInstance == null)
                {
                    continue;
                }

                var shaderFieldInstance = translator.GenerateAccessChain(thisOp, interfaceField.ShaderField.mMeta.mName, context);
                if (copyMode == InterfaceFieldCopyMode.Input)
                {
                    translator.CreateStoreOp(context.mCurrentBlock, shaderFieldInstance, interfaceInstance);
                }
                else
                {
                    translator.CreateStoreOp(context.mCurrentBlock, interfaceInstance, shaderFieldInstance);
                }
            }
        }
예제 #14
0
        public static void CreateGlobalVariableInitializeFunction(FrontEndTranslator translator, ShaderType shaderType, ShaderEntryPointInfo entryPoint, EntryPointInterfaceInfo interfaceInfo, FrontEndContext context)
        {
            // First check if any global variables that need the variable initialization function exist. If not then don't emit anything.
            bool globalVariablesExist = false;

            foreach (var globalField in interfaceInfo.GlobalFields)
            {
                if (globalField.InitialValue != null)
                {
                    globalVariablesExist = true;
                }
            }
            if (!globalVariablesExist)
            {
                return;
            }

            var library            = translator.mCurrentLibrary;
            var voidType           = library.FindType(new TypeKey(typeof(void)));
            var initGlobalFunction = translator.CreateFunctionAndType(shaderType, voidType, "InitGlobals", null, null);

            initGlobalFunction.mBlocks.Add(new ShaderBlock());
            entryPoint.mGlobalsInitializationFunction = initGlobalFunction;

            // Add the store op for each global variable
            context.mCurrentFunction = initGlobalFunction;
            context.mCurrentBlock    = initGlobalFunction.mBlocks[0];
            foreach (var globalField in interfaceInfo.GlobalFields)
            {
                if (globalField.InitialValue != null)
                {
                    translator.CreateStoreOp(context.mCurrentBlock, globalField.InstanceOp, globalField.InitialValue);
                }
            }
            translator.FixupBlockTerminators(context.mCurrentFunction);
        }
예제 #15
0
 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
         });
     }
 }
예제 #16
0
        public static void ResolveVectorSwizzleSetter(FrontEndTranslator translator, FrontEndContext context, AttributeData attribute, ISymbol returnType, IShaderIR selfInstance, IShaderIR rhsIR)
        {
            var swizzleElements = attribute.ConstructorArguments[0].Values;
            var selfValue       = translator.GetOrGenerateValueTypeFromIR(context.mCurrentBlock, selfInstance);
            var selfValueType   = selfValue.mResultType.GetDereferenceType();
            var componentCount  = (UInt32)(selfValueType.mParameters[1] as ShaderConstantLiteral).mValue;

            var rhs = translator.GetOrGenerateValueTypeFromIR(context.mCurrentBlock, rhsIR);

            // If we're setting just a single element, then do an access chain and to set that element
            if (swizzleElements.Length == 1)
            {
                // Find what element we're setting
                var constantLiteral     = translator.CreateConstantLiteral((UInt32)swizzleElements[0].Value);
                var memberIndexConstant = translator.CreateConstantOp(translator.FindType(typeof(uint)), constantLiteral);
                // Lookup the result type
                var resultType = translator.mCurrentLibrary.FindType(new TypeKey(returnType));
                resultType = resultType.FindPointerType(selfValue.mResultType.mStorageClass);
                // Build the access chain to the element
                var memberVariableOp = translator.CreateOp(context.mCurrentBlock, OpInstructionType.OpAccessChain, resultType, new List <IShaderIR> {
                    selfInstance, memberIndexConstant
                });

                // Then set this back to the lhs side
                translator.CreateStoreOp(context.mCurrentBlock, memberVariableOp, rhs);
            }
            // Otherwise construct a new vector and set it over
            else
            {
                var swizzleArgs = new List <IShaderIR>()
                {
                    selfValue, rhs
                };

                // Build up a set of what element indices were in the swizzle
                var elementSet = new HashSet <UInt32>();
                foreach (var element in swizzleElements)
                {
                    elementSet.Add((UInt32)element.Value);
                }

                // Foreach element in the new vector, choose if we take it from the rhs or the lhs. If the element index is in the swizzle ops,
                // then take the next element from rhs, otherwise take the same index from lhs.
                var rhsElementIndex = 0u;
                for (uint element = 0; element < componentCount; ++element)
                {
                    if (elementSet.Contains(element))
                    {
                        swizzleArgs.Add(translator.CreateConstantLiteral(componentCount + rhsElementIndex));
                        ++rhsElementIndex;
                    }
                    else
                    {
                        swizzleArgs.Add(translator.CreateConstantLiteral(element));
                    }
                }
                // To build the setter, first create the new vector from components in the lhs/rhs as appropriate.
                var op = translator.CreateOp(context.mCurrentBlock, OpInstructionType.OpVectorShuffle, selfValueType, swizzleArgs);
                // Then set this back to the lhs side
                translator.CreateStoreOp(context.mCurrentBlock, selfInstance, op);
            }
        }
예제 #17
0
 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
     });
 }
예제 #18
0
 public ShaderOp CastFloatToUInt(ShaderType resultType, IShaderIR expressionOp, FrontEndContext context)
 {
     return(SimpleCast(resultType, OpInstructionType.OpConvertFToU, expressionOp, context));
 }
예제 #19
0
 public ShaderOp GetOwnerInstance(FrontEndTranslator translator, ShaderOp ownerOp, FrontEndContext context)
 {
     if (GetOwnerDelegate == null)
     {
         return(ownerOp);
     }
     return(GetOwnerDelegate(translator, this, ownerOp, context));
 }
예제 #20
0
        static void CombinedSampledImageValueTypeIntrinsic(FrontEndTranslator translator, FrontEndContext context, ImageIntrinsicAttributeData intrinsicData, ShaderType returnType, List <IShaderIR> arguments)
        {
            var valueOps = new List <IShaderIR>();

            var sampledImageParam = translator.GetOrGenerateValueTypeFromIR(context.mCurrentBlock, arguments[0]);
            var sampledImageType  = sampledImageParam.mResultType;
            var imageType         = sampledImageType.mParameters[0] as ShaderType;

            // Pull the image out of the sampled image.
            var imageOp = translator.CreateOp(context.mCurrentBlock, OpInstructionType.OpImage, imageType, new List <IShaderIR>()
            {
                sampledImageParam
            });

            valueOps.Add(imageOp);
            WriteArguments(translator, context, valueOps, intrinsicData, arguments, 1);
            var op = translator.CreateOp(context.mCurrentBlock, intrinsicData.OpType, returnType, valueOps);

            context.Push(op);
        }
예제 #21
0
        /////////////////////////////////////////////////////////////// Loops
        public void GenerateGenericLoop(IEnumerable <SyntaxNode> initializerNodes, IEnumerable <SyntaxNode> iteratorNodes, SyntaxNode conditionalNode, StatementSyntax loopScopeNode, FrontEndContext context)
        {
            // Always walk the initializer node statements first if they exists. The contents of this go before any loop block.
            if (initializerNodes != null)
            {
                foreach (var initializerNode in initializerNodes)
                {
                    WalkAndGetResult(initializerNode);
                }
            }

            // A basic while looks like a header block that always jumps to a condition block.
            // The condition block will choose to jump either to the loop block or to the merge point.
            // The loop block will always branch to the continue target unless a break happens which
            // will branch to the merge block (after the loop).
            // The continue block will always jump back to the header block.
            var headerBlock    = mFrontEnd.CreateBlock("headerBlock");
            var conditionBlock = mFrontEnd.CreateBlock("conditionBlock");
            var loopTrueBlock  = mFrontEnd.CreateBlock("loop-body");
            var continueBlock  = mFrontEnd.CreateBlock("continueBlock");
            var mergeBlock     = mFrontEnd.CreateBlock("after-loop");

            // Always jump to the header block
            mFrontEnd.CreateOp(context.mCurrentBlock, OpInstructionType.OpBranch, null, new List <IShaderIR> {
                headerBlock
            });

            // The header always jumps to the conditional
            context.mCurrentFunction.mBlocks.Add(headerBlock);
            GenerateLoopHeaderBlock(headerBlock, conditionBlock, mergeBlock, continueBlock, context);

            // The conditional will jump to either the loop body or the merge point (after the loop)
            context.mCurrentFunction.mBlocks.Add(conditionBlock);
            GenerateLoopConditionBlock(conditionalNode, conditionBlock, loopTrueBlock, mergeBlock, context);

            // Walk all of the statements in the loop body and jump to either the merge or continue block
            context.mCurrentFunction.mBlocks.Add(loopTrueBlock);
            GenerateLoopStatements(loopScopeNode, loopTrueBlock, mergeBlock, continueBlock, context);

            // The continue block always just jumps to the header block
            context.mCurrentFunction.mBlocks.Add(continueBlock);
            GenerateLoopContinueBlock(iteratorNodes, continueBlock, headerBlock, context);

            // Afterwards the active block is always the merge point
            context.mCurrentFunction.mBlocks.Add(mergeBlock);
            context.mCurrentBlock = mergeBlock;
        }
예제 #22
0
        public ShaderOp CastFloatToBool(ShaderType resultType, IShaderIR expressionOp, FrontEndContext context)
        {
            var constantOp = CreateConstantOp <float>(0.0f);

            return(SimpleCompareCast(resultType, OpInstructionType.OpFOrdNotEqual, expressionOp, constantOp, context));
        }
예제 #23
0
        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
            });
        }
예제 #24
0
        public static void ConstructShaderType(FrontEndTranslator translator, ShaderType shaderType, FrontEndContext context)
        {
            var selfOp = translator.ConstructAndInitializeOpVariable(shaderType, context);

            selfOp.DebugInfo.Name = "self";
            context.mThisOp       = selfOp;
        }
예제 #25
0
        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();
        }
예제 #26
0
 public ShaderOp GetFieldInstance(FrontEndTranslator translator, ShaderInterfaceField interfaceField, FrontEndContext context)
 {
     if (interfaceField.GetInstance == null)
     {
         return(null);
     }
     return(interfaceField.GetInstance(translator, interfaceField, context));
 }
예제 #27
0
        public static void ResolveMatrixDefaultConstructor(FrontEndTranslator translator, FrontEndContext context, ShaderType vectorType)
        {
            var componentType  = vectorType.mParameters[0] as ShaderType;
            var componentCount = (UInt32)(vectorType.mParameters[1] as ShaderConstantLiteral).mValue;

            // This direct call to the vector resolver is less than ideal, but works for now
            VectorResolvers.ResolveVectorDefaultConstructor(translator, context, componentType);
            var zeroConstant = context.Pop();

            var constructorArgs = new List <IShaderIR>();

            for (var i = 0; i < componentCount; ++i)
            {
                constructorArgs.Add(zeroConstant);
            }
            var op = translator.CreateOp(context.mCurrentBlock, OpInstructionType.OpCompositeConstruct, vectorType, constructorArgs);

            context.Push(op);
        }
예제 #28
0
        void LogicalOrAnd(SyntaxNode lhsExpression, SyntaxNode rhsExpression, FrontEndContext context, bool isOr)
        {
            var translator = context.mFrontEnd;
            var boolType   = translator.FindType(typeof(bool));

            // Walk the left hand operator (this can change the current block)
            var leftIR = context.mCurrentPass.WalkAndGetResult(lhsExpression);
            // In the current block, get the value type result of the left hand side
            var leftOp = translator.GetOrGenerateValueTypeFromIR(context.mCurrentBlock, leftIR);

            // Logical ors/ands have to generate conditionals due to short circuit evaluation. To store the temporary
            // result we have to either generate a temporary variable or use an OpPhi instruction. For convenience generate a temporary.
            var temp = translator.CreateOpVariable(boolType.FindPointerType(StorageClass.Function), context);

            if (isOr)
            {
                temp.DebugInfo.Name = "tempOr";
            }
            else
            {
                temp.DebugInfo.Name = "tempAnd";
            }

            // If statements always have 3 new blocks
            var ifTrue     = translator.CreateBlock("ifTrue");
            var ifFalse    = translator.CreateBlock("ifFalse");
            var mergePoint = translator.CreateBlock("mergePoint");
            // Mark the current block as a selection that merges at the merge block
            var currentBlock = context.mCurrentBlock;

            currentBlock.mBlockType  = BlockType.Selection;
            currentBlock.mMergePoint = mergePoint;

            // Branch to the true or false block depending on the value of the left op.
            // Logical Or/And are the same except for which branch they short-circuit on so
            // simply flip the true/false blocks to differentiate between them.
            var selectControlMask = translator.CreateConstantLiteral <uint>((uint)Spv.SelectionControlMask.SelectionControlMaskNone);

            translator.CreateOp(currentBlock, OpInstructionType.OpSelectionMerge, null, new List <IShaderIR> {
                mergePoint, selectControlMask
            });
            if (isOr)
            {
                translator.CreateOp(currentBlock, OpInstructionType.OpBranchConditional, null, new List <IShaderIR> {
                    leftOp, ifTrue, ifFalse
                });
            }
            else
            {
                translator.CreateOp(currentBlock, OpInstructionType.OpBranchConditional, null, new List <IShaderIR> {
                    leftOp, ifFalse, ifTrue
                });
            }


            // In the true condition of a LogicalOr, we don't have to walk the left
            // hand side so simply store the result into the temp variable and branch to the merge point.
            context.mCurrentBlock = ifTrue;
            context.mCurrentFunction.mBlocks.Add(ifTrue);
            translator.CreateStoreOp(ifTrue, temp, leftOp);
            translator.CreateOp(ifTrue, OpInstructionType.OpBranch, null, new List <IShaderIR> {
                mergePoint
            });

            // In the false block we have to evaluate the right hand side. If there are nested Ors/Ands they will each
            // generate an if/else chain that has to be evaluated but without actually evaluating a side that needs to be short circuited.
            context.mCurrentBlock = ifFalse;
            context.mCurrentFunction.mBlocks.Add(ifFalse);
            var rightIR = context.mCurrentPass.WalkAndGetResult(rhsExpression);

            // Walking the right hand side can change the current block
            currentBlock = context.mCurrentBlock;
            // Always store the result of the right hand side into our temp
            translator.CreateStoreOp(currentBlock, temp, rightIR);
            // And always branch to the merge point
            translator.CreateOp(currentBlock, OpInstructionType.OpBranch, null, new List <IShaderIR> {
                mergePoint
            });

            // Now continue control flow from the merge point with the result of this expression as our temporary result
            context.mCurrentBlock = mergePoint;
            context.mCurrentFunction.mBlocks.Add(mergePoint);
            context.Push(temp);
        }
예제 #29
0
        public static void ResolveVectorDefaultConstructor(FrontEndTranslator translator, FrontEndContext context, ShaderType vectorType)
        {
            var componentType  = vectorType.mParameters[0] as ShaderType;
            var componentCount = (UInt32)(vectorType.mParameters[1] as ShaderConstantLiteral).mValue;

            var zeroConstantLiteral = translator.CreateConstantLiteralZero(componentType);
            var zeroConstant        = translator.CreateConstantOp(componentType, zeroConstantLiteral);

            var constructorArgs = new List <IShaderIR>();

            for (var i = 0; i < componentCount; ++i)
            {
                constructorArgs.Add(zeroConstant);
            }
            var op = translator.CreateOp(context.mCurrentBlock, OpInstructionType.OpCompositeConstruct, vectorType, constructorArgs);

            context.Push(op);
        }
        static void SplitSampledImageValueTypeIntrinsic(FrontEndTranslator translator, FrontEndContext context, ImageIntrinsicAttributeData intrinsicData, ShaderType returnType, List <IShaderIR> arguments)
        {
            var valueOps = new List <IShaderIR>();

            var imageParam   = translator.GetOrGenerateValueTypeFromIR(context.mCurrentBlock, arguments[0]);
            var samplerParam = translator.GetOrGenerateValueTypeFromIR(context.mCurrentBlock, arguments[1]);

            // Try and generate a sampled image type for this image. If we do create a new type that wasn't necessary that's fine because it'll be de-duped in the binary backend.
            var sampledImageTypeStr = new TypeName {
                Name = "GeneratedSampledImage_" + imageParam.mResultType.ToString()
            };
            var sampledImageType = translator.FindType(new TypeKey(sampledImageTypeStr));

            if (sampledImageType == null)
            {
                sampledImageType = translator.CreateType(new TypeKey(sampledImageTypeStr), sampledImageTypeStr, OpType.SampledImage, null);
                sampledImageType.mParameters.Add(imageParam.mResultType.GetDereferenceType());
            }

            // Combine the image and sampler together into a sampled image. This is a bit annoying, but a sampled image
            // can't be stored into a variable so this has to be a temporary. Use this combined sampled image in place of the first two args to the intrinsics.
            var sampledImageOp = translator.CreateOp(context.mCurrentBlock, OpInstructionType.OpSampledImage, sampledImageType, new List <IShaderIR>()
            {
                imageParam, samplerParam
            });

            valueOps.Add(sampledImageOp);
            WriteArguments(translator, context, valueOps, intrinsicData, arguments, 2);
            var op = translator.CreateOp(context.mCurrentBlock, intrinsicData.OpType, returnType, valueOps);

            context.Push(op);
        }