Compare commits

..

No commits in common. "4f89325d297f0b35a0775de6ec8f4b933a309127" and "3ffdf8a9294d36e8e30184d12928ab8426790896" have entirely different histories.

9 changed files with 63 additions and 189 deletions

@ -1 +1 @@
Subproject commit 330896a7be6db93b17b3b47734e449817bb30b7a Subproject commit 356f8e9ec2a6118b75e32d2a2ed7dbf4297aba78

View File

@ -1,22 +0,0 @@
namespace MoonWorks
{
public enum FrameLimiterMode
{
Uncapped,
Capped
}
public struct FrameLimiterSettings
{
public FrameLimiterMode Mode;
public int Cap;
public FrameLimiterSettings(
FrameLimiterMode mode,
int cap
) {
Mode = mode;
Cap = cap;
}
}
}

14
src/FramerateSettings.cs Normal file
View File

@ -0,0 +1,14 @@
namespace MoonWorks
{
public enum FramerateMode
{
Uncapped,
Capped
}
public struct FramerateSettings
{
public FramerateMode Mode;
public int Cap;
}
}

View File

@ -29,15 +29,23 @@ namespace MoonWorks
private bool FramerateCapped = false; private bool FramerateCapped = false;
private TimeSpan FramerateCapTimeSpan = TimeSpan.Zero; private TimeSpan FramerateCapTimeSpan = TimeSpan.Zero;
public Window Window { get; }
public GraphicsDevice GraphicsDevice { get; } public GraphicsDevice GraphicsDevice { get; }
public AudioDevice AudioDevice { get; } public AudioDevice AudioDevice { get; }
public Inputs Inputs { get; } public Inputs Inputs { get; }
public Window MainWindow { get; } private Dictionary<PresentMode, RefreshCS.Refresh.PresentMode> moonWorksToRefreshPresentMode = new Dictionary<PresentMode, RefreshCS.Refresh.PresentMode>
{
{ PresentMode.Immediate, RefreshCS.Refresh.PresentMode.Immediate },
{ PresentMode.Mailbox, RefreshCS.Refresh.PresentMode.Mailbox },
{ PresentMode.FIFO, RefreshCS.Refresh.PresentMode.FIFO },
{ PresentMode.FIFORelaxed, RefreshCS.Refresh.PresentMode.FIFORelaxed }
};
public Game( public Game(
WindowCreateInfo windowCreateInfo, WindowCreateInfo windowCreateInfo,
FrameLimiterSettings frameLimiterSettings, PresentMode presentMode,
FramerateSettings framerateSettings,
int targetTimestep = 60, int targetTimestep = 60,
bool debugMode = false bool debugMode = false
) )
@ -45,7 +53,12 @@ namespace MoonWorks
Timestep = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / targetTimestep); Timestep = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / targetTimestep);
gameTimer = Stopwatch.StartNew(); gameTimer = Stopwatch.StartNew();
SetFrameLimiter(frameLimiterSettings); FramerateCapped = framerateSettings.Mode == FramerateMode.Capped;
if (FramerateCapped)
{
FramerateCapTimeSpan = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / framerateSettings.Cap);
}
for (int i = 0; i < previousSleepTimes.Length; i += 1) for (int i = 0; i < previousSleepTimes.Length; i += 1)
{ {
@ -62,25 +75,19 @@ namespace MoonWorks
Inputs = new Inputs(); Inputs = new Inputs();
Window = new Window(windowCreateInfo);
GraphicsDevice = new GraphicsDevice( GraphicsDevice = new GraphicsDevice(
Backend.Vulkan, Window.Handle,
moonWorksToRefreshPresentMode[presentMode],
debugMode debugMode
); );
MainWindow = new Window(windowCreateInfo, GraphicsDevice.WindowFlags | SDL.SDL_WindowFlags.SDL_WINDOW_HIDDEN);
if (!GraphicsDevice.ClaimWindow(MainWindow, windowCreateInfo.PresentMode))
{
throw new System.SystemException("Could not claim window!");
}
AudioDevice = new AudioDevice(); AudioDevice = new AudioDevice();
} }
public void Run() public void Run()
{ {
MainWindow.Show();
while (!quit) while (!quit)
{ {
Tick(); Tick();
@ -89,26 +96,12 @@ namespace MoonWorks
Destroy(); Destroy();
AudioDevice.Dispose(); AudioDevice.Dispose();
MainWindow.Dispose();
GraphicsDevice.Dispose(); GraphicsDevice.Dispose();
Window.Dispose();
SDL.SDL_Quit(); SDL.SDL_Quit();
} }
public void SetFrameLimiter(FrameLimiterSettings settings)
{
FramerateCapped = settings.Mode == FrameLimiterMode.Capped;
if (FramerateCapped)
{
FramerateCapTimeSpan = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / settings.Cap);
}
else
{
FramerateCapTimeSpan = TimeSpan.Zero;
}
}
protected abstract void Update(TimeSpan delta); protected abstract void Update(TimeSpan delta);
protected abstract void Draw(double alpha); protected abstract void Draw(double alpha);
protected virtual void Destroy() {} protected virtual void Destroy() {}
@ -231,14 +224,7 @@ namespace MoonWorks
{ {
if (evt.window.windowEvent == SDL.SDL_WindowEventID.SDL_WINDOWEVENT_SIZE_CHANGED) if (evt.window.windowEvent == SDL.SDL_WindowEventID.SDL_WINDOWEVENT_SIZE_CHANGED)
{ {
var window = Window.Lookup(evt.window.windowID); Window.SizeChanged((uint) evt.window.data1, (uint) evt.window.data2);
window.SizeChanged((uint) evt.window.data1, (uint) evt.window.data2);
}
else if (evt.window.windowEvent == SDL.SDL_WindowEventID.SDL_WINDOWEVENT_CLOSE)
{
var window = Window.Lookup(evt.window.windowID);
GraphicsDevice.UnclaimWindow(window);
window.Dispose();
} }
} }

View File

@ -13,18 +13,15 @@ namespace MoonWorks.Graphics
public IntPtr Handle { get; } public IntPtr Handle { get; }
// some state for debug validation // some state for debug validation
GraphicsPipeline currentGraphicsPipeline; GraphicsPipeline currentGraphicsPipeline = null;
ComputePipeline currentComputePipeline; ComputePipeline currentComputePipeline = null;
bool renderPassActive; bool renderPassActive = false;
// called from RefreshDevice // called from RefreshDevice
internal CommandBuffer(GraphicsDevice device, IntPtr handle) internal CommandBuffer(GraphicsDevice device, IntPtr handle)
{ {
Device = device; Device = device;
Handle = handle; Handle = handle;
currentGraphicsPipeline = null;
currentComputePipeline = null;
renderPassActive = false;
} }
// FIXME: we can probably use the NativeMemory functions to not have to generate arrays here // FIXME: we can probably use the NativeMemory functions to not have to generate arrays here
@ -818,7 +815,7 @@ namespace MoonWorks.Graphics
return new Texture( return new Texture(
Device, Device,
texturePtr, texturePtr,
window.SwapchainFormat, Device.GetSwapchainFormat(window),
width, width,
height height
); );

View File

@ -8,10 +8,6 @@ namespace MoonWorks.Graphics
public class GraphicsDevice : IDisposable public class GraphicsDevice : IDisposable
{ {
public IntPtr Handle { get; } public IntPtr Handle { get; }
public Backend Backend { get; }
private uint windowFlags;
public SDL2.SDL.SDL_WindowFlags WindowFlags => (SDL2.SDL.SDL_WindowFlags) windowFlags;
// Built-in video pipeline // Built-in video pipeline
private ShaderModule VideoVertexShader { get; } private ShaderModule VideoVertexShader { get; }
@ -22,44 +18,25 @@ namespace MoonWorks.Graphics
private readonly List<WeakReference<GraphicsResource>> resources = new List<WeakReference<GraphicsResource>>(); private readonly List<WeakReference<GraphicsResource>> resources = new List<WeakReference<GraphicsResource>>();
private static bool usingCustomVideoShaders;
private static string customVideoVertexShaderFilepath;
private static string customVideoFragmentShaderFilepath;
public GraphicsDevice( public GraphicsDevice(
Backend preferredBackend, IntPtr deviceWindowHandle,
Refresh.PresentMode presentMode,
bool debugMode bool debugMode
) )
{ {
Backend = (Backend) Refresh.Refresh_SelectBackend((Refresh.Backend) preferredBackend, out windowFlags); var presentationParameters = new Refresh.PresentationParameters
if (Backend == Backend.Invalid)
{ {
throw new System.Exception("Could not set graphics backend!"); deviceWindowHandle = deviceWindowHandle,
} presentMode = presentMode
};
Handle = Refresh.Refresh_CreateDevice( Handle = Refresh.Refresh_CreateDevice(
presentationParameters,
Conversions.BoolToByte(debugMode) Conversions.BoolToByte(debugMode)
); );
Stream videoVertexShaderStream; VideoVertexShader = new ShaderModule(this, GetEmbeddedResource("MoonWorks.Shaders.FullscreenVert.spv"));
Stream videoFragmentShaderStream; VideoFragmentShader = new ShaderModule(this, GetEmbeddedResource("MoonWorks.Shaders.YUV2RGBAFrag.spv"));
if (!usingCustomVideoShaders)
{
videoVertexShaderStream = GetEmbeddedResource("MoonWorks.Shaders.FullscreenVert.spv");
videoFragmentShaderStream = GetEmbeddedResource("MoonWorks.Shaders.YUV2RGBAFrag.spv");
}
else
{
videoVertexShaderStream = File.Open(customVideoVertexShaderFilepath, FileMode.Open, FileAccess.Read);
videoFragmentShaderStream = File.Open(customVideoFragmentShaderFilepath, FileMode.Open, FileAccess.Read);
}
VideoVertexShader = new ShaderModule(this, videoVertexShaderStream);
VideoFragmentShader = new ShaderModule(this, videoFragmentShaderStream);
videoVertexShaderStream.Close();
videoFragmentShaderStream.Close();
VideoPipeline = new GraphicsPipeline( VideoPipeline = new GraphicsPipeline(
this, this,
@ -79,43 +56,6 @@ namespace MoonWorks.Graphics
); );
} }
public bool ClaimWindow(Window window, PresentMode presentMode)
{
var success = Conversions.ByteToBool(
Refresh.Refresh_ClaimWindow(
Handle,
window.Handle,
(Refresh.PresentMode) presentMode
)
);
if (success)
{
window.Claimed = true;
window.SwapchainFormat = GetSwapchainFormat(window);
}
return success;
}
public void UnclaimWindow(Window window)
{
Refresh.Refresh_UnclaimWindow(
Handle,
window.Handle
);
window.Claimed = false;
}
public void SetPresentMode(Window window, PresentMode presentMode)
{
Refresh.Refresh_SetSwapchainPresentMode(
Handle,
window.Handle,
(Refresh.PresentMode) presentMode
);
}
public CommandBuffer AcquireCommandBuffer() public CommandBuffer AcquireCommandBuffer()
{ {
return new CommandBuffer(this, Refresh.Refresh_AcquireCommandBuffer(Handle, 0)); return new CommandBuffer(this, Refresh.Refresh_AcquireCommandBuffer(Handle, 0));
@ -142,7 +82,7 @@ namespace MoonWorks.Graphics
Refresh.Refresh_Wait(Handle); Refresh.Refresh_Wait(Handle);
} }
private TextureFormat GetSwapchainFormat(Window window) public TextureFormat GetSwapchainFormat(Window window)
{ {
return (TextureFormat) Refresh.Refresh_GetSwapchainFormat(Handle, window.Handle); return (TextureFormat) Refresh.Refresh_GetSwapchainFormat(Handle, window.Handle);
} }
@ -168,16 +108,6 @@ namespace MoonWorks.Graphics
return typeof(GraphicsDevice).Assembly.GetManifestResourceStream(name); return typeof(GraphicsDevice).Assembly.GetManifestResourceStream(name);
} }
/// <summary>
/// Use this ONLY for platforms with non-standard graphics APIs where the shader code can't be embedded into the assembly!
/// </summary>
public static void UseCustomVideoShaders(string vertexShaderFilePath, string fragmentShaderFilePath)
{
usingCustomVideoShaders = true;
customVideoVertexShaderFilepath = vertexShaderFilePath;
customVideoFragmentShaderFilepath = fragmentShaderFilePath;
}
protected virtual void Dispose(bool disposing) protected virtual void Dispose(bool disposing)
{ {
if (!IsDisposed) if (!IsDisposed)

View File

@ -1,6 +1,9 @@
using System; using System;
namespace MoonWorks /* Recreate all the enums in here so we don't need to explicitly
* reference the RefreshCS namespace when using MoonWorks.Graphics
*/
namespace MoonWorks.Graphics
{ {
public enum PresentMode public enum PresentMode
{ {
@ -9,13 +12,7 @@ namespace MoonWorks
FIFO, FIFO,
FIFORelaxed FIFORelaxed
} }
}
/* Recreate all the enums in here so we don't need to explicitly
* reference the RefreshCS namespace when using MoonWorks.Graphics
*/
namespace MoonWorks.Graphics
{
public enum PrimitiveType public enum PrimitiveType
{ {
PointList, PointList,
@ -283,12 +280,4 @@ namespace MoonWorks.Graphics
FloatOpaqueWhite, FloatOpaqueWhite,
IntOpaqueWhite IntOpaqueWhite
} }
public enum Backend
{
DontCare,
Vulkan,
PS5,
Invalid
}
} }

View File

@ -1,5 +1,4 @@
using System; using System;
using System.Collections.Generic;
using SDL2; using SDL2;
namespace MoonWorks namespace MoonWorks
@ -11,32 +10,29 @@ namespace MoonWorks
public uint Width { get; private set; } public uint Width { get; private set; }
public uint Height { get; private set; } public uint Height { get; private set; }
public bool Claimed { get; internal set; }
public MoonWorks.Graphics.TextureFormat SwapchainFormat { get; internal set; }
private bool IsDisposed; private bool IsDisposed;
private static Dictionary<uint, Window> idLookup = new Dictionary<uint, Window>(); public Window(WindowCreateInfo windowCreateInfo)
public Window(WindowCreateInfo windowCreateInfo, SDL.SDL_WindowFlags flags)
{ {
var windowFlags = SDL.SDL_WindowFlags.SDL_WINDOW_VULKAN;
if (windowCreateInfo.ScreenMode == ScreenMode.Fullscreen) if (windowCreateInfo.ScreenMode == ScreenMode.Fullscreen)
{ {
flags |= SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN; windowFlags |= SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN;
} }
else if (windowCreateInfo.ScreenMode == ScreenMode.BorderlessWindow) else if (windowCreateInfo.ScreenMode == ScreenMode.BorderlessWindow)
{ {
flags |= SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP; windowFlags |= SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP;
} }
if (windowCreateInfo.SystemResizable) if (windowCreateInfo.SystemResizable)
{ {
flags |= SDL.SDL_WindowFlags.SDL_WINDOW_RESIZABLE; windowFlags |= SDL.SDL_WindowFlags.SDL_WINDOW_RESIZABLE;
} }
if (windowCreateInfo.StartMaximized) if (windowCreateInfo.StartMaximized)
{ {
flags |= SDL.SDL_WindowFlags.SDL_WINDOW_MAXIMIZED; windowFlags |= SDL.SDL_WindowFlags.SDL_WINDOW_MAXIMIZED;
} }
ScreenMode = windowCreateInfo.ScreenMode; ScreenMode = windowCreateInfo.ScreenMode;
@ -47,13 +43,11 @@ namespace MoonWorks
SDL.SDL_WINDOWPOS_UNDEFINED, SDL.SDL_WINDOWPOS_UNDEFINED,
(int) windowCreateInfo.WindowWidth, (int) windowCreateInfo.WindowWidth,
(int) windowCreateInfo.WindowHeight, (int) windowCreateInfo.WindowHeight,
flags windowFlags
); );
Width = windowCreateInfo.WindowWidth; Width = windowCreateInfo.WindowWidth;
Height = windowCreateInfo.WindowHeight; Height = windowCreateInfo.WindowHeight;
idLookup.Add(SDL.SDL_GetWindowID(Handle), this);
} }
public void ChangeScreenMode(ScreenMode screenMode) public void ChangeScreenMode(ScreenMode screenMode)
@ -87,16 +81,6 @@ namespace MoonWorks
Height = height; Height = height;
} }
internal static Window Lookup(uint windowID)
{
return idLookup.ContainsKey(windowID) ? idLookup[windowID] : null;
}
internal void Show()
{
SDL.SDL_ShowWindow(Handle);
}
internal void SizeChanged(uint width, uint height) internal void SizeChanged(uint width, uint height)
{ {
Width = width; Width = width;
@ -112,7 +96,6 @@ namespace MoonWorks
// dispose managed state (managed objects) // dispose managed state (managed objects)
} }
idLookup.Remove(SDL.SDL_GetWindowID(Handle));
SDL.SDL_DestroyWindow(Handle); SDL.SDL_DestroyWindow(Handle);
IsDisposed = true; IsDisposed = true;

View File

@ -6,7 +6,6 @@
public uint WindowWidth; public uint WindowWidth;
public uint WindowHeight; public uint WindowHeight;
public ScreenMode ScreenMode; public ScreenMode ScreenMode;
public PresentMode PresentMode;
public bool SystemResizable; public bool SystemResizable;
public bool StartMaximized; public bool StartMaximized;
@ -15,7 +14,6 @@
uint windowWidth, uint windowWidth,
uint windowHeight, uint windowHeight,
ScreenMode screenMode, ScreenMode screenMode,
PresentMode presentMode,
bool systemResizable = false, bool systemResizable = false,
bool startMaximized = false bool startMaximized = false
) { ) {
@ -23,7 +21,6 @@
WindowWidth = windowWidth; WindowWidth = windowWidth;
WindowHeight = windowHeight; WindowHeight = windowHeight;
ScreenMode = screenMode; ScreenMode = screenMode;
PresentMode = presentMode;
SystemResizable = systemResizable; SystemResizable = systemResizable;
StartMaximized = startMaximized; StartMaximized = startMaximized;
} }