Reimplemented basic RenderEngine for SK

This commit is contained in:
Yoshi Askharoun
2021-07-16 16:03:13 -05:00
parent a44a3ddc3f
commit cc8deff38a
15 changed files with 428 additions and 93 deletions
@@ -8,25 +8,17 @@ namespace Microsoft.Iris.Render
{
public enum GraphicsDeviceType
{
Unknown = -1,
Unknown = -1,
None,
Gdi,
Direct3D9,
XeDirectX9,
None = 0b0000_0000_0000_0000,
Gdi = 0b0000_0000_0000_0001,
Direct3D9 = 0b0000_0000_0000_0010,
XeDirectX9 = 0b0000_0000_0000_0011,
Metal,
OpenGL,
Vulkan,
Dawn,
/// <summary>
/// Skia's GPU backend
/// </summary>
Ganesh,
/// <summary>
/// Skia's GPU backend
/// </summary>
SKGanesh = Ganesh,
Skia = 0b0000_0000_0001_0000,
Metal = 0b0000_0000_0001_0001,
OpenGL = 0b0000_0000_0001_0010,
Vulkan = 0b0000_0000_0001_0011,
Dawn = 0b0000_0000_0001_0100,
}
}
@@ -11,9 +11,10 @@ namespace Microsoft.Iris.Render
public interface IRenderEngine : IRenderObject, IDisposable
{
void Initialize(
GraphicsDeviceType typeGraphics,
GraphicsRenderingQuality renderingQuality,
SoundDeviceType typeSound);
SkiaSharp.SKSurface skSurface,
GraphicsDeviceType typeGraphics,
GraphicsRenderingQuality renderingQuality,
SoundDeviceType typeSound);
IRenderSession Session { get; }
@@ -13,7 +13,7 @@ namespace Microsoft.Iris.Render.Internal
[Serializable]
internal struct GraphicsCaps
{
internal uint DeviceType;
internal GraphicsDeviceType DeviceType;
internal int MaxSimultaneousTextures;
internal int MaxTextureWidth;
internal int MaxTextureHeight;
@@ -4,6 +4,7 @@
// MVID: D47658B8-A8EA-43D6-8837-ECE823BFFFC1
// Assembly location: C:\Program Files\Zune\UIX.RenderApi.dll
using Microsoft.Iris.Library;
using Microsoft.Iris.Render.Common;
using Microsoft.Iris.Render.Protocol;
using Microsoft.Iris.Render.Sound;
@@ -92,9 +93,10 @@ namespace Microsoft.Iris.Render.Internal
}
void IRenderEngine.Initialize(
GraphicsDeviceType typeGraphics,
GraphicsRenderingQuality renderingQuality,
SoundDeviceType typeSound)
SkiaSharp.SKSurface skSurface,
GraphicsDeviceType typeGraphics,
GraphicsRenderingQuality renderingQuality,
SoundDeviceType typeSound)
{
Debug2.Validate(this.m_messagingSession.IsConnected, typeof(InvalidOperationException), "Must be connected before attempting to initialize");
Debug2.Validate(this.m_renderSession != null, typeof(ArgumentNullException), "Session must exist before calling Initialize");
@@ -128,9 +130,9 @@ namespace Microsoft.Iris.Render.Internal
internal SoundDevice SoundDevice => this.m_soundDevice;
internal Vector<Microsoft.Iris.Render.Internal.GraphicsCaps> GraphicsCaps => this.m_renderCaps.Graphics;
internal Vector<GraphicsCaps> GraphicsCaps => this.m_renderCaps.Graphics;
internal Vector<Microsoft.Iris.Render.Internal.SoundCaps> SoundCaps => this.m_renderCaps.Sound;
internal Vector<SoundCaps> SoundCaps => this.m_renderCaps.Sound;
private void DoEvents(uint nTimeoutInMsecs)
{
@@ -178,9 +180,9 @@ namespace Microsoft.Iris.Render.Internal
private bool IsGraphicsDeviceAvailable(GraphicsDeviceType type, bool fFilterRecommended)
{
foreach (Microsoft.Iris.Render.Internal.GraphicsCaps graphic in this.m_renderCaps.Graphics)
foreach (GraphicsCaps graphic in this.m_renderCaps.Graphics)
{
if ((GraphicsDeviceType)graphic.DeviceType == type)
if (graphic.DeviceType.FulfillsRequirement(type))
return !fFilterRecommended || graphic.DriverWarning == 0;
}
return false;
@@ -0,0 +1,99 @@
// Decompiled with JetBrains decompiler
// Type: Microsoft.Iris.Render.Internal.RenderCaps
// Assembly: UIX.RenderApi, Version=4.8.0.0, Culture=neutral, PublicKeyToken=ddd0da4d3e678217
// MVID: D47658B8-A8EA-43D6-8837-ECE823BFFFC1
// Assembly location: C:\Program Files\Zune\UIX.RenderApi.dll
using Microsoft.Iris.Render.Common;
using Microsoft.Iris.Render.Protocol;
using Microsoft.Iris.Render.Protocols.Splash.Rendering;
using SkiaSharp;
using System;
namespace Microsoft.Iris.Render.Internal
{
internal class SkiaRenderCaps : RenderObject, IRenderCapsCallback
{
private SKSurface m_remoteObject;
private Vector<GraphicsCaps> m_graphicsCapsList;
private Vector<SoundCaps> m_soundCapsList;
private bool m_hasValidCaps;
private bool m_capsPending;
private uint m_currentRequestId;
internal SkiaRenderCaps(SKSurface skSurface)
{
this.m_hasValidCaps = false;
this.m_capsPending = false;
this.m_currentRequestId = 0U;
this.m_graphicsCapsList = new Vector<GraphicsCaps>();
this.m_soundCapsList = new Vector<SoundCaps>();
this.m_remoteObject = skSurface;
}
internal bool HasValidCaps => this.m_hasValidCaps;
internal Vector<GraphicsCaps> Graphics => this.m_graphicsCapsList;
internal Vector<SoundCaps> Sound => this.m_soundCapsList;
internal void RequestCaps()
{
if (this.m_capsPending)
return;
++this.m_currentRequestId;
this.m_capsPending = true;
// TODO: Is there any way to get the graphics capabilities from an SKSurface?
Graphics.Add(new GraphicsCaps
{
DeviceType = GraphicsDeviceType.Skia
});
((IRenderCapsCallback)this).OnEndCapsCheck(default, 0);
}
internal event EventHandler CapsAvailable;
protected void NotifyCapsAvailable()
{
if (this.CapsAvailable == null)
return;
this.CapsAvailable(this, EventArgs.Empty);
}
void IRenderCapsCallback.OnBeginCapsCheck(RENDERHANDLE target, uint cookie)
{
this.m_graphicsCapsList.Clear();
this.m_soundCapsList.Clear();
this.m_hasValidCaps = false;
}
void IRenderCapsCallback.OnEndCapsCheck(RENDERHANDLE target, uint cookie)
{
this.m_hasValidCaps = true;
this.m_capsPending = false;
this.NotifyCapsAvailable();
}
void IRenderCapsCallback.OnGraphicsCaps(
RENDERHANDLE target,
uint cookie,
GraphicsCaps caps)
{
if ((int)this.m_currentRequestId != (int)cookie)
return;
this.m_graphicsCapsList.Add(caps);
}
void IRenderCapsCallback.OnSoundCaps(
RENDERHANDLE target,
uint cookie,
SoundCaps caps)
{
if ((int)this.m_currentRequestId != (int)cookie)
return;
this.m_soundCapsList.Add(caps);
}
}
}
@@ -0,0 +1,222 @@
using Microsoft.Iris.Library;
using Microsoft.Iris.Render.Common;
using Microsoft.Iris.Render.Protocol;
using Microsoft.Iris.Render.Sound;
using System;
using System.Collections;
namespace Microsoft.Iris.Render.Internal
{
internal class SkiaRenderEngine : RenderObject, IRenderEngine, IRenderObject, IDisposable
{
private static BitArray s_contexts;
private static uint s_contextIdSeed = 1;
private static uint s_maxContextId = 254;
private IrisEngineInfo m_engineInfo;
private RenderToken m_primaryToken;
private MessagingSession m_messagingSession;
private SkiaRenderCaps m_renderCaps;
private GraphicsDeviceType m_typeGraphics;
private SoundDeviceType m_typeSound;
private InputSystem m_inputSystem;
private SoundDevice m_soundDevice;
private ContextID m_localContextId;
private ContextID m_engineContextId;
static SkiaRenderEngine() => s_contexts = new BitArray((int)s_maxContextId + 1);
internal SkiaRenderEngine(IrisEngineInfo engineInfo, IRenderHost renderHost)
{
Debug2.Validate(engineInfo != null, typeof(ArgumentNullException), nameof(engineInfo));
Debug2.Validate(renderHost != null, typeof(ArgumentNullException), nameof(renderHost));
m_engineInfo = engineInfo;
m_engineContextId = AllocateContextId();
m_localContextId = AllocateContextId();
m_primaryToken = new RenderToken(engineInfo, m_localContextId, m_engineContextId, RENDERGROUP.NULL);
m_messagingSession = new MessagingSession(renderHost, this.m_primaryToken);
this.m_renderCaps = new SkiaRenderCaps(engineInfo.Surface);
this.m_renderCaps.RequestCaps();
}
protected override void Dispose(bool fInDispose)
{
try
{
if (fInDispose)
{
//this.m_renderSession.ReleaseSharedResources();
//if (this.m_renderWindow != null)
// this.m_renderWindow.WindowCreatedEvent -= new EventHandler(OnRenderWindowCreated);
if (m_soundDevice != null)
m_soundDevice.Dispose();
//if (this.m_renderWindow != null)
// this.m_renderWindow.Dispose();
if (m_inputSystem != null)
m_inputSystem.Dispose();
//if (this.m_displayManager != null)
// this.m_displayManager.Dispose();
//if (this.m_renderSession != null)
// this.m_renderSession.Dispose();
if (this.m_messagingSession != null)
{
if (this.m_messagingSession.IsConnected)
this.m_messagingSession.Disconnect();
this.m_messagingSession.Dispose();
}
FreeContextId(m_localContextId);
FreeContextId(m_engineContextId);
}
m_soundDevice = null;
//this.m_displayManager = null;
//this.m_renderWindow = null;
//this.m_renderSession = null;
this.m_messagingSession = null;
}
finally
{
base.Dispose(fInDispose);
}
}
void IRenderEngine.Initialize(
SkiaSharp.SKSurface skSurface,
GraphicsDeviceType typeGraphics,
GraphicsRenderingQuality renderingQuality,
SoundDeviceType typeSound)
{
Debug2.Validate(IsGraphicsDeviceAvailable(typeGraphics, false), typeof(InvalidOperationException), "Graphics device type not available");
Debug2.Validate(IsSoundDeviceAvailable(typeSound), typeof(InvalidOperationException), "Sound device type not available");
m_typeGraphics = typeGraphics;
m_typeSound = typeSound;
// TODO: Set up input system
//m_inputSystem = new InputSystem(this.m_renderSession, this.m_renderWindow);
}
IRenderSession IRenderEngine.Session => null;//throw new NotSupportedException("Skia does not use render sessions"); m_renderSession;
internal RenderSession Session => null;
IRenderWindow IRenderEngine.Window => null;
IDisplayManager IRenderEngine.DisplayManager => null;
public InputSystem InputSystem => throw new NotImplementedException("Skia does not support input yet");// m_inputSystem;
internal SoundDevice SoundDevice => m_soundDevice;
internal Vector<GraphicsCaps> GraphicsCaps => this.m_renderCaps.Graphics;
internal Vector<SoundCaps> SoundCaps => this.m_renderCaps.Sound;
private void DoEvents(uint nTimeoutInMsecs)
{
MessagingSession.DoEvents(nTimeoutInMsecs);
}
void IRenderEngine.WaitForWork(uint nTimeoutInMsecs)
{
EngineApi.SpWaitMessage(nTimeoutInMsecs, IntPtr.Zero);
}
void IRenderEngine.FlushBatch()
{
}
bool IRenderEngine.IsGraphicsDeviceAvailable(
GraphicsDeviceType type,
bool fFilterRecommended)
{
return IsGraphicsDeviceAvailable(type, fFilterRecommended);
}
private bool IsGraphicsDeviceAvailable(GraphicsDeviceType type, bool fFilterRecommended)
{
foreach (GraphicsCaps graphic in this.m_renderCaps.Graphics)
{
if (graphic.DeviceType.FulfillsRequirement(type))
return !fFilterRecommended || graphic.DriverWarning == 0;
}
return false;
}
bool IRenderEngine.IsSoundDeviceAvailable(SoundDeviceType type) => IsSoundDeviceAvailable(type);
private bool IsSoundDeviceAvailable(SoundDeviceType type)
{
if (type == SoundDeviceType.None)
return true;
foreach (SoundCaps soundCaps in this.m_renderCaps.Sound)
{
if ((SoundDeviceType)soundCaps.DeviceType == type)
return true;
}
return false;
}
private void OnRenderWindowCreated(object sender, EventArgs args)
{
SoundDevice soundDevice = null;
switch (m_typeSound)
{
case SoundDeviceType.None:
m_soundDevice = soundDevice;
break;
case SoundDeviceType.DirectSound8:
//soundDevice = new Ds8SoundDevice(this.m_renderSession, m_renderWindow);
//goto case SoundDeviceType.None;
case SoundDeviceType.WaveAudio:
case SoundDeviceType.XAudio:
case SoundDeviceType.XAudio2:
Debug2.Validate(false, typeof(NotImplementedException), "{0} is not yet supported");
break;
default:
Debug2.Validate(false, typeof(ArgumentException), "typeSound");
break;
}
}
internal static ContextID AllocateContextId()
{
uint num1 = 0;
lock (s_contexts)
{
for (int index = 0; index < s_maxContextId; ++index)
{
uint num2 = s_contextIdSeed++;
if (s_contextIdSeed > s_maxContextId)
s_contextIdSeed = 1U;
if (!s_contexts[(int)num2])
{
num1 = num2;
s_contexts[(int)num1] = true;
break;
}
}
}
Debug2.Validate(num1 != 0U, typeof(InvalidOperationException), "Failed to allocate a context ID");
return ContextID.FromUInt32(num1);
}
private static void FreeContextId(ContextID contextId)
{
uint uint32 = ContextID.ToUInt32(contextId);
Debug2.Validate(s_contexts[(int)uint32], typeof(InvalidOperationException), "ContextID is not in use");
lock (s_contexts)
s_contexts[(int)uint32] = false;
}
protected override void Invariant()
{
Debug2.Validate(m_localContextId != ContextID.NULL, typeof(InvalidOperationException), "local ContextId should not be NULL while running");
Debug2.Validate(m_engineContextId != ContextID.NULL, typeof(InvalidOperationException), "engine ContextId should not be NULL while running");
}
bool IRenderEngine.ProcessNativeEvents() => true;
void IRenderEngine.InterThreadWake()
{
}
}
}
@@ -5,38 +5,43 @@
// Assembly location: C:\Program Files\Zune\UIX.RenderApi.dll
using Microsoft.Iris.Render.Protocol;
using SkiaSharp;
using System;
namespace Microsoft.Iris.Render
{
public sealed class IrisEngineInfo : EngineInfo
{
private SKSurface m_skSurface;
private ConnectionInfo m_connectionInfo;
public static EngineInfo CreateLocal() => new IrisEngineInfo(true);
public static EngineInfo CreateLocal(SKSurface skSurface) => new IrisEngineInfo(skSurface, true);
public static EngineInfo CreateRemote() => new IrisEngineInfo(true, TransportProtocol.TCP, "127.0.0.1", false);
public static EngineInfo CreateRemote(SKSurface skSurface) => new IrisEngineInfo(skSurface, true, TransportProtocol.TCP, "127.0.0.1", false);
internal IrisEngineInfo(bool isPrimary)
: base(EngineType.Iris)
internal IrisEngineInfo(SKSurface skSurface, bool isPrimary) : base(EngineType.Iris)
{
if (!isPrimary)
throw new NotImplementedException("Local connections to an existing engine are not supported yet");
this.m_connectionInfo = new LocalConnectionInfo();
this.m_skSurface = skSurface;
}
internal IrisEngineInfo(
bool isPrimary,
TransportProtocol protocol,
string sessionName,
bool swapByteOrder)
: base(EngineType.Iris)
SKSurface skSurface,
bool isPrimary,
TransportProtocol protocol,
string sessionName,
bool swapByteOrder)
: base(EngineType.Iris)
{
if (!isPrimary)
throw new NotImplementedException("Local connections to an existing engine are not supported yet");
this.m_connectionInfo = new RemoteConnectionInfo(protocol, sessionName, swapByteOrder);
this.m_skSurface = skSurface;
}
internal ConnectionInfo ConnectionInfo => this.m_connectionInfo;
internal SKSurface Surface => this.m_skSurface;
}
}
@@ -240,8 +240,6 @@ namespace Microsoft.Iris.Render.Protocol
}
if (this.m_isBatchingMessages)
this.FlushBatch();
return;
// TODO: What does this do?
while (this.m_pingRequestCount > 0)
DoEvents(uint.MaxValue);
}
@@ -27,7 +27,7 @@ namespace Microsoft.Iris.Render
Debug2.Validate(renderHost != null, typeof(ArgumentNullException), nameof(renderHost));
IRenderEngine renderEngine = null;
if (engineInfo.Type == EngineType.Iris)
renderEngine = new RenderEngine(engineInfo as IrisEngineInfo, renderHost);
renderEngine = new SkiaRenderEngine(engineInfo as IrisEngineInfo, renderHost);
return renderEngine;
}
@@ -12,5 +12,6 @@ namespace Microsoft.Iris.Render
DirectSound8,
WaveAudio,
XAudio,
XAudio2,
}
}