Sign in to follow this  
StarBP

Reducing State Changes when Calling Direct3D Effects

Recommended Posts

I was working on a system to use a genetic algorithm to compress images using the GPU, and I am proud to announce that IT IS FINISHED!!! (well, at least the alpha version is; there is still no file format for it) It gets around 1,200 generations per second on a GeForce 8600 GT. The only problem is that it is severely limited by the state changes which occur during every pass of the sum reduction algorithm at the Effect.BeginPass(0) and Effect.EndPass() calls. More than half of these state changes are blatantly unnecessary (PIX says that all texture samplers, even those that aren't even used in the passes involved, are being set as part of each BeginPass call). The source can be found at http://tinyurl.com/mvothv (There is a binary in the bin/Release folder). It is released under the General Public License, simply meaning that all applications utilizing any part of this source code must reveal their source code, as well. I may change this licensing restriction at a later date, but the GPL version will always be the only free version. This program is based on Roger Alsing's original SLOW EvoLisa program (a fast, source-only version of it [still in GDI+, thus much slower than even my existing Direct3D version] can be found at http://starcalc.110mb.com/EvoLisa.zip). [Edited by - StarBP on June 22, 2009 8:39:46 AM]

Share this post


Link to post
Share on other sites
Here is the specific section of the source that has all the state changes (you can download the full source from the TinyURL link in the first post):

if (activeLogHeight > 1 && activeLogWidth > 1 && activeLogWidth * activeLogHeight > 512)
{
fitnessRenderToSurface2.BeginScene(fitnessSurface2);
device.VertexFormat = CustomVertex.PositionTextured.Format;
device.SetStreamSource(0, fitnessVBHalf, 0);
device.VertexDeclaration = fitnessVertexDeclaration;
fitnessEffect.Technique = "VersionOneOtherParts";
fitnessEffect.SetValue("TextureOne", fitnessTexture1);
fitnessEffect.SetValue("FitnessMatrix", fitnessMatrix);
fitnessEffect.SetValue("xOffset", (float)(0.5 / (double)logWidth));
fitnessEffect.SetValue("yOffset", (float)(0.5 / (double)logHeight));
fitnessEffect.Begin(0);
fitnessEffect.BeginPass(0);
device.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2);
fitnessEffect.EndPass();
fitnessEffect.End();
fitnessRenderToSurface2.EndScene(Filter.None);
activeLogHeight /= 2;
activeLogWidth /= 2;
}
#region Some more ping-ponging back and forth for the reduction
if (activeLogHeight > 1 && activeLogWidth > 1 && activeLogWidth * activeLogHeight > 512)
{
fitnessRenderToSurface1.BeginScene(fitnessSurface1);
device.VertexFormat = CustomVertex.PositionTextured.Format;
device.SetStreamSource(0, fitnessVBFourth, 0);
device.VertexDeclaration = fitnessVertexDeclaration;
fitnessEffect.Technique = "VersionOneOtherParts";
fitnessEffect.SetValue("TextureOne", fitnessTexture2);
fitnessEffect.SetValue("FitnessMatrix", fitnessMatrix);
fitnessEffect.SetValue("xOffset", (float)(0.5 / (double)logWidth));
fitnessEffect.SetValue("yOffset", (float)(0.5 / (double)logHeight));
fitnessEffect.Begin(0);
fitnessEffect.BeginPass(0);
device.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2);
fitnessEffect.EndPass();
fitnessEffect.End();
fitnessRenderToSurface1.EndScene(Filter.None);
activeLogHeight /= 2;
activeLogWidth /= 2;
}

if (activeLogHeight > 1 && activeLogWidth > 1 && activeLogWidth * activeLogHeight > 512)
{
fitnessRenderToSurface2.BeginScene(fitnessSurface2);
device.VertexFormat = CustomVertex.PositionTextured.Format;
device.SetStreamSource(0, fitnessVBEighth, 0);
device.VertexDeclaration = fitnessVertexDeclaration;
fitnessEffect.Technique = "VersionOneOtherParts";
fitnessEffect.SetValue("TextureOne", fitnessTexture1);
fitnessEffect.SetValue("FitnessMatrix", fitnessMatrix);
fitnessEffect.SetValue("xOffset", (float)(0.5 / (double)logWidth));
fitnessEffect.SetValue("yOffset", (float)(0.5 / (double)logHeight));
fitnessEffect.Begin(0);
fitnessEffect.BeginPass(0);
device.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2);
fitnessEffect.EndPass();
fitnessEffect.End();
fitnessRenderToSurface2.EndScene(Filter.None);
activeLogHeight /= 2;
activeLogWidth /= 2;
}

if (activeLogHeight > 1 && activeLogWidth > 1 && activeLogWidth * activeLogHeight > 512)
{
fitnessRenderToSurface1.BeginScene(fitnessSurface1);
device.VertexFormat = CustomVertex.PositionTextured.Format;
device.SetStreamSource(0, fitnessVBSixteenth, 0);
device.VertexDeclaration = fitnessVertexDeclaration;
fitnessEffect.Technique = "VersionOneOtherParts";
fitnessEffect.SetValue("TextureOne", fitnessTexture2);
fitnessEffect.SetValue("FitnessMatrix", fitnessMatrix);
fitnessEffect.SetValue("xOffset", (float)(0.5 / (double)logWidth));
fitnessEffect.SetValue("yOffset", (float)(0.5 / (double)logHeight));
fitnessEffect.Begin(0);
fitnessEffect.BeginPass(0);
device.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2);
fitnessEffect.EndPass();
fitnessEffect.End();
fitnessRenderToSurface1.EndScene(Filter.None);
activeLogHeight /= 2;
activeLogWidth /= 2;
}

if (activeLogHeight > 1 && activeLogWidth > 1 && activeLogWidth * activeLogHeight > 512)
{
fitnessRenderToSurface2.BeginScene(fitnessSurface2);
device.VertexFormat = CustomVertex.PositionTextured.Format;
device.SetStreamSource(0, fitnessVBThirtySecond, 0);
device.VertexDeclaration = fitnessVertexDeclaration;
fitnessEffect.Technique = "VersionOneOtherParts";
fitnessEffect.SetValue("TextureOne", fitnessTexture1);
fitnessEffect.SetValue("FitnessMatrix", fitnessMatrix);
fitnessEffect.SetValue("xOffset", (float)(0.5 / (double)logWidth));
fitnessEffect.SetValue("yOffset", (float)(0.5 / (double)logHeight));
fitnessEffect.Begin(0);
fitnessEffect.BeginPass(0);
device.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2);
fitnessEffect.EndPass();
fitnessEffect.End();
fitnessRenderToSurface2.EndScene(Filter.None);
activeLogHeight /= 2;
activeLogWidth /= 2;
}

if (activeLogHeight > 1 && activeLogWidth > 1 && activeLogWidth * activeLogHeight > 512)
{
fitnessRenderToSurface1.BeginScene(fitnessSurface1);
device.VertexFormat = CustomVertex.PositionTextured.Format;
device.SetStreamSource(0, fitnessVBSixtyFourth, 0);
device.VertexDeclaration = fitnessVertexDeclaration;
fitnessEffect.Technique = "VersionOneOtherParts";
fitnessEffect.SetValue("TextureOne", fitnessTexture2);
fitnessEffect.SetValue("FitnessMatrix", fitnessMatrix);
fitnessEffect.SetValue("xOffset", (float)(0.5 / (double)logWidth));
fitnessEffect.SetValue("yOffset", (float)(0.5 / (double)logHeight));
fitnessEffect.Begin(0);
fitnessEffect.BeginPass(0);
device.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2);
fitnessEffect.EndPass();
fitnessEffect.End();
fitnessRenderToSurface1.EndScene(Filter.None);
activeLogHeight /= 2;
activeLogWidth /= 2;
}

if (activeLogHeight > 1 && activeLogWidth > 1 && activeLogWidth * activeLogHeight > 512)
{
fitnessRenderToSurface2.BeginScene(fitnessSurface2);
device.VertexFormat = CustomVertex.PositionTextured.Format;
device.SetStreamSource(0, fitnessVB128, 0);
device.VertexDeclaration = fitnessVertexDeclaration;
fitnessEffect.Technique = "VersionOneOtherParts";
fitnessEffect.SetValue("TextureOne", fitnessTexture1);
fitnessEffect.SetValue("FitnessMatrix", fitnessMatrix);
fitnessEffect.SetValue("xOffset", (float)(0.5 / (double)logWidth));
fitnessEffect.SetValue("yOffset", (float)(0.5 / (double)logHeight));
fitnessEffect.Begin(0);
fitnessEffect.BeginPass(0);
device.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2);
fitnessEffect.EndPass();
fitnessEffect.End();
fitnessRenderToSurface2.EndScene(Filter.None);
activeLogHeight /= 2;
activeLogWidth /= 2;
}

if (activeLogHeight > 1 && activeLogWidth > 1 && activeLogWidth * activeLogHeight > 512)
{
fitnessRenderToSurface1.BeginScene(fitnessSurface1);
device.Clear(ClearFlags.Target, Color.Black, 1.0f, 0);
device.VertexFormat = CustomVertex.PositionTextured.Format;
device.SetStreamSource(0, fitnessVB256, 0);
device.VertexDeclaration = fitnessVertexDeclaration;
fitnessEffect.Technique = "VersionOneOtherParts";
fitnessEffect.SetValue("TextureOne", fitnessTexture2);
fitnessEffect.SetValue("FitnessMatrix", fitnessMatrix);
fitnessEffect.SetValue("xOffset", (float)(0.5 / (double)logWidth));
fitnessEffect.SetValue("yOffset", (float)(0.5 / (double)logHeight));
fitnessEffect.Begin(0);
fitnessEffect.BeginPass(0);
device.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2);
fitnessEffect.EndPass();
fitnessEffect.End();
fitnessRenderToSurface1.EndScene(Filter.None);
activeLogHeight /= 2;
activeLogWidth /= 2;
}

if (activeLogHeight > 1 && activeLogWidth > 1 && activeLogWidth * activeLogHeight > 512)
{
fitnessRenderToSurface2.BeginScene(fitnessSurface2);
device.Clear(ClearFlags.Target, Color.Black, 1.0f, 0);
device.VertexFormat = CustomVertex.PositionTextured.Format;
device.SetStreamSource(0, fitnessVB512, 0);
device.VertexDeclaration = fitnessVertexDeclaration;
fitnessEffect.Technique = "VersionOneOtherParts";
fitnessEffect.SetValue("TextureOne", fitnessTexture1);
fitnessEffect.SetValue("FitnessMatrix", fitnessMatrix);
fitnessEffect.SetValue("xOffset", (float)(0.5 / (double)logWidth));
fitnessEffect.SetValue("yOffset", (float)(0.5 / (double)logHeight));
fitnessEffect.Begin(0);
fitnessEffect.BeginPass(0);
device.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2);
fitnessEffect.EndPass();
fitnessEffect.End();
fitnessRenderToSurface2.EndScene(Filter.None);
activeLogHeight /= 2;
activeLogWidth /= 2;
}

if (activeLogHeight > 1 && activeLogWidth > 1 && activeLogWidth * activeLogHeight > 512)
{
fitnessRenderToSurface1.BeginScene(fitnessSurface1);
device.Clear(ClearFlags.Target, Color.Black, 1.0f, 0);
device.VertexFormat = CustomVertex.PositionTextured.Format;
device.SetStreamSource(0, fitnessVB1024, 0);
device.VertexDeclaration = fitnessVertexDeclaration;
fitnessEffect.Technique = "VersionOneOtherParts";
fitnessEffect.SetValue("TextureOne", fitnessTexture2);
fitnessEffect.SetValue("FitnessMatrix", fitnessMatrix);
fitnessEffect.SetValue("xOffset", (float)(0.5 / (double)logWidth));
fitnessEffect.SetValue("yOffset", (float)(0.5 / (double)logHeight));
fitnessEffect.Begin(0);
fitnessEffect.BeginPass(0);
device.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2);
fitnessEffect.EndPass();
fitnessEffect.End();
fitnessRenderToSurface1.EndScene(Filter.None);
activeLogHeight /= 2;
activeLogWidth /= 2;
}
#endregion




Running the code in PIX in single-frame (F12) mode and expanding the BeginPass(0) and EndPass() calls in the viewer will give you insight into the unnecessary state changes that are taking place. Note especially (in the CPU-time graph) that these state changes take up the bulk of the code running time.

[Edited by - StarBP on June 22, 2009 10:40:58 AM]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this