Skip to content

Commit

Permalink
Merge pull request #400 from Sergio0694/dev/raw-multiline-toggle
Browse files Browse the repository at this point in the history
Only emit raw multiline string literals when possible
  • Loading branch information
Sergio0694 authored Oct 8, 2022
2 parents 5c83ac3 + dab94bd commit 37ebca1
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using ComputeSharp.D2D1.__Internals;
using ComputeSharp.SourceGeneration.Helpers;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
Expand All @@ -19,9 +20,16 @@ partial class BuildHlslSource
/// </summary>
/// <param name="hlslSource">The input HLSL source.</param>
/// <param name="hierarchyDepth">The depth of the hierarchy for this type (used to calculate the right indentation).</param>
/// <param name="useRawMultiLineStringLiteralExpression">Whether to use a raw multiline string literal expression</param>
/// <returns>The resulting <see cref="MethodDeclarationSyntax"/> instance for the <c>BuildHlslSource</c> method.</returns>
public static MethodDeclarationSyntax GetSyntax(string hlslSource, int hierarchyDepth)
public static MethodDeclarationSyntax GetSyntax(string hlslSource, int hierarchyDepth, bool useRawMultiLineStringLiteralExpression)
{
SyntaxToken hlslSourceLiteralExpression = useRawMultiLineStringLiteralExpression switch
{
true => SyntaxTokenHelper.CreateRawMultilineStringLiteral(hlslSource, hierarchyDepth),
false => Literal(hlslSource)
};

// This code produces a method declaration as follows:
//
// readonly void global::ComputeSharp.D2D1.__Internals.ID2D1Shader.BuildHlslSource(out string hlslSource)
Expand All @@ -38,9 +46,7 @@ public static MethodDeclarationSyntax GetSyntax(string hlslSource, int hierarchy
AssignmentExpression(
SyntaxKind.SimpleAssignmentExpression,
IdentifierName("hlslSource"),
LiteralExpression(
SyntaxKind.StringLiteralExpression,
SyntaxTokenHelper.CreateRawMultilineStringLiteral(hlslSource, hierarchyDepth))))));
LiteralExpression(SyntaxKind.StringLiteralExpression, hlslSourceLiteralExpression)))));
}
}
}
18 changes: 12 additions & 6 deletions src/ComputeSharp.D2D1.SourceGenerators/ID2D1ShaderGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -208,18 +208,24 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
context.AddSource($"{item.Info.Hierarchy.FilenameHint}.{nameof(LoadDispatchData)}.g.cs", compilationUnit.GetText(Encoding.UTF8));
});

// Get the BuildHlslSource() info (hierarchy and HLSL source)
IncrementalValuesProvider<(HierarchyInfo Hierarchy, string HlslSource)> hlslSourceInfo =
// Check whether raw multiline string literals can be used (C# 11)
IncrementalValueProvider<bool> canUseRawMultilineStringLiterals =
context.ParseOptionsProvider
.Select((item, _) => item is CSharpParseOptions { LanguageVersion: >= LanguageVersion.CSharp11 });

// Get the BuildHlslSource() info (hierarchy, HLSL source and parsing options)
IncrementalValuesProvider<((HierarchyInfo Hierarchy, string HlslSource) Info, bool CanUseRawMultilineStringLiterals)> hlslSourceInfo =
shaderInfoWithErrors
.Select(static (item, _) => (item.Hierarchy, item.HlslShaderSource.HlslSource));
.Select(static (item, _) => (item.Hierarchy, item.HlslShaderSource.HlslSource))
.Combine(canUseSkipLocalsInit);

// Generate the BuildHlslSource() methods
context.RegisterSourceOutput(hlslSourceInfo, static (context, item) =>
{
MethodDeclarationSyntax buildHlslStringMethod = BuildHlslSource.GetSyntax(item.HlslSource, item.Hierarchy.Hierarchy.Length);
CompilationUnitSyntax compilationUnit = GetCompilationUnitFromMethod(item.Hierarchy, buildHlslStringMethod, canUseSkipLocalsInit: false);
MethodDeclarationSyntax buildHlslStringMethod = BuildHlslSource.GetSyntax(item.Info.HlslSource, item.Info.Hierarchy.Hierarchy.Length, item.CanUseRawMultilineStringLiterals);
CompilationUnitSyntax compilationUnit = GetCompilationUnitFromMethod(item.Info.Hierarchy, buildHlslStringMethod, canUseSkipLocalsInit: false);
context.AddSource($"{item.Hierarchy.FilenameHint}.{nameof(BuildHlslSource)}.g.cs", compilationUnit.GetText(Encoding.UTF8));
context.AddSource($"{item.Info.Hierarchy.FilenameHint}.{nameof(BuildHlslSource)}.g.cs", compilationUnit.GetText(Encoding.UTF8));
});

// Get a filtered sequence to enable caching for the HLSL source info, before the shader compilation step
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)Extensions\AttributeDataExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Extensions\IncrementalValueProviderExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Extensions\CompilationExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Extensions\DiagnosticsExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Extensions\HashCodeExtensions.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using Microsoft.CodeAnalysis;

namespace ComputeSharp.SourceGeneration.Extensions;

/// <summary>
/// Extension methods for the <see cref="IncrementalValueProvider{TValue}"/> type.
/// </summary>
internal static class IncrementalValueProviderExtensions
{
/// <summary>
/// Combines three <see cref="IncrementalValueProvider{TValue}"/> instances.
/// </summary>
/// <typeparam name="T1">The type of values produced by the first <see cref="IncrementalValueProvider{TValue}"/> input.</typeparam>
/// <typeparam name="T2">The type of values produced by the second <see cref="IncrementalValueProvider{TValue}"/> input.</typeparam>
/// <typeparam name="T3">The type of values produced by the third <see cref="IncrementalValueProvider{TValue}"/> input.</typeparam>
/// <param name="source1">The first <see cref="IncrementalValueProvider{TValue}"/> input.</param>
/// <param name="source2">The second <see cref="IncrementalValueProvider{TValue}"/> input.</param>
/// <param name="source3">The third <see cref="IncrementalValueProvider{TValue}"/> input.</param>
/// <returns>The resulting combined <see cref="IncrementalValueProvider{TValue}"/> result.</returns>
public static IncrementalValueProvider<(T1, T2, T3)> Combine<T1, T2, T3>(
this IncrementalValueProvider<T1> source1,
IncrementalValueProvider<T2> source2,
IncrementalValueProvider<T3> source3)
{
return
source1
.Combine(source2)
.Combine(source3)
.Select(static (items, _) => (items.Left.Left, items.Left.Right, items.Right));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using ComputeSharp.__Internals;
using ComputeSharp.SourceGeneration.Helpers;
using ComputeSharp.SourceGenerators.Models;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
Expand All @@ -24,12 +25,13 @@ partial class BuildHlslSource
/// <param name="hlslSourceInfo">The input <see cref="HlslShaderSourceInfo"/> instance to use.</param>
/// <param name="supportsDynamicShaders">Indicates whether or not dynamic shaders are supported.</param>
/// <param name="hierarchyDepth">The depth of the hierarchy for this type (used to calculate the right indentation).</param>
/// <param name="useRawMultiLineStringLiteralExpression">Whether to use a raw multiline string literal expression</param>
/// <returns>The resulting <see cref="MethodDeclarationSyntax"/> instance for the <c>BuildHlslSource</c> method.</returns>
public static MethodDeclarationSyntax GetSyntax(HlslShaderSourceInfo hlslSourceInfo, bool supportsDynamicShaders, int hierarchyDepth)
public static MethodDeclarationSyntax GetSyntax(HlslShaderSourceInfo hlslSourceInfo, bool supportsDynamicShaders, int hierarchyDepth, bool useRawMultiLineStringLiteralExpression)
{
// Generate the necessary body statements depending on whether dynamic shaders are supported
ImmutableArray<StatementSyntax> bodyStatements = supportsDynamicShaders
? GenerateRenderMethodBody(hlslSourceInfo, hierarchyDepth)
? GenerateRenderMethodBody(hlslSourceInfo, hierarchyDepth, useRawMultiLineStringLiteralExpression)
: GenerateEmptyMethodBody();

// This code produces a method declaration as follows:
Expand Down Expand Up @@ -81,8 +83,9 @@ private static ImmutableArray<StatementSyntax> GenerateEmptyMethodBody()
/// </summary>
/// <param name="hlslSourceInfo">The input <see cref="HlslShaderSourceInfo"/> instance to use.</param>
/// <param name="hierarchyDepth">The depth of the hierarchy for this type (used to calculate the right indentation).</param>
/// <param name="useRawMultiLineStringLiteralExpression">Whether to use a raw multiline string literal expression</param>
/// <returns>The series of statements to build the HLSL source to compile to execute the current shader.</returns>
private static ImmutableArray<StatementSyntax> GenerateRenderMethodBody(HlslShaderSourceInfo hlslSourceInfo, int hierarchyDepth)
private static ImmutableArray<StatementSyntax> GenerateRenderMethodBody(HlslShaderSourceInfo hlslSourceInfo, int hierarchyDepth, bool useRawMultiLineStringLiteralExpression)
{
using ImmutableArrayBuilder<StatementSyntax> statements = ImmutableArrayBuilder<StatementSyntax>.Rent();

Expand Down Expand Up @@ -112,19 +115,23 @@ void FlushText()
{
if (textBuilder.Length > 0)
{
string text = textBuilder.ToString();
string hlslSource = textBuilder.ToString();

textBuilder.Append(text);
textBuilder.Append(hlslSource);

sizeHint += textBuilder.Length;

SyntaxToken hlslSourceLiteralExpression = useRawMultiLineStringLiteralExpression switch
{
true => SyntaxTokenHelper.CreateRawMultilineStringLiteral(hlslSource, hierarchyDepth),
false => Literal(hlslSource)
};

statements.Add(
ExpressionStatement(
InvocationExpression(
MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, IdentifierName("builder"), IdentifierName("Append")))
.AddArgumentListArguments(Argument(LiteralExpression(
SyntaxKind.StringLiteralExpression,
SyntaxTokenHelper.CreateRawMultilineStringLiteral(text, hierarchyDepth))))));
.AddArgumentListArguments(Argument(LiteralExpression(SyntaxKind.StringLiteralExpression, hlslSourceLiteralExpression)))));

textBuilder.Clear();
}
Expand Down
11 changes: 8 additions & 3 deletions src/ComputeSharp.SourceGenerators/IShaderGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,16 +154,21 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
context.AddSource($"{item.Info.Hierarchy.FilenameHint}.{nameof(LoadDispatchData)}.g.cs", compilationUnit.GetText(Encoding.UTF8));
});

// Check whether raw multiline string literals can be used (C# 11)
IncrementalValueProvider<bool> canUseRawMultilineStringLiterals =
context.ParseOptionsProvider
.Select((item, _) => item is CSharpParseOptions { LanguageVersion: >= LanguageVersion.CSharp11 });

// Get the BuildHlslSource info (hierarchy, HLSL source and parsing options)
IncrementalValuesProvider<((HierarchyInfo Hierarchy, HlslShaderSourceInfo HlslShaderSource) Info, (bool CanUseSkipLocalsInit, bool SupportsDynamicShaders) Options)> hlslSourceInfo =
IncrementalValuesProvider<((HierarchyInfo Hierarchy, HlslShaderSourceInfo HlslShaderSource) Info, (bool CanUseSkipLocalsInit, bool SupportsDynamicShaders, bool CanUseRawMultilineStringLiterals) Options)> hlslSourceInfo =
shaderInfoWithErrors
.Select(static (item, _) => (item.Hierarchy, item.HlslShaderSource))
.Combine(canUseSkipLocalsInit.Combine(supportsDynamicShaders));
.Combine(canUseSkipLocalsInit.Combine(supportsDynamicShaders, canUseRawMultilineStringLiterals));

// Generate the BuildHlslSource() methods
context.RegisterSourceOutput(hlslSourceInfo, static (context, item) =>
{
MethodDeclarationSyntax buildHlslStringMethod = BuildHlslSource.GetSyntax(item.Info.HlslShaderSource, item.Options.SupportsDynamicShaders, item.Info.Hierarchy.Hierarchy.Length);
MethodDeclarationSyntax buildHlslStringMethod = BuildHlslSource.GetSyntax(item.Info.HlslShaderSource, item.Options.SupportsDynamicShaders, item.Info.Hierarchy.Hierarchy.Length, item.Options.CanUseRawMultilineStringLiterals);
CompilationUnitSyntax compilationUnit = GetCompilationUnitFromMethod(item.Info.Hierarchy, buildHlslStringMethod, item.Options.CanUseSkipLocalsInit);
context.AddSource($"{item.Info.Hierarchy.FilenameHint}.{nameof(BuildHlslSource)}.g.cs", compilationUnit.GetText(Encoding.UTF8));
Expand Down

0 comments on commit 37ebca1

Please sign in to comment.