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

DemoBytom / DemoEngine / 23769862947

30 Mar 2026 10:01PM UTC coverage: 30.548% (+0.007%) from 30.541%
23769862947

push

coveralls.net

DemoBytom
Drawing Mandlebrot fractal

1276 of 4177 relevant lines covered (30.55%)

0.37 hits per line

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

0.0
/src/Demo.Engine.Platform.DirectX12/ForwardPlusRenderer/GPassService.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.CodeAnalysis;
5
using System.Runtime.InteropServices;
6
using Demo.Engine.Core.ValueObjects;
7
using Demo.Engine.Platform.DirectX12.RenderingResources;
8
using Demo.Engine.Platform.DirectX12.Shaders;
9
using Microsoft.Extensions.Logging;
10
using Vortice.Direct3D;
11
using Vortice.Direct3D12;
12
using Vortice.DXGI;
13

14
namespace Demo.Engine.Platform.DirectX12.ForwardPlusRenderer;
15

16
/// <summary>
17
/// Geometry pass - Depth (pre)pass + render pass
18
/// </summary>
19
/// <param name="logger"></param>
20
/// <param name="renderingEngine"></param>
21
internal sealed class GPassService(
×
22
    ILogger<GPassService> logger,
×
23
    ID3D12RenderingEngine renderingEngine,
×
24
    IEngineShaderManager engineShaderManager)
×
25
    : IGPassService,
26
      IDisposable
27
{
28
    private bool _disposedValue;
29

30
    private const Format MAIN_BUFFER_FORMAT = Format.R16G16B16A16_Float;
31
    private const Format DEPTH_BUFFER_FORMAT = Format.D32_Float;
32

33
    private static readonly (Width width, Height height) _defaultSize = (1024, 768);
×
34

35
    private (Width width, Height height) _currentSize = _defaultSize;
×
36

37
    private RenderTexture? _gpasMainBuffer = null;
38
    private DepthBufferTexture? _gpassDepthBuffer = null;
39
    private ID3D12RootSignature? _rootSignature = null;
40
    private ID3D12PipelineState? _pipelineStateObject = null;
41

42
    // TODO NRT!
43
    public RenderTexture MainBuffer => _gpasMainBuffer!;
×
44
    public DepthBufferTexture DepthBuffer => _gpassDepthBuffer!;
×
45

46
#if DEBUG
47
    private readonly ClearValue _clearValue = new()
48
    {
49
        Format = MAIN_BUFFER_FORMAT,
50
        Color = new(0.5f, 0.5f, 0.5f, 1),
51
    };
52
#else
53
    private readonly ClearValue _clearValue = new()
×
54
    {
×
55
        Format = MAIN_BUFFER_FORMAT,
×
56
        Color = new(0.0f, 0.0f, 0.0f, 1),
×
57
    };
×
58
#endif
59

60
    [MemberNotNullWhen(true,
61
        nameof(_gpasMainBuffer),
62
        nameof(_gpassDepthBuffer),
63
        nameof(_rootSignature),
64
        nameof(_pipelineStateObject))]
65
    public bool Initialize()
66
        => CreateBuffers(_defaultSize.width, _defaultSize.height)
×
67
        && CreatePsoAndRootSignature()
×
68
        ;
69

70
    public void SetSize(Width width, Height height)
71
    {
72
        var (currentWidth, currentHeight) = _currentSize;
×
73
        if (width > currentWidth || height > currentHeight)
×
74
        {
75
            var (newWidth, newHeight) = (
×
76
                Width.Max(currentWidth, width),
×
77
                Height.Max(currentHeight, height));
×
78

79
            if (CreateBuffers(newWidth, newHeight))
×
80
            {
81
                _currentSize = (newWidth, newHeight);
×
82
            }
83
            else
84
            {
85
                logger.LogErrorCreatingGPassBuffers(width, height);
×
86
            }
87
        }
88
    }
×
89

90
    public void DepthPrepass(
91
        ID3D12GraphicsCommandList commandList,
92
        in FrameInfo frameInfo)
93
    {
94
        //TODO
95
    }
×
96

97
    int _frame = 0;
98

99
    private readonly struct MandlebrotData
100
    {
101
        public float Width { get; init; }
102
        public float Height { get; init; }
103
        public uint Frame { get; init; }
104
    }
105

106
    public void Render(
107
        ID3D12GraphicsCommandList commandList,
108
        in FrameInfo frameInfo)
109
    {
110
        commandList.SetGraphicsRootSignature(_rootSignature);
×
111
        commandList.SetPipelineState(_pipelineStateObject);
×
112

113
        var mandlebrotData = new MandlebrotData
×
114
        {
×
115
            Width = _currentSize.width.Value,
×
116
            Height = _currentSize.height.Value,
×
117
            Frame = (uint)++_frame,
×
118
        };
×
119
        commandList.SetGraphicsRoot32BitConstants(
×
120
            rootParameterIndex: 0,
×
121
            srcData: mandlebrotData,
×
122
            destOffsetIn32BitValues: 0);
×
123

124
        commandList.IASetPrimitiveTopology(
×
125
            PrimitiveTopology.TriangleList);
×
126

127
        commandList.DrawInstanced(
×
128
            vertexCountPerInstance: 3,
×
129
            instanceCount: 1,
×
130
            startVertexLocation: 0,
×
131
            startInstanceLocation: 0);
×
132
    }
×
133

134
    public void AddTransitionForDepthPrepass(ResourceBarrierGroup barriers)
135
        => barriers.AddTransitionBarrier(
×
136
            resource: _gpassDepthBuffer!.Resource,
×
137
            before: ResourceStates.DepthRead
×
138
                  | ResourceStates.PixelShaderResource
×
139
                  | ResourceStates.NonPixelShaderResource,
×
140
            after: ResourceStates.DepthWrite);
×
141

142
    public void AddTransitionForGPass(ResourceBarrierGroup barriers)
143
        => barriers
×
144
            .AddTransitionBarrier(
×
145
                resource: _gpasMainBuffer!.Resource,
×
146
                before: ResourceStates.PixelShaderResource,
×
147
                after: ResourceStates.RenderTarget)
×
148
            .AddTransitionBarrier(
×
149
                resource: _gpassDepthBuffer!.Resource,
×
150
                before: ResourceStates.DepthWrite,
×
151
                after: ResourceStates.DepthRead
×
152
                     | ResourceStates.PixelShaderResource
×
153
                     | ResourceStates.NonPixelShaderResource);
×
154

155
    public void AddTranstionForPostProcess(ResourceBarrierGroup barriers)
156
        => barriers.AddTransitionBarrier(
×
157
            resource: _gpasMainBuffer!.Resource,
×
158
            before: ResourceStates.RenderTarget,
×
159
            after: ResourceStates.PixelShaderResource);
×
160

161
    public void SetRenderTargetsForDepthPrepass(ID3D12GraphicsCommandList commandList)
162
    {
163
        commandList.ClearDepthStencilView(
×
164
            depthStencilView: _gpassDepthBuffer!.DSV,
×
165
            clearFlags: ClearFlags.Depth | ClearFlags.Stencil,
×
166
            depth: 0.0f,
×
167
            stencil: 0);
×
168
        commandList.OMSetRenderTargets(
×
169
            renderTargetDescriptor: CpuDescriptorHandle.Default,
×
170
            depthStencilDescriptor: _gpassDepthBuffer!.DSV);
×
171
    }
×
172

173
    public void SetRenderTargetsForGPass(ID3D12GraphicsCommandList commandList)
174
    {
175
        var rtv = _gpasMainBuffer!.RTV(0);
×
176
        var dsv = _gpassDepthBuffer!.DSV;
×
177

178
        commandList.ClearRenderTargetView(
×
179
            renderTargetView: rtv,
×
180
            color: _clearValue.Color);
×
181
        commandList.OMSetRenderTargets(
×
182
            renderTargetDescriptor: rtv,
×
183
            depthStencilDescriptor: dsv);
×
184
    }
×
185

186
    [MemberNotNullWhen(true, nameof(_gpasMainBuffer), nameof(_gpassDepthBuffer))]
187
    private bool CreateBuffers(Width width, Height height)
188
    {
189
        _gpasMainBuffer?.Dispose();
×
190
        _gpassDepthBuffer?.Dispose();
×
191

192
        //Create main buffer
193
        _gpasMainBuffer = RenderTexture.CreateComittedResource(
×
194
            renderingEngine: renderingEngine,
×
195
            resourceDescription: new()
×
196
            {
×
197
                Alignment = 0,
×
198
                DepthOrArraySize = 1,
×
199
                Dimension = ResourceDimension.Texture2D,
×
200
                Flags = ResourceFlags.AllowRenderTarget,
×
201
                Format = MAIN_BUFFER_FORMAT,
×
202
                Layout = TextureLayout.Unknown,
×
203
                MipLevels = 0, // automatically calculate mip levels count
×
204
                SampleDescription = new(1, 0),
×
205

×
206
                Height = (uint)height.Value,
×
207
                Width = (uint)width.Value,
×
208
            },
×
209
            initialStates: ResourceStates.PixelShaderResource,
×
210
            clearValue: _clearValue,
×
211
            shaderResourceViewDescription: null);
×
212

213
        //Create depth buffer
214
        _gpassDepthBuffer = DepthBufferTexture.CreateComittedResource(
×
215
            renderingEngine: renderingEngine,
×
216
            resourceDescription: new()
×
217
            {
×
218
                Alignment = 0,
×
219
                DepthOrArraySize = 1,
×
220
                Dimension = ResourceDimension.Texture2D,
×
221
                Flags = ResourceFlags.AllowDepthStencil,
×
222
                Format = DEPTH_BUFFER_FORMAT,
×
223
                Layout = TextureLayout.Unknown,
×
224
                MipLevels = 1,
×
225
                SampleDescription = new(1, 0),
×
226
                Height = (uint)height.Value,
×
227
                Width = (uint)width.Value,
×
228
            },
×
229
            initialStates: ResourceStates.DepthRead
×
230
                         | ResourceStates.PixelShaderResource
×
231
                         | ResourceStates.NonPixelShaderResource,
×
232
            clearValue: new()
×
233
            {
×
234
                Format = DEPTH_BUFFER_FORMAT,
×
235
                DepthStencil = new()
×
236
                {
×
237
                    Depth = 0.0f,
×
238
                    Stencil = 0,
×
239
                },
×
240
            });
×
241

242
        _gpasMainBuffer.Resource.NameObject(
×
243
            "GPass main buffer",
×
244
            logger);
×
245
        _gpassDepthBuffer.Resource.NameObject(
×
246
            "GPass depth buffer",
×
247
            logger);
×
248

249
        return _gpasMainBuffer.Resource is not null
×
250
            && _gpassDepthBuffer.Resource is not null;
×
251
    }
252

253
    [MemberNotNullWhen(true, nameof(_rootSignature), nameof(_pipelineStateObject))]
254
    private bool CreatePsoAndRootSignature()
255
    {
256
        if (_rootSignature is not null)
×
257
        {
258
            throw new InvalidOperationException("Root signature already created!");
×
259
        }
260
        if (_pipelineStateObject is not null)
×
261
        {
262
            throw new InvalidOperationException("Pipeline state object already created!");
×
263
        }
264

265
        RootParameter1[] parameters =
×
266
        [
×
267
            //RootParameter1.ConstantBufferViewRootParameter(
×
268
            //    visibility: ShaderVisibility.Vertex,
×
269
            //    shaderRegister: 0,
×
270
            //    registerSpace: 0,
×
271
            //    flags: RootDescriptorFlags.DataStaticWhileSetAtExecute),
×
272
            RootParameter1.ConstantsRootParameter(
×
273
                numConstants: 3,
×
274
                visibility: ShaderVisibility.Pixel,
×
275
                shaderRegister: 1),
×
276
        ];
×
277

278
        //const RootSignatureFlags ROOT_SIGNATURE_FLAGS =
279
        //    RootSignatureFlags.AllowInputAssemblerInputLayout
280
        //    | RootSignatureFlags.DenyAmplificationShaderRootAccess
281
        //    | RootSignatureFlags.DenyDomainShaderRootAccess
282
        //    | RootSignatureFlags.DenyGeometryShaderRootAccess
283
        //    | RootSignatureFlags.DenyHullShaderRootAccess
284
        //    | RootSignatureFlags.DenyMeshShaderRootAccess
285
        //    ;
286

287
        // This should be an equivalent to the above
288
        //const RootSignatureFlags ROOT_SIGNATURE_FLAGS = RootSignatureHelpers.DenyAll
289
        //    & ~RootSignatureFlags.DenyPixelShaderRootAccess
290
        //    & ~RootSignatureFlags.DenyVertexShaderRootAccess
291
        //    & RootSignatureFlags.AllowInputAssemblerInputLayout
292
        //    ;
293

294
        _rootSignature = renderingEngine.Device.CreateRootSignature(
×
295
            new RootSignatureDescription1(
×
296
                //ROOT_SIGNATURE_FLAGS,
×
297
                RootSignatureExtensions.DenyAll
×
298
                & ~RootSignatureFlags.DenyPixelShaderRootAccess,
×
299
                parameters));
×
300

301
        _rootSignature.NameObject(
×
302
            "GPass root signature",
×
303
            logger);
×
304

305
        //var vertexShader = engineShaderManager.GetShader(ShaderId.TriangleVS);
306
        //var pixelShader = engineShaderManager.GetShader(ShaderId.TrianglePS);
307
        var vertexShader = engineShaderManager.GetShader(ShaderId.FullscreenTriangleVS);
×
308
        var pixelShader = engineShaderManager.GetShader(ShaderId.FillColorPS);
×
309
        var primitiveTopology = PrimitiveTopologyType.Triangle;
×
310
        var renderTagetFormats = new Format[] { MAIN_BUFFER_FORMAT };
×
311
        var depthStencilFormat = DEPTH_BUFFER_FORMAT;
×
312

313
        //        // TEMP - vertex layout from Cube
314
        //        //InputLayout = new InputLayoutDescription
315
        //        //{
316
        //        //    Elements = Cube.VertexLayout(),
317
        //        //}
318

319
        PipelineStateStream stream = new()
×
320
        {
×
321
            RootSignature = new(_rootSignature),
×
322
            VertexShader = new(vertexShader.ShaderBlob.Span),
×
323
            PixelShader = new(pixelShader.ShaderBlob.Span),
×
324
            PrimitiveTopology = new(primitiveTopology),
×
325
            RenderTargetFormats = new(renderTagetFormats),
×
326
            DepthStencilFormat = new(depthStencilFormat),
×
327
            Rasterizer = new(RasterizerDescription.CullNone),
×
328
            DepthStencil = new(DepthStencilDescription.None),
×
329
        };
×
330

331
        _pipelineStateObject = renderingEngine.Device.CreatePipelineState(stream);
×
332

333
        _pipelineStateObject.NameObject(
×
334
            "GPass pipeline state object",
×
335
            logger);
×
336

337
        return true;
×
338
    }
339

340
    [StructLayout(LayoutKind.Sequential)]
341
    private readonly struct PipelineStateStream
342
    {
343
        public required PipelineStateSubObjectTypeRootSignature RootSignature { get; init; }
344
        public required PipelineStateSubObjectTypeVertexShader VertexShader { get; init; }
345
        public required PipelineStateSubObjectTypePixelShader PixelShader { get; init; }
346
        public required PipelineStateSubObjectTypePrimitiveTopology PrimitiveTopology { get; init; }
347
        public required PipelineStateSubObjectTypeRenderTargetFormats RenderTargetFormats { get; init; }
348
        public required PipelineStateSubObjectTypeDepthStencilFormat DepthStencilFormat { get; init; }
349
        public required PipelineStateSubObjectTypeRasterizer Rasterizer { get; init; }
350
        public required PipelineStateSubObjectTypeDepthStencil DepthStencil { get; init; }
351
    }
352

353
    private void Dispose(bool disposing)
354
    {
355
        if (!_disposedValue)
×
356
        {
357
            if (disposing)
×
358
            {
359
                _gpassDepthBuffer?.Dispose();
×
360
                _gpasMainBuffer?.Dispose();
×
361
                _rootSignature?.Dispose();
×
362
                _pipelineStateObject?.Dispose();
×
363
            }
364

365
            _disposedValue = true;
×
366
        }
367
    }
×
368

369
    public void Dispose()
370
    {
371
        // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
372
        Dispose(disposing: true);
×
373
        GC.SuppressFinalize(this);
×
374
    }
×
375
}
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