0
\$\begingroup\$

I'm trying to solve a bug I have in my XNA game.

I have an Effect that I want to apply on the screen when I activate an Item.

Currently, I have this weird bug where it throws an exception in the Main method, highlights"

using (Game1 game = new Game1(args))
{
    game.Run(); // Throws exception here
}

An unhandled exception of type 'System.InvalidOperationException' occurred in Microsoft.Xna.Framework.Graphics.dll
Additional information: Cannot call Present when a render target is active.

I've come to understand that it has something to do with RenderTarget2D and setting the render target.

Currently, that's the code that draws (Sorry, 2 months of working on a game with 3 other guys, and our code is hardly readable):

    /// <summary>
    /// This is called when the game should draw itself.
    /// </summary>
    /// <param name="gameTime">Provides a snapshot of timing values.</param>
    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.Crimson);

        try
        {
            if (effWholeScreenEffect != null)
                ///////////////////////////////////////////////////////////////////////////////
                DrawWithFullScreenEffect(); // That's when it's supposed to negate whole screen                
            else
                PerformDraw();
        }
        catch { }
        finally
        {
            base.Draw(gameTime);
        }
    }

    private void DrawWithFullScreenEffect()
    {
        var rtbSaver = GraphicsDevice.GetRenderTargets();

        using (RenderTarget2D rtScreen = new RenderTarget2D(GraphicsDevice, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height))
        {
            GraphicsDevice.SetRenderTarget(rtScreen);

            PerformDraw();

            if (effWholeScreenEffect != null)
            {
                spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, null, null, null, effRingOfGodsFury);
            }
            else
            {
                spriteBatch.Begin();
            }

            GraphicsDevice.SetRenderTarget(null);

            // Draw whole screen
            spriteBatch.Draw(rtScreen, new Rectangle(0, 0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height), Color.White);

            spriteBatch.End();
        }
    }

    private void PerformDraw()
    {
        #region Game World Section
        // Draw game map
        gameMap.Draw(spriteBatch, GraphicsDevice.Viewport);

        // Draw connection players
        cntConnection.DrawPlayers(spriteBatch);

        try
        {
            projectileHandler.Draw(spriteBatch);
        }
        catch
        {

        }

        #endregion

        #region Hud Section

        #region Inventory Draw

        int nCurrItem = 0;

        // Run over player's inventory dictionary
        for (byte bCurrIndex = 0; bCurrIndex < Inventory.INVENTORY_SIZE; bCurrIndex++)
        {
            // If the player got the item
            if (localPlayer.Inventory[bCurrIndex] != null)
            {
                // Set fill amount parameter
                effItemIcons.Parameters["fFillAmount"].SetValue(localPlayer.Inventory[bCurrIndex].FillAmount);

                spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, null, null, null, null);

                // If player has an item selected and its the current item
                if ((localPlayer.SelectedItem != -1) &&
                    (localPlayer.SelectedItem == bCurrIndex))
                {
                    // Draw the icon
                    spriteBatch.Draw(tSelectedBorder,
                                     new Rectangle(8 + (50 * nCurrItem),
                                                   GraphicsDevice.Viewport.Height - 72,
                                                   52,
                                                   52),
                                     Color.White);
                }
                else
                {
                    effItemIcons.CurrentTechnique.Passes["CoolDown"].Apply();
                }

                // If mana cost is bigger than current mana
                if (localPlayer.Inventory[bCurrIndex].ManaCost > localPlayer.MP)
                {
                    effItemIcons.CurrentTechnique.Passes["NotEnoughMana"].Apply();
                }

                // Draw the icon
                spriteBatch.Draw(localPlayer.Inventory[bCurrIndex].Icon,
                                 new Rectangle(10 + (50 * nCurrItem),
                                               GraphicsDevice.Viewport.Height - 70,
                                               48,
                                               48),
                                 Color.White);

                spriteBatch.End();

                spriteBatch.Begin();

                // Write the key
                spriteBatch.DrawString(sfPlayerNameFont,
                                       bCurrIndex.ToString(),
                                       new Vector2(25 + (50 * nCurrItem),
                                                   GraphicsDevice.Viewport.Height - 20),
                                       Color.White);

                spriteBatch.End();

                nCurrItem++;
            }
        }

        #endregion

        spriteBatch.Begin();

        #region Team Score

        spriteBatch.Draw(tScoreBoardTexture,
                         new Rectangle(GraphicsDevice.Viewport.Width / 2 - tScoreBoardTexture.Width / 2,
                                       5,
                                       tScoreBoardTexture.Width, tScoreBoardTexture.Height),
                         Color.White);

        spriteBatch.DrawString(sfScoreBoardFont,
                               cntConnection.GoatScore.ToString(),
                               new Vector2(GraphicsDevice.Viewport.Width / 2 + 20, 30),
                               Color.Azure);

        spriteBatch.DrawString(sfScoreBoardFont,
                               cntConnection.HolyCowsScore.ToString(),
                               new Vector2(GraphicsDevice.Viewport.Width / 2 - 40, 30),
                               Color.Azure);

        spriteBatch.DrawString(sfScoreBoardFont,
                                ((double)(cntConnection.RoundTimeRemaining / 100) / 10).ToString(),
                                new Vector2(GraphicsDevice.Viewport.Width / 2 - 50, 60), Color.Azure);

        #endregion

        #region Mini Score Tab

        #region Layout

        spriteBatch.Draw(tMiniScoreTab,
                         new Rectangle(GraphicsDevice.Viewport.Width - tMiniScoreTab.Width,
                                       0, tMiniScoreTab.Width, tMiniScoreTab.Height),
                         Color.White);

        #endregion

        #region Information

        spriteBatch.DrawString(sfMiniScoresTabFont,
                               "Ping : " + cntConnection.Ping +
                               "\nGold : " + localPlayer.Gold,
                               new Vector2(GraphicsDevice.Viewport.Width - 350, 5),
                               Color.Azure);

        spriteBatch.DrawString(sfMiniScoresTabFont,
                               "Kill      : " + localPlayer.Kills +
                               "\nDeath : " + localPlayer.Deaths,
                               new Vector2(GraphicsDevice.Viewport.Width - 255, 5),
                               Color.Azure);

        spriteBatch.DrawString(sfMiniScoresTabFont,
                               "Health : " + localPlayer.HP +
                               " / " + localPlayer.MaxHP + "\n" +
                               "Mana   : " + localPlayer.MP +
                               " / " + localPlayer.MaxMP,
                               new Vector2(GraphicsDevice.Viewport.Width - 160, 5),
                               Color.Azure);


        #endregion

        #endregion

        #region Scores Tab

        // If bIsScoreTab is true
        if (bIsScoreTabShown)
        {
            // Draw the ping shiiiiiiit
            ScoresTab.Draw(spriteBatch,
                           cntConnection.Players,
                           ScoresTab.nPing,
                           GraphicsDevice.Viewport.Width - ScoresTab.FRAME_WIDTH + 30,
                           65);

            #region DEBUG

            if (DEBUG_MODE)
            {
                // Draw the velocity shiiiiiiit
                spriteBatch.DrawString(sfPlayerNameFont,
                                       "VelX : " + Math.Round(localPlayer.VelX, 3) +
                                       "\nVelY : " + Math.Round(localPlayer.VelY, 3),
                                       new Vector2(GraphicsDevice.Viewport.Width / 100, 20), Color.White);
                // Draw the velocity shiiiiiiit
                spriteBatch.DrawString(sfPlayerNameFont,
                                       "| PosX : " + localPlayer.PosX +
                                       "\n| PosY : " + localPlayer.PosY,
                                       new Vector2(GraphicsDevice.Viewport.Width / 100 + 120, 20), Color.White);

                // Show the camera position
                spriteBatch.DrawString(sfPlayerNameFont,
                                       "| ViewportX : " + Camera.CameraVector.X +
                                       "\n| ViewportY : " + Camera.CameraVector.Y,
                                       new Vector2(GraphicsDevice.Viewport.Width / 100 + 250, 20), Color.White);
            }

            #endregion
        }

        #endregion

        #region Shop

        if (bIsShopOpen)
        {
            ItemShop.Draw(spriteBatch, GraphicsDevice.Viewport);
        }

        #endregion

        #region Messages

        // Go over messages
        for (int nCurrMessage = 0;
             nCurrMessage < cntConnection.Messages.Length;
             nCurrMessage++)
        {
            if (cntConnection.Messages[nCurrMessage].MessageType != ActionType.Empty)
            {
                spriteBatch.DrawString(sfMiniScoresTabFont,
                                       cntConnection.Players[cntConnection.Messages[nCurrMessage].ActionPerformerID].Name +
                                       cntConnection.Messages[nCurrMessage].Mess +
                                       cntConnection.Players[cntConnection.Messages[nCurrMessage].ActionRecieverID].Name,
                                       new Vector2(5, 5 + (15 * nCurrMessage)), Color.White);
            }
        }

        #endregion

        spriteBatch.End();

        #endregion
    }

I haven't found any valuable information regarding that exception, so I hoped you guys would know more than me...

Thanks for reading and I hope the code hasn't given you some kind of cancer.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Well, first of all, here's a tip for you (in bold uppercase, because you should remember it): NEVER EVER THROW AWAY ERRORS this is called yoda exception handling (Do, or not to do, but never try), and is a bad habit. \$\endgroup\$
    – Bálint
    Dec 8, 2016 at 20:53
  • \$\begingroup\$ Trust me, It's been long since I touched the code, and that try-catch block is non of my doing, even though I can't guarantee I wouldn't have done the same. The code in this project is horrendous. I've part of the project in a different project, github to project, and I've done that using my own ECS implementation for XNA, and also a custom pub-sub library that works for both the client and the server (although coupling them to the same implementation of the library, but the project isn't perfect anyway :P) \$\endgroup\$ Dec 12, 2016 at 18:58

1 Answer 1

1
\$\begingroup\$

The root cause isn't obvious to me, but:

try //Try to do some drawing
{
   ...
}
catch
{
   //If there are any errors (NullReference, DeviceLost, etc.), just ignore them
}
finally
{
   //And Present() anyway (evidently with a RenderTarget set)
   base.Draw(gameTime);
}

Instead:

try
{
   ... //Try to do some drawing
   base.Draw(gameTime); //then Present()
}
catch (DeviceLostException ex) //Most-specific first
{
   //Recover or gracefully abort
}
catch (Exception ex) //Least-specific catch-all
{
   int a = 1; //When this breakpoint is hit, inspect ex and figure out what should happen
   //  ^-- Add breakpoint
   throw ex; //Something unknown is definitely wrong; do not continue
}

Possible null reference:
(using the clue that something is happening before GraphicsDevice.SetRenderTarget(null)):

if (effWholeScreenEffect != null)
{
   //spriteBatch.Begin(..., effRingOfGodsFury);
   spriteBatch.Begin(..., effWholeScreenEffect); //Did you mean...
}

or:

//if (effWholeScreenEffect != null)
if (effRingOfGodsFury != null) //Did you mean...
{
   spriteBatch.Begin(..., effRingOfGodsFury);
}

WARNING:

using (RenderTarget2D rtScreen = new RenderTarget2D(GraphicsDevice, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height))

Create and initialize the rendertarget once, any time the backbuffer dimensions (Viewport?) change. You may need to use the RendertargetUsage.PreserveContents flag during creation.

\$\endgroup\$
11
  • \$\begingroup\$ 1. Regarding catching exceptions, I admit all the content should be in the try section, and with catching, I only do that when I have to - if I don't really havr special cases, there isn't much point for me to do that. \$\endgroup\$ Mar 15, 2016 at 5:28
  • \$\begingroup\$ 2. Regarding the RenderTarget2D, you're saying that instead of doing "using..." every time, I should save it as a variable? \$\endgroup\$ Mar 15, 2016 at 5:29
  • \$\begingroup\$ @GioraGuttsait, you could also just GraphicsDevice.SetRenderTarget(null); with the catch. The problem is not really how you organize the try, but how you respond in the catch. \$\endgroup\$
    – Jon
    Mar 15, 2016 at 6:15
  • \$\begingroup\$ The question is - How do I respond to the things I catch? I used to have an exception thrown at a random SpriteBatch.End() call, so we wrapped it up with a try. Now this thing shows up. \$\endgroup\$ Mar 15, 2016 at 6:16
  • \$\begingroup\$ @GioraGuttsait, correct; it is wasteful to recreate it over and over. Destroy and recreate it once in the appropriate BackBufferResized callback. You can save it anywhere conveniently accessible as a static. \$\endgroup\$
    – Jon
    Mar 15, 2016 at 6:16

You must log in to answer this question.

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