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

DemoBytom / DemoEngine / 23923671492

02 Apr 2026 09:44PM UTC coverage: 30.519% (-0.03%) from 30.548%
23923671492

push

coveralls.net

DemoBytom
Drawing Julia Set fractal

1276 of 4181 relevant lines covered (30.52%)

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
    private readonly struct FractalData
98
    {
99
        public float Width { get; init; }
100
        public float Height { get; init; }
101
        public uint Frame { get; init; }
102
    }
103

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

111
        var fractalData = new FractalData
×
112
        {
×
113
            Width = _currentSize.width.Value,
×
114
            Height = _currentSize.height.Value,
×
115
            Frame = frameInfo.UPS_Frame,
×
116
        };
×
117
        commandList.SetGraphicsRoot32BitConstants(
×
118
            rootParameterIndex: 0,
×
119
            srcData: fractalData,
×
120
            destOffsetIn32BitValues: 0);
×
121

122
        commandList.IASetPrimitiveTopology(
×
123
            PrimitiveTopology.TriangleList);
×
124

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

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

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

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

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

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

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

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

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

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

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

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

247
        return _gpasMainBuffer.Resource is not null
×
248
            && _gpassDepthBuffer.Resource is not null;
×
249
    }
250

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

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

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

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

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

299
        _rootSignature.NameObject(
×
300
            "GPass root signature",
×
301
            logger);
×
302

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

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

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

329
        _pipelineStateObject = renderingEngine.Device.CreatePipelineState(stream);
×
330

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

335
        return true;
×
336
    }
337

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

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

363
            _disposedValue = true;
×
364
        }
365
    }
×
366

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