-
-
Notifications
You must be signed in to change notification settings - Fork 128
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #720 from Sergio0694/dev/d2d-enable-runtime-compil…
…ation Add [D2DEnableRuntimeCompilation] and analyzers
- Loading branch information
Showing
17 changed files
with
410 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
39 changes: 39 additions & 0 deletions
39
...1.SourceGenerators/Diagnostics/Analyzers/D2DEnableRuntimeCompilationOnAssemblyAnalyzer.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
using System.Collections.Immutable; | ||
using ComputeSharp.SourceGeneration.Extensions; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.Diagnostics; | ||
using static ComputeSharp.SourceGeneration.Diagnostics.DiagnosticDescriptors; | ||
|
||
namespace ComputeSharp.D2D1.SourceGenerators; | ||
|
||
/// <summary> | ||
/// A diagnostic analyzer that generates diagnostics for the [D2DEnableRuntimeCompilation] attribute, when used on an assembly. | ||
/// </summary> | ||
[DiagnosticAnalyzer(LanguageNames.CSharp)] | ||
public sealed class D2DEnableRuntimeCompilationOnAssemblyAnalyzer : DiagnosticAnalyzer | ||
{ | ||
/// <inheritdoc/> | ||
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = ImmutableArray.Create(D2DRuntimeCompilationOnAssemblyNotNecessary); | ||
|
||
/// <inheritdoc/> | ||
public override void Initialize(AnalysisContext context) | ||
{ | ||
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); | ||
context.EnableConcurrentExecution(); | ||
|
||
context.RegisterCompilationAction(static context => | ||
{ | ||
IAssemblySymbol assemblySymbol = context.Compilation.Assembly; | ||
|
||
// Emit a diagnostic if an assembly has both [D2DShaderProfile] and [D2DEnableRuntimeCompilation] (the latter is useless) | ||
if (assemblySymbol.TryGetAttributeWithFullyQualifiedMetadataName("ComputeSharp.D2D1.D2DShaderProfileAttribute", out _) && | ||
assemblySymbol.TryGetAttributeWithFullyQualifiedMetadataName("ComputeSharp.D2D1.D2DEnableRuntimeCompilationAttribute", out AttributeData? attributeData)) | ||
{ | ||
context.ReportDiagnostic(Diagnostic.Create( | ||
D2DRuntimeCompilationOnAssemblyNotNecessary, | ||
attributeData.GetLocation(), | ||
assemblySymbol)); | ||
} | ||
}); | ||
} | ||
} |
97 changes: 97 additions & 0 deletions
97
....D2D1.SourceGenerators/Diagnostics/Analyzers/D2DEnableRuntimeCompilationOnTypeAnalyzer.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
using System.Collections.Immutable; | ||
using System.Linq; | ||
using ComputeSharp.SourceGeneration.Extensions; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.Diagnostics; | ||
using static ComputeSharp.SourceGeneration.Diagnostics.DiagnosticDescriptors; | ||
|
||
namespace ComputeSharp.D2D1.SourceGenerators; | ||
|
||
/// <summary> | ||
/// A diagnostic analyzer that generates diagnostics for the [D2DEnableRuntimeCompilation] attribute, when used on a type. | ||
/// </summary> | ||
[DiagnosticAnalyzer(LanguageNames.CSharp)] | ||
public sealed class D2DEnableRuntimeCompilationOnTypeAnalyzer : DiagnosticAnalyzer | ||
{ | ||
/// <inheritdoc/> | ||
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = ImmutableArray.Create( | ||
D2DRuntimeCompilationDisabled, | ||
D2DRuntimeCompilationAlreadyEnabled, | ||
D2DRuntimeCompilationOnTypeNotNecessary); | ||
|
||
/// <inheritdoc/> | ||
public override void Initialize(AnalysisContext context) | ||
{ | ||
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); | ||
context.EnableConcurrentExecution(); | ||
|
||
context.RegisterCompilationStartAction(static context => | ||
{ | ||
// Get the [D2DShaderProfile], [D2DEnableRuntimeCompilation] and [D2DGeneratedPixelShaderDescriptor] symbols | ||
if (context.Compilation.GetTypeByMetadataName("ComputeSharp.D2D1.D2DShaderProfileAttribute") is not { } d2DShaderProfileAttributeSymbol || | ||
context.Compilation.GetTypeByMetadataName("ComputeSharp.D2D1.D2DEnableRuntimeCompilationAttribute") is not { } d2DEnableRuntimeCompilationAttributeSymbol || | ||
context.Compilation.GetTypeByMetadataName("ComputeSharp.D2D1.D2DGeneratedPixelShaderDescriptorAttribute") is not { } d2DGeneratedPixelShaderDescriptorAttributeSymbol) | ||
{ | ||
return; | ||
} | ||
|
||
context.RegisterSymbolAction(context => | ||
{ | ||
// Only struct types are possible targets | ||
if (context.Symbol is not INamedTypeSymbol { TypeKind: TypeKind.Struct } typeSymbol) | ||
{ | ||
return; | ||
} | ||
|
||
// Skip the type if it's not a generated shader descriptor target | ||
if (!typeSymbol.HasAttributeWithType(d2DGeneratedPixelShaderDescriptorAttributeSymbol)) | ||
{ | ||
return; | ||
} | ||
|
||
// This analyzer will detect the following cases: | ||
// 1) Shader not precompiled, and missing [D2DEnableRuntimeCompilation] (D2DRuntimeCompilationDisabled) | ||
// 2) Shader with [D2DEnableRuntimeCompilation] on the assembly and also on the shader type (D2DRuntimeCompilationAlreadyEnabled) | ||
// 3) Shader being precompiled, but also with [D2DEnableRuntimeCompilation] (D2DRuntimeCompilationNotNecessary) | ||
bool hasD2DShaderProfileAttributeOnAssembly = typeSymbol.ContainingAssembly.HasAttributeWithType(d2DShaderProfileAttributeSymbol); | ||
bool hasD2DShaderProfileAttributeOnType = typeSymbol.HasAttributeWithType(d2DShaderProfileAttributeSymbol); | ||
bool hasD2DEnableRuntimeCompilationAttributeOnAssembly = typeSymbol.ContainingAssembly.HasAttributeWithType(d2DEnableRuntimeCompilationAttributeSymbol); | ||
bool hasD2DEnableRuntimeCompilationAttributeOnType = typeSymbol.TryGetAttributeWithType( | ||
d2DEnableRuntimeCompilationAttributeSymbol, | ||
out AttributeData? d2DEnableRuntimeCompilationAttributeData); | ||
|
||
// If [D2DEnableRuntimeCompilation] is present on the type and also on the assembly, emit a diagnostic (2) | ||
if (hasD2DEnableRuntimeCompilationAttributeOnAssembly && hasD2DEnableRuntimeCompilationAttributeOnType) | ||
{ | ||
context.ReportDiagnostic(Diagnostic.Create( | ||
D2DRuntimeCompilationAlreadyEnabled, | ||
d2DEnableRuntimeCompilationAttributeData!.GetLocation(), | ||
typeSymbol)); | ||
} | ||
|
||
// Check if the shader is precompiled: | ||
// - If it is, we should check that it's not annotated with [D2DEnableRuntimeCompilation] | ||
// - If it is not, we should check that it is annotated with [D2DEnableRuntimeCompilation] | ||
if (hasD2DShaderProfileAttributeOnType || hasD2DShaderProfileAttributeOnAssembly) | ||
{ | ||
// Emit a diagnostic if [D2DEnableRuntimeCompilation] is present on the type (3) | ||
if (hasD2DEnableRuntimeCompilationAttributeOnType) | ||
{ | ||
context.ReportDiagnostic(Diagnostic.Create( | ||
D2DRuntimeCompilationOnTypeNotNecessary, | ||
d2DEnableRuntimeCompilationAttributeData!.GetLocation(), | ||
typeSymbol)); | ||
} | ||
} | ||
else if (!hasD2DEnableRuntimeCompilationAttributeOnType && !hasD2DEnableRuntimeCompilationAttributeOnAssembly) | ||
{ | ||
// Emit a diagnostic if there is no [D2DEnableRuntimeCompilation] set anywhere (1) | ||
context.ReportDiagnostic(Diagnostic.Create( | ||
D2DRuntimeCompilationDisabled, | ||
typeSymbol.Locations.FirstOrDefault(), | ||
typeSymbol)); | ||
} | ||
}, SymbolKind.NamedType); | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
27 changes: 27 additions & 0 deletions
27
src/ComputeSharp.D2D1/Attributes/D2DEnableRuntimeCompilation.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
using System; | ||
|
||
namespace ComputeSharp.D2D1; | ||
|
||
/// <summary> | ||
/// An attribute that indicates that runtime compilation of D2D shaders is enabled. | ||
/// This attribute is required for all shaders that are not compiled at build time. | ||
/// </summary> | ||
/// <remarks> | ||
/// <para> | ||
/// Precompiling shaders at build time is recommended, as it enables additional validation | ||
/// and diagnostics, and provides better performance at runtime when dispatching the shaders. | ||
/// </para> | ||
/// <para> | ||
/// This option can be used in advanced scenarios, for instance when trying to minimize | ||
/// binary size (which should only be done after carefully measuring the actual difference). | ||
/// </para> | ||
/// <para> | ||
/// Note that not using this attribute does not mean that trying to compile shaders at runtime will | ||
/// fail. The purpose of this attribute is to allow declaring shader types that are not precompiled. | ||
/// All other features, such as manually compiling a shader type with specific compile options or | ||
/// with a different shader profile, or manually compiling a shader from source at runtime, are | ||
/// always supported, regardless of whether nor not this attribute is used. | ||
/// </para> | ||
/// </remarks> | ||
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Assembly, AllowMultiple = false)] | ||
public sealed class D2DEnableRuntimeCompilationAttribute : Attribute; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.