Initial UIXsup implementation

This commit is contained in:
Yoshi Askharoun
2026-07-22 02:48:34 -05:00
parent dee717296c
commit 1fa9ed8db3
9 changed files with 166 additions and 1 deletions
+37
View File
@@ -0,0 +1,37 @@
name: UIXrender CI
on:
push:
pull_request:
jobs:
build:
# UIXrender/UIXsup are implemented cross-platform (Silk.NET, no Windows-specific
# APIs), but NativeAOT can't cross-compile Linux->Windows, and the P/Invoke-based
# managed consumers we need to stay compatible with (UIX.dll et al) only run on
# Windows today -- so Windows is what Phase 0 verifies against here. Other RIDs can
# get their own job later once there's something worth publishing them for.
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
dotnet-version: "8.0.x"
- name: Restore
run: dotnet restore MicrosoftIris.sln
- name: Build solution
run: dotnet build MicrosoftIris.sln -c Release --no-restore
- name: Publish UIXrender (NativeAOT, win-x64)
run: dotnet publish UIXrender/UIXrender.csproj -c Release -f net8.0 -r win-x64 --self-contained -p:PublishAot=true
- name: Publish UIXsup (NativeAOT, win-x64)
run: dotnet publish UIXsup/UIXsup.csproj -c Release -f net8.0 -r win-x64 --self-contained -p:PublishAot=true
# TODO: run the Windows-only interop test harness (Tests/UIXrender.Interop.Tests)
# against the published DLLs once it exists (Phase 0 spike step) — see
# logs/UIXrender/Architecture.md and the plan for context.
+3 -1
View File
@@ -19,7 +19,9 @@
</PropertyGroup>
<PropertyGroup Condition=" $([MSBuild]::IsOsPlatform('Windows')) ">
<TargetFrameworks>$(TargetFrameworks);net461;net8.0-windows10.0.22000</TargetFrameworks>
<TargetFrameworks>$(TargetFrameworks);net8.0-windows10.0.22000</TargetFrameworks>
<TargetFrameworks Condition=" $(EnableNetFXTarget) == 'true' ">$(TargetFrameworks);net461;</TargetFrameworks>
</PropertyGroup>
<Choose>
+2
View File
@@ -7,5 +7,7 @@
<RootNamespace></RootNamespace>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<EnableNetFXTarget>true</EnableNetFXTarget>
</PropertyGroup>
</Project>
+2
View File
@@ -7,6 +7,8 @@
<RootNamespace></RootNamespace>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<EnableNetFXTarget>true</EnableNetFXTarget>
</PropertyGroup>
<ItemGroup>
+7
View File
@@ -6,5 +6,12 @@
<RootNamespace>Microsoft.Iris.Render</RootNamespace>
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<PublishAot>true</PublishAot>
<!-- Required for PublishAot to emit an actual exporting shared library (.dll/.so)
for the [UnmanagedCallersOnly] methods below: without this, PublishAot
alone produces a native executable, not something P/Invoke-able. -->
<NativeLib>Shared</NativeLib>
</PropertyGroup>
</Project>
+48
View File
@@ -0,0 +1,48 @@
namespace Microsoft.Iris.Support;
// Mirrors Microsoft.Iris.Render.DebugCategory (UIX.RenderApi/Microsoft/Iris/Render/DebugCategory.cs)
// field-for-field: ordinal values are part of the wire contract with the already-shipped
// managed callers (DebugGetCategoryLevel/DebugSetCategoryLevel pass this by value), so
// the order here must match exactly, not just the names.
public enum DebugCategory
{
Animation,
Critical,
Deprecated,
Dispatcher,
Dump,
Dx9Wrapper,
DynamicSurface,
Failure,
FormWindow,
GraphicsCache,
IFC,
ObjectCache,
Performance,
Profile,
Queues,
Render,
Sounds,
Surface,
SurfacePool,
SurfaceRestoration,
Timeouts,
Transport,
WindowState,
Effect,
HTTP,
ExternalCount,
Protocol,
RenderHost,
DumpException,
Focus,
Input,
TreeDisposal,
VisualSizePos,
Visual,
Painting,
RenderWindow,
ImageLoad,
ImageCache,
TotalCount,
}
+22
View File
@@ -0,0 +1,22 @@
namespace Microsoft.Iris.Support;
internal static class DebugState
{
private static readonly byte[] s_categoryLevels = new byte[(int)DebugCategory.TotalCount];
public static bool TimedWriteLines { get; set; }
public static string WriteLinePrefix { get; set; } = string.Empty;
public static byte GetCategoryLevel(DebugCategory category)
{
int index = (int)category;
return (uint)index < (uint)s_categoryLevels.Length ? s_categoryLevels[index] : (byte)0;
}
public static void SetCategoryLevel(DebugCategory category, byte level)
{
int index = (int)category;
if ((uint)index < (uint)s_categoryLevels.Length)
s_categoryLevels[index] = level;
}
}
+38
View File
@@ -0,0 +1,38 @@
using System;
using System.Runtime.InteropServices;
namespace Microsoft.Iris.Support.Interop;
// [UnmanagedCallersOnly] exports matching the 5 DllImport("UIXsup.dll") declarations in
// the already-shipped managed callers (eDebugApi.cs / DebugHelpers.cs) field-for-field.
// See logs/UIXrender/UIXsup.md for why parameters are byte*/int here instead of
// string/bool (ANSI marshaling, blittability) and for the DebugDisplayErrorStack scope
// gap noted below.
public static unsafe class DebugApi
{
[UnmanagedCallersOnly(EntryPoint = "DebugDisplayErrorStack")]
public static int DebugDisplayErrorStack(byte* stMessage, byte* filename, int line, byte* title, byte* stackTrace)
{
string timestamp = DebugState.TimedWriteLines ? $"[{DateTime.Now:HH:mm:ss.fff}] " : string.Empty;
Console.Error.WriteLine(
$"{timestamp}{DebugState.WriteLinePrefix}{PtrToString(title)}: {PtrToString(stMessage)} ({PtrToString(filename)}:{line})\n{PtrToString(stackTrace)}");
// TODO: no interactive dialog UI yet (see logs/UIXrender/UIXsup.md) -- always
// reports "don't break".
return 0;
}
[UnmanagedCallersOnly(EntryPoint = "DebugSetTimedWriteLines")]
public static void DebugSetTimedWriteLines(int fEnabled) => DebugState.TimedWriteLines = fEnabled != 0;
[UnmanagedCallersOnly(EntryPoint = "DebugSetWriteLinePrefix")]
public static void DebugSetWriteLinePrefix(byte* stPrefix) => DebugState.WriteLinePrefix = PtrToString(stPrefix) ?? string.Empty;
[UnmanagedCallersOnly(EntryPoint = "DebugGetCategoryLevel")]
public static byte DebugGetCategoryLevel(DebugCategory cat) => DebugState.GetCategoryLevel(cat);
[UnmanagedCallersOnly(EntryPoint = "DebugSetCategoryLevel")]
public static void DebugSetCategoryLevel(DebugCategory cat, byte level) => DebugState.SetCategoryLevel(cat, level);
private static string PtrToString(byte* p) => p == null ? null : Marshal.PtrToStringAnsi((IntPtr)p);
}
+7
View File
@@ -6,5 +6,12 @@
<RootNamespace>Microsoft.Iris.Support</RootNamespace>
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<PublishAot>true</PublishAot>
<!-- Required for PublishAot to emit an actual exporting shared library (.dll/.so)
for the [UnmanagedCallersOnly] methods below: without this, PublishAot
alone produces a native executable, not something P/Invoke-able. -->
<NativeLib>Shared</NativeLib>
</PropertyGroup>
</Project>