make new opengl source generator
This commit is contained in:
@@ -0,0 +1,169 @@
|
|||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// file="GlHandleApiFilter"
|
||||||
|
// Project: StgSharp
|
||||||
|
// Copyright (c) Nitload.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using StgSharp.GenerateGL.Registry;
|
||||||
|
|
||||||
|
namespace StgSharp.GenerateGL.Generation
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Replaces registry object-class GLuint values with the managed GlHandle type.
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class GlHandleApiFilter : IGlApiFilter
|
||||||
|
{
|
||||||
|
|
||||||
|
public IReadOnlyList<ManagedMethodDefinition> Apply(
|
||||||
|
GlCommandDefinition command,
|
||||||
|
IReadOnlyList<ManagedMethodDefinition> methods,
|
||||||
|
GlEquivalentTypeMapper typeMapper
|
||||||
|
)
|
||||||
|
{
|
||||||
|
ArgumentNullException.ThrowIfNull(command);
|
||||||
|
ArgumentNullException.ThrowIfNull(methods);
|
||||||
|
ArgumentNullException.ThrowIfNull(typeMapper);
|
||||||
|
|
||||||
|
bool wrapsReturn = string.Equals(
|
||||||
|
command.Return.TypeName,
|
||||||
|
"GLuint",
|
||||||
|
StringComparison.Ordinal) &&
|
||||||
|
command.Return.ObjectClass is not null;
|
||||||
|
return Array.AsReadOnly(
|
||||||
|
methods.Select(
|
||||||
|
method => ConvertMethod(method, wrapsReturn)).ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ManagedMethodDefinition ConvertMethod(
|
||||||
|
ManagedMethodDefinition method,
|
||||||
|
bool wrapsReturn
|
||||||
|
)
|
||||||
|
{
|
||||||
|
ManagedParameterDefinition[] converted = method.Parameters.Select(
|
||||||
|
ConvertParameter).ToArray();
|
||||||
|
if (method.Invocation is not DirectInvocation direct ||
|
||||||
|
!converted.Any(value => value.IsHandleSpan))
|
||||||
|
{
|
||||||
|
return method with
|
||||||
|
{
|
||||||
|
ReturnType = wrapsReturn ? "GlHandle" : method.ReturnType,
|
||||||
|
Parameters = Array.AsReadOnly(converted),
|
||||||
|
WrapHandleReturn = wrapsReturn,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Dictionary<string, int> spanByLengthName = new Dictionary<string, int>(
|
||||||
|
StringComparer.Ordinal);
|
||||||
|
for (int index = 0; index < converted.Length; index++)
|
||||||
|
{
|
||||||
|
ManagedParameterDefinition parameter = converted[index];
|
||||||
|
string? length = parameter.NativeParameter?.Length;
|
||||||
|
if (parameter.IsHandleSpan &&
|
||||||
|
length is not null &&
|
||||||
|
IsIdentifier(length))
|
||||||
|
{
|
||||||
|
spanByLengthName.TryAdd(length, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dictionary<int, int> oldToNew = new Dictionary<int, int>();
|
||||||
|
List<ManagedParameterDefinition> parameters = new List<ManagedParameterDefinition>();
|
||||||
|
for (int oldIndex = 0; oldIndex < converted.Length; oldIndex++)
|
||||||
|
{
|
||||||
|
ManagedParameterDefinition parameter = converted[oldIndex];
|
||||||
|
if (spanByLengthName.ContainsKey(parameter.Name))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
oldToNew.Add(oldIndex, parameters.Count);
|
||||||
|
parameters.Add(parameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ManagedArgument> arguments = new List<ManagedArgument>(direct.Arguments.Count);
|
||||||
|
foreach (ManagedArgument argument in direct.Arguments)
|
||||||
|
{
|
||||||
|
if (argument is not ParameterArgument sourceArgument)
|
||||||
|
{
|
||||||
|
arguments.Add(argument);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ManagedParameterDefinition sourceParameter = converted[sourceArgument.ParameterIndex];
|
||||||
|
if (spanByLengthName.TryGetValue(
|
||||||
|
sourceParameter.Name,
|
||||||
|
out int spanOldIndex))
|
||||||
|
{
|
||||||
|
arguments.Add(new SpanLengthArgument(oldToNew[spanOldIndex]));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
arguments.Add(
|
||||||
|
new ParameterArgument(oldToNew[sourceArgument.ParameterIndex]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return method with
|
||||||
|
{
|
||||||
|
ReturnType = wrapsReturn ? "GlHandle" : method.ReturnType,
|
||||||
|
Parameters = Array.AsReadOnly(parameters.ToArray()),
|
||||||
|
Invocation = new DirectInvocation(Array.AsReadOnly(arguments.ToArray())),
|
||||||
|
WrapHandleReturn = wrapsReturn,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ManagedParameterDefinition ConvertParameter(
|
||||||
|
ManagedParameterDefinition parameter
|
||||||
|
)
|
||||||
|
{
|
||||||
|
GlParameterDefinition? source = parameter.NativeParameter;
|
||||||
|
if (source is null ||
|
||||||
|
source.ObjectClass is null ||
|
||||||
|
!string.Equals(source.TypeName, "GLuint", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
return parameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pointerDepth = source.DeclarationText.Count(value => value == '*');
|
||||||
|
bool isSpan = pointerDepth == 1 && source.Length is not null;
|
||||||
|
string type;
|
||||||
|
if (isSpan)
|
||||||
|
{
|
||||||
|
type = source.DeclarationText.Contains("const", StringComparison.Ordinal)
|
||||||
|
? "ReadOnlySpan<GlHandle>"
|
||||||
|
: "Span<GlHandle>";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
type = pointerDepth == 0
|
||||||
|
? "GlHandle"
|
||||||
|
: $"GlHandle{new string('*', pointerDepth)}";
|
||||||
|
}
|
||||||
|
|
||||||
|
return parameter with
|
||||||
|
{
|
||||||
|
Type = type,
|
||||||
|
IsHandle = true,
|
||||||
|
IsHandleSpan = isSpan,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsIdentifier(
|
||||||
|
string value
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (value.Length == 0 ||
|
||||||
|
!char.IsLetter(value[0]) && value[0] != '_')
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value.Skip(1).All(character => char.IsLetterOrDigit(character) || character == '_');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,391 @@
|
|||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// file="GlOverloadApiFilter"
|
||||||
|
// Project: StgSharp
|
||||||
|
// Copyright (c) Nitload.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using StgSharp.GenerateGL.Registry;
|
||||||
|
|
||||||
|
namespace StgSharp.GenerateGL.Generation
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Replaces verified C-style command families with managed overloads.
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class GlOverloadApiFilter : IGlApiFilter
|
||||||
|
{
|
||||||
|
|
||||||
|
private static readonly Regex _matrixUniformPattern = new Regex(
|
||||||
|
@"^gl(?<family>ProgramUniform|Uniform)Matrix(?<columns>[2-4])" +
|
||||||
|
@"(?:x(?<rows>[2-4]))?(?<type>f|d)v$",
|
||||||
|
RegexOptions.Compiled | RegexOptions.CultureInvariant);
|
||||||
|
|
||||||
|
private static readonly Regex _uniformPattern = new Regex(
|
||||||
|
@"^gl(?<family>ProgramUniform|Uniform)(?<width>[1-4])" +
|
||||||
|
@"(?<type>ui|f|i|d)(?<vector>v?)$",
|
||||||
|
RegexOptions.Compiled | RegexOptions.CultureInvariant);
|
||||||
|
|
||||||
|
private static readonly Regex _vertexAttribPattern = new Regex(
|
||||||
|
@"^glVertexAttrib(?<width>[1-4])(?<type>d|f|s)(?<vector>v?)$",
|
||||||
|
RegexOptions.Compiled | RegexOptions.CultureInvariant);
|
||||||
|
|
||||||
|
private static readonly string[] _components = { "X", "Y", "Z", "W" };
|
||||||
|
|
||||||
|
public IReadOnlyList<ManagedMethodDefinition> Apply(
|
||||||
|
GlCommandDefinition command,
|
||||||
|
IReadOnlyList<ManagedMethodDefinition> methods,
|
||||||
|
GlEquivalentTypeMapper typeMapper
|
||||||
|
)
|
||||||
|
{
|
||||||
|
ArgumentNullException.ThrowIfNull(command);
|
||||||
|
ArgumentNullException.ThrowIfNull(methods);
|
||||||
|
ArgumentNullException.ThrowIfNull(typeMapper);
|
||||||
|
|
||||||
|
Match matrixMatch = _matrixUniformPattern.Match(command.Name);
|
||||||
|
if (matrixMatch.Success)
|
||||||
|
{
|
||||||
|
return RewriteMatrixUniform(command, matrixMatch, typeMapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
Match uniformMatch = _uniformPattern.Match(command.Name);
|
||||||
|
if (uniformMatch.Success)
|
||||||
|
{
|
||||||
|
return RewriteUniform(command, uniformMatch, typeMapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
Match vertexAttribMatch = _vertexAttribPattern.Match(command.Name);
|
||||||
|
if (vertexAttribMatch.Success)
|
||||||
|
{
|
||||||
|
return vertexAttribMatch.Groups["vector"].Value.Length == 0
|
||||||
|
? Array.AsReadOnly(
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
methods[0] with { Name = "VertexAttrib" },
|
||||||
|
})
|
||||||
|
: Array.Empty<ManagedMethodDefinition>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return methods;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ReadOnlyCollection<ManagedMethodDefinition> RewriteUniform(
|
||||||
|
GlCommandDefinition command,
|
||||||
|
Match match,
|
||||||
|
GlEquivalentTypeMapper typeMapper
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int width = int.Parse(
|
||||||
|
match.Groups["width"].Value,
|
||||||
|
CultureInfo.InvariantCulture);
|
||||||
|
string componentType = ReadComponentType(match.Groups["type"].Value);
|
||||||
|
bool isVector = match.Groups["vector"].Value.Length != 0;
|
||||||
|
int prefixCount = match.Groups["family"].Value == "ProgramUniform" ? 2 : 1;
|
||||||
|
string methodName = match.Groups["family"].Value;
|
||||||
|
|
||||||
|
ValidateUniformSignature(
|
||||||
|
command,
|
||||||
|
width,
|
||||||
|
componentType,
|
||||||
|
prefixCount,
|
||||||
|
isVector,
|
||||||
|
typeMapper);
|
||||||
|
|
||||||
|
List<ManagedParameterDefinition> prefix = ReadNativeParameters(
|
||||||
|
command,
|
||||||
|
prefixCount,
|
||||||
|
typeMapper);
|
||||||
|
List<ManagedArgument> prefixArguments = ReadParameterArguments(prefix.Count);
|
||||||
|
if (isVector)
|
||||||
|
{
|
||||||
|
if (width is 2 or 3)
|
||||||
|
{
|
||||||
|
return Array.AsReadOnly(Array.Empty<ManagedMethodDefinition>());
|
||||||
|
}
|
||||||
|
|
||||||
|
GlParameterDefinition valueParameter = command.Parameters[^1];
|
||||||
|
string spanElementType = width == 1
|
||||||
|
? componentType
|
||||||
|
: $"Vec{width}<{componentType}>";
|
||||||
|
List<ManagedParameterDefinition> parameters = new List<ManagedParameterDefinition>(prefix)
|
||||||
|
{
|
||||||
|
new ManagedParameterDefinition(
|
||||||
|
$"ReadOnlySpan<{spanElementType}>",
|
||||||
|
"values",
|
||||||
|
valueParameter),
|
||||||
|
};
|
||||||
|
ManagedInvocation invocation = width == 1
|
||||||
|
? new PinnedSpanInvocation(
|
||||||
|
prefixArguments,
|
||||||
|
parameters.Count - 1,
|
||||||
|
componentType)
|
||||||
|
: new PinnedVectorSpanInvocation(
|
||||||
|
prefixArguments,
|
||||||
|
parameters.Count - 1,
|
||||||
|
componentType,
|
||||||
|
spanElementType);
|
||||||
|
return Array.AsReadOnly(
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
new ManagedMethodDefinition(
|
||||||
|
methodName,
|
||||||
|
"void",
|
||||||
|
Array.AsReadOnly(parameters.ToArray()),
|
||||||
|
command,
|
||||||
|
invocation),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ManagedMethodDefinition> methods = new List<ManagedMethodDefinition>();
|
||||||
|
List<ManagedParameterDefinition> scalarParameters = ReadNativeParameters(
|
||||||
|
command,
|
||||||
|
command.Parameters.Count,
|
||||||
|
typeMapper);
|
||||||
|
methods.Add(
|
||||||
|
new ManagedMethodDefinition(
|
||||||
|
methodName,
|
||||||
|
"void",
|
||||||
|
Array.AsReadOnly(scalarParameters.ToArray()),
|
||||||
|
command,
|
||||||
|
new DirectInvocation(ReadParameterArguments(scalarParameters.Count))));
|
||||||
|
|
||||||
|
if (width > 1)
|
||||||
|
{
|
||||||
|
List<ManagedParameterDefinition> vectorParameters = new List<ManagedParameterDefinition>(prefix)
|
||||||
|
{
|
||||||
|
new ManagedParameterDefinition(
|
||||||
|
$"Vec{width}<{componentType}>",
|
||||||
|
"value"),
|
||||||
|
};
|
||||||
|
List<ManagedArgument> vectorArguments = new List<ManagedArgument>(prefixArguments);
|
||||||
|
for (int index = 0; index < width; index++)
|
||||||
|
{
|
||||||
|
vectorArguments.Add(
|
||||||
|
new VectorComponentArgument(
|
||||||
|
vectorParameters.Count - 1,
|
||||||
|
_components[index]));
|
||||||
|
}
|
||||||
|
|
||||||
|
methods.Add(
|
||||||
|
new ManagedMethodDefinition(
|
||||||
|
methodName,
|
||||||
|
"void",
|
||||||
|
Array.AsReadOnly(vectorParameters.ToArray()),
|
||||||
|
command,
|
||||||
|
new DirectInvocation(Array.AsReadOnly(vectorArguments.ToArray()))));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Array.AsReadOnly(methods.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IReadOnlyList<ManagedMethodDefinition> RewriteMatrixUniform(
|
||||||
|
GlCommandDefinition command,
|
||||||
|
Match match,
|
||||||
|
GlEquivalentTypeMapper typeMapper
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int columns = int.Parse(
|
||||||
|
match.Groups["columns"].Value,
|
||||||
|
CultureInfo.InvariantCulture);
|
||||||
|
int rows = match.Groups["rows"].Success
|
||||||
|
? int.Parse(
|
||||||
|
match.Groups["rows"].Value,
|
||||||
|
CultureInfo.InvariantCulture)
|
||||||
|
: columns;
|
||||||
|
string componentType = ReadComponentType(match.Groups["type"].Value);
|
||||||
|
int prefixCount = match.Groups["family"].Value == "ProgramUniform" ? 2 : 1;
|
||||||
|
string methodName = match.Groups["family"].Value;
|
||||||
|
|
||||||
|
ValidateMatrixSignature(
|
||||||
|
command,
|
||||||
|
columns,
|
||||||
|
rows,
|
||||||
|
componentType,
|
||||||
|
prefixCount,
|
||||||
|
typeMapper);
|
||||||
|
if (columns != 4 || rows != 4 || componentType != "float")
|
||||||
|
{
|
||||||
|
return Array.Empty<ManagedMethodDefinition>();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ManagedParameterDefinition> prefix = ReadNativeParameters(
|
||||||
|
command,
|
||||||
|
prefixCount,
|
||||||
|
typeMapper);
|
||||||
|
List<ManagedArgument> prefixArguments = ReadParameterArguments(prefix.Count);
|
||||||
|
GlParameterDefinition transposeSource = command.Parameters[prefixCount + 1];
|
||||||
|
GlParameterDefinition valueSource = command.Parameters[prefixCount + 2];
|
||||||
|
|
||||||
|
List<ManagedParameterDefinition> singleParameters = new List<ManagedParameterDefinition>(prefix)
|
||||||
|
{
|
||||||
|
new ManagedParameterDefinition("bool", "transpose", transposeSource),
|
||||||
|
new ManagedParameterDefinition("GraphicsMatrix", "value", valueSource),
|
||||||
|
};
|
||||||
|
List<ManagedParameterDefinition> spanParameters = new List<ManagedParameterDefinition>(prefix)
|
||||||
|
{
|
||||||
|
new ManagedParameterDefinition("bool", "transpose", transposeSource),
|
||||||
|
new ManagedParameterDefinition(
|
||||||
|
"ReadOnlySpan<GraphicsMatrix>",
|
||||||
|
"values",
|
||||||
|
valueSource),
|
||||||
|
};
|
||||||
|
|
||||||
|
return Array.AsReadOnly(
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
new ManagedMethodDefinition(
|
||||||
|
methodName,
|
||||||
|
"void",
|
||||||
|
Array.AsReadOnly(singleParameters.ToArray()),
|
||||||
|
command,
|
||||||
|
new Matrix4Invocation(
|
||||||
|
prefixArguments,
|
||||||
|
singleParameters.Count - 2,
|
||||||
|
singleParameters.Count - 1,
|
||||||
|
false)),
|
||||||
|
new ManagedMethodDefinition(
|
||||||
|
methodName,
|
||||||
|
"void",
|
||||||
|
Array.AsReadOnly(spanParameters.ToArray()),
|
||||||
|
command,
|
||||||
|
new Matrix4Invocation(
|
||||||
|
prefixArguments,
|
||||||
|
spanParameters.Count - 2,
|
||||||
|
spanParameters.Count - 1,
|
||||||
|
true)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ValidateUniformSignature(
|
||||||
|
GlCommandDefinition command,
|
||||||
|
int width,
|
||||||
|
string componentType,
|
||||||
|
int prefixCount,
|
||||||
|
bool isVector,
|
||||||
|
GlEquivalentTypeMapper typeMapper
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int expectedCount = prefixCount + (isVector ? 2 : width);
|
||||||
|
if (command.Parameters.Count != expectedCount)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
$"Uniform command '{command.Name}' does not match its recognized shape.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isVector)
|
||||||
|
{
|
||||||
|
GlParameterDefinition count = command.Parameters[prefixCount];
|
||||||
|
GlParameterDefinition value = command.Parameters[prefixCount + 1];
|
||||||
|
string expectedLength = $"{count.Name}*{width}";
|
||||||
|
string expectedKind = $"Vector{width}";
|
||||||
|
if (typeMapper.ReadParameterType(value) != $"{componentType}*" ||
|
||||||
|
!string.Equals(value.Length, expectedLength, StringComparison.Ordinal) &&
|
||||||
|
!(width == 1 && string.Equals(
|
||||||
|
value.Length,
|
||||||
|
count.Name,
|
||||||
|
StringComparison.Ordinal)) ||
|
||||||
|
!string.Equals(value.Kind, expectedKind, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
$"Uniform command '{command.Name}' has inconsistent vector metadata.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int index = prefixCount; index < command.Parameters.Count; index++)
|
||||||
|
{
|
||||||
|
if (typeMapper.ReadParameterType(command.Parameters[index]) != componentType)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
$"Uniform command '{command.Name}' has inconsistent component types.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ValidateMatrixSignature(
|
||||||
|
GlCommandDefinition command,
|
||||||
|
int columns,
|
||||||
|
int rows,
|
||||||
|
string componentType,
|
||||||
|
int prefixCount,
|
||||||
|
GlEquivalentTypeMapper typeMapper
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (command.Parameters.Count != prefixCount + 3)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
$"Matrix command '{command.Name}' does not match its recognized shape.");
|
||||||
|
}
|
||||||
|
|
||||||
|
GlParameterDefinition count = command.Parameters[prefixCount];
|
||||||
|
GlParameterDefinition value = command.Parameters[prefixCount + 2];
|
||||||
|
if (typeMapper.ReadParameterType(value) != $"{componentType}*" ||
|
||||||
|
!string.Equals(
|
||||||
|
value.Kind,
|
||||||
|
$"Matrix{columns}x{rows}",
|
||||||
|
StringComparison.Ordinal) ||
|
||||||
|
!string.Equals(
|
||||||
|
value.Length,
|
||||||
|
$"{count.Name}*{columns * rows}",
|
||||||
|
StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
$"Matrix command '{command.Name}' has inconsistent matrix metadata.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<ManagedParameterDefinition> ReadNativeParameters(
|
||||||
|
GlCommandDefinition command,
|
||||||
|
int count,
|
||||||
|
GlEquivalentTypeMapper typeMapper
|
||||||
|
)
|
||||||
|
{
|
||||||
|
List<ManagedParameterDefinition> parameters = new List<ManagedParameterDefinition>(count);
|
||||||
|
for (int index = 0; index < count; index++)
|
||||||
|
{
|
||||||
|
GlParameterDefinition source = command.Parameters[index];
|
||||||
|
parameters.Add(
|
||||||
|
new ManagedParameterDefinition(
|
||||||
|
typeMapper.ReadParameterType(source),
|
||||||
|
source.Name,
|
||||||
|
source));
|
||||||
|
}
|
||||||
|
|
||||||
|
return parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<ManagedArgument> ReadParameterArguments(
|
||||||
|
int count
|
||||||
|
)
|
||||||
|
{
|
||||||
|
List<ManagedArgument> arguments = new List<ManagedArgument>(count);
|
||||||
|
for (int index = 0; index < count; index++)
|
||||||
|
{
|
||||||
|
arguments.Add(new ParameterArgument(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
return arguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ReadComponentType(
|
||||||
|
string suffix
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return suffix switch
|
||||||
|
{
|
||||||
|
"f" => "float",
|
||||||
|
"i" => "int",
|
||||||
|
"ui" => "uint",
|
||||||
|
"d" => "double",
|
||||||
|
_ => throw new InvalidOperationException(
|
||||||
|
$"Unsupported uniform component suffix '{suffix}'."),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// file="IGlApiFilter"
|
||||||
|
// Project: StgSharp
|
||||||
|
// Copyright (c) Nitload.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using StgSharp.GenerateGL.Registry;
|
||||||
|
|
||||||
|
namespace StgSharp.GenerateGL.Generation
|
||||||
|
{
|
||||||
|
internal interface IGlApiFilter
|
||||||
|
{
|
||||||
|
|
||||||
|
IReadOnlyList<ManagedMethodDefinition> Apply(
|
||||||
|
GlCommandDefinition command,
|
||||||
|
IReadOnlyList<ManagedMethodDefinition> methods,
|
||||||
|
GlEquivalentTypeMapper typeMapper
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// file="ManagedApiModel"
|
||||||
|
// Project: StgSharp
|
||||||
|
// Copyright (c) Nitload.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using StgSharp.GenerateGL.Registry;
|
||||||
|
|
||||||
|
namespace StgSharp.GenerateGL.Generation
|
||||||
|
{
|
||||||
|
internal sealed record ManagedMethodDefinition(
|
||||||
|
string Name,
|
||||||
|
string ReturnType,
|
||||||
|
IReadOnlyList<ManagedParameterDefinition> Parameters,
|
||||||
|
GlCommandDefinition NativeCommand,
|
||||||
|
ManagedInvocation Invocation,
|
||||||
|
bool WrapHandleReturn = false
|
||||||
|
);
|
||||||
|
|
||||||
|
internal sealed record ManagedParameterDefinition(
|
||||||
|
string Type,
|
||||||
|
string Name,
|
||||||
|
GlParameterDefinition? NativeParameter = null,
|
||||||
|
bool IsHandle = false,
|
||||||
|
bool IsHandleSpan = false
|
||||||
|
);
|
||||||
|
|
||||||
|
internal abstract record ManagedInvocation;
|
||||||
|
|
||||||
|
internal sealed record DirectInvocation(
|
||||||
|
IReadOnlyList<ManagedArgument> Arguments
|
||||||
|
) : ManagedInvocation;
|
||||||
|
|
||||||
|
internal sealed record PinnedSpanInvocation(
|
||||||
|
IReadOnlyList<ManagedArgument> PrefixArguments,
|
||||||
|
int SpanParameterIndex,
|
||||||
|
string ElementType
|
||||||
|
) : ManagedInvocation;
|
||||||
|
|
||||||
|
internal sealed record PinnedVectorSpanInvocation(
|
||||||
|
IReadOnlyList<ManagedArgument> PrefixArguments,
|
||||||
|
int SpanParameterIndex,
|
||||||
|
string ComponentType,
|
||||||
|
string VectorType
|
||||||
|
) : ManagedInvocation;
|
||||||
|
|
||||||
|
internal sealed record Matrix4Invocation(
|
||||||
|
IReadOnlyList<ManagedArgument> PrefixArguments,
|
||||||
|
int TransposeParameterIndex,
|
||||||
|
int MatrixParameterIndex,
|
||||||
|
bool IsSpan
|
||||||
|
) : ManagedInvocation;
|
||||||
|
|
||||||
|
internal abstract record ManagedArgument;
|
||||||
|
|
||||||
|
internal sealed record ParameterArgument(
|
||||||
|
int ParameterIndex
|
||||||
|
) : ManagedArgument;
|
||||||
|
|
||||||
|
internal sealed record VectorComponentArgument(
|
||||||
|
int ParameterIndex,
|
||||||
|
string Component
|
||||||
|
) : ManagedArgument;
|
||||||
|
|
||||||
|
internal sealed record SpanLengthArgument(
|
||||||
|
int ParameterIndex
|
||||||
|
) : ManagedArgument;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// file="ManagedApiPlanner"
|
||||||
|
// Project: StgSharp
|
||||||
|
// Copyright (c) Nitload.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using StgSharp.GenerateGL.Registry;
|
||||||
|
|
||||||
|
namespace StgSharp.GenerateGL.Generation
|
||||||
|
{
|
||||||
|
internal sealed class ManagedApiPlanner
|
||||||
|
{
|
||||||
|
|
||||||
|
private readonly IReadOnlyList<IGlApiFilter> _filters = Array.AsReadOnly<IGlApiFilter>(
|
||||||
|
new IGlApiFilter[]
|
||||||
|
{
|
||||||
|
new GlOverloadApiFilter(),
|
||||||
|
new GlHandleApiFilter(),
|
||||||
|
});
|
||||||
|
private readonly GlEquivalentTypeMapper _typeMapper;
|
||||||
|
|
||||||
|
public ManagedApiPlanner(
|
||||||
|
GlEquivalentTypeMapper typeMapper
|
||||||
|
)
|
||||||
|
{
|
||||||
|
ArgumentNullException.ThrowIfNull(typeMapper);
|
||||||
|
_typeMapper = typeMapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyList<ManagedMethodDefinition> Plan(
|
||||||
|
IReadOnlyList<GlCommandDefinition> commands
|
||||||
|
)
|
||||||
|
{
|
||||||
|
ArgumentNullException.ThrowIfNull(commands);
|
||||||
|
|
||||||
|
List<ManagedMethodDefinition> result = new List<ManagedMethodDefinition>();
|
||||||
|
foreach (GlCommandDefinition command in commands)
|
||||||
|
{
|
||||||
|
IReadOnlyList<ManagedMethodDefinition> methods = Array.AsReadOnly(
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
CreateRawMethod(command),
|
||||||
|
});
|
||||||
|
foreach (IGlApiFilter filter in _filters)
|
||||||
|
{
|
||||||
|
methods = filter.Apply(command, methods, _typeMapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.AddRange(methods);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Array.AsReadOnly(result.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Validate(
|
||||||
|
IEnumerable<ManagedMethodDefinition> methods
|
||||||
|
)
|
||||||
|
{
|
||||||
|
ArgumentNullException.ThrowIfNull(methods);
|
||||||
|
|
||||||
|
Dictionary<string, ManagedMethodDefinition> signatures = new Dictionary<string, ManagedMethodDefinition>(
|
||||||
|
StringComparer.Ordinal);
|
||||||
|
foreach (ManagedMethodDefinition method in methods)
|
||||||
|
{
|
||||||
|
string signature = $"{method.Name}({string.Join(",", method.Parameters.Select(value => value.Type))})";
|
||||||
|
if (signatures.TryGetValue(signature, out ManagedMethodDefinition? previous))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
$"Managed overload '{signature}' is produced by both " +
|
||||||
|
$"'{previous.NativeCommand.Name}' and '{method.NativeCommand.Name}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
signatures.Add(signature, method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ManagedMethodDefinition CreateRawMethod(
|
||||||
|
GlCommandDefinition command
|
||||||
|
)
|
||||||
|
{
|
||||||
|
List<ManagedParameterDefinition> parameters = new List<ManagedParameterDefinition>(
|
||||||
|
command.Parameters.Count);
|
||||||
|
List<ManagedArgument> arguments = new List<ManagedArgument>(
|
||||||
|
command.Parameters.Count);
|
||||||
|
for (int index = 0; index < command.Parameters.Count; index++)
|
||||||
|
{
|
||||||
|
GlParameterDefinition source = command.Parameters[index];
|
||||||
|
parameters.Add(
|
||||||
|
new ManagedParameterDefinition(
|
||||||
|
_typeMapper.ReadParameterType(source),
|
||||||
|
source.Name,
|
||||||
|
source));
|
||||||
|
arguments.Add(new ParameterArgument(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ManagedMethodDefinition(
|
||||||
|
ReadMethodName(command.Name),
|
||||||
|
_typeMapper.ReadReturnType(command),
|
||||||
|
Array.AsReadOnly(parameters.ToArray()),
|
||||||
|
command,
|
||||||
|
new DirectInvocation(Array.AsReadOnly(arguments.ToArray())));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ReadMethodName(
|
||||||
|
string commandName
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return commandName.StartsWith("gl", StringComparison.Ordinal) &&
|
||||||
|
commandName.Length > 2
|
||||||
|
? commandName[2..]
|
||||||
|
: commandName;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -49,22 +49,41 @@ namespace StgSharp.GenerateGL.Generation
|
|||||||
{
|
{
|
||||||
ArgumentNullException.ThrowIfNull(registry);
|
ArgumentNullException.ThrowIfNull(registry);
|
||||||
|
|
||||||
IReadOnlyList<GlCommandDefinition> commands = ReadCoreCommands(registry);
|
IReadOnlyList<GlCommandGroup> commandGroups = ReadCoreCommandGroups(registry);
|
||||||
|
IReadOnlyList<GlCommandDefinition> commands = Array.AsReadOnly(
|
||||||
|
commandGroups.SelectMany(value => value.Commands).ToArray());
|
||||||
GlEquivalentTypeMapper typeMapper = new GlEquivalentTypeMapper(registry);
|
GlEquivalentTypeMapper typeMapper = new GlEquivalentTypeMapper(registry);
|
||||||
return new GeneratedFileSet(
|
ManagedApiPlanner apiPlanner = new ManagedApiPlanner(typeMapper);
|
||||||
new[]
|
List<ManagedCommandGroup> managedGroups = commandGroups.Select(
|
||||||
|
group => new ManagedCommandGroup(
|
||||||
|
group,
|
||||||
|
apiPlanner.Plan(group.Commands))).ToList();
|
||||||
|
ManagedApiPlanner.Validate(
|
||||||
|
managedGroups.SelectMany(value => value.Methods));
|
||||||
|
List<GeneratedFile> files = new List<GeneratedFile>
|
||||||
{
|
{
|
||||||
new GeneratedFile("glconst.cs", GenerateConstants(registry)),
|
new GeneratedFile("glconst.cs", GenerateConstants(registry)),
|
||||||
new GeneratedFile(
|
new GeneratedFile(
|
||||||
"OpenglContext.g.cs",
|
"OpenglContext.g.cs",
|
||||||
GenerateContext(commands, typeMapper)),
|
GenerateContext(commands, typeMapper)),
|
||||||
|
};
|
||||||
|
for (int index = 0; index < managedGroups.Count; index++)
|
||||||
|
{
|
||||||
|
ManagedCommandGroup managedGroup = managedGroups[index];
|
||||||
|
GlCommandGroup group = managedGroup.Source;
|
||||||
|
files.Add(
|
||||||
new GeneratedFile(
|
new GeneratedFile(
|
||||||
"OpenGLFunction.Raw.g.cs",
|
group.FileName,
|
||||||
GenerateFunctions(commands, typeMapper)),
|
GenerateFunctions(
|
||||||
});
|
managedGroup.Methods,
|
||||||
|
group.Description,
|
||||||
|
index == 0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ReadOnlyCollection<GlCommandDefinition> ReadCoreCommands(
|
return new GeneratedFileSet(files);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ReadOnlyCollection<GlCommandGroup> ReadCoreCommandGroups(
|
||||||
GlRegistryModel registry
|
GlRegistryModel registry
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@@ -82,6 +101,8 @@ namespace StgSharp.GenerateGL.Generation
|
|||||||
List<string> order = new List<string>();
|
List<string> order = new List<string>();
|
||||||
HashSet<string> known = new HashSet<string>(StringComparer.Ordinal);
|
HashSet<string> known = new HashSet<string>(StringComparer.Ordinal);
|
||||||
HashSet<string> active = new HashSet<string>(StringComparer.Ordinal);
|
HashSet<string> active = new HashSet<string>(StringComparer.Ordinal);
|
||||||
|
Dictionary<string, string> introducedVersions = new Dictionary<string, string>(
|
||||||
|
StringComparer.Ordinal);
|
||||||
foreach (GlFeatureDefinition feature in registry.Features.Where(
|
foreach (GlFeatureDefinition feature in registry.Features.Where(
|
||||||
value => string.Equals(value.Api, ApiName, StringComparison.Ordinal)))
|
value => string.Equals(value.Api, ApiName, StringComparison.Ordinal)))
|
||||||
{
|
{
|
||||||
@@ -103,6 +124,7 @@ namespace StgSharp.GenerateGL.Generation
|
|||||||
if (known.Add(reference.Name))
|
if (known.Add(reference.Name))
|
||||||
{
|
{
|
||||||
order.Add(reference.Name);
|
order.Add(reference.Name);
|
||||||
|
introducedVersions.Add(reference.Name, feature.Number);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -113,8 +135,72 @@ namespace StgSharp.GenerateGL.Generation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Array.AsReadOnly(
|
List<GlCommandDefinition> foundation = new List<GlCommandDefinition>();
|
||||||
order.Where(active.Contains).Select(value => definitions[value]).ToArray());
|
Dictionary<string, List<GlCommandDefinition>> versionGroups = new Dictionary<string, List<GlCommandDefinition>>(
|
||||||
|
StringComparer.Ordinal);
|
||||||
|
List<string> versionOrder = new List<string>();
|
||||||
|
foreach (string commandName in order.Where(active.Contains))
|
||||||
|
{
|
||||||
|
string version = introducedVersions[commandName];
|
||||||
|
if (IsFoundationVersion(version))
|
||||||
|
{
|
||||||
|
foundation.Add(definitions[commandName]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!versionGroups.TryGetValue(
|
||||||
|
version,
|
||||||
|
out List<GlCommandDefinition>? commands))
|
||||||
|
{
|
||||||
|
commands = new List<GlCommandDefinition>();
|
||||||
|
versionGroups.Add(version, commands);
|
||||||
|
versionOrder.Add(version);
|
||||||
|
}
|
||||||
|
|
||||||
|
commands.Add(definitions[commandName]);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<GlCommandGroup> groups = new List<GlCommandGroup>
|
||||||
|
{
|
||||||
|
new GlCommandGroup(
|
||||||
|
"OpenGLFunction.Base.g.cs",
|
||||||
|
"Desktop OpenGL forwarding methods introduced through 3.2 and retained by the target core profile",
|
||||||
|
Array.AsReadOnly(foundation.ToArray())),
|
||||||
|
};
|
||||||
|
foreach (string version in versionOrder)
|
||||||
|
{
|
||||||
|
groups.Add(
|
||||||
|
new GlCommandGroup(
|
||||||
|
$"OpenGLFunction.v{version.Replace('.', '_')}.g.cs",
|
||||||
|
$"Desktop OpenGL {version} core-profile forwarding methods",
|
||||||
|
Array.AsReadOnly(versionGroups[version].ToArray())));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Array.AsReadOnly(groups.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsFoundationVersion(
|
||||||
|
string version
|
||||||
|
)
|
||||||
|
{
|
||||||
|
string[] components = version.Split('.');
|
||||||
|
if (components.Length != 2 ||
|
||||||
|
!int.TryParse(
|
||||||
|
components[0],
|
||||||
|
NumberStyles.None,
|
||||||
|
CultureInfo.InvariantCulture,
|
||||||
|
out int major) ||
|
||||||
|
!int.TryParse(
|
||||||
|
components[1],
|
||||||
|
NumberStyles.None,
|
||||||
|
CultureInfo.InvariantCulture,
|
||||||
|
out int minor))
|
||||||
|
{
|
||||||
|
throw new InvalidDataException(
|
||||||
|
$"OpenGL feature version '{version}' is not a major.minor number.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return major < 3 || major == 3 && minor <= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool AppliesToCoreGl(
|
private static bool AppliesToCoreGl(
|
||||||
@@ -319,62 +405,53 @@ namespace StgSharp.GenerateGL.Generation
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static string GenerateFunctions(
|
private static string GenerateFunctions(
|
||||||
IReadOnlyList<GlCommandDefinition> commands,
|
IReadOnlyList<ManagedMethodDefinition> methods,
|
||||||
GlEquivalentTypeMapper typeMapper
|
string description,
|
||||||
|
bool includeContextState
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
StringBuilder builder = new StringBuilder(512 * 1024);
|
StringBuilder builder = new StringBuilder(512 * 1024);
|
||||||
AppendGeneratedHeader(builder, "Desktop OpenGL core forwarding methods");
|
AppendGeneratedHeader(builder, description);
|
||||||
|
builder.Append("using StgSharp.Mathematics.Graphics;\n\n");
|
||||||
|
builder.Append("using System;\n");
|
||||||
builder.Append("using System.Runtime.CompilerServices;\n\n");
|
builder.Append("using System.Runtime.CompilerServices;\n\n");
|
||||||
builder.Append("namespace StgSharp.Graphics.OpenGL\n");
|
builder.Append("namespace StgSharp.Graphics.OpenGL\n");
|
||||||
builder.Append("{\n");
|
builder.Append("{\n");
|
||||||
builder.Append(" public unsafe partial class OpenGLFunction\n");
|
builder.Append(" public unsafe partial class OpenGLFunction\n");
|
||||||
builder.Append(" {\n");
|
builder.Append(" {\n");
|
||||||
|
if (includeContextState)
|
||||||
|
{
|
||||||
builder.Append("\n private readonly OpenglContext* __context;\n");
|
builder.Append("\n private readonly OpenglContext* __context;\n");
|
||||||
builder.Append("\n internal OpenGLFunction(OpenglContext* context)\n");
|
builder.Append("\n internal OpenGLFunction(OpenglContext* context)\n");
|
||||||
builder.Append(" {\n");
|
builder.Append(" {\n");
|
||||||
builder.Append(" __context = context;\n");
|
builder.Append(" __context = context;\n");
|
||||||
builder.Append(" }\n");
|
builder.Append(" }\n");
|
||||||
foreach (GlCommandDefinition command in commands)
|
}
|
||||||
|
|
||||||
|
foreach (ManagedMethodDefinition method in methods)
|
||||||
{
|
{
|
||||||
string returnType = typeMapper.ReadReturnType(command);
|
|
||||||
string methodName = ReadMethodName(command.Name);
|
|
||||||
builder.Append("\n [MethodImpl(MethodImplOptions.AggressiveInlining)]\n");
|
builder.Append("\n [MethodImpl(MethodImplOptions.AggressiveInlining)]\n");
|
||||||
builder.Append(" public ");
|
builder.Append(" public ");
|
||||||
builder.Append(returnType);
|
builder.Append(method.ReturnType);
|
||||||
builder.Append(' ');
|
builder.Append(' ');
|
||||||
builder.Append(methodName);
|
builder.Append(method.Name);
|
||||||
builder.Append('(');
|
builder.Append('(');
|
||||||
for (int index = 0; index < command.Parameters.Count; index++)
|
for (int index = 0; index < method.Parameters.Count; index++)
|
||||||
{
|
{
|
||||||
if (index != 0)
|
if (index != 0)
|
||||||
{
|
{
|
||||||
builder.Append(", ");
|
builder.Append(", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
GlParameterDefinition parameter = command.Parameters[index];
|
ManagedParameterDefinition parameter = method.Parameters[index];
|
||||||
builder.Append(typeMapper.ReadParameterType(parameter));
|
builder.Append(parameter.Type);
|
||||||
builder.Append(' ');
|
builder.Append(' ');
|
||||||
builder.Append(EscapeIdentifier(parameter.Name));
|
builder.Append(EscapeIdentifier(parameter.Name));
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.Append(")\n");
|
builder.Append(")\n");
|
||||||
builder.Append(" {\n");
|
builder.Append(" {\n");
|
||||||
builder.Append(" ");
|
AppendInvocation(builder, method);
|
||||||
if (returnType != "void")
|
|
||||||
{
|
|
||||||
builder.Append("return ");
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.Append("__context->");
|
|
||||||
builder.Append(command.Name);
|
|
||||||
builder.Append('(');
|
|
||||||
builder.Append(
|
|
||||||
string.Join(
|
|
||||||
", ",
|
|
||||||
command.Parameters.Select(
|
|
||||||
value => EscapeIdentifier(value.Name))));
|
|
||||||
builder.Append(");\n");
|
|
||||||
builder.Append(" }\n");
|
builder.Append(" }\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -383,14 +460,252 @@ namespace StgSharp.GenerateGL.Generation
|
|||||||
return builder.ToString();
|
return builder.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string ReadMethodName(
|
private static void AppendInvocation(
|
||||||
string commandName
|
StringBuilder builder,
|
||||||
|
ManagedMethodDefinition method
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return commandName.StartsWith("gl", StringComparison.Ordinal) &&
|
switch (method.Invocation)
|
||||||
commandName.Length > 2
|
{
|
||||||
? commandName[2..]
|
case DirectInvocation direct:
|
||||||
: commandName;
|
AppendDirectInvocation(builder, method, direct);
|
||||||
|
break;
|
||||||
|
case PinnedSpanInvocation pinned:
|
||||||
|
AppendPinnedSpanInvocation(builder, method, pinned);
|
||||||
|
break;
|
||||||
|
case PinnedVectorSpanInvocation pinnedVector:
|
||||||
|
AppendPinnedVectorSpanInvocation(builder, method, pinnedVector);
|
||||||
|
break;
|
||||||
|
case Matrix4Invocation matrix:
|
||||||
|
AppendMatrix4Invocation(builder, method, matrix);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
$"Unsupported managed invocation '{method.Invocation.GetType().Name}'.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AppendDirectInvocation(
|
||||||
|
StringBuilder builder,
|
||||||
|
ManagedMethodDefinition method,
|
||||||
|
DirectInvocation invocation
|
||||||
|
)
|
||||||
|
{
|
||||||
|
List<int> fixedParameters = new List<int>();
|
||||||
|
for (int index = 0; index < method.Parameters.Count; index++)
|
||||||
|
{
|
||||||
|
if (method.Parameters[index].IsHandleSpan)
|
||||||
|
{
|
||||||
|
fixedParameters.Add(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int indentation = 12;
|
||||||
|
foreach (int parameterIndex in fixedParameters)
|
||||||
|
{
|
||||||
|
ManagedParameterDefinition parameter = method.Parameters[parameterIndex];
|
||||||
|
builder.Append(' ', indentation);
|
||||||
|
builder.Append("fixed (GlHandle* __");
|
||||||
|
builder.Append(parameter.Name);
|
||||||
|
builder.Append(" = ");
|
||||||
|
builder.Append(EscapeIdentifier(parameter.Name));
|
||||||
|
builder.Append(")\n");
|
||||||
|
builder.Append(' ', indentation);
|
||||||
|
builder.Append("{\n");
|
||||||
|
indentation += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.Append(' ', indentation);
|
||||||
|
if (method.WrapHandleReturn)
|
||||||
|
{
|
||||||
|
builder.Append("return GlHandle.Create(");
|
||||||
|
}
|
||||||
|
else if (method.ReturnType != "void")
|
||||||
|
{
|
||||||
|
builder.Append("return ");
|
||||||
|
}
|
||||||
|
|
||||||
|
AppendNativeCall(builder, method, invocation.Arguments);
|
||||||
|
builder.Append(method.WrapHandleReturn ? ");\n" : ";\n");
|
||||||
|
for (int index = fixedParameters.Count - 1; index >= 0; index--)
|
||||||
|
{
|
||||||
|
indentation -= 4;
|
||||||
|
builder.Append(' ', indentation);
|
||||||
|
builder.Append("}\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AppendPinnedSpanInvocation(
|
||||||
|
StringBuilder builder,
|
||||||
|
ManagedMethodDefinition method,
|
||||||
|
PinnedSpanInvocation invocation
|
||||||
|
)
|
||||||
|
{
|
||||||
|
ManagedParameterDefinition span = method.Parameters[invocation.SpanParameterIndex];
|
||||||
|
builder.Append(" fixed (");
|
||||||
|
builder.Append(invocation.ElementType);
|
||||||
|
builder.Append("* __value = ");
|
||||||
|
builder.Append(EscapeIdentifier(span.Name));
|
||||||
|
builder.Append(")\n");
|
||||||
|
builder.Append(" {\n");
|
||||||
|
builder.Append(" __context->");
|
||||||
|
builder.Append(method.NativeCommand.Name);
|
||||||
|
builder.Append('(');
|
||||||
|
AppendArguments(builder, method, invocation.PrefixArguments);
|
||||||
|
if (invocation.PrefixArguments.Count != 0)
|
||||||
|
{
|
||||||
|
builder.Append(", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.Append(EscapeIdentifier(span.Name));
|
||||||
|
builder.Append(".Length, __value);\n");
|
||||||
|
builder.Append(" }\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AppendPinnedVectorSpanInvocation(
|
||||||
|
StringBuilder builder,
|
||||||
|
ManagedMethodDefinition method,
|
||||||
|
PinnedVectorSpanInvocation invocation
|
||||||
|
)
|
||||||
|
{
|
||||||
|
ManagedParameterDefinition span = method.Parameters[invocation.SpanParameterIndex];
|
||||||
|
string spanName = EscapeIdentifier(span.Name);
|
||||||
|
builder.Append(" fixed (");
|
||||||
|
builder.Append(invocation.VectorType);
|
||||||
|
builder.Append("* __vector = ");
|
||||||
|
builder.Append(spanName);
|
||||||
|
builder.Append(")\n");
|
||||||
|
builder.Append(" {\n");
|
||||||
|
builder.Append(" __context->");
|
||||||
|
builder.Append(method.NativeCommand.Name);
|
||||||
|
builder.Append('(');
|
||||||
|
AppendArguments(builder, method, invocation.PrefixArguments);
|
||||||
|
if (invocation.PrefixArguments.Count != 0)
|
||||||
|
{
|
||||||
|
builder.Append(", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.Append(spanName);
|
||||||
|
builder.Append(".Length, (");
|
||||||
|
builder.Append(invocation.ComponentType);
|
||||||
|
builder.Append("*)__vector);\n");
|
||||||
|
builder.Append(" }\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AppendMatrix4Invocation(
|
||||||
|
StringBuilder builder,
|
||||||
|
ManagedMethodDefinition method,
|
||||||
|
Matrix4Invocation invocation
|
||||||
|
)
|
||||||
|
{
|
||||||
|
ManagedParameterDefinition transpose = method.Parameters[invocation.TransposeParameterIndex];
|
||||||
|
ManagedParameterDefinition matrix = method.Parameters[invocation.MatrixParameterIndex];
|
||||||
|
string transposeName = EscapeIdentifier(transpose.Name);
|
||||||
|
string matrixName = EscapeIdentifier(matrix.Name);
|
||||||
|
if (invocation.IsSpan)
|
||||||
|
{
|
||||||
|
builder.Append(" fixed (GraphicsMatrix* __value = ");
|
||||||
|
builder.Append(matrixName);
|
||||||
|
builder.Append(")\n");
|
||||||
|
builder.Append(" {\n");
|
||||||
|
builder.Append(" __context->");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
builder.Append(" __context->");
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.Append(method.NativeCommand.Name);
|
||||||
|
builder.Append('(');
|
||||||
|
AppendArguments(builder, method, invocation.PrefixArguments);
|
||||||
|
if (invocation.PrefixArguments.Count != 0)
|
||||||
|
{
|
||||||
|
builder.Append(", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.Append(invocation.IsSpan ? $"{matrixName}.Length" : "1");
|
||||||
|
builder.Append(", ");
|
||||||
|
builder.Append(transposeName);
|
||||||
|
builder.Append(" ? (byte)1 : (byte)0, (float*)");
|
||||||
|
builder.Append(invocation.IsSpan ? "__value" : $"&{matrixName}");
|
||||||
|
builder.Append(");\n");
|
||||||
|
if (invocation.IsSpan)
|
||||||
|
{
|
||||||
|
builder.Append(" }\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AppendNativeCall(
|
||||||
|
StringBuilder builder,
|
||||||
|
ManagedMethodDefinition method,
|
||||||
|
IReadOnlyList<ManagedArgument> arguments
|
||||||
|
)
|
||||||
|
{
|
||||||
|
builder.Append("__context->");
|
||||||
|
builder.Append(method.NativeCommand.Name);
|
||||||
|
builder.Append('(');
|
||||||
|
AppendArguments(builder, method, arguments);
|
||||||
|
builder.Append(')');
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AppendArguments(
|
||||||
|
StringBuilder builder,
|
||||||
|
ManagedMethodDefinition method,
|
||||||
|
IReadOnlyList<ManagedArgument> arguments
|
||||||
|
)
|
||||||
|
{
|
||||||
|
for (int index = 0; index < arguments.Count; index++)
|
||||||
|
{
|
||||||
|
if (index != 0)
|
||||||
|
{
|
||||||
|
builder.Append(", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (arguments[index])
|
||||||
|
{
|
||||||
|
case ParameterArgument parameterArgument:
|
||||||
|
ManagedParameterDefinition parameter = method.Parameters[
|
||||||
|
parameterArgument.ParameterIndex];
|
||||||
|
string parameterName = EscapeIdentifier(parameter.Name);
|
||||||
|
if (!parameter.IsHandle)
|
||||||
|
{
|
||||||
|
builder.Append(parameterName);
|
||||||
|
}
|
||||||
|
else if (parameter.Type.EndsWith('*'))
|
||||||
|
{
|
||||||
|
builder.Append("(uint*)");
|
||||||
|
builder.Append(parameterName);
|
||||||
|
}
|
||||||
|
else if (parameter.IsHandleSpan)
|
||||||
|
{
|
||||||
|
builder.Append("(uint*)__");
|
||||||
|
builder.Append(parameter.Name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
builder.Append(parameterName);
|
||||||
|
builder.Append(".Value");
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case SpanLengthArgument spanLengthArgument:
|
||||||
|
builder.Append(
|
||||||
|
EscapeIdentifier(
|
||||||
|
method.Parameters[spanLengthArgument.ParameterIndex].Name));
|
||||||
|
builder.Append(".Length");
|
||||||
|
break;
|
||||||
|
case VectorComponentArgument componentArgument:
|
||||||
|
builder.Append(
|
||||||
|
EscapeIdentifier(
|
||||||
|
method.Parameters[componentArgument.ParameterIndex].Name));
|
||||||
|
builder.Append('.');
|
||||||
|
builder.Append(componentArgument.Component);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
$"Unsupported managed argument '{arguments[index].GetType().Name}'.");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string EscapeIdentifier(
|
private static string EscapeIdentifier(
|
||||||
@@ -418,5 +733,16 @@ namespace StgSharp.GenerateGL.Generation
|
|||||||
string Literal
|
string Literal
|
||||||
);
|
);
|
||||||
|
|
||||||
|
private sealed record GlCommandGroup(
|
||||||
|
string FileName,
|
||||||
|
string Description,
|
||||||
|
IReadOnlyList<GlCommandDefinition> Commands
|
||||||
|
);
|
||||||
|
|
||||||
|
private sealed record ManagedCommandGroup(
|
||||||
|
GlCommandGroup Source,
|
||||||
|
IReadOnlyList<ManagedMethodDefinition> Methods
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user