Issue with assigning shader values

Mar 12, 2010 at 11:29 PM

Hi,

I am having a lot of trouble assigning values to shaders. For example the following Gaussian Blur shader refuses to work. For some reason when I set shader.SOURCE_TEXTURE_SIZE = Texture.Size; it gives me something different than when I manually enter 1280 into the shader code. This should not happen! I tried to debug it with PIX but I can't figure out what the ASM is doing (it does not appear to be compiled into the same code). Its hard to tell because PIX is not showing me all of the registers and I cant tell where the values come from because I cannot debug with the source code.

 

float4 GaussianBlurH (in float2 in_vTexCoord:TEXCOORD0)	: COLOR0
{
float4 vColor = 0;
float2 vTexCoord = in_vTexCoord;

for (int i = -12; i < 12; i++)
{
float g = 1.0f / sqrt(2.0f * 3.14159 * g_fSigma * g_fSigma);
float fWeight = (g * exp(-(i * i) / (2 * g_fSigma * g_fSigma)));
vTexCoord.x = in_vTexCoord.x + (i / SOURCE_TEXTURE_SIZE.x);
float4 vSample = tex2D(TextureSampler, vTexCoord);
vColor += vSample * fWeight;
}

return vColor;
}

If that wasn't enough the code is not doing what it does usually using XNA alone (it should blur horizontally... it does not with Xen).

 

Coordinator
Mar 13, 2010 at 12:12 AM
Edited Mar 13, 2010 at 10:32 AM

Hi. I can reproduce a bug with this.

 

How are you defining  g_fSigma? If you are setting a default value, then that's quite likely the problem.

There seems to be a bug with pre-shader default input values. If you only assign g_fSigma in the shader, then try and assign SOURCE_TEXTURE_SIZE in code, then it will rerun the preshader code, but use an invalid value for g_fSigma.

If you mark g_fSigma as GLOBAL and assign it that way, then it seems to work. If you manually set g_fSigma as well, then it seems to work.

eg:

this.shader.G_fSigma = 8;
this.shader.SOURCE_TEXTURE_SIZE = new Vector2(1024, 512);

works for me. However not assigning G_fSigma doesn't work.

etc.

Also, note that there is a very efficient blur filter in xen: Xen.Ex.Filters.BlurFilter.

Mar 13, 2010 at 12:45 AM
Edited Mar 13, 2010 at 1:13 AM

Thanks for the help! I cannot get it to work regardless of whether sigma is set from outside. Its strange...

I did not know about the filters. =)

Also, why are the DrawTarget.Begin() and End() menthods internal. After adding the following 2 lines to Begin and End, respectively, they have been very useful to me.

if (state.DrawTarget != this)
                state.DrawTarget = this;

for example if i want to draw a full screen quad to apply various effects and toggle between draw targets it becomes a hassle without Begin and End. However, I may be doing things in a way that is not intended.

 

Also, the constructor for Xen.Ex.Filters.TextureDownsample can be shortened using the following:

        /// <summary>
	/// Construct the texture downsampler
	/// </summary>
	/// <param name="source">Source texture to read</param>
	/// <param name="target">Target texture to write to</param>
        public TextureDownsample(DrawTargetTexture2D source, DrawTargetTexture2D target)
{
DrawTargetTexture2D a = null, b = null;
Create(source, target, ref a, ref b, (int)target.Size.X, (int)target.Size.Y);
}


/// <summary> /// Construct the texture downsampler /// </summary> /// <param name="source">Source texture to read</param> /// <param name="target">Target texture to write to</param> /// <param name="intermediate">Intermediate texture (if null, will be created as required)</param> /// <param name="intermediate2">Second intermediate texture (if null, will be created as required)</param> /// <param name="targetWidth">target width to downsample to</param> /// <param name="targetHeight">target height to downsample to</param> public TextureDownsample(DrawTargetTexture2D source, DrawTargetTexture2D target, ref DrawTargetTexture2D intermediate, ref DrawTargetTexture2D intermediate2, int targetWidth, int targetHeight)
{
Create(source, target, ref intermediate, ref intermediate2, targetWidth, targetHeight);
}


/// <summary> /// Create the texture downsampler /// </summary> /// <param name="source">Source texture to read</param> /// <param name="target">Target texture to write to</param> /// <param name="intermediate">Intermediate texture (if null, will be created as required)</param> /// <param name="intermediate2">Second intermediate texture (if null, will be created as required)</param> /// <param name="targetWidth">target width to downsample to</param> /// <param name="targetHeight">target height to downsample to</param> private void Create(DrawTargetTexture2D source, DrawTargetTexture2D target, ref DrawTargetTexture2D intermediate, ref DrawTargetTexture2D intermediate2, int targetWidth, int targetHeight)
{
constructor code goes here...
}

 

 

 

Coordinator
Mar 13, 2010 at 10:47 AM

I integrated your shader into Tut 09, and it worked fine. Provided Sigma was a positive value. So I'm not entirely sure. It may be a vertex shader issue?

You should not be directly calling Begin/End on the draw target, they are internal because they are only intended to be called internally!. There are a lot of reasons for this, the most significant is switching to and from RenderTargets has very different behavior on the xbox and PC. On the xbox, every time you do this, it destroys the contents of the render target and depth buffer. If you want to draw to the same DrawTarget more than once, simply use Clone(). This will make a duplicate which draws to the same render targets, but can be setup independently.
Beyond that, there is a lot of internal state tracking that happens when you call Draw(), directly calling Begin will bypass this, and potentially screw something up elsewhere.

Basically, you should not ping-pong between render targets, expecting their contents to be preserved. This is hugely slow on the 360, and inefficient on the PC. DrawTargets are setup the way they are to force you to do everything you need to do all at once. :-)

As for your constructor, yes, that makes it easier - however you then have no idea that two new render targets have been created. You could easily leak memory without realising it. By making it explicit, the user has to manage them, and dispose them (if they choose to).

Cheers :-)