Shaders working on iOS but not Android (Workaround found)

Is there anything different about the way shaders work on iOS compared to Android?

Im in the process of porting a working MonoGame iOS project to Android and everything is working correctly except for my shaders.

The following is a shockwave type effect which works perfect on iOS:

sampler2D samplerState : register(s0);

float xcenter = 0.5f;
float ycenter = 0.5f;
float magnitude = 0.5f;
float width = 0.5f;

float4 main(float2 texCoord : TEXCOORD0) : COLOR0
{ 
    float4 colour;
    float xdif = texCoord.x - xcenter;
    float ydif = texCoord.y - ycenter;
    float distance = sqrt(xdif * xdif + ydif * ydif) - width;
    float offset = abs(distance);

    if (distance < 0.1 && distance > -0.2) 
    {
        if (distance < 0.0)
        {
             offset = (0.2 - offset) / 2.0;
        }
        else
               
        {
            offset = (0.1 - offset);
        }

        texCoord.x += -(xdif * offset * magnitude);
        texCoord.y += -(ydif * offset * magnitude);
        colour = tex2D(samplerState, texCoord);
        colour.a = offset * 12.0;
     } 
     else 
     {
        colour.a = 0.0;
     }

     return colour; 
}

technique shockwave 
{ 
    pass P0
    { 
        pixelShader = compile ps_2_0 main(); 
    } 
}

And the drawing:

        spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied, null, null, null, GlobalAssets.shockwave);
        spriteBatch.Draw(finalTarget, Vector2.Zero, Color.White);
        spriteBatch.End();

On Android the above just makes the screen flash black, I also have 2 other shaders that are functioning incorrectly on Android but work fine on iOS.

Im hoping its just something simple I’m missing when compiling it for Android but I’m at a loss.

Bump, anyone got any suggestions?

Ive tried the obvious stuff like setting SV_Position, COLOR0 etc but no dice, still outputs a black screen. My understanding was that iOS and Android use the same shaders so must be missing something simple, especially as all 3 of my shaders are outputting black :confused:

EDIT:
Quick test of just the shaders in a new project has revealed they’re working, something must have gone squiffy in my main project.

Some further digging and it turns out its something to do with RenderTargets.

The shaders work perfectly if I just draw a texture and add the shader to the spritebatch.begin() call.

If I create a RenderTarget2D and do it like this, the shader renders just black or with strange outputs:

        graphics.GraphicsDevice.SetRenderTarget(target1);
        graphics.GraphicsDevice.Clear(Color.Black);

        spriteBatch.Begin();
        spriteBatch.Draw(tex, new Rectangle(0, 0, 1280, 720), Color.White);
        spriteBatch.End();

        graphics.GraphicsDevice.SetRenderTarget(null);
        graphics.GraphicsDevice.Clear(Color.Black);

        spriteBatch.Begin(0, null, null, null, null, shaderEffect);
        spriteBatch.Draw(target1, Vector2.Zero, Color.White);
        spriteBatch.End();

This is an Android only problem as far as I can tell. Im on MonoGame 3.4 too, not sure if anything is different in 3.5. Will recompile shaders in 3.5 to test shortly.

Can you show us the rendertarget (creation)?

I just use default setting except the size:

screenTarget = new RenderTarget2D(ScreenManager.GraphicsDevice, 1280, 768);

I tried some experimenting with preserving state etc last night but no joy. They work perfectly with no shaders, problem only occurs when applying effects.

The game has several layered RenderTargets to achieve various effects, all fine on iOS and also fine on Android without shaders :confused:

You can re-create the problem in a blank project with a single shader and render target.

EDIT: Its also worth nothing that i use AlphaTestEffect on one RenderTarget in the full game and that works fine, its only custom shaders that appear to cause issues.

Is anyone able to point me to where in the MonoGame code swapping render targets is dealt with? Ive done some digging but I’m not totally sure where that specific bit of code is.

This only seems to be an issue when the render target is switched, like something about the texture is being lost when a shader is applied and the target is swapped.

Build monogame yourself and use your own monogame dlls as reference and you can follow through the source code when debugging your game

I am already, I always add monogame to my solutions as a project so I can make edits if need be.

I’ve been nosing through the SetRenderTarget methods in GraphicsDevice.cs but unable to find anything that might cause this issue… not that I really know what I’m looking for since the graphics handling is bit over my head.

Happy new year by the way :slight_smile:

UPDATE: This appears to be fixed in MG 3.6… I have shaders working using the latest build :smiley: BUT now I have sound effect problems as detailed here: https://github.com/MonoGame/MonoGame/issues/5418

If anyone else encounters similar problems on Android the solution at the moment is to create a hybrid of MonoGame 3.6 and 3.4

The shaders work in 3.6 but sound effects dont, in 3.4 the sound effects work but the shaders dont.

I fixed it by using MG 3.4 and replacing the ‘Shader’, ‘Effects’ & ‘Vertices’ folders with the MG 3.6 versions then fixing any remaining reference errors from GraphicsDevice.cs and a few other files. After that I needed to recompile my shaders in the MG 3.6 builder.

Voila, working shaders and working SFX.

Hopefully the Android SFX issues will be fixed before the official 3.6 release but its a work around for now.