• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

DemoBytom / DemoEngine / 23389549430

21 Mar 2026 09:40PM UTC coverage: 32.417% (-0.05%) from 32.468%
23389549430

push

coveralls.net

DemoBytom
Mediator shader compilation and loading at the start of the app

Shader compilation and loading is now performed through Mediator, at the start of the application, instead when `MainLoop` starts. This should ensure (for now) that shaders are properly compiled and loaded when needed (for example in `GPass`)

1262 of 3893 relevant lines covered (32.42%)

0.36 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.51
/src/Demo.Engine.Core/Services/MainLoopService.cs
1
// Copyright © Michał Dembski and contributors.
2
// Distributed under MIT license. See LICENSE file in the root for more information.
3

4
using System.Diagnostics;
5
using Demo.Engine.Core.Features.StaThread;
6
using Demo.Engine.Core.Interfaces;
7
using Demo.Engine.Core.Interfaces.Rendering;
8
using Demo.Engine.Core.Requests.Keyboard;
9
using Demo.Engine.Core.ValueObjects;
10
using Mediator;
11
using Microsoft.Extensions.Logging;
12

13
namespace Demo.Engine.Core.Services;
14

15
internal sealed class MainLoopService
16
    : IMainLoopService,
17
      IAsyncDisposable
18
{
19
    private readonly ILogger<MainLoopService> _logger;
20
    private readonly IStaThreadWriter _staThreadWriter;
21
    private readonly IMediator _mediator;
22
    private readonly IFpsTimer _fpsTimer;
23
    private readonly IMainLoopLifetime _mainLoopLifetime;
24
    private readonly ILoopJob _loopJob;
25
    private bool _disposedValue;
26

27
    public Task ExecutingTask { get; }
28

29
    public MainLoopService(
1✔
30
        ILogger<MainLoopService> logger,
1✔
31
        IStaThreadWriter staThreadWriter,
1✔
32
        IMediator mediator,
1✔
33
        IFpsTimer fpsTimer,
1✔
34
        IRenderingEngine renderingEngine,
1✔
35
        IMainLoopLifetime mainLoopLifetime,
1✔
36
        ILoopJob loopJob)
1✔
37
    {
38
        _logger = logger;
1✔
39
        _staThreadWriter = staThreadWriter;
1✔
40
        _mediator = mediator;
1✔
41
        _fpsTimer = fpsTimer;
1✔
42
        _mainLoopLifetime = mainLoopLifetime;
1✔
43
        _loopJob = loopJob;
1✔
44
        ExecutingTask = Task.Run(async () =>
1✔
45
        {
1✔
46
            try
1✔
47
            {
1✔
48
                await DoAsync(renderingEngine);
1✔
49
            }
1✔
50
            catch (TaskCanceledException)
×
51
            {
1✔
52
                _mainLoopLifetime.Cancel();
×
53
            }
×
54
            catch (Exception ex)
×
55
            {
1✔
56
                _logger.LogMainLoopFailedWithError(ex);
×
57
                _mainLoopLifetime.Cancel();
×
58
                throw;
×
59
            }
1✔
60
        });
1✔
61
    }
1✔
62

63
    private async Task DoAsync(
64
        IRenderingEngine renderingEngine)
65
    {
66
        var keyboardHandle = await _mediator.Send(new KeyboardHandleRequest(), CancellationToken.None);
1✔
67
        var keyboardCharCache = await _mediator.Send(new KeyboardCharCacheRequest(), CancellationToken.None);
1✔
68

69
        var surfaces = new RenderingSurfaceId[]
1✔
70
        {
1✔
71
            await _staThreadWriter.CreateSurface(
1✔
72
                _mainLoopLifetime.Token),
1✔
73
            //await _channelWriter.CreateSurface(
1✔
74
            //    _mainLoopLifetime.Token),
1✔
75
        };
1✔
76

77
        var previous = Stopwatch.GetTimestamp();
1✔
78
        var lag = TimeSpan.Zero;
1✔
79

80
        var msPerUpdate = TimeSpan.FromSeconds(1) / 60;
1✔
81

82
        var doEventsOk = true;
1✔
83

84
        while (
1✔
85
            doEventsOk
1✔
86
            //&& IsRunning
1✔
87
            && !_disposedValue
1✔
88
            && !_mainLoopLifetime.Token.IsCancellationRequested)
1✔
89
        {
90
            var current = Stopwatch.GetTimestamp();
1✔
91
            var elapsed = Stopwatch.GetElapsedTime(previous, current);
1✔
92
            previous = current;
1✔
93
            lag += elapsed;
1✔
94

95
            //process input
96
            // TODO!
97

98
            while (lag >= msPerUpdate)
1✔
99
            {
100
                //Update
101
                // TODO - fix the UPS timer.. somehow :D
102
                _fpsTimer.StopUpdateTimer();
1✔
103
                foreach (var renderingSurfaceId in surfaces)
1✔
104
                {
105
                    if (!renderingEngine.TryGetRenderingSurface(
106
                        renderingSurfaceId,
1✔
107
                        out var renderingSurface))
1✔
108
                    {
109
                        _logger.LogRenderingSurfaceNotFound(
×
110
                            renderingSurfaceId);
×
111
                        break;
×
112
                    }
113

114
                    await _loopJob.Update(
1✔
115
                          renderingSurface,
1✔
116
                          keyboardHandle,
1✔
117
                          keyboardCharCache);
1✔
118
                }
119
                lag -= msPerUpdate;
1✔
120
                _fpsTimer.StartUpdateTimer();
1✔
121
            }
122

123
            //Render
124
            foreach (var renderingSurfaceId in surfaces)
1✔
125
            {
126
                doEventsOk &= await _staThreadWriter.DoEventsOk(
1✔
127
                    renderingSurfaceId,
1✔
128
                    _mainLoopLifetime.Token);
1✔
129

130
                using var scope = _fpsTimer.StartRenderingTimerScope(
1✔
131
                    renderingSurfaceId);
1✔
132

133
                _loopJob.Render(
1✔
134
                    renderingEngine,
1✔
135
                    renderingSurfaceId);
1✔
136
            }
137
        }
138
        _mainLoopLifetime.Cancel();
1✔
139
    }
1✔
140

141
    private async ValueTask Dispose(bool disposing)
142
    {
143
        if (!_disposedValue)
1✔
144
        {
145
            if (disposing)
1✔
146
            {
147
            }
148

149
            _disposedValue = true;
1✔
150
            //Make sure the loop finishes
151
            await ExecutingTask;
1✔
152
        }
153
    }
1✔
154

155
    public async ValueTask DisposeAsync()
156
    {
157
        // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
158
        await Dispose(disposing: true);
1✔
159
        GC.SuppressFinalize(this);
1✔
160
    }
1✔
161
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc