Monogame RenderTarget2D 填满显卡内存

Monogame RenderTarget2D filling up graphic card memory

我在尝试在 Monogame 中创建 Post 处理器 class 时遇到问题。

我的显卡内存在几秒钟内就满了,我不明白为什么。

我已经 post在 Monogame 社区论坛中解决了完整的问题。但也许其他人可以帮助我解决问题。

参考 Monogame 社区 post:http://community.monogame.net/t/problem-with-rendertarget2d-fills-up-the-graphic-card-memory/2730/3

我已经在 Monogame 社区论坛上描述了这个问题。

我已经解决了我的问题,现在我的后处理器看起来像这样:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Brick
{
    class Postprocessor
    {
        private Effect CurrentEffect;
        private Effect DefaultEffect;
        private bool Multipass;

        private RenderTarget2D FinalImage;
        private RenderTarget2D EmptyTarget;

        public int Passescount
        {
            get 
            {
                return CurrentEffect.CurrentTechnique.Passes.Count;
            }
        }

        public Postprocessor(Effect EffectToUse, Effect StandardEffect)
        {
            if (!ChangeCurrentEffect(EffectToUse))
                return;
            DefaultEffect = StandardEffect;
            EmptyTarget = new RenderTarget2D(DefaultEffect.GraphicsDevice, GameSettings.WindowWidth, GameSettings.WindowHeight);
        }
        public bool ChangeCurrentEffect(Effect EffectToUse)
        {
            CurrentEffect = EffectToUse;
            if (CurrentEffect.CurrentTechnique.Passes.Count > 1)
                Multipass = true;
            else
                Multipass = false;
            return true;
        }

        private bool CheckIfParameterExist(string Name)
        {
            foreach (EffectParameter parameter in CurrentEffect.Parameters)
            {
                if (parameter.Name == Name)
                    return true;
            }
            return false;
        }

        public void Update(GameTime gametime, Vector2 MousePosition)
        {
            SetParameters((float)gametime.TotalGameTime.TotalSeconds, MousePosition);
        }

        private void SetParameters(float gametime, Vector2 MousePosition)
        {
            if (CheckIfParameterExist("GameTime"))
                CurrentEffect.Parameters["GameTime"].SetValue(gametime);
            if (CheckIfParameterExist("MousePosition"))
                CurrentEffect.Parameters["MousePosition"].SetValue(MousePosition);
        }

        public void Draw(GraphicsDevice graphics, RenderTarget2D Target, SpriteBatch SB)
        {
            if (Multipass)
            {
                FinalImage = MultiCallPostprocess(graphics, SB, Target);
            }
            else
            {
                FinalImage = SinglePostprocessCall(graphics, SB, Target, 0);
            }
            graphics.Clear(Color.Transparent);
            DefaultEffect.CurrentTechnique.Passes[0].Apply();
            SB.Draw(FinalImage, new Rectangle(0, 0, FinalImage.Width, FinalImage.Height), Color.White);
        }

        private RenderTarget2D MultiCallPostprocess(GraphicsDevice graphics, SpriteBatch SB, RenderTarget2D DrawTarget)
        {
            for (int i = 0; i < CurrentEffect.CurrentTechnique.Passes.Count; i++)
            {
                DrawTarget = SinglePostprocessCall(graphics, SB, DrawTarget, i);
            }
            return DrawTarget;
        }

        private RenderTarget2D SinglePostprocessCall(GraphicsDevice graphics, SpriteBatch SB, RenderTarget2D DrawTarget, int PassPosition)
        {
            EmptyTarget.Dispose();
            EmptyTarget = new RenderTarget2D(graphics, DrawTarget.Width, DrawTarget.Height);
            if (CurrentEffect.CurrentTechnique.Passes.Count >= PassPosition)
            {
                graphics.SetRenderTarget(EmptyTarget);
                graphics.Clear(Color.Transparent);
                CurrentEffect.CurrentTechnique.Passes[PassPosition].Apply();
                SB.Draw(DrawTarget, new Rectangle(0, 0, DrawTarget.Width, DrawTarget.Height), Color.White);
                graphics.SetRenderTarget(null);
            }
            else
            {
                EmptyTarget = DrawTarget;
            }
            return CloneRenderTarget(EmptyTarget);
        }
        private RenderTarget2D CloneRenderTarget(RenderTarget2D target)
        {
            var clone = new RenderTarget2D(target.GraphicsDevice, target.Width,
                target.Height, target.LevelCount > 1, target.Format,
                target.DepthStencilFormat, target.MultiSampleCount,
                target.RenderTargetUsage);

            for (int i = 0; i < target.LevelCount; i++)
            {
                double rawMipWidth = target.Width / Math.Pow(2, i);
                double rawMipHeight = target.Height / Math.Pow(2, i);

                // make sure that mipmap dimensions are always > 0.
                int mipWidth = (rawMipWidth < 1) ? 1 : (int)rawMipWidth;
                int mipHeight = (rawMipHeight < 1) ? 1 : (int)rawMipHeight;

                var mipData = new Color[mipWidth * mipHeight];
                target.GetData(i, null, mipData, 0, mipData.Length);
                clone.SetData(i, null, mipData, 0, mipData.Length);
            }

            return clone;
        }

    }
}

重要的功能是 "CloneRenderTarget" 似乎从没有此功能的旧 RenderTarget2D 创建一个新的 RenderTarget2D 它只是创建一个指针,因此如果您处置副本,原始副本也会被处置。