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); }
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); }
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); }
/// <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); }
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); }
/// <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); }
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); } }
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); }
void AddPrimitiveIntrinsics(FrontEndTranslator translator) { var floatType = translator.FindType(typeof(float)); SpecialResolvers.CreateSimpleIntrinsicFunction(translator, new FunctionKey("float.operator +(float, float)"), OpInstructionType.OpFAdd, floatType); }