Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add UWP CoreApplication sample #852

Open
wants to merge 22 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
d06dc63
Add draft CoreWindow sample for D2D
Sergio0694 Jul 26, 2024
bed13c5
Implement blank 'CoreWindow' startup
Sergio0694 Jul 26, 2024
5aa1d73
Exclude all 'Microsoft.Web.WebView2' assets
Sergio0694 Jul 26, 2024
0834598
Add 'ApplicationViewTitleBarExtensions' type
Sergio0694 Jul 26, 2024
3771e94
Implement initial simplified render loop
Sergio0694 Jul 26, 2024
aff2f8e
Enable some CsWinRT size saving options
Sergio0694 Jul 26, 2024
0a228d7
Simplify .appxmanifest files
Sergio0694 Jul 30, 2024
5cdeda7
Enable final NativeAOT configuration
Sergio0694 Jul 30, 2024
6f559bb
Use new GUID for CoreWindow .appxmanifest
Sergio0694 Jul 30, 2024
8411b7a
Simplify namespaces in 'CoreWindow' sample
Sergio0694 Jul 31, 2024
b014847
Refactor render code into 'CoreApplication' helpers
Sergio0694 Jul 31, 2024
16e719a
Select shader by pressing number keys
Sergio0694 Jul 31, 2024
8c07fea
Enable resizing when resizing the window
Sergio0694 Jul 31, 2024
d93485d
Fix crash when resizing the window
Sergio0694 Jul 31, 2024
987ec48
Update dependencies in CoreWindow sample
Sergio0694 Aug 14, 2024
9f0042c
Disable 'CsWinRTEnableDefaultCustomTypeMappings'
Sergio0694 Aug 14, 2024
ebf6411
Update .csproj for latest changes
Sergio0694 Sep 11, 2024
68c5bfd
Add experimental Xbox support
Sergio0694 Sep 11, 2024
f6fcf0c
Publish the CoreWindow sample in CI
Sergio0694 Sep 12, 2024
68161fe
Rename CoreWindow sample
Sergio0694 Sep 18, 2024
0d10cad
Correctly remove WebView2 references
Sergio0694 Sep 19, 2024
de4f225
Publish Xbox flavor of UWP sample in CI script
Sergio0694 Sep 19, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,21 @@ jobs:
msbuild samples\ComputeSharp.SwapChain.WinUI\ComputeSharp.SwapChain.WinUI.csproj /restore -t:publish
/p:Configuration=Release /p:Platform=${{matrix.platform}} /p:RuntimeIdentifier=win-${{matrix.platform}}

# Publish the D2D1 UWP (CoreApplication) sample app with NativeAOT
- if: matrix.platform == 'x64'
name: Publish ComputeSharp.SwapChain.D2D1.Uwp
run: >
msbuild samples\ComputeSharp.SwapChain.D2D1.Uwp\ComputeSharp.SwapChain.D2D1.Uwp.csproj /restore -t:publish
/p:Configuration=Release /p:Platform=${{matrix.platform}} /p:RuntimeIdentifier=win-${{matrix.platform}}

# Publish the D2D1 UWP sample app again with NativeAOT, with Xbox support
- if: matrix.platform == 'x64'
name: Publish ComputeSharp.SwapChain.D2D1.Uwp (Xbox)
run: >
$env:EXPERIMENTAL_XBOX_SUPPORT='true';
msbuild samples\ComputeSharp.SwapChain.D2D1.Uwp\ComputeSharp.SwapChain.D2D1.Uwp.csproj /restore -t:publish
/p:Configuration=Release /p:Platform=${{matrix.platform}} /p:RuntimeIdentifier=win-${{matrix.platform}}

# Download the NuGet packages generated in the previous job and use them
# to build and run the sample project referencing them. This is used as
# a test to ensure the NuGet packages work in a consuming project.
Expand Down
16 changes: 16 additions & 0 deletions ComputeSharp.sln
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "ComputeSharp.D2D1.UI", "src
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ComputeSharp.D2D1.Uwp", "src\ComputeSharp.D2D1.Uwp\ComputeSharp.D2D1.Uwp.csproj", "{716DF19E-69BA-4A9C-9CA4-BFD196152F46}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ComputeSharp.SwapChain.D2D1.Uwp", "samples\ComputeSharp.SwapChain.D2D1.Uwp\ComputeSharp.SwapChain.D2D1.Uwp.csproj", "{9FBE070E-A210-4CEF-9F04-61C2B269C600}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Expand Down Expand Up @@ -488,6 +490,18 @@ Global
{716DF19E-69BA-4A9C-9CA4-BFD196152F46}.Release|ARM64.Build.0 = Release|ARM64
{716DF19E-69BA-4A9C-9CA4-BFD196152F46}.Release|x64.ActiveCfg = Release|x64
{716DF19E-69BA-4A9C-9CA4-BFD196152F46}.Release|x64.Build.0 = Release|x64
{9FBE070E-A210-4CEF-9F04-61C2B269C600}.Debug|ARM64.ActiveCfg = Debug|ARM64
{9FBE070E-A210-4CEF-9F04-61C2B269C600}.Debug|ARM64.Build.0 = Debug|ARM64
{9FBE070E-A210-4CEF-9F04-61C2B269C600}.Debug|ARM64.Deploy.0 = Debug|ARM64
{9FBE070E-A210-4CEF-9F04-61C2B269C600}.Debug|x64.ActiveCfg = Debug|x64
{9FBE070E-A210-4CEF-9F04-61C2B269C600}.Debug|x64.Build.0 = Debug|x64
{9FBE070E-A210-4CEF-9F04-61C2B269C600}.Debug|x64.Deploy.0 = Debug|x64
{9FBE070E-A210-4CEF-9F04-61C2B269C600}.Release|ARM64.ActiveCfg = Release|ARM64
{9FBE070E-A210-4CEF-9F04-61C2B269C600}.Release|ARM64.Build.0 = Release|ARM64
{9FBE070E-A210-4CEF-9F04-61C2B269C600}.Release|ARM64.Deploy.0 = Release|ARM64
{9FBE070E-A210-4CEF-9F04-61C2B269C600}.Release|x64.ActiveCfg = Release|x64
{9FBE070E-A210-4CEF-9F04-61C2B269C600}.Release|x64.Build.0 = Release|x64
{9FBE070E-A210-4CEF-9F04-61C2B269C600}.Release|x64.Deploy.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -527,6 +541,7 @@ Global
{B4F6A41C-AA9A-4302-92B3-AC64CF2E30F5} = {A5013F9B-92EC-419F-B0B3-3D6B721E7104}
{1A3E20B3-F711-41C0-82EA-3B53A575955C} = {0ED8F632-5E17-46BE-8CC3-B14A82D4AEB1}
{551EF4FB-F34F-412A-B3E6-E345797560ED} = {0ED8F632-5E17-46BE-8CC3-B14A82D4AEB1}
{9FBE070E-A210-4CEF-9F04-61C2B269C600} = {0ED8F632-5E17-46BE-8CC3-B14A82D4AEB1}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4664C5E3-0340-4E22-BCFD-98AAEDF5F2DC}
Expand All @@ -550,6 +565,7 @@ Global
src\ComputeSharp.CodeFixing\ComputeSharp.CodeFixing.projitems*{9b4448b1-200f-4966-8a13-a508691b3003}*SharedItemsImports = 5
src\ComputeSharp.Win32.D2D1\ComputeSharp.Win32.D2D1.projitems*{9da1da9f-f8b2-4b25-be80-c21f773029e3}*SharedItemsImports = 13
samples\ComputeSharp.SwapChain.Shaders.D2D1\ComputeSharp.SwapChain.Shaders.D2D1.projitems*{9ea5ae9d-c39a-4f43-b03e-0a848ea2558a}*SharedItemsImports = 5
samples\ComputeSharp.SwapChain.Shaders.D2D1\ComputeSharp.SwapChain.Shaders.D2D1.projitems*{9fbe070e-a210-4cef-9f04-61c2b269c600}*SharedItemsImports = 5
src\ComputeSharp.D2D1.UI\ComputeSharp.D2D1.UI.projitems*{a2a2171b-0baf-4a2a-bfb3-3357ef714bf0}*SharedItemsImports = 13
src\ComputeSharp.D2D1.UI\ComputeSharp.D2D1.UI.projitems*{bd9e6556-357e-4c20-bfcd-fb131f9372fa}*SharedItemsImports = 5
samples\ComputeSharp.SwapChain.Shaders\ComputeSharp.SwapChain.Shaders.projitems*{c12d7ace-98ed-4813-8118-6667c34f484f}*SharedItemsImports = 5
Expand Down
6 changes: 3 additions & 3 deletions samples/ComputeSharp.SwapChain.D2D1.Cli/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@
// If a shader is found, run it
if (effect is not null)
{
Win32Application win32Application = new();
Win32Application application = new();

win32Application.Draw += (_, e) =>
application.Draw += (_, e) =>
{
// Set the effect properties
effect.ElapsedTime = e.TotalTime;
Expand All @@ -46,7 +46,7 @@
e.DrawingSession.DrawImage(effect);
};

Win32ApplicationRunner.Run(win32Application, "ComputeSharp.D2D1");
Win32ApplicationRunner.Run(application, "ComputeSharp.D2D1");

return S.S_OK;
}
Expand Down
120 changes: 120 additions & 0 deletions samples/ComputeSharp.SwapChain.D2D1.Uwp/App.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
using System.Diagnostics.CodeAnalysis;
using ComputeSharp.SwapChain.D2D1.Backend;
using ComputeSharp.SwapChain.D2D1.Extensions;
using ComputeSharp.SwapChain.Shaders.D2D1;
using Windows.ApplicationModel.Core;
using Windows.UI.Core;
using Windows.UI.ViewManagement;

namespace ComputeSharp.SwapChain.D2D1;

/// <summary>
/// A sample app rendering D2D shaders into a <see cref="CoreWindow"/> instance.
/// </summary>
public sealed partial class App : IFrameworkViewSource, IFrameworkView
{
/// <summary>
/// The collection of available pixel shader effects.
/// </summary>
private static readonly PixelShaderEffect[] Effects =
[
new PixelShaderEffect.For<ColorfulInfinity>(static (time, width, height) => new((float)time.TotalSeconds, new int2(width, height))),
new PixelShaderEffect.For<FractalTiling>(static (time, width, height) => new((float)time.TotalSeconds, new int2(width, height))),
new PixelShaderEffect.For<TwoTiledTruchet>(static (time, width, height) => new((float)time.TotalSeconds, new int2(width, height))),
new PixelShaderEffect.For<MengerJourney>(static (time, width, height) => new((float)time.TotalSeconds, new int2(width, height))),
new PixelShaderEffect.For<Octagrams>(static (time, width, height) => new((float)time.TotalSeconds, new int2(width, height))),
new PixelShaderEffect.For<ProteanClouds>(static (time, width, height) => new((float)time.TotalSeconds, new int2(width, height))),
new PixelShaderEffect.For<PyramidPattern>(static (time, width, height) => new((float)time.TotalSeconds, new int2(width, height))),
new PixelShaderEffect.For<TriangleGridContouring>(static (time, width, height) => new((float)time.TotalSeconds, new int2(width, height))),
new PixelShaderEffect.For<TerracedHills>(static (time, width, height) => new((float)time.TotalSeconds, new int2(width, height)))
];

/// <summary>
/// The <see cref="CoreApplicationView"/> for the current app instance.
/// </summary>
private CoreApplicationView? applicationView;

/// <summary>
/// The <see cref="CoreWindow"/> used to display the app content.
/// </summary>
private CoreWindow? window;

/// <summary>
/// The currently selected effect (one of the items in <see cref="Effects"/>).
/// </summary>
private PixelShaderEffect selectedEffect = Effects[0];

/// <summary>
/// The entry point for the application.
/// </summary>
public static void Main()
{
CoreApplication.Run(new App());
}

/// <inheritdoc/>
public IFrameworkView CreateView()
{
return this;
}

/// <inheritdoc/>
[MemberNotNull(nameof(applicationView))]
public void Initialize(CoreApplicationView applicationView)
{
this.applicationView = applicationView;
}

/// <inheritdoc/>
[MemberNotNull(nameof(window))]
public void SetWindow(CoreWindow window)
{
this.window = window;
}

/// <inheritdoc/>
public void Load(string entryPoint)
{
}

/// <inheritdoc/>
public void Run()
{
this.applicationView!.TitleBar.ExtendViewIntoTitleBar = true;

ApplicationView.GetForCurrentView().TitleBar.StyleTitleBarForExtendedIntoViewMode();

// Switch the shader to use when pressing the number keys
this.window!.CharacterReceived += (s, e) =>
{
if (e.KeyCode is >= '1' and <= '9')
{
this.selectedEffect = Effects[(int)(e.KeyCode - '1')];

e.Handled = true;
}
};

CoreWindowApplication application = new();

application.Draw += (s, e) =>
{
PixelShaderEffect effect = this.selectedEffect;

// Set the effect properties
effect.ElapsedTime = e.TotalTime;
effect.ScreenWidth = (int)e.ScreenWidth;
effect.ScreenHeight = (int)e.ScreenHeight;

// Draw the effect
e.DrawingSession.DrawImage(effect);
};

CoreWindowApplicationRunner.Run(application, this.window);
}

/// <inheritdoc/>
public void Uninitialize()
{
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
using System;
using System.Diagnostics.CodeAnalysis;
using Microsoft.Graphics.Canvas;
using Windows.Graphics.Display;
using Windows.Graphics.Imaging;
using Windows.UI.Core;

namespace ComputeSharp.SwapChain.D2D1.Backend;

/// <summary>
/// A simple <see cref="CoreWindow"/> application handling a D2D swapchain.
/// </summary>
internal sealed class CoreWindowApplication
{
/// <summary>
/// The <see cref="CanvasDevice"/> instance to use.
/// </summary>
private CanvasDevice? canvasDevice;

/// <summary>
/// The <see cref="CanvasSwapChain"/> instance to use to render frames.
/// </summary>
private CanvasSwapChain? canvasSwapChain;

/// <summary>
/// Whether or not the window has been resized and requires the buffers to be updated.
/// </summary>
private volatile bool isResizePending;

/// <summary>
/// The current screen width in raw pixels.
/// </summary>
private uint screenWidth;

/// <summary>
/// The current screen height in raw pixels.
/// </summary>
private uint screenHeight;

/// <summary>
/// Raised whenever a draw operation can be performed.
/// </summary>
public event EventHandler<DrawEventArgs>? Draw;

/// <summary>
/// Initializes the current application.
/// </summary>
/// <param name="window">The <see cref="CoreWindow"/> instance.</param>
[MemberNotNull(nameof(canvasDevice))]
[MemberNotNull(nameof(canvasSwapChain))]
public unsafe void OnInitialize(CoreWindow window)
{
// Create a new canvas device, which will handle DX11/D2D initialization
CanvasDevice canvasDevice = new();

// Create the swapchain for rendering (it is automatically tied to the window)
CanvasSwapChain canvasSwapChain = CanvasSwapChain.CreateForCoreWindow(
resourceCreator: canvasDevice,
coreWindow: window,
dpi: DisplayInformation.GetForCurrentView().LogicalDpi);

// Save the Win2D objects for later use
this.canvasDevice = canvasDevice;
this.canvasSwapChain = canvasSwapChain;

// Store the initial size of the screen
this.screenWidth = canvasSwapChain.SizeInPixels.Width;
this.screenHeight = canvasSwapChain.SizeInPixels.Height;
}

/// <summary>
/// Resizes the current application.
/// </summary>
public void OnResize()
{
this.isResizePending = true;
}

/// <summary>
/// Updates the current application.
/// </summary>
/// <param name="time">The current time since the start of the application.</param>
public void OnUpdate(TimeSpan time)
{
if (this.isResizePending)
{
// Resize the swapchain if needed (the size is calculated automatically)
this.canvasSwapChain!.ResizeBuffers(0, 0);

BitmapSize bitmapSize = this.canvasSwapChain!.SizeInPixels;

this.screenWidth = bitmapSize.Width;
this.screenHeight = bitmapSize.Height;

this.isResizePending = false;
}

// Create the drawing session and invoke all registered draw handler
using (CanvasDrawingSession canvasDrawingSession = this.canvasSwapChain!.CreateDrawingSession(default))
{
Draw?.Invoke(this, new DrawEventArgs
{
ScreenWidth = this.screenWidth,
ScreenHeight = this.screenHeight,
TotalTime = time,
DrawingSession = canvasDrawingSession
});
}

// Wait for v-sync
this.canvasSwapChain.WaitForVerticalBlank();

// Present the new frame
this.canvasSwapChain.Present(syncInterval: 1);
}

/// <summary>
/// Arguments for <see cref="Draw"/>.
/// </summary>
public sealed class DrawEventArgs : EventArgs
{
/// <summary>
/// Gets the screen width in raw pixels.
/// </summary>
public required uint ScreenWidth { get; init; }

/// <summary>
/// Gets the screen height in raw pixels.
/// </summary>
public required uint ScreenHeight { get; init; }

/// <summary>
/// Gets the total time for the rendering loop.
/// </summary>
public required TimeSpan TotalTime { get; init; }

/// <summary>
/// Gets the <see cref="CanvasDrawingSession"/> instance to use.
/// </summary>
public required CanvasDrawingSession DrawingSession { get; init; }
}
}
Loading