Skip to content

Commit

Permalink
Merge pull request #127 from firox263/feature/gstreamer
Browse files Browse the repository at this point in the history
WIP: GStreamer
  • Loading branch information
badcel authored Dec 28, 2020
2 parents 718edcd + ad7ecd9 commit 460e33d
Show file tree
Hide file tree
Showing 65 changed files with 1,391 additions and 149 deletions.
11 changes: 10 additions & 1 deletion Build/Projects.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,16 @@ public static class Projects
private const string GTKCHAMPLAIN = "../Libs/GtkChamplain/";
private const string CLUTTER = "../Libs/Clutter/";
private const string GTKCLUTTER = "../Libs/GtkClutter/";
private const string GST = "../Libs/Gst/";
private const string CAIRO = "../Libs/Cairo/";
private const string GDK3 = "../Libs/Gdk3/";
private const string PANGO = "../Libs/Pango/";
private const string XLIB = "../Libs/Xlib/";

public const string GST = "../Libs/Gst/";
public const string GST_BASE = "../Libs/Gst.Base/";
public const string GST_AUDIO = "../Libs/Gst.Audio/";
public const string GST_VIDEO = "../Libs/Gst.Video/";
public const string GST_PBUTILS = "../Libs/Gst.Pbutils/";

private const string BUILD_Test = "../Tests/Build.Tests/";
private const string GOBJECT_TEST = "../Tests/Libs/GObject.Tests/";
Expand Down Expand Up @@ -87,6 +92,10 @@ public static readonly (Project Project, Type Type)[] LibraryProjects =
(CHAMPLAIN, "Champlain-0.12.gir", "libchamplain-0.12", false),
(GTKCHAMPLAIN, "GtkChamplain-0.12.gir", "libchamplain-gtk-0.12.so.0", false),*/
(new Project(GST, "Gst-1.0.gir"), typeof(GObjectGenerator)),
(new Project(GST_AUDIO, "GstAudio-1.0.gir"), typeof(GObjectGenerator)),
(new Project(GST_VIDEO, "GstVideo-1.0.gir"), typeof(GObjectGenerator)),
(new Project(GST_PBUTILS, "GstPbutils-1.0.gir"), typeof(GObjectGenerator)),
(new Project(GST_BASE, "GstBase-1.0.gir"), typeof(GObjectGenerator))
/*(GDK4, "Gdk-4.0.gir", "libgtk-4.so.0", true),//GTK4
(GSK4, "Gsk-4.0.gir", "libgtk-4.so.0", true),//GTK4
(GTK4, GTK4_GIR, "libgtk-4.so.0", true) //GTK4*/
Expand Down
2 changes: 1 addition & 1 deletion Generator/GObjectGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ protected override void GenerateConstants(IEnumerable<GConstant> constants, stri
Generate(
templateName: "constants",
subfolder: "Classes",
fileName: "Constant",
fileName: "Constants",
scriptObject: scriptObject
);
}
Expand Down
7 changes: 5 additions & 2 deletions Generator/Generator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,10 @@ protected void Generate(string templateName, string subfolder,
fileName = Path.Combine(subfolder, fileName + ".Generated.cs");

K loader = Activator.CreateInstance<K>();
var context = new TemplateContext { TemplateLoader = loader };

// Scriban has a Loop iteration limit of 1000 by default. This is nowhere near
// enough for the number of constants some libraries define (e.g. Gdk).
var context = new TemplateContext { TemplateLoader = loader, LoopLimit = 10000};
context.PushGlobal(scriptObject);
context.IndentWithInclude = true;

Expand All @@ -234,7 +237,7 @@ protected void Generate(string templateName, string subfolder,
{
//TODO: Workaround for missing ATK!
Console.WriteLine(
$"Skipping file {fileName} because it looks like an ATK class which is not supported.");
$"Skipping file {fileName} because it looks like an ATK class which is not yet supported.");
return;
}

Expand Down
3 changes: 3 additions & 0 deletions Generator/Gir/GClass.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ public class GClass : GInterface

[XmlElement("signal", Namespace = "http://www.gtk.org/introspection/glib/1.0")]
public List<GSignal> Signals { get; set; } = default!;

[XmlElement ("field")]
public List<GField> Fields { get; set; } = default!;

[XmlAttribute("parent")]
public string? Parent { get; set; }
Expand Down
File renamed without changes.
3 changes: 3 additions & 0 deletions Generator/Gir/GParameter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ public class GParameter : IType

[XmlAttribute("direction")]
public string? Direction { get; set; }

[XmlAttribute ("caller-allocates")]
public bool CallerAllocates;

[XmlElement("doc")]
public GDoc? Doc { get; set; }
Expand Down
3 changes: 0 additions & 3 deletions Generator/Gir/GRecord.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ public class GRecord : GClass
{
#region Properties

[XmlElement("field")]
public List<GField> Fields { get; set; } = default!;

[XmlAttribute("is-gtype-struct-for", Namespace = "http://www.gtk.org/introspection/glib/1.0")]
public string? GLibIsGTypeStructFor;

Expand Down
2 changes: 1 addition & 1 deletion Generator/Resolver/AliasResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,4 @@ private bool TryGet(string typeName, Func<GAlias, string, bool> predicate, [NotN

#endregion
}
}
}
107 changes: 90 additions & 17 deletions Generator/Resolver/TypeResolver.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using Gir;

namespace Generator
Expand All @@ -9,17 +9,18 @@ public class ResolvedType : IEquatable<ResolvedType>

public string Type { get; }
public string Attribute { get; }
public bool IsRef { get; }

public Direction Direction { get; }

#endregion

#region Constructors

public ResolvedType(string type, bool isRef = false, string attribute = "")
public ResolvedType(string type, Direction dir = Direction.Value, string attribute = "")
{
Type = type;
Attribute = attribute;
IsRef = isRef;
Direction = dir;
}

#endregion
Expand All @@ -28,8 +29,19 @@ public ResolvedType(string type, bool isRef = false, string attribute = "")

public override string ToString() => GetTypeString();

public string GetTypeString() => Attribute + (IsRef ? "ref " : string.Empty) + Type;
public string GetFieldString() => Attribute + (IsRef ? "IntPtr" : Type);
// public string GetTypeString() => Attribute + (IsRef ? "ref " : string.Empty) + Type;

public string GetTypeString() => Attribute + Direction switch
{
Direction.Value => Type,
Direction.In => "in " + Type,
Direction.OutCalleeAllocates => "out " + Type,
Direction.OutCallerAllocates => "ref " + Type,
Direction.InOut => "ref " + Type,
_ => Type,
};

public string GetFieldString() => Direction == Direction.Value ? Type : "IntPtr";

#endregion

Expand All @@ -39,7 +51,7 @@ public bool Equals(ResolvedType? other)
{
if (other is null) return false;
if (ReferenceEquals(this, other)) return true;
return Type == other.Type && IsRef == other.IsRef;
return Type == other.Type && Direction == other.Direction;
}

public override bool Equals(object? obj)
Expand All @@ -52,12 +64,21 @@ public override bool Equals(object? obj)

public override int GetHashCode()
{
return HashCode.Combine(Type, IsRef);
return HashCode.Combine(Type, Direction);
}

#endregion
}

public enum Direction
{
Value,
In,
OutCalleeAllocates,
OutCallerAllocates,
InOut,
}

internal class MyType
{
#region Properties
Expand All @@ -68,6 +89,8 @@ internal class MyType
public bool IsPointer { get; set; }
public bool IsValueType { get; set; }
public bool IsParameter { get; set; }

public Direction Direction { get; set; }

#endregion

Expand Down Expand Up @@ -103,8 +126,8 @@ public TypeResolver(AliasResolver resolver)
public ResolvedType Resolve(IType typeInfo) => typeInfo switch
{
GField f when f.Callback is { } => new ResolvedType("IntPtr"),
{ Array: { CType: { } n } } when n.EndsWith("**") => new ResolvedType("IntPtr", true),
{ Type: { } gtype } => GetTypeName(ConvertGType(gtype, typeInfo is GParameter)),
{ Array: { CType: { } n } } when n.EndsWith("**") => new ResolvedType("IntPtr", Direction.InOut),
{ Type: { } gtype } => GetTypeName(ConvertGType(gtype, typeInfo is GParameter, typeInfo)),
{ Array: { Length: { } length, Type: { CType: { } } gtype } } => GetTypeName(ResolveArrayType(gtype, typeInfo is GParameter, length)),
{ Array: { Length: { } length, Type: { Name: "utf8" } name } } => GetTypeName(StringArray(length, typeInfo is GParameter)),
{ Array: { Length: "1", Type: {Name: "guint8"}}} => new ResolvedType("byte[]"),
Expand Down Expand Up @@ -133,7 +156,7 @@ private MyType ResolveArrayType(GType arrayType, bool isParameter, string? lengt
return type;
}

private MyType ConvertGType(GType gtype, bool isParameter)
private MyType ConvertGType(GType gtype, bool isParameter, IType? typeInfo = null)
{
var ctype = gtype.CType;
if (ctype is null)
Expand All @@ -148,6 +171,22 @@ private MyType ConvertGType(GType gtype, bool isParameter)
MyType? result = ResolveCType(ctype);
result.IsParameter = isParameter;

// Read in Direction
if (isParameter && typeInfo != null)
{
var param = (GParameter) typeInfo;
result.Direction = param.Direction switch
{
"in" => Direction.In,
"out" => Direction.OutCalleeAllocates, // TODO: Should this be the default?
"inout" => Direction.InOut,
_ => Direction.Value
};

if (param.CallerAllocates)
result.Direction = Direction.OutCallerAllocates;
}

if (!result.IsValueType && gtype.Name is { })
{
result.Type = resolvedName ?? gtype.Name;
Expand All @@ -159,18 +198,42 @@ private MyType ConvertGType(GType gtype, bool isParameter)
private ResolvedType GetTypeName(MyType type)
=> type switch
{
// Pointers
{ Type: "gpointer" } => new ResolvedType("IntPtr"),
{ Type: "guintptr" } => new ResolvedType("IntPtr"), // TODO: UIntPtr instead? (Maybe not: not CLS-compliant)
{ IsArray: false, Type: "void", IsPointer: true } => new ResolvedType("IntPtr"),
{ IsArray: false, Type: "byte", IsPointer: true, IsParameter: true } => new ResolvedType("string"), //string in parameters are marshalled automatically

// String Related Functions
{ Type: "utf8" } => new ResolvedType("string"), // TODO: We can possibly get rid of this depending on usage?
{ IsArray: false, Direction: Direction.OutCalleeAllocates, Type: "byte", IsPointer: true, IsParameter: true } t => new ResolvedType("IntPtr", Direction.OutCalleeAllocates),
{ IsArray: false, Direction: Direction.InOut, Type: "byte", IsPointer: true, IsParameter: true } t => new ResolvedType("IntPtr", Direction.InOut),
{ IsArray: false, Type: "byte", IsPointer: true, IsParameter: true } => new ResolvedType("string"),
{ IsArray: false, Type: "byte", IsPointer: true, IsParameter: false } => new ResolvedType("IntPtr"),
{ IsArray: true, Type: "byte", IsPointer: true, IsParameter: true, ArrayLengthParameter: { } l } => new ResolvedType("string[]", attribute: GetMarshal(l)),
{ IsArray: false, IsPointer: true, IsValueType: true } => new ResolvedType(type.Type, true),

// Value Type (Non-Pointer)
{ IsArray: false, IsValueType: true, IsPointer: false } => new ResolvedType(type.Type, type.Direction),

// Value Type (Pointer)
{ IsArray: false, IsValueType: true, IsPointer: true, Direction: Direction.Value } => new ResolvedType(type.Type, Direction.InOut), // Don't marshal pointers by value
{ IsArray: false, IsValueType: true, IsPointer: true } => new ResolvedType(type.Type, type.Direction),

// Reference Types
{ IsArray: false, Direction: Direction.In, IsPointer: true } => new ResolvedType("IntPtr", Direction.In), // TODO: Do we need this one?
{ IsArray: false, IsPointer: true, Direction: Direction.InOut } => new ResolvedType("IntPtr"), // Avoid ref
{ IsArray: false, IsPointer: true, IsValueType: false, Direction: not Direction.Value } => new ResolvedType("IntPtr", type.Direction),

// Fallback to plain IntPtr
{ IsArray: false, IsPointer: true, IsValueType: false } => new ResolvedType("IntPtr"),
{ IsArray: true, Type: "byte", IsPointer: true } => new ResolvedType("IntPtr", true), //string array

// Arrays
{ IsArray: true, Type: "byte", IsPointer: true } => new ResolvedType("IntPtr", Direction.InOut), //string array
{ IsArray: true, IsValueType: false, IsParameter: true, ArrayLengthParameter: { } l } => new ResolvedType("IntPtr[]", attribute: GetMarshal(l)),
{ IsArray: true, IsValueType: true, IsParameter: true, ArrayLengthParameter: { } l } => new ResolvedType(type.Type + "[]", attribute: GetMarshal(l)),
{ IsArray: true, IsValueType: true, ArrayLengthParameter: { } } => new ResolvedType(type.Type + "[]"),
{ IsArray: true, IsValueType: true, ArrayLengthParameter: null } => new ResolvedType("IntPtr"),

// Fallback to type name
_ => new ResolvedType(type.Type)
};

Expand All @@ -184,12 +247,17 @@ private MyType ResolveCType(string cType)

MyType? result = cType switch
{
// TODO: We might not need these
// Some gir files seem to use them though?
"none" => ValueType("void"),
"any" => IntPtr(),

"void" => ValueType("void"),
"gboolean" => ValueType("bool"),
"gfloat" => Float(),
"float" => Float(),

//"GCallback" => ReferenceType("Delegate"), // Signature of a callback is determined by the context in which it is used
//"GCallback" => ReferenceType("Delegate"), // Signature of a callback is determined by the context in which it is used

"gconstpointer" => IntPtr(),
"va_list" => IntPtr(),
Expand All @@ -199,9 +267,13 @@ private MyType ResolveCType(string cType)
var t when t.StartsWith("Atk") => IntPtr(),
var t when t.StartsWith("Cogl") => IntPtr(),

// TODO: We need to be able to designate any type as a value type, rather than
// hardcoding it into the generator. The generator rewrite should let us
// use ref structs for all structs, rather than these select cases:
"GValue" => Value(),
//"GError" => Error(),
//"GVariantType" => VariantType(),
"GTypeQuery" => TypeQuery(),
// "GError" => Error(),
// "GVariantType" => VariantType(),

"guint16" => UShort(),
"gushort" => UShort(),
Expand Down Expand Up @@ -264,6 +336,7 @@ var t when t.StartsWith("Cogl") => IntPtr(),
private MyType ULong() => ValueType("ulong");
private MyType Float() => ValueType("float");
private MyType Error() => ValueType("Error");
private MyType TypeQuery() => ValueType("TypeQuery");
private MyType VariantType() => ValueType("VariantType");

private MyType ValueType(string str) => new MyType(str) { IsValueType = true };
Expand Down
15 changes: 15 additions & 0 deletions Generator/Templates/GObject/class.sbntxt
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,21 @@ namespace {{ namespace }}
#endregion

{{~ end ~}}

#region Fields

[StructLayout(LayoutKind.Sequential)]
protected {{'new'|get_if_parent}} struct Fields : IObjectStruct
{
{{ if (has_parent) && (name != "InitiallyUnowned") && (fields.size > 0)
fields[0].type.name = string.append fields[0].type.name ".Fields"
end}}
{{~ for $field in fields }}
{{ include 'field.sbntxt' $field }}
{{ end }}
}
#endregion

{{~ end ~}}
#region Native

Expand Down
2 changes: 1 addition & 1 deletion Generator/Templates/GObject/constants.sbntxt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ using System.Runtime.InteropServices;

namespace {{ namespace }}
{
public partial class Constant
public partial class Constants
{
{{~ for constant in constants }}
{{ include 'constant.sbntxt' constant ~}}
Expand Down
Loading

0 comments on commit 460e33d

Please sign in to comment.