3
\$\begingroup\$

I've got a bit of experience with shaders in general, having implemented a couple, very simple, 3D fragment and vertex shaders in OpenGL/WebGL in the past. Currently, I'm working on a 2D game engine in XNA 4.0 and I'm struggling with the process of integrating per-object and full-scene shaders in my current architecture.

I'm using a component-entity design, wherein my "Entities" are merely collections of components that are acted upon by discreet system managers (SpatialProvider, SceneProvider, etc). In the context of this question, my draw call looks something like this:

  • SceneProvider::Draw(GameTime) calls...
  • ComponentManager::Draw(GameTime, SpriteBatch) which calls (on each drawable component)
  • DrawnComponent::Draw(GameTime, SpriteBatch)

The SpriteBatch is set up, with the default SpriteBatch shader, in the SceneProvider class just before it tells the ComponentManager to start rendering the scene. From my understanding, if a component needs to use a special shader to draw itself, it must do the following when it's Draw(GameTime, SpriteBatch) method is invoked:

public void Draw(GameTime gameTime, SpriteBatch spriteBatch)
{
    spriteBatch.End();
    spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, null, null, null, EffectShader, ViewMatrix);

    // Draw things here that are shaded by the "EffectShader."

    spriteBatch.End();
    spriteBatch.Begin(/* same settings that were set by SceneProvider to ensure the rest of the scene is rendered normally */);
}

My question is, having been told that numerous calls to SpriteBatch.Begin() and SpriteBatch.End() within a single frame is terrible for performance and creates a number of special cases for my drawing logic, is there a better way to do this? Is there a way to instruct the currently running SpriteBatch to simply change the Effect shader it is using for this particular draw call and then switch it back before the function ends?

\$\endgroup\$
2
  • 2
    \$\begingroup\$ No, and this is why many shaders and passes are horrible on performance. \$\endgroup\$
    – DMan
    Apr 15, 2012 at 3:52
  • 4
    \$\begingroup\$ Although, note that "horrible on performance" is relative. You'd be shocked and surprised at how many dont-do-that rules many AAA games violate and still have gorgeous visuals running on contemporary hardware. If you need a lot of shaders, have a lot of shaders. Don't worry about what the performance will be unless you have actual measurements indicating that the number of shaders/passes are causing performance problems on target hardware. \$\endgroup\$ Apr 16, 2012 at 9:24

2 Answers 2

1
\$\begingroup\$

i had the same problem in my engine.

the solution i choose was to draw every sprite that should be affected to a rendertarget and draw it with the effect to the backbuffer.

\$\endgroup\$
1
\$\begingroup\$

Instead of Drawing in Draw() you could generate list of commands (one of them being Begin, with shader as parameter) and other would be Draw calls)

And then you can sort those commands to call Begin as little as possible

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .