Hello out there,
I’m currently working at a Postprocessor class for my game. Now the effects are working fine but the graphic card memory is filling up. After around 1 Minute, 80% of the memory is used. It’s seems like the postprocessor isn’t deleting the RenderTarget2D without difficulty from the device.
the code I’m using is the following:
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)
{
RenderTarget2D ReturnImage = DrawTarget;
for (int i = 0; i < CurrentEffect.CurrentTechnique.Passes.Count; i++)
{
ReturnImage = SinglePostprocessCall(graphics, SB, ReturnImage, i);
}
return ReturnImage;
}
private RenderTarget2D SinglePostprocessCall(GraphicsDevice graphics, SpriteBatch SB, RenderTarget2D DrawTarget, int PassPosition)
{
RenderTarget2D ReturnImage = new RenderTarget2D(graphics, DrawTarget.Width, DrawTarget.Height);
if (CurrentEffect.CurrentTechnique.Passes.Count >= PassPosition)
{
graphics.SetRenderTarget(ReturnImage);
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
{
ReturnImage = DrawTarget;
}
return ReturnImage;
}
}
}
The 2 Shaders I’m using to test this looks like this:
DefaultShader:
sampler TextureSampler : register(s0);
float4 Default(float4 position : SV_Position, float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
{
float4 tex = tex2D(TextureSampler, texCoord);
return tex*color;
}
technique DefaultTechnique
{
pass Default
{
PixelShader = compile ps_3_0 Default();
}
}
CurrentEffect:
sampler TextureSampler : register(s0);
float2 MousePosition = { 0.5, 0.5 };
float4 BlackWhite(float4 position : SV_Position, float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
{
float4 tex = tex2D(TextureSampler, texCoord);
tex.gb = tex.r;
return tex*color;
}
float4 RadialBlur(float2 texCoord : TEXCOORD0 ) : COLOR
{
float BlurStart = 1.0f;
float BlurWidth = -0.1;
int nsamples = 10;
texCoord -= MousePosition; float4 c = 0;
for(int i=0; i <nsamples; i++)
{
float scale = BlurStart + BlurWidth*(i/(float) (nsamples-1));
c += tex2D(TextureSampler, texCoord * scale + MousePosition);
}
c /= nsamples;
return c;
}
technique Technique1
{
pass BlackWhite
{
PixelShader = compile ps_3_0 BlackWhite();
}
pass RadialBlur
{
PixelShader = compile ps_3_0 RadialBlur();
}
}
The Draw call in my Game1 class is this:
protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); float Time = (float)gameTime.TotalGameTime.TotalSeconds / 100;
// TODO: Add your drawing code here spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
GraphicsDevice.SetRenderTarget(PostProcessingTarget); WindowManager.Draw(spriteBatch); if (GameSettings.MouseVisible) spriteBatch.Draw(MouseCursor, cursorPos, Color.White);
GraphicsDevice.SetRenderTarget(null);
PostProcessingTarget.Height), Color.White);
PostEffectProcessor.Draw(GraphicsDevice, PostProcessingTarget, spriteBatch);
if (ShowDebugInfo) spriteBatch.DrawString(basic, String.Format("FPS: {1}{0}CPU Load: {2}{0}Active Windows: {3}{0}Postprocessor passes: {4}", Environment.NewLine, Debug.FrameCounter.GetAverageFrames(), Debug.CPULoad.GetCurrentCPULoad(), WindowManager.ActiveScreenNumber(), PostEffectProcessor.Passescount), new Vector2(10, 10), Color.Red); spriteBatch.End(); base.Draw(gameTime); }
If I change the following in my Postprocessor class the memory leak is gone. But now if i use 2 effects the outcome is strange:
private RenderTarget2D SinglePostprocessCall(GraphicsDevice graphics, SpriteBatch SB, RenderTarget2D DrawTarget, int PassPosition) { RenderTarget2D ReturnImage = EmptyTarget; if (CurrentEffect.CurrentTechnique.Passes.Count >= PassPosition) { graphics.SetRenderTarget(ReturnImage); 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 { ReturnImage = DrawTarget; } return ReturnImage; }
Creating a new RenderTarget2D every frame gives the following output on the screen:
(Memory leak)
After some seconds there is a lot of data in the graphic card memory.
if i change the line to use the EmptyTarget the output is this:
(No Memory leak)
the memory usage on the graphic card is around 11% (it doesn’t increase overtime)
Update
If the shader contains only 1 pass the code using the EmptyTarget just work fine.
Any ideas what I’m doing wrong i don’t get it …
Thanks for your help.