public static string Negate(CodeGenContext context, AstOperation operation, InstInfo info) { IAstNode src = operation.GetSource(0); VariableType type = GetSrcVarType(operation.Inst, 0); string srcExpr = GetSoureExpr(context, src, type); NumberFormatter.TryFormat(0, type, out string zero); // Starting in the 496.13 NVIDIA driver, there's an issue with assigning variables to negated expressions. // (-expr) does not work, but (0.0 - expr) does. This should be removed once the issue is resolved. return($"{zero} - {Enclose(srcExpr, src, operation.Inst, info, false)}"); }
public static string ImageLoadOrStore(CodeGenContext context, AstOperation operation) { AstTextureOperation texOp = (AstTextureOperation)operation; bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0; // TODO: Bindless texture support. For now we just return 0/do nothing. if (isBindless) { switch (texOp.Inst) { case Instruction.ImageStore: return "// imageStore(bindless)"; case Instruction.ImageLoad: NumberFormatter.TryFormat(0, texOp.Format.GetComponentType(), out string imageConst); return imageConst; default: return NumberFormatter.FormatInt(0); } } bool isArray = (texOp.Type & SamplerType.Array) != 0; bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0; string texCall; if (texOp.Inst == Instruction.ImageAtomic) { texCall = (texOp.Flags & TextureFlags.AtomicMask) switch { TextureFlags.Add => "imageAtomicAdd", TextureFlags.Minimum => "imageAtomicMin", TextureFlags.Maximum => "imageAtomicMax", TextureFlags.Increment => "imageAtomicAdd", // TODO: Clamp value. TextureFlags.Decrement => "imageAtomicAdd", // TODO: Clamp value. TextureFlags.BitwiseAnd => "imageAtomicAnd", TextureFlags.BitwiseOr => "imageAtomicOr", TextureFlags.BitwiseXor => "imageAtomicXor", TextureFlags.Swap => "imageAtomicExchange", TextureFlags.CAS => "imageAtomicCompSwap", _ => "imageAtomicAdd", }; } else { texCall = texOp.Inst == Instruction.ImageLoad ? "imageLoad" : "imageStore"; } int srcIndex = isBindless ? 1 : 0; string Src(VariableType type) { return GetSoureExpr(context, texOp.GetSource(srcIndex++), type); } string indexExpr = null; if (isIndexed) { indexExpr = Src(VariableType.S32); } string imageName = OperandManager.GetImageName(context.Config.Stage, texOp, indexExpr); texCall += "(" + imageName; int coordsCount = texOp.Type.GetDimensions(); int pCount = coordsCount + (isArray ? 1 : 0); void Append(string str) { texCall += ", " + str; } string ApplyScaling(string vector) { if (context.Config.Stage.SupportsRenderScale() && texOp.Inst == Instruction.ImageLoad && !isBindless && !isIndexed) { // Image scales start after texture ones. int scaleIndex = context.Config.GetTextureDescriptors().Length + context.Config.FindImageDescriptorIndex(texOp); if (pCount == 3 && isArray) { // The array index is not scaled, just x and y. vector = "ivec3(Helper_TexelFetchScale((" + vector + ").xy, " + scaleIndex + "), (" + vector + ").z)"; } else if (pCount == 2 && !isArray) { vector = "Helper_TexelFetchScale(" + vector + ", " + scaleIndex + ")"; } } return vector; } if (pCount > 1) { string[] elems = new string[pCount]; for (int index = 0; index < pCount; index++) { elems[index] = Src(VariableType.S32); } Append(ApplyScaling("ivec" + pCount + "(" + string.Join(", ", elems) + ")")); } else { Append(Src(VariableType.S32)); } if (texOp.Inst == Instruction.ImageStore) { VariableType type = texOp.Format.GetComponentType(); string[] cElems = new string[4]; for (int index = 0; index < 4; index++) { if (srcIndex < texOp.SourcesCount) { cElems[index] = Src(type); } else { cElems[index] = type switch { VariableType.S32 => NumberFormatter.FormatInt(0), VariableType.U32 => NumberFormatter.FormatUint(0), _ => NumberFormatter.FormatFloat(0) }; } } string prefix = type switch { VariableType.S32 => "i", VariableType.U32 => "u", _ => string.Empty }; Append(prefix + "vec4(" + string.Join(", ", cElems) + ")"); } if (texOp.Inst == Instruction.ImageAtomic) { VariableType type = texOp.Format.GetComponentType(); if ((texOp.Flags & TextureFlags.AtomicMask) == TextureFlags.CAS) { Append(Src(type)); // Compare value. } string value = (texOp.Flags & TextureFlags.AtomicMask) switch { TextureFlags.Increment => NumberFormatter.FormatInt(1, type), // TODO: Clamp value TextureFlags.Decrement => NumberFormatter.FormatInt(-1, type), // TODO: Clamp value _ => Src(type) }; Append(value); texCall += ")"; if (type != VariableType.S32) { texCall = "int(" + texCall + ")"; } } else { texCall += ")" + (texOp.Inst == Instruction.ImageLoad ? GetMask(texOp.Index) : ""); } return texCall; }