mirror of
https://github.com/Facepunch/sbox-public.git
synced 2026-01-10 15:28:37 -05:00
This commit imports the C# engine code and game files, excluding C++ source code. [Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
192 lines
4.8 KiB
C#
192 lines
4.8 KiB
C#
using Humanizer;
|
|
using System.Threading;
|
|
|
|
namespace Sandbox.Engine.Shaders;
|
|
|
|
class ProgramSource
|
|
{
|
|
internal ShaderProgramType ProgramType;
|
|
|
|
public bool IsOutOfDate { get; set; }
|
|
|
|
~ProgramSource()
|
|
{
|
|
if ( builder.IsValid )
|
|
{
|
|
builder.Delete();
|
|
builder = default;
|
|
}
|
|
}
|
|
|
|
CVfxByteCodeManager builder;
|
|
|
|
/// <summary>
|
|
/// Compile a single program on this shader
|
|
/// </summary>
|
|
internal async Task<bool> Compile( ShaderCompileOptions options, Shader vfx, string source, ShaderCompile.Results result, CancellationToken token, string absolutePath, string relativePath )
|
|
{
|
|
//Console.WriteLine( $" {ProgramType}: {(IsOutOfDate ? "out of date" : "okay")}" );
|
|
|
|
bool nonInteractiveConsole = Console.IsOutputRedirected || Console.IsInputRedirected || Console.IsErrorRedirected;
|
|
|
|
using var context = ShaderCompile.GetSharedContext( ProgramType );
|
|
context.MaskedSource = ShaderTools.MaskShaderSource( source, ProgramType, false );
|
|
|
|
ShaderPreprocessor preprocessor = new( new ShaderPreprocessorOptions() { ExpandIncludes = true, IgnoreCoreIncludes = true } );
|
|
context.MaskedSource = preprocessor.Preprocess( context.MaskedSource, absolutePath, relativePath );
|
|
|
|
FastTimer fastTimer = FastTimer.StartNew();
|
|
|
|
var stepResult = new ShaderCompile.Results.Program();
|
|
result.Programs.Add( stepResult );
|
|
|
|
List<CompiledCombo> allCompiles = new();
|
|
|
|
var p = vfx.GetProgram( ProgramType );
|
|
|
|
var combos = p.EnumerateCombos( ProgramType )
|
|
.ToArray()
|
|
.OrderBy( x => Guid.NewGuid() )
|
|
.ToArray();
|
|
|
|
var totalCombos = combos.Length;
|
|
|
|
stepResult.Name = $"{ProgramType}";
|
|
stepResult.ComboCount = totalCombos;
|
|
stepResult.Source = context.MaskedSource;
|
|
|
|
if ( options.ConsoleOutput )
|
|
{
|
|
Console.ForegroundColor = ConsoleColor.Green;
|
|
Console.WriteLine( $" {ProgramType} - {totalCombos:n0} {"combo".Pluralize()}" );
|
|
Console.ForegroundColor = ConsoleColor.White;
|
|
}
|
|
|
|
var originalPos = nonInteractiveConsole ? default : Console.GetCursorPosition();
|
|
var updateUI = () =>
|
|
{
|
|
if ( nonInteractiveConsole )
|
|
{
|
|
Console.Write( $" {Math.Floor( ((double)allCompiles.Count / (double)totalCombos) * 100.0 )}%" );
|
|
}
|
|
else
|
|
{
|
|
Console.SetCursorPosition( Console.WindowLeft, originalPos.Top );
|
|
Console.Write( new string( ' ', 8 ) );
|
|
Console.SetCursorPosition( Console.WindowLeft, originalPos.Top );
|
|
Console.Write( $" {Math.Floor( ((double)allCompiles.Count / (double)totalCombos) * 100.0 )}%" );
|
|
Console.SetCursorPosition( Console.WindowLeft, originalPos.Top );
|
|
}
|
|
};
|
|
|
|
var timeBetweenUpdates = nonInteractiveConsole ? 2000 : 32;
|
|
int errors = 0;
|
|
|
|
var compileCombo = ( ShaderProgram.Combo d ) =>
|
|
{
|
|
try
|
|
{
|
|
if ( errors > 0 )
|
|
return;
|
|
|
|
if ( token.IsCancellationRequested )
|
|
return;
|
|
|
|
var result = ShaderCompile.CompileSingleCombo( vfx, this, d.Static, d.Dynamic, context, !options.ForceRecompile );
|
|
|
|
lock ( this )
|
|
{
|
|
if ( !result.IsSuccess )
|
|
{
|
|
Interlocked.Add( ref errors, 1 );
|
|
}
|
|
|
|
allCompiles.Add( result );
|
|
|
|
if ( options.ConsoleOutput && fastTimer.ElapsedMilliSeconds > timeBetweenUpdates )
|
|
{
|
|
fastTimer = FastTimer.StartNew();
|
|
updateUI();
|
|
}
|
|
}
|
|
}
|
|
catch ( System.Exception e )
|
|
{
|
|
Log.Warning( e );
|
|
}
|
|
};
|
|
|
|
if ( options.SingleThreaded )
|
|
{
|
|
foreach ( var d in combos )
|
|
{
|
|
await Task.Run( () => compileCombo( d ), token );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
await Task.Run( () =>
|
|
{
|
|
Parallel.ForEach( combos, compileCombo );
|
|
}, token );
|
|
}
|
|
|
|
token.ThrowIfCancellationRequested();
|
|
|
|
//
|
|
// deduplicate the compiler outputs, add them to our log
|
|
//
|
|
{
|
|
var outputs = string.Join( '\n', allCompiles.Select( x => x.CompilerOutput ).Distinct() ).Trim();
|
|
|
|
foreach ( var line in outputs.Split( '\n', StringSplitOptions.RemoveEmptyEntries ) )
|
|
{
|
|
if ( options.ConsoleOutput )
|
|
{
|
|
Console.WriteLine( line );
|
|
}
|
|
|
|
stepResult.Log( line );
|
|
}
|
|
}
|
|
|
|
// One of our compiles failed, so just bail
|
|
if ( allCompiles.Any( x => !x.IsSuccess ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if ( builder.IsValid )
|
|
{
|
|
builder.Delete();
|
|
builder = default;
|
|
}
|
|
|
|
builder = CVfxByteCodeManager.Create();
|
|
|
|
foreach ( var staticGroup in allCompiles.GroupBy( x => x.StaticCombo ).OrderBy( x => x.Key ) )
|
|
{
|
|
builder.OnStaticCombo( staticGroup.Key );
|
|
|
|
foreach ( var entry in staticGroup.OrderBy( x => x.DynamicCombo ) )
|
|
{
|
|
builder.OnDynamicCombo( entry.GetResult() );
|
|
|
|
vfx.native.WriteCombo( ProgramType, entry.StaticCombo, entry.DynamicCombo, entry.GetResult() );
|
|
}
|
|
}
|
|
|
|
stepResult.Success = true;
|
|
return true;
|
|
}
|
|
|
|
public byte[] BuildCompiledShader( Shader vfx )
|
|
{
|
|
// Step 1. Copy all our compiled shaders into a CVfxByteCodeManager
|
|
using var buffer = CUtlBuffer.Create();
|
|
vfx.native.WriteProgramToBuffer( ProgramType, builder, buffer );
|
|
|
|
return buffer.ToArray();
|
|
}
|
|
}
|