C# Blazor and Canvas

I was beyond excited to discover that there was already an extension for Blazor to be able to interact with an HTML5 canvas called Blazor Extensions Canvas. So I spun up Visual Studio and created a new Blazor client project and begin to strip away all the bloat.

After getting rid of most of the bloat, my App.razor was now just:

<div class="container">
    <BECanvas Width="640" Height="480" @ref="_canvasReference"></BECanvas>
</div>

You can find the full source code at my Github here, but I’ll show some pertinent bits below. The first being that in the javascript side I have a main game loop that calls back into the C# code using InvokeMethodAsync:

function gameLoop(timeStamp) {
    window.requestAnimationFrame(gameLoop);
    game.instance.invokeMethodAsync('GameLoop', 
                                    timeStamp, 
                                    game.canvas.width, 
                                    game.canvas.height);
}

And then on the C# side I’ve got the GameLoop function as such with calls being made to populate the canvas:

[JSInvokable]
public async ValueTask GameLoop(float timeStamp, int width, int height)
{
...
    await _context.BeginBatchAsync();
    await context.SetFillStyleAsync("green");
    await context.FillRectAsync(x, y, 50, 50);
...
    await _context.EndBatchAsync();
}

Pretty soon I had a rectangle bouncing around the screen and an FPS counter! It was chilling at a rock solid 60FPS and I thought this was going to be my new tool to develop games for games jams to be played in the browser. So next I bumped it up to 20 rectangles just to make sure everything was still smooth and I noticed the FPS dropping a bit sometimes, I chalked it up to being run in debug and kept going with structuring the code.

Soon though I remembered reading that this wasn’t great for performance and so I dropped down 200 rectangles and to my horror it was maxing out at 22 FPS on a machine with a 1080Ti.

After verifying that hardware acceleration in chrome was in fact enabled, and opening up a more “native” wasm project that I had worked on before that could handle 10s of thousand sprites at once, I learned that the JSInterop was killing this dream.

The back and fourth between JS and C# is just to big of an overhead right now, I might experiment with “rendering” all of the images onto a surface of sorts and only calling a canvas draw function once per frame, but for now Blazor does not seem like a great candidate for game development.

Leave a Comment

Your email address will not be published. Required fields are marked *