Exemple #1
0
        public void BeginRenderPass(IGameContext gameContext, IRenderContext renderContext, IRenderPass previousPass,
                                    RenderTarget2D postProcessingSource)
        {
            _renderTarget = _renderTargetBackBufferUtilities.UpdateRenderTarget(_renderTarget, gameContext);

            // Blit to the capture target.
            _graphicsBlit.Blit(renderContext, postProcessingSource, _renderTarget);

            // Blit to the output.
            _graphicsBlit.Blit(renderContext, postProcessingSource);
        }
Exemple #2
0
        public override void Render(IGameContext gameContext, IRenderContext renderContext)
        {
            base.Render(gameContext, renderContext);

            if (renderContext.IsCurrentRenderPass<I2DDirectRenderPass>())
            {
                if (_analyzerEntity.TopLeftNormalized != null && _analyzerEntity.TopRightNormalized != null &&
                    _analyzerEntity.BottomLeftNormalized != null && _analyzerEntity.BottomRightNormalized != null)
                {
                    _cachedTopLeft = _analyzerEntity.TopLeftNormalized;
                    _cachedTopRight = _analyzerEntity.TopRightNormalized;
                    _cachedBottomLeft = _analyzerEntity.BottomLeftNormalized;
                    _cachedBottomRight = _analyzerEntity.BottomRightNormalized;
                }

                if (_cachedTopLeft != null && _cachedTopRight != null &&
                    _cachedBottomLeft != null && _cachedBottomRight != null)
                { 
                    _warpFromPolygonEffect.Effect.Parameters["TopLeft"].SetValue(_cachedTopLeft.Value);
                    _warpFromPolygonEffect.Effect.Parameters["TopRight"].SetValue(_cachedTopRight.Value);
                    _warpFromPolygonEffect.Effect.Parameters["BottomLeft"].SetValue(_cachedBottomLeft.Value);
                    _warpFromPolygonEffect.Effect.Parameters["BottomRight"].SetValue(_cachedBottomRight.Value);
                    _warpFromPolygonEffect.Effect.Parameters["Alpha"].SetValue(_alpha);

                    _graphicsBlit.Blit(
                        renderContext,
                        _webcamEntity.VideoCaptureFrame,
                        null,
                        _warpFromPolygonEffect.Effect,
                        BlendState.AlphaBlend);
                }
            }
        }
        public void BeginRenderPass(IGameContext gameContext, IRenderContext renderContext, IRenderPass previousPass, RenderTarget2D postProcessingSource)
        {
            var effect = GetEffect();

            if (effect != null)
            {
                _graphicsBlit.Blit(renderContext, postProcessingSource, null, effect);
            }
        }
        public void BeginRenderPass(IGameContext gameContext, IRenderContext renderContext, IRenderPass previousPass, RenderTarget2D postProcessingSource)
        {
            if (!_invertEffect.IsReady)
            {
                return;
            }

            _graphicsBlit.Blit(renderContext, postProcessingSource, null, _invertEffect.Asset.Effect);
        }
Exemple #5
0
        public void BeginRenderPass(IGameContext gameContext, IRenderContext renderContext, IRenderPass previousPass,
                                    RenderTarget2D postProcessingSource)
        {
            if (RenderPipelineStateAvailable != null)
            {
                RenderPipelineStateAvailable(postProcessingSource);
            }

            // Blit to the output.
            _graphicsBlit.Blit(renderContext, postProcessingSource);
        }
        public void BeginRenderPass(IGameContext gameContext, IRenderContext renderContext, IRenderPass previousPass, RenderTarget2D postProcessingSource)
        {
            // TODO Make iterations work.

            _blurEffect.NativeEffect.Parameters["PixelWidth"].SetValue(1f / postProcessingSource.Width);
            _blurEffect.NativeEffect.Parameters["PixelHeight"].SetValue(1f / postProcessingSource.Height);
            //_blurEffect.CurrentTechnique.Passes[0].Apply();

            // Parameters will get applied when blitting occurs.

            _graphicsBlit.Blit(renderContext, postProcessingSource, null, _blurEffect);
        }
        public void WriteThumbnailIfNecessary(IGameContext gameContext, IRenderContext renderContext)
        {
            var path = _projectManager?.Project?.ProjectPath;

            if (path == null || !path.Exists)
            {
                return;
            }

            var editorPath = Path.Combine(Path.Combine(path.FullName, "Build", "Editor"));

            Directory.CreateDirectory(editorPath);

            var thumbnailFile = new FileInfo(Path.Combine(editorPath, "Thumbnail.png"));

            var startTime = _loadedGame.GetPlayingStartTime();

            if (startTime != null && (DateTime.UtcNow - startTime.Value).TotalMinutes >= 1)
            {
                if (!thumbnailFile.Exists || thumbnailFile.LastWriteTimeUtc < DateTime.UtcNow.AddHours(-4))
                {
                    _consoleHandle.LogInfo("Sampling current game screen as thumbnail for project...");

                    var srt = _loadedGame.GetCurrentGameRenderTarget();
                    var rt  = new RenderTarget2D(renderContext.GraphicsDevice, 128, 128, false, SurfaceFormat.Color, DepthFormat.None);
                    _graphicsBlit.Blit(renderContext, srt, rt);

                    try
                    {
                        using (var writer = new FileStream(thumbnailFile.FullName, FileMode.Create, FileAccess.Write))
                        {
                            rt.SaveAsPng(writer, 128, 128);
                        }
                    }
                    catch
                    {
                        thumbnailFile.Delete();
                        throw;
                    }

                    rt.Dispose();
                }
            }
        }
Exemple #8
0
        public void Render(IGameContext gameContext, IRenderContext renderContext)
        {
            try
            {
                renderContext.Render(gameContext);

                // NOTE: We MUST clear the depth buffer because OpenGL will not do it for us.
                renderContext.GraphicsDevice.Clear(
                    ClearOptions.DepthBuffer,
                    Microsoft.Xna.Framework.Color.Transparent,
                    renderContext.GraphicsDevice.Viewport.MaxDepth,
                    0);

                _primary   = _renderTargetBackBufferUtilities.UpdateRenderTarget(_primary, gameContext);
                _secondary = _renderTargetBackBufferUtilities.UpdateRenderTarget(_secondary, gameContext);

                if (_primary == null || _secondary == null)
                {
                    // These are null if the window is minimized or invalid, in which case we don't
                    // render anything anyway.
                    return;
                }

                var         standardRenderPasses       = _standardRenderPasses.ToArray();
                var         postProcessingRenderPasses = _postProcessingRenderPasses.ToArray();
                IRenderPass previousPass = null;
                IRenderPass nextPass     = null;

                var entities = gameContext.World.GetEntitiesForWorld(gameContext.Hierarchy).ToArray();

#if !DISABLE_PIPELINE_TARGETS
                renderContext.PushRenderTarget(_primary);
#endif

                for (var i = 0; i < standardRenderPasses.Length; i++)
                {
                    var pass = standardRenderPasses[i];
                    using (_profiler.Measure("r-" + pass.GetType().Name))
                    {
                        _isFirstRenderPass = previousPass == null;
                        _renderPass        = pass;
                        SetupRenderPassViewport(renderContext, pass);
                        pass.BeginRenderPass(gameContext, renderContext, previousPass, null);
                        previousPass = pass;
                        RenderPass(gameContext, renderContext, pass, entities);
                        if (i < standardRenderPasses.Length - 1)
                        {
                            nextPass = standardRenderPasses[i + 1];
                        }
                        else if (_transientStandardRenderPasses.Count > 0)
                        {
                            nextPass = _transientStandardRenderPasses[0];
                        }
                        else if (postProcessingRenderPasses.Length > 0)
                        {
                            nextPass = postProcessingRenderPasses[0];
                        }
                        else if (_transientPostProcessingRenderPasses.Count > 0)
                        {
                            nextPass = _transientPostProcessingRenderPasses[0];
                        }
                        else
                        {
                            nextPass = null;
                        }
                        pass.EndRenderPass(gameContext, renderContext, nextPass);
                    }
                }

                var loop = 100;
                while (_transientStandardRenderPasses.Count > 0 && loop-- >= 0)
                {
                    var transientStandardRenderPasses = _transientStandardRenderPasses.ToArray();
                    _transientStandardRenderPasses.Clear();

                    for (var i = 0; i < transientStandardRenderPasses.Length; i++)
                    {
                        var pass = transientStandardRenderPasses[i];
                        using (_profiler.Measure("r-" + pass.GetType().Name))
                        {
                            _isFirstRenderPass = previousPass == null;
                            _renderPass        = pass;
                            SetupRenderPassViewport(renderContext, pass);
                            pass.BeginRenderPass(gameContext, renderContext, previousPass, null);
                            previousPass = pass;
                            RenderPass(gameContext, renderContext, pass, entities);
                            if (i < transientStandardRenderPasses.Length - 1)
                            {
                                nextPass = transientStandardRenderPasses[i + 1];
                            }
                            else if (_transientStandardRenderPasses.Count > 0)
                            {
                                nextPass = _transientStandardRenderPasses[0];
                            }
                            else if (postProcessingRenderPasses.Length > 0)
                            {
                                nextPass = postProcessingRenderPasses[0];
                            }
                            else if (_transientPostProcessingRenderPasses.Count > 0)
                            {
                                nextPass = _transientPostProcessingRenderPasses[0];
                            }
                            else
                            {
                                nextPass = null;
                            }
                            pass.EndRenderPass(gameContext, renderContext, nextPass);
                        }
                    }
                }
                if (loop < 0)
                {
                    throw new InvalidOperationException(
                              "Exceeded the number of AppendTransientRenderPass iterations (100).  Ensure you " +
                              "are not unconditionally calling AppendTransientRenderPass within another render pass.");
                }

#if !DISABLE_PIPELINE_TARGETS
                renderContext.PopRenderTarget();
#endif

                if (postProcessingRenderPasses.Length == 0 && _transientPostProcessingRenderPasses.Count == 0)
                {
                    // Blit the primary render target to the backbuffer and return.
#if !DISABLE_PIPELINE_TARGETS
                    _graphicsBlit.Blit(renderContext, _primary);
#endif
                    return;
                }

                var currentSource = _primary;
                var currentDest   = _secondary;

#if !DISABLE_PIPELINE_TARGETS
                renderContext.PushRenderTarget(currentDest);
#endif

                for (var i = 0; i < postProcessingRenderPasses.Length; i++)
                {
                    var pass = postProcessingRenderPasses[i];
                    using (_profiler.Measure("r-" + pass.GetType().Name))
                    {
                        _isFirstRenderPass = previousPass == null;
                        _renderPass        = pass;
                        pass.BeginRenderPass(gameContext, renderContext, previousPass, currentSource);
                        previousPass = pass;
                        if (i < postProcessingRenderPasses.Length - 1)
                        {
                            nextPass = postProcessingRenderPasses[i + 1];
                        }
                        else if (_transientPostProcessingRenderPasses.Count > 0)
                        {
                            nextPass = _transientPostProcessingRenderPasses[0];
                        }
                        else
                        {
                            nextPass = null;
                        }
                        pass.EndRenderPass(gameContext, renderContext, nextPass);

                        var temp = currentSource;
                        currentSource = currentDest;
                        currentDest   = temp;

#if !DISABLE_PIPELINE_TARGETS
                        renderContext.PopRenderTarget();
                        renderContext.PushRenderTarget(currentDest);
#endif

                        // NOTE: This does not clear the new destination render target; it is expected that
                        // post-processing effects will fully overwrite the destination.
                    }
                }

                loop = 100;
                while (_transientPostProcessingRenderPasses.Count > 0 && loop-- >= 0)
                {
                    var transientPostProcessingRenderPasses = _transientPostProcessingRenderPasses.ToArray();
                    _transientPostProcessingRenderPasses.Clear();

                    for (var i = 0; i < transientPostProcessingRenderPasses.Length; i++)
                    {
                        var pass = transientPostProcessingRenderPasses[i];
                        using (_profiler.Measure("r-" + pass.GetType().Name))
                        {
                            _isFirstRenderPass = previousPass == null;
                            _renderPass        = pass;
                            pass.BeginRenderPass(gameContext, renderContext, previousPass, currentSource);
                            previousPass = pass;
                            if (i < transientPostProcessingRenderPasses.Length - 1)
                            {
                                nextPass = transientPostProcessingRenderPasses[i + 1];
                            }
                            else if (_transientPostProcessingRenderPasses.Count > 0)
                            {
                                nextPass = _transientPostProcessingRenderPasses[0];
                            }
                            else
                            {
                                nextPass = null;
                            }
                            pass.EndRenderPass(gameContext, renderContext, nextPass);

                            var temp = currentSource;
                            currentSource = currentDest;
                            currentDest   = temp;

#if !DISABLE_PIPELINE_TARGETS
                            renderContext.PopRenderTarget();
                            renderContext.PushRenderTarget(currentDest);
#endif

                            // NOTE: This does not clear the new destination render target; it is expected that
                            // post-processing effects will fully overwrite the destination.
                        }
                    }
                }
                if (loop < 0)
                {
                    throw new InvalidOperationException(
                              "Exceeded the number of AppendTransientRenderPass iterations (100).  Ensure you " +
                              "are not unconditionally calling AppendTransientRenderPass within another render pass.");
                }

#if !DISABLE_PIPELINE_TARGETS
                renderContext.PopRenderTarget();

                _graphicsBlit.Blit(renderContext, currentSource);
#endif
            }
            finally
            {
                _renderPass        = null;
                _isFirstRenderPass = false;
            }
        }
Exemple #9
0
 public void BeginRenderPass(IGameContext gameContext, IRenderContext renderContext, IRenderPass previousPass, RenderTarget2D postProcessingSource)
 {
     _graphicsBlit.Blit(renderContext, postProcessingSource, null, _effect);
 }
Exemple #10
0
        public void BeginRenderPass(
            IGameContext gameContext,
            IRenderContext renderContext,
            IRenderPass previousPass,
            RenderTarget2D postProcessingSource)
        {
            _colorRenderTarget         = _renderTargetBackBufferUtilities.UpdateCustomRenderTarget(_colorRenderTarget, gameContext, SurfaceFormat.Color, DepthFormat.Depth24, null);
            _normalRenderTarget        = _renderTargetBackBufferUtilities.UpdateCustomRenderTarget(_normalRenderTarget, gameContext, SurfaceFormat.Color, DepthFormat.None, null);
            _depthRenderTarget         = _renderTargetBackBufferUtilities.UpdateCustomRenderTarget(_depthRenderTarget, gameContext, SurfaceFormat.Single, DepthFormat.None, null);
            _specularRenderTarget      = _renderTargetBackBufferUtilities.UpdateCustomRenderTarget(_specularRenderTarget, gameContext, SurfaceFormat.Color, DepthFormat.None, null);
            _diffuseLightRenderTarget  = _renderTargetBackBufferUtilities.UpdateCustomRenderTarget(_diffuseLightRenderTarget, gameContext, null, DepthFormat.None, null);
            _specularLightRenderTarget = _renderTargetBackBufferUtilities.UpdateCustomRenderTarget(_specularLightRenderTarget, gameContext, null, DepthFormat.None, null);

            if (_rasterizerStateCullNone == null)
            {
                _rasterizerStateCullNone                      = new RasterizerState();
                _rasterizerStateCullNone.CullMode             = CullMode.None;
                _rasterizerStateCullNone.FillMode             = FillMode.Solid;
                _rasterizerStateCullNone.DepthBias            = 0;
                _rasterizerStateCullNone.MultiSampleAntiAlias = true;
                _rasterizerStateCullNone.ScissorTestEnable    = false;
                _rasterizerStateCullNone.SlopeScaleDepthBias  = 0;
                _rasterizerStateCullNone.DepthClipEnable      = true;
            }

            if (_rasterizerStateCullClockwiseFace == null)
            {
                _rasterizerStateCullClockwiseFace                      = new RasterizerState();
                _rasterizerStateCullClockwiseFace.CullMode             = CullMode.CullClockwiseFace;
                _rasterizerStateCullClockwiseFace.FillMode             = FillMode.Solid;
                _rasterizerStateCullClockwiseFace.DepthBias            = 0;
                _rasterizerStateCullClockwiseFace.MultiSampleAntiAlias = true;
                _rasterizerStateCullClockwiseFace.ScissorTestEnable    = false;
                _rasterizerStateCullClockwiseFace.SlopeScaleDepthBias  = 0;
                _rasterizerStateCullClockwiseFace.DepthClipEnable      = true;
            }

            if (_rasterizerStateCullCounterClockwiseFace == null)
            {
                _rasterizerStateCullCounterClockwiseFace                      = new RasterizerState();
                _rasterizerStateCullCounterClockwiseFace.CullMode             = CullMode.CullCounterClockwiseFace;
                _rasterizerStateCullCounterClockwiseFace.FillMode             = FillMode.Solid;
                _rasterizerStateCullCounterClockwiseFace.DepthBias            = 0;
                _rasterizerStateCullCounterClockwiseFace.MultiSampleAntiAlias = true;
                _rasterizerStateCullCounterClockwiseFace.ScissorTestEnable    = false;
                _rasterizerStateCullCounterClockwiseFace.SlopeScaleDepthBias  = 0;
                _rasterizerStateCullCounterClockwiseFace.DepthClipEnable      = true;
            }

            if (_depthStencilState == null)
            {
                _depthStencilState = DepthStencilState.Default;
            }

            if (_lightDepthStencilState == null)
            {
                _lightDepthStencilState = DepthStencilState.None;
            }

            if (_blendState == null)
            {
                _blendState = BlendState.Opaque;
            }

            if (_lightBlendState == null)
            {
                _lightBlendState = BlendState.AlphaBlend;
            }

            renderContext.PushRenderTarget(
                _colorRenderTarget,
                _normalRenderTarget,
                _depthRenderTarget,
                _specularRenderTarget);

            if (ClearDepthBuffer || ClearTarget)
            {
                var target = ClearDepthBuffer ? ClearOptions.DepthBuffer : ClearOptions.Target;
                if (ClearDepthBuffer && ClearTarget)
                {
                    target = ClearOptions.DepthBuffer | ClearOptions.Target;
                }
                renderContext.GraphicsDevice.Clear(
                    target,
                    Microsoft.Xna.Framework.Color.Transparent,
                    renderContext.GraphicsDevice.Viewport.MaxDepth,
                    0);
            }

            // Clear the geometry buffer before moving into main rendering.
            _graphicsBlit.Blit(
                renderContext,
                null,
                null,
                _gbufferClearEffect.Effect);

            _previousDepthStencilState = renderContext.GraphicsDevice.DepthStencilState;
            _previousRasterizerState   = renderContext.GraphicsDevice.RasterizerState;
            _previousBlendState        = renderContext.GraphicsDevice.BlendState;

            renderContext.GraphicsDevice.DepthStencilState = _depthStencilState;
            renderContext.GraphicsDevice.RasterizerState   = _rasterizerStateCullCounterClockwiseFace;
            renderContext.GraphicsDevice.BlendState        = _blendState;
        }
Exemple #11
0
            public RenderPipelineWorld(
                IAssetManager assetManager,
                I2DRenderUtilities renderUtilities,
                IGraphicsFactory graphicsFactory,
                IAssert assert,
                ITestAttachment testAttachment,
                IRenderTargetBackBufferUtilities renderTargetBackBufferUtilities,
                IGraphicsBlit graphicsBlit)
            {
                _renderUtilities                 = renderUtilities;
                _assert                          = assert;
                _testAttachment                  = testAttachment;
                _texture                         = assetManager.Get <TextureAsset>("texture.Player");
                _invertPostProcess               = graphicsFactory.CreateInvertPostProcessingRenderPass();
                _blurPostProcess                 = graphicsFactory.CreateBlurPostProcessingRenderPass();
                _customPostProcess               = graphicsFactory.CreateCustomPostProcessingRenderPass("effect.MakeRed");
                _captureInlinePostProcess        = graphicsFactory.CreateCaptureInlinePostProcessingRenderPass();
                _renderTargetBackBufferUtilities = renderTargetBackBufferUtilities;
                _graphicsBlit                    = graphicsBlit;
                _captureInlinePostProcess.RenderPipelineStateAvailable = (gameContext, renderContext, previousPass, d) =>
                {
                    if (!_isValidRun)
                    {
                        return;
                    }

                    _renderTarget = _renderTargetBackBufferUtilities.UpdateCustomRenderTarget(_renderTarget, renderContext, SurfaceFormat.Color, DepthFormat.None, 1);

                    // Blit to the capture target.
                    _graphicsBlit.Blit(renderContext, d, _renderTarget);

#if MANUAL_TEST
#elif RECORDING
                    using (var writer = new StreamWriter("output" + _frame + ".png"))
                    {
                        _renderTarget.SaveAsPng(writer.BaseStream, Width, Height);
                    }
#else
                    var baseStream =
                        typeof(RenderPipelineWorld).Assembly.GetManifestResourceStream(
                            "Protogame.Tests.Expected.RenderPipeline.output" + _frame + ".png");
                    _assert.NotNull(baseStream);
                    var memoryStream = new MemoryStream();
                    _renderTarget.SaveAsPng(memoryStream, Width, Height);
                    // ReSharper disable once AssignNullToNotNullAttribute
                    var expected = new Bitmap(baseStream);
                    var actual   = new Bitmap(memoryStream);

                    _assert.Equal(expected.Height, actual.Height);
                    _assert.Equal(expected.Width, actual.Width);
                    var totalPixelValues     = 0L;
                    var incorrectPixelValues = 0L;
                    for (var x = 0; x < expected.Width; x++)
                    {
                        for (var y = 0; y < expected.Height; y++)
                        {
                            var expectedPixel = expected.GetPixel(x, y);
                            var actualPixel   = actual.GetPixel(x, y);

                            totalPixelValues += 255 * 4;

                            if (expectedPixel != actualPixel)
                            {
                                var diffA = System.Math.Abs((int)actualPixel.A - (int)expectedPixel.A);
                                var diffR = System.Math.Abs((int)actualPixel.R - (int)expectedPixel.R);
                                var diffG = System.Math.Abs((int)actualPixel.G - (int)expectedPixel.G);
                                var diffB = System.Math.Abs((int)actualPixel.B - (int)expectedPixel.B);

                                incorrectPixelValues += (diffA + diffR + diffG + diffB);
                            }
                        }
                    }

                    var percentage = (100 - ((incorrectPixelValues / (double)totalPixelValues) * 100f));

                    var combination = _combinations[_frame % _combinations.Count];
                    _testAttachment.Attach("name-" + combination.Id, combination.Name);
                    _testAttachment.Attach("expected-" + combination.Id, baseStream);
                    _testAttachment.Attach("actual-" + combination.Id, memoryStream);
                    _testAttachment.Attach("threshold-" + combination.Id, 99.9);
                    _testAttachment.Attach("measured-" + combination.Id, percentage);

                    if (percentage <= 99.9f)
                    {
                        combination.FailureMessage = "The actual rendered image did not match the expected image close enough (99.9%).";
                    }

                    //memoryStream.Dispose();
                    //baseStream.Dispose();
#endif

#if MANUAL_TEST
                    _manualTest++;
                    if (_manualTest % 60 == 0)
                    {
                        _frame++;
                    }
#else
                    _frame++;
#endif
                };

                this.Entities = new List <IEntity>();
            }
        public void Render(IGameContext gameContext, IRenderContext renderContext)
        {
            try
            {
                renderContext.Render(gameContext);

                _primary   = _renderTargetBackBufferUtilities.UpdateRenderTarget(_primary, gameContext);
                _secondary = _renderTargetBackBufferUtilities.UpdateRenderTarget(_secondary, gameContext);

                var standardRenderPasses       = _standardRenderPasses.ToArray();
                var postProcessingRenderPasses = _postProcessingRenderPasses.ToArray();
                //IRenderPass[] transientStandardRenderPasses;
                //IRenderPass[] transientPostProcessingRenderPasses;
                IRenderPass previousPass = null;
                IRenderPass nextPass     = null;

                var entities = gameContext.World.Entities.ToArray();

#if !DISABLE_PIPELINE_TARGETS
                renderContext.PushRenderTarget(_primary);
#endif

                for (var i = 0; i < standardRenderPasses.Length; i++)
                {
                    var pass = standardRenderPasses[i];
                    _isFirstRenderPass = previousPass == null;
                    _renderPass        = pass;
                    pass.BeginRenderPass(gameContext, renderContext, previousPass, null);
                    previousPass = pass;
                    RenderPass(gameContext, renderContext, entities);
                    if (i < standardRenderPasses.Length - 1)
                    {
                        nextPass = standardRenderPasses[i + 1];
                    }
                    else if (_transientStandardRenderPasses.Count > 0)
                    {
                        nextPass = _transientStandardRenderPasses[0];
                    }
                    else if (postProcessingRenderPasses.Length > 0)
                    {
                        nextPass = postProcessingRenderPasses[0];
                    }
                    else if (_transientPostProcessingRenderPasses.Count > 0)
                    {
                        nextPass = _transientPostProcessingRenderPasses[0];
                    }
                    else
                    {
                        nextPass = null;
                    }
                    pass.EndRenderPass(gameContext, renderContext, nextPass);
                }

                var loop = 100;
                while (_transientStandardRenderPasses.Count > 0 && loop-- >= 0)
                {
                    var transientStandardRenderPasses = _transientStandardRenderPasses.ToArray();
                    _transientStandardRenderPasses.Clear();

                    for (var i = 0; i < transientStandardRenderPasses.Length; i++)
                    {
                        var pass = transientStandardRenderPasses[i];
                        _isFirstRenderPass = previousPass == null;
                        _renderPass        = pass;
                        pass.BeginRenderPass(gameContext, renderContext, previousPass, null);
                        previousPass = pass;
                        RenderPass(gameContext, renderContext, entities);
                        if (i < transientStandardRenderPasses.Length - 1)
                        {
                            nextPass = transientStandardRenderPasses[i + 1];
                        }
                        else if (_transientStandardRenderPasses.Count > 0)
                        {
                            nextPass = _transientStandardRenderPasses[0];
                        }
                        else if (postProcessingRenderPasses.Length > 0)
                        {
                            nextPass = postProcessingRenderPasses[0];
                        }
                        else if (_transientPostProcessingRenderPasses.Count > 0)
                        {
                            nextPass = _transientPostProcessingRenderPasses[0];
                        }
                        else
                        {
                            nextPass = null;
                        }
                        pass.EndRenderPass(gameContext, renderContext, nextPass);
                    }
                }
                if (loop < 0)
                {
                    throw new InvalidOperationException(
                              "Exceeded the number of AppendTransientRenderPass iterations (100).  Ensure you " +
                              "are not unconditionally calling AppendTransientRenderPass within another render pass.");
                }

#if !DISABLE_PIPELINE_TARGETS
                renderContext.PopRenderTarget();
#endif

                if (postProcessingRenderPasses.Length == 0 && _transientPostProcessingRenderPasses.Count == 0)
                {
                    // Blit the primary render target to the backbuffer and return.
#if !DISABLE_PIPELINE_TARGETS
                    _graphicsBlit.Blit(renderContext, _primary);
#endif
                    return;
                }

                var currentSource = _primary;
                var currentDest   = _secondary;

#if !DISABLE_PIPELINE_TARGETS
                renderContext.PushRenderTarget(currentDest);
#endif

                for (var i = 0; i < postProcessingRenderPasses.Length; i++)
                {
                    var pass = postProcessingRenderPasses[i];
                    _isFirstRenderPass = previousPass == null;
                    _renderPass        = pass;
                    pass.BeginRenderPass(gameContext, renderContext, previousPass, currentSource);
                    previousPass = pass;
                    if (i < postProcessingRenderPasses.Length - 1)
                    {
                        nextPass = postProcessingRenderPasses[i + 1];
                    }
                    else if (_transientPostProcessingRenderPasses.Count > 0)
                    {
                        nextPass = _transientPostProcessingRenderPasses[0];
                    }
                    else
                    {
                        nextPass = null;
                    }
                    pass.EndRenderPass(gameContext, renderContext, nextPass);

                    var temp = currentSource;
                    currentSource = currentDest;
                    currentDest   = temp;

#if !DISABLE_PIPELINE_TARGETS
                    renderContext.PopRenderTarget();
                    renderContext.PushRenderTarget(currentDest);
#endif

                    // NOTE: This does not clear the new destination render target; it is expected that
                    // post-processing effects will fully overwrite the destination.
                }

                loop = 100;
                while (_transientPostProcessingRenderPasses.Count > 0 && loop-- >= 0)
                {
                    var transientPostProcessingRenderPasses = _transientPostProcessingRenderPasses.ToArray();
                    _transientPostProcessingRenderPasses.Clear();

                    for (var i = 0; i < transientPostProcessingRenderPasses.Length; i++)
                    {
                        var pass = transientPostProcessingRenderPasses[i];
                        _isFirstRenderPass = previousPass == null;
                        _renderPass        = pass;
                        pass.BeginRenderPass(gameContext, renderContext, previousPass, currentSource);
                        previousPass = pass;
                        if (i < transientPostProcessingRenderPasses.Length - 1)
                        {
                            nextPass = transientPostProcessingRenderPasses[i + 1];
                        }
                        else if (_transientPostProcessingRenderPasses.Count > 0)
                        {
                            nextPass = _transientPostProcessingRenderPasses[0];
                        }
                        else
                        {
                            nextPass = null;
                        }
                        pass.EndRenderPass(gameContext, renderContext, nextPass);

                        var temp = currentSource;
                        currentSource = currentDest;
                        currentDest   = temp;

#if !DISABLE_PIPELINE_TARGETS
                        renderContext.PopRenderTarget();
                        renderContext.PushRenderTarget(currentDest);
#endif

                        // NOTE: This does not clear the new destination render target; it is expected that
                        // post-processing effects will fully overwrite the destination.
                    }
                }
                if (loop < 0)
                {
                    throw new InvalidOperationException(
                              "Exceeded the number of AppendTransientRenderPass iterations (100).  Ensure you " +
                              "are not unconditionally calling AppendTransientRenderPass within another render pass.");
                }

#if !DISABLE_PIPELINE_TARGETS
                renderContext.PopRenderTarget();

                _graphicsBlit.Blit(renderContext, currentSource);
#endif
            }
            finally
            {
                _renderPass        = null;
                _isFirstRenderPass = false;
            }
        }