public static async Task EmitScope(this CodegenContext context, Action cb) { await context.EmitLine("{"); ++context.IndentLevel; cb(); --context.IndentLevel; await context.EmitLine("}"); }
private static async Task EmitClassStructEnumBlock(this CodegenContext context, string type, string name, Func <Task> cb) { await context.EmitLine($"{type} {name}"); await context.EmitLine("{"); ++context.IndentLevel; await cb(); --context.IndentLevel; await context.EmitLine("};"); }
public static async Task EmitStructAccess(this CodegenContext context, string access) { if (!access.EndsWith(':')) { access = access + ":"; } --context.IndentLevel; await context.EmitLine(access); ++context.IndentLevel; }
public async Task GenerateCommandBufferHeader(string bufferClass, string fileName, List <KeyValuePair <string, FunctionEntry> > functionList) { using (var header = CreateHeader(fileName)) { var context = new CodegenContext(header); await context.EmitLine("#pragma once"); await context.EmitLine("#include <glad/glad.h>"); await context.EmitLine("#include \"gl_resource_manager.hpp\""); await context.EmitLine("#include \"raw_rw_buffer.hpp\""); if (Registry.EnumTypes.Count > 0) { await context.EmitLine("#include \"gl_function_enums.hpp\""); } context.EmitLine(); await context.EmitLine("namespace multigl"); await context.EmitScope(async() => { await context.EmitClass(bufferClass, async() => { await context.EmitStructAccess("public"); await context.EmitLine($"{bufferClass}(ResourceManager& manager);"); await context.EmitLine($"~{bufferClass}();"); context.EmitLine(); await context.EmitStructAccess("public"); var accessTracker = context.CreateAccessTracker("public"); foreach (var fk in functionList) { var function = fk.Value; await accessTracker.WriteAccess(function.Access); var noGLName = function.NoGLName; if (!function.ShouldReturnAsFinalArgPointer) { context.EmitIndent(); await context.Emit($"{function.Type.ReturnType} {noGLName}("); for (int i = 0; i < function.Type.Arguments.Count; ++i) { var arg = function.Type.Arguments[i]; var fullType = $"{(arg.IsEnumType ? "multigl::" : "")}{arg.Type}"; await context.Emit($"{fullType} {arg.Name}"); if (i < function.Type.Arguments.Count - 1) { await context.Emit(", "); } } await context.EmitLineUnindented(");"); } else { context.EmitIndent(); await context.Emit($"void {noGLName}("); for (int i = 0; i < function.Type.Arguments.Count; ++i) { var arg = function.Type.Arguments[i]; await context.Emit($"{arg.Type} {arg.Name}"); await context.Emit(", "); } await context.Emit($"{function.Type.ReturnType}* returnVal = 0"); await context.EmitLineUnindented(");"); } } context.EmitLine(); await context.EmitStructAccess("public"); await context.EmitLine("void ProcessCommands();"); context.EmitLine(); await context.EmitStructAccess("private"); await context.EmitLine($"ResourceManager& {ResourceManager};"); await context.EmitLine($"raw_rw_buffer {DataBuffer};"); if (bufferClass == ImmediateBufferClass) { await context.EmitLine("bool m_HasSubmittedWork;"); } }); }); } }
public async Task GenerateEnumTypeHeader() { string enumType = null; int numValues = Registry.Functions.Count; if (numValues < byte.MaxValue) { enumType = "uint8_t"; } else if (numValues < ushort.MaxValue) { enumType = "uint16_t"; } else if ((uint)numValues < uint.MaxValue) { enumType = "uint32_t"; } using (var header = CreateHeader("gl_function_enums.hpp")) { var context = new CodegenContext(header); await context.EmitLine("#pragma once"); await context.EmitLine("#include <stdint.h>"); if (Registry.EnumTypes.Count > 0) { await context.EmitLine("#include <glad/glad.h>"); } context.EmitLine(); await context.EmitLine("namespace multigl"); await context.EmitScope(async() => { await context.EmitLine($"typedef {enumType} gl_command_id_t;"); await context.EmitLine("namespace CommandIdEnum"); await context.EmitScope(async() => { await context.EmitEnum("Enum : gl_command_id_t", async() => { foreach (var v in Registry.Functions) { await context.EmitLine($"{v.Value.NoGLName},"); } await context.EmitLine("Count"); }); }); await context.EmitLine("typedef CommandIdEnum::Enum CommandId;"); foreach (var enumType in Registry.EnumTypes) { context.EmitLine(); await context.EmitLine($"namespace {enumType.Value.Name}Enum"); await context.EmitScope(async() => { await context.EmitEnum("Enum : GLenum", async() => { int cur = 0; int cnt = enumType.Value.Values.Count; foreach (var v in enumType.Value.Values) { context.EmitIndent(); await context.Emit($"{v.Key} = {v.Value}"); ++cur; if (cur < cnt) { await context.Emit(","); } context.EmitLineUnindented(); } }); }); await context.EmitLine($"typedef {enumType.Value.Name}Enum::Enum {enumType.Value.Name};"); } }); } }
public async Task GenerateCommandBufferWriteSource(string bufferClass, string fileName, List <KeyValuePair <string, FunctionEntry> > functionList) { using (var source = CreateSourceFile(fileName)) { var context = new CodegenContext(source); await context.EmitLine($"#include <{(bufferClass == CommandBufferClass ? "gl_command_buffer.hpp" : "gl_immediate_buffer.hpp")}>"); context.EmitLine(); await context.EmitLine("using namespace multigl;"); await context.EmitLine($"{bufferClass}::{bufferClass}(ResourceManager& mgr) : {ResourceManager}(mgr)"); if (bufferClass == ImmediateBufferClass) { ++context.IndentLevel; await context.EmitLine(", m_HasSubmittedWork(false)"); --context.IndentLevel; } await context.EmitScope(() => {}); context.EmitLine(); if (bufferClass == ImmediateBufferClass) { await context.EmitLine($"{bufferClass}::~{bufferClass}()"); await context.EmitScope(async() => { await context.EmitLine("if (!m_HasSubmittedWork)"); await context.EmitScope(async() => { await context.EmitLine("// TODO: Submit queue to main thread"); }); await context.EmitLine("// TODO: Wait on job system task here"); }); } else { await context.EmitLine($"{bufferClass}::~{bufferClass}(){{}}"); } context.EmitLine(); foreach (var fk in functionList) { var overrideList = Tracker.GetOverrideList(fk.Key); var function = fk.Value; var noGLName = function.NoGLName; if (!function.ShouldReturnAsFinalArgPointer) { await context.Emit($"{function.Type.ReturnType} {bufferClass}::{noGLName}("); for (int i = 0; i < function.Type.Arguments.Count; ++i) { var arg = function.Type.Arguments[i]; var fullType = $"{(arg.IsEnumType ? "multigl::" : "")}{arg.Type}"; await context.Emit($"{fullType} {arg.Name}"); if (i < function.Type.Arguments.Count - 1) { await context.Emit(", "); } } await context.EmitLineUnindented(")"); } else { await context.Emit($"void {bufferClass}::{noGLName}("); for (int i = 0; i < function.Type.Arguments.Count; ++i) { var arg = function.Type.Arguments[i]; await context.Emit($"{arg.Type} {arg.Name}"); await context.Emit(", "); } await context.Emit($"{function.Type.ReturnType}* returnVal"); await context.EmitLineUnindented(")"); } await context.EmitScope(async() => { await context.EmitLine($"{DataBuffer}.write_command(CommandId::{function.NoGLName});"); Func <Task> defaultWriteFunc = async() => { if (!function.ShouldReturnAsFinalArgPointer) { if (function.Type.ReturnType == "void") { for (int i = 0; i < function.Type.Arguments.Count; ++i) { var arg = function.Type.Arguments[i]; var argWriteOverride = Tracker.GetArgumentTypeWriteOverride(arg.Type); if (argWriteOverride != null) { await argWriteOverride(context, function, arg); } else { await context.EmitLine($"{DataBuffer}.write({arg.Name});"); } } } else { await context.EmitLine($"#if defined(MGL_STRICT_COMPILATION)"); await context.EmitLine($"#error Unimplemented function with return value"); await context.EmitLine($"#endif"); } } else { for (int i = 0; i < function.Type.Arguments.Count; ++i) { var arg = function.Type.Arguments[i]; var argWriteOverride = Tracker.GetArgumentTypeWriteOverride(arg.Type); if (argWriteOverride != null) { await argWriteOverride(context, function, arg); } else { await context.EmitLine($"{DataBuffer}.write({arg.Name});"); } } await context.EmitLine($"{DataBuffer}.write(returnVal);"); } }; if (overrideList == null || overrideList.Count == 0) { await defaultWriteFunc(); } else { bool hasRun = false; foreach (var v in overrideList) { if (v.ModifyWriteFunction != null) { await v.ModifyWriteFunction(context, defaultWriteFunc, function); hasRun = true; } } if (!hasRun) { await defaultWriteFunc(); } } }); context.EmitLine(); } } }
public async Task GenerateCommandBufferReadSource(string bufferClass, string fileName, List <KeyValuePair <string, FunctionEntry> > functionList) { using (var source = CreateSourceFile(fileName)) { var context = new CodegenContext(source); await context.EmitLine($"#include <{(bufferClass == CommandBufferClass ? "gl_command_buffer.hpp" : "gl_immediate_buffer.hpp")}>"); await context.EmitLine("#include <gl_utilities.hpp>"); context.EmitLine(); await context.EmitLine("using namespace multigl;"); await context.EmitLine($"void {bufferClass}::ProcessCommands()"); await context.EmitScope(async() => { await context.EmitLine($"while({DataBuffer}.has_commands())"); await context.EmitScope(async() => { await context.EmitLine($"auto cmd = {DataBuffer}.read_command();"); await context.EmitLine("switch(cmd)"); await context.EmitScope(async() => { foreach (var fk in functionList) { var overrideList = Tracker.GetOverrideList(fk.Key); var function = fk.Value; await context.EmitLine($"case CommandId::{function.NoGLName}:"); await context.EmitScope(async() => { Func <Task> defaultReadFunc = async() => { if (!function.ShouldReturnAsFinalArgPointer) { var args = function.Type.Arguments; for (int i = 0; i < args.Count; ++i) { var arg = args[i]; var argReadOverride = Tracker.GetArgumentTypeReadOverride(arg.Type); if (argReadOverride != null) { await argReadOverride(context, function, arg); } else { var fullType = $"{(arg.IsEnumType ? "multigl::" : "")}{arg.Type}"; await context.EmitLine($"{fullType} {arg.Name} = {DataBuffer}.read<{fullType}>();"); } } } else { var args = function.Type.Arguments; for (int i = 0; i < args.Count; ++i) { var arg = args[i]; var argReadOverride = Tracker.GetArgumentTypeReadOverride(arg.Type); if (argReadOverride != null) { await argReadOverride(context, function, arg); } else { var fullType = $"{(arg.IsEnumType ? "multigl::" : "")}{arg.Type}"; await context.EmitLine($"{arg.Type} {arg.Name} = {DataBuffer}.read<{fullType}>();"); } } { var fullType = $"{(function.Type.IsReturnEnum ? "multigl::" : "")}{function.Type.ReturnType}"; await context.EmitLine($"auto returnVal = {DataBuffer}.read<{fullType}*>();"); } await context.EmitLine("if (returnVal)"); await context.EmitScope(async() => { context.EmitIndent(); if (function.Type.IsReturnEnum) { await context.Emit($"GL_CHECK(*returnVal = {function.Type.ReturnType}({function.Name}("); } else { await context.Emit($"GL_CHECK(*returnVal = ({function.Name}("); } for (int i = 0; i < args.Count; ++i) { var arg = args[i]; await context.Emit($"{arg.Name}"); if (i < args.Count - 1) { await context.Emit(", "); } } await context.EmitLineUnindented($")));"); await context.EmitLine("return;"); }); } }; if (overrideList == null || overrideList.Count == 0) { var args = function.Type.Arguments; await defaultReadFunc(); context.EmitIndent(); await context.Emit($"GL_CHECK({function.Name}("); for (int i = 0; i < args.Count; ++i) { var arg = args[i]; await context.Emit($"{arg.Name}"); if (i < args.Count - 1) { await context.Emit(", "); } } await context.EmitLineUnindented($"));"); } else { bool hasRun = false; foreach (var v in overrideList) { if (v.ModifyReadFunction != null) { await v.ModifyReadFunction(context, defaultReadFunc, function); hasRun = true; } } if (!hasRun) { var args = function.Type.Arguments; await defaultReadFunc(); context.EmitIndent(); await context.Emit($"GL_CHECK({function.Name}("); for (int i = 0; i < args.Count; ++i) { var arg = args[i]; await context.Emit($"{arg.Name}"); if (i < args.Count - 1) { await context.Emit(", "); } } await context.EmitLineUnindented($"));"); } } await context.EmitLine($"break;"); }); } }); }); await context.EmitLine($"{DataBuffer}.reset();"); }); } }