Beispiel #1
0
        public static ShaderOp GenerateInterfaceStructAndOp(FrontEndTranslator translator, List <ShaderInterfaceField> interfaceFields, TypeName structName, string instanceName, StorageClass storageClass)
        {
            var interfaceStruct = translator.FindType(new TypeKey(structName));

            // Generate the interface struct if it doesn't already exist (uniform buffers already exist)
            if (interfaceStruct == null)
            {
                interfaceStruct = translator.CreateType(new TypeKey(structName), structName, OpType.Struct, null);
                foreach (var interfaceField in interfaceFields)
                {
                    interfaceStruct.mFields.Add(interfaceField.ShaderField);
                }
            }

            var opPointerType = translator.FindOrCreatePointerType(new TypeKey(structName), structName, storageClass);
            var op            = translator.CreateOp(OpInstructionType.OpVariable, opPointerType, null);

            ShaderInterfaceField.InstanceAccessDelegate fieldInstanceGetFunction = (FrontEndTranslator translator, ShaderInterfaceField interfaceField, FrontEndContext context) =>
            {
                return(translator.GenerateAccessChain(op, interfaceField.ShaderField.mMeta.mName, context));
            };

            foreach (var interfaceField in interfaceFields)
            {
                interfaceField.GetInstance = fieldInstanceGetFunction;
            }

            op.DebugInfo.Name = instanceName;
            return(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);
        }
        static public void CreateCompositeConstructIntrinsic(FrontEndTranslator translator, INamedTypeSymbol typeSymbol, IMethodSymbol methodSymbol, AttributeData attribute)
        {
            var shaderReturnType = translator.FindType(new TypeKey(typeSymbol));

            ShaderLibrary.InstrinsicDelegate callback = (FrontEndTranslator translator, List <IShaderIR> arguments, FrontEndContext context) =>
            {
                ProcessCompositeConstructIntrinsic(translator, shaderReturnType, arguments, context);
            };
            translator.mCurrentLibrary.CreateIntrinsicFunction(new FunctionKey(methodSymbol), callback);
        }
        static public void CreateSampledImageIntrinsicFunction(FrontEndTranslator translator, INamedTypeSymbol typeSymbol, IMethodSymbol methodSymbol, AttributeData attribute)
        {
            var intrinsicData = ImageIntrinsicAttributeData.Parse(attribute);

            if (intrinsicData == null)
            {
                throw new Exception("Failed to parse attribute");
            }

            var shaderReturnType = translator.FindType(new TypeKey(methodSymbol.ReturnType));

            ShaderLibrary.InstrinsicDelegate callback = null;

            var param0Type = translator.FindType(new TypeKey(methodSymbol.Parameters[0].Type));

            if (param0Type.mBaseType == OpType.SampledImage)
            {
                callback = (FrontEndTranslator translator, List <IShaderIR> arguments, FrontEndContext context) =>
                {
                    SampledImageValueTypeIntrinsic(translator, context, intrinsicData, shaderReturnType, arguments);
                };
            }
            else if (param0Type.mBaseType == OpType.Image)
            {
                var param1Type = translator.FindType(new TypeKey(methodSymbol.Parameters[1].Type));
                if (param1Type.mBaseType == OpType.Sampler)
                {
                    callback = (FrontEndTranslator translator, List <IShaderIR> arguments, FrontEndContext context) =>
                    {
                        SplitSampledImageValueTypeIntrinsic(translator, context, intrinsicData, shaderReturnType, arguments);
                    };
                }
            }

            if (callback == null)
            {
                throw new Exception("Failed to parse attribute");
            }

            translator.mCurrentLibrary.CreateIntrinsicFunction(new FunctionKey(methodSymbol), callback);
        }
        /// <summary>
        /// Creates a simple intrinsic type (one whos ops are just value types of the args one-for-one) callback for the given symbol information from the provided attribute.
        /// </summary>
        static public void CreateSimpleIntrinsicType(FrontEndTranslator translator, INamedTypeSymbol typeSymbol, IMethodSymbol methodSymbol, AttributeData attribute)
        {
            var opTypeStr        = attribute.ConstructorArguments[0].Value.ToString();
            var opType           = (OpInstructionType)Enum.Parse(typeof(OpInstructionType), opTypeStr, true);
            var shaderReturnType = translator.FindType(new TypeKey(methodSymbol.ReturnType));

            ShaderLibrary.InstrinsicDelegate callback = (FrontEndTranslator translator, List <IShaderIR> arguments, FrontEndContext context) =>
            {
                SimpleValueTypeIntrinsic(translator, context, opType, shaderReturnType, arguments);
            };
            translator.mCurrentLibrary.CreateIntrinsicFunction(new FunctionKey(methodSymbol), callback);
        }
Beispiel #6
0
        public static bool ValidateMatrixPrimitive(FrontEndTranslator translator, INamedTypeSymbol typeSymbol, AttributeData attribute, out ShaderType columnType, out UInt32 columnCount)
        {
            columnCount = (UInt32)attribute.ConstructorArguments[1].Value;
            // The component type must be a vector type
            ISymbol componentTypeSymbol = attribute.ConstructorArguments[0].Value as ISymbol;

            columnType = translator.FindType(new TypeKey(componentTypeSymbol));
            if (columnType == null || columnType.mBaseType != OpType.Vector)
            {
                return(false);
            }
            return(true);
        }
Beispiel #7
0
        public static ShaderType ProcessVectorType(FrontEndTranslator translator, INamedTypeSymbol typeSymbol, AttributeData attribute)
        {
            var componentType  = translator.FindType(new TypeKey(attribute.ConstructorArguments[0].Value as ISymbol));
            var componentCount = (UInt32)attribute.ConstructorArguments[1].Value;

            var shaderType = translator.CreateType(typeSymbol, OpType.Vector);

            shaderType.mParameters.Add(componentType);
            shaderType.mParameters.Add(translator.CreateConstantLiteral(componentCount));

            ProcessVectorDefaultConstructor(translator, typeSymbol, shaderType);

            return(shaderType);
        }
Beispiel #8
0
        /// <summary>
        /// Processes a function to create a simple extension intrinsic (one whos ops are just value types of the args one-for-one) callback for the given symbol information from the provided attribute.
        /// </summary>
        static public void ProcessSimpleExtensionIntrinsic(FrontEndTranslator translator, INamedTypeSymbol typeSymbol, IMethodSymbol methodSymbol, AttributeData attribute)
        {
            var extensionName = attribute.ConstructorArguments[0].Value.ToString();
            var opTypeStr     = attribute.ConstructorArguments[1].Value.ToString();
            // @JoshD: Hack that this is tied to GLSLstd450. This should ideally be extended to work  on any extension library type
            var extOpType        = (GLSLstd450)Enum.Parse(typeof(GLSLstd450), opTypeStr, true);
            var shaderReturnType = translator.FindType(new TypeKey(methodSymbol.ReturnType));

            ShaderLibrary.InstrinsicDelegate callback = (FrontEndTranslator translator, List <IShaderIR> arguments, FrontEndContext context) =>
            {
                ResolveSimpleExtensionIntrinsic(translator, context, extensionName, (int)extOpType, shaderReturnType, arguments);
            };
            translator.mCurrentLibrary.CreateIntrinsicFunction(new FunctionKey(methodSymbol), callback);
        }
Beispiel #9
0
        public static ShaderType ProcessSampledImageType(FrontEndTranslator translator, INamedTypeSymbol typeSymbol, AttributeData attribute)
        {
            var imageType = translator.FindType(new TypeKey(attribute.ConstructorArguments[0].Value as ITypeSymbol));

            // Validate the image type param is an image type
            if (imageType == null || imageType.mBaseType != OpType.Image)
            {
                throw new System.Exception();
            }

            var shaderType = translator.CreateType(typeSymbol, OpType.SampledImage);

            shaderType.mParameters.Add(imageType);
            shaderType.mStorageClass = StorageClass.UniformConstant;
            return(shaderType);
        }
Beispiel #10
0
        /// <summary>
        /// Creates an intrinsic to retrieve an element from an array. This unfortunately has to use OpAccessChain because the other
        /// instruction requires an integer literal, but OpAccessChain returns a pointer (which isn't exposed). This function will return the element as a value type.
        /// </summary>
        static public void CreateArrayGetType(FrontEndTranslator translator, INamedTypeSymbol typeSymbol, IMethodSymbol methodSymbol, AttributeData attribute)
        {
            var shaderReturnType  = translator.FindType(new TypeKey(methodSymbol.ReturnType));
            var pointerReturnType = shaderReturnType.FindPointerType(StorageClass.Function);

            ShaderLibrary.InstrinsicDelegate callback = (FrontEndTranslator translator, List <IShaderIR> arguments, FrontEndContext context) =>
            {
                var selfOp        = arguments[0];
                var indexOp       = translator.GetOrGenerateValueTypeFromIR(context.mCurrentBlock, arguments[1]);
                var accessChainOp = translator.CreateOp(context.mCurrentBlock, OpInstructionType.OpAccessChain, pointerReturnType, new List <IShaderIR> {
                    selfOp, indexOp
                });
                // Always convert the pointer to a value type
                var returnOp = translator.GetOrGenerateValueTypeFromIR(context.mCurrentBlock, accessChainOp);
                context.Push(returnOp);
            };
            translator.mCurrentLibrary.CreateIntrinsicFunction(new FunctionKey(methodSymbol), callback);
        }
Beispiel #11
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);
            }
        }
Beispiel #12
0
        public static ShaderType ProcessImageType(FrontEndTranslator translator, INamedTypeSymbol typeSymbol, AttributeData attribute)
        {
            ShaderType sampledType = null;

            Shader.ImageDimension        dimension        = Shader.ImageDimension.Dim2D;
            Shader.ImageDepthMode        depthMode        = Shader.ImageDepthMode.None;
            Shader.ImageArrayedMode      arrayedMode      = Shader.ImageArrayedMode.None;
            Shader.ImageMultiSampledMode multiSampledMode = Shader.ImageMultiSampledMode.SingleSampled;
            Shader.ImageSampledMode      sampledMode      = Shader.ImageSampledMode.Sampling;
            Shader.ImageFormat           imageFormat      = Shader.ImageFormat.Unknown;

            // Load all constructor args by type.
            foreach (var argument in attribute.ConstructorArguments)
            {
                var argName = TypeAliases.GetTypeName(argument.Type);
                if (argName == TypeAliases.GetTypeName <Type>())
                {
                    sampledType = translator.FindType(new TypeKey(argument.Value as ITypeSymbol));
                }
                else if (argName == TypeAliases.GetTypeName <Shader.ImageDimension>())
                {
                    dimension = (Shader.ImageDimension)argument.Value;
                }
                else if (argName == TypeAliases.GetTypeName <Shader.ImageDepthMode>())
                {
                    depthMode = (Shader.ImageDepthMode)argument.Value;
                }
                else if (argName == TypeAliases.GetTypeName <Shader.ImageArrayedMode>())
                {
                    arrayedMode = (Shader.ImageArrayedMode)argument.Value;
                }
                else if (argName == TypeAliases.GetTypeName <Shader.ImageMultiSampledMode>())
                {
                    multiSampledMode = (Shader.ImageMultiSampledMode)argument.Value;
                }
                else if (argName == TypeAliases.GetTypeName <Shader.ImageSampledMode>())
                {
                    sampledMode = (Shader.ImageSampledMode)argument.Value;
                }
                else if (argName == TypeAliases.GetTypeName <Shader.ImageFormat>())
                {
                    imageFormat = (Shader.ImageFormat)argument.Value;
                }
            }
            // Handle named arguments
            foreach (var pair in attribute.NamedArguments)
            {
                if (pair.Key == "SampledType")
                {
                    sampledType = translator.FindType(new TypeKey(pair.Value.Value as ITypeSymbol));
                }
                else if (pair.Key == "Dimension")
                {
                    dimension = (Shader.ImageDimension)pair.Value.Value;
                }
                else if (pair.Key == "DepthMode")
                {
                    depthMode = (Shader.ImageDepthMode)pair.Value.Value;
                }
                else if (pair.Key == "ArrayedMode")
                {
                    arrayedMode = (Shader.ImageArrayedMode)pair.Value.Value;
                }
                else if (pair.Key == "MultiSampledMode")
                {
                    multiSampledMode = (Shader.ImageMultiSampledMode)pair.Value.Value;
                }
                else if (pair.Key == "SampledMode")
                {
                    sampledMode = (Shader.ImageSampledMode)pair.Value.Value;
                }
                else if (pair.Key == "ImageFormat")
                {
                    imageFormat = (Shader.ImageFormat)pair.Value.Value;
                }
            }

            // Validate input type. SpirV spec says: "Sampled Type is the type of the components that result
            // from sampling or reading from this image type. Must be ascalar numerical type or OpTypeVoid"
            if (sampledType == null || (sampledType.mBaseType != OpType.Bool && sampledType.mBaseType != OpType.Int && sampledType.mBaseType != OpType.Float && sampledType.mBaseType != OpType.Void))
            {
                throw new Exception();
            }

            var shaderType = translator.CreateType(typeSymbol, OpType.Image);

            shaderType.mParameters.Add(sampledType);
            shaderType.mParameters.Add(translator.CreateConstantLiteral((UInt32)dimension));
            shaderType.mParameters.Add(translator.CreateConstantLiteral((UInt32)depthMode));
            shaderType.mParameters.Add(translator.CreateConstantLiteral((UInt32)arrayedMode));
            shaderType.mParameters.Add(translator.CreateConstantLiteral((UInt32)multiSampledMode));
            shaderType.mParameters.Add(translator.CreateConstantLiteral((UInt32)sampledMode));
            shaderType.mParameters.Add(translator.CreateConstantLiteral((UInt32)imageFormat));
            shaderType.mStorageClass = StorageClass.UniformConstant;

            return(shaderType);
        }
Beispiel #13
0
        void AddPrimitiveIntrinsics(FrontEndTranslator translator)
        {
            var floatType = translator.FindType(typeof(float));

            SpecialResolvers.CreateSimpleIntrinsicFunction(translator, new FunctionKey("float.operator +(float, float)"), OpInstructionType.OpFAdd, floatType);
        }