Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XNA/Mono Effect Throwing Runtime Cast Exception

Tags:

c#

xna

monogame

As a foreword, the exact same code works just fine in XNA, but Monogame throws an exception. This likely requires someone familiar with the Monogame rendering pipeline.

During the Draw section of my game, there's a ShadowmapResolver that renders out a texture that is the final calculated light pattern from a given light. It's receiving an exception when rendering from what is essentially EffectPass.Apply() complaining that from somewhere within Mono theres an attempted cast from int32[] to Single[]. Here's my code that calls it:

private void ExecuteTechnique(Texture2D source, RenderTarget2D destination,
                              string techniqueName, Texture2D shadowMap)
{
    graphicsDevice.SetRenderTarget(destination);
    graphicsDevice.Clear(Color.Transparent);

    resolveShadowsEffect.Parameters["renderTargetSizeX"].SetValue((float)baseSizeX);
    resolveShadowsEffect.Parameters["renderTargetSizeY"].SetValue((float)baseSizeY);

    if (source != null)
        resolveShadowsEffect.Parameters["InputTexture"].SetValue(source);
    if (shadowMap != null)
        resolveShadowsEffect.Parameters["ShadowMapTexture"].SetValue(shadowMap);

    resolveShadowsEffect.CurrentTechnique = resolveShadowsEffect
        .Techniques[techniqueName];

    try
    {
        foreach (EffectPass pass in resolveShadowsEffect.CurrentTechnique.Passes)
        {
            pass.Apply(); // <--- InvalidCastException re-enters my program here
            quadRender.Render(Vector2.One * -1, Vector2.One);
        }
    }
    catch (Exception ex)
    {
        Util.Log(LogManager.LogLevel.Critical, ex.Message);
    }
    graphicsDevice.SetRenderTarget(null);
}

And here is the stacktrace:

at Microsoft.Xna.Framework.Graphics.ConstantBuffer.SetData(Int32 offset, Int32 rows, Int32 columns, Object data)
   at Microsoft.Xna.Framework.Graphics.ConstantBuffer.SetParameter(Int32 offset, EffectParameter param)
   at Microsoft.Xna.Framework.Graphics.ConstantBuffer.Update(EffectParameterCollection parameters)
   at Microsoft.Xna.Framework.Graphics.EffectPass.Apply()
   at JASG.ShadowmapResolver.ExecuteTechnique(Texture2D source, RenderTarget2D destination, String techniqueName, Texture2D shadowMap) in C:\Users\[snip]\dropbox\Projects\JASG2\JASG\JASG\Rendering\ShadowmapResolver.cs:line 253

So it would appear that one of the parameters of my shader which I am trying to set is confusing monogame somehow, but I don't see what it could be. I'm pushing floats, not int arrays. I even tried changing the RenderTarget2D.SurfaceFormat from Color to Single for all my targets and textures, still gives the exact same error.

Outside of the function I gave, in a broader scope, there are no other parameters being set since another EffectPass.Apply. There are multiple other effects that render without error before this one.

In case it helps, here's the source for the MonoGame Framework regarding ConstantBuffer.SetData()

private void SetData(int offset, int rows, int columns, object data)
{
    // Shader registers are always 4 bytes and all the
    // incoming data objects should be 4 bytes per element.
    const int elementSize = 4;
    const int rowSize = elementSize * 4;

    // Take care of a single element.
    if (rows == 1 && columns == 1)
    {
        // EffectParameter stores all values in arrays by default.             
        if (data is Array)
            Buffer.BlockCopy(data as Array, 0, _buffer, offset, elementSize);
        else
        {
            // TODO: When we eventually expose the internal Shader 
            // API then we will need to deal with non-array elements.
            throw new NotImplementedException();   
        }
    }

    // Take care of the single copy case!
    else if (rows == 1 || (rows == 4 && columns == 4))
        Buffer.BlockCopy(data as Array, 0, _buffer, offset, rows*columns*elementSize);
    else
    {
        var source = data as Array;

        var stride = (columns*elementSize);
        for (var y = 0; y < rows; y++)
            Buffer.BlockCopy(source, stride*y, _buffer, offset + (rowSize*y), 
                             columns*elementSize);
    }
}

Is this some sort of marshaling problem? Thanks for your time!

Edit: P.S.: The exception is an InvalidCastException and not a NotImplementedException.

like image 381
selkathguy Avatar asked Mar 10 '14 16:03

selkathguy


2 Answers

Not sure if this helps you or not but the only casting I see being done is the data as Array. I would bet that it is crashing on the line :

Buffer.BlockCopy(data as Array, 0, _buffer, offset, rows*columns*elementSize);

or

var source = data as Array;

Because they don't do any type checking before casting there. If that is the line it is crashing on it is because they don't seem to support non-array data values. I don't know this framework well enough to give you a solid answer on how to work around this. I would probably report this as a bug to the makers here

like image 157
Ben Echols Avatar answered Sep 27 '22 17:09

Ben Echols


Try 2MGFX tool which optimizes shaders for monogame. MGFX tool tips

like image 21
Wallstrider Avatar answered Sep 27 '22 18:09

Wallstrider