Shader job quality on Mobile (2D effects)

Hello everyone. I can’t get it right and need your help.

So, the input data.
I have a drawing\coloring application, so I use Canvas and Raw Textures to display images to color.
To improve coloring speed I decided to try shaders and it did helped, though it`s great on PC it’s horrible on mobile.

This is on the PC


And this is on Mobile (Android 6.0.1 Samsung Note 4)

This is the code, where texture is main image Texture and mapTexture is Texture of the same size that maps image zones.

rt = new RenderTexture(mapBuilder.map.width, mapBuilder.map.height, 16);
rt.Create();

colMat = new Material(Shader.Find("Coloring/ColorReplace"));
colMat.SetTexture("_Ref", mapTexture);

colMat.SetTexture("_MainTex", texture);
colMat.SetColor("_Color", fillType.Evaluate());

colMat.SetFloat("_ZoneX", hit.x / (float)texture.width);
colMat.SetFloat("_ZoneY", hit.y / (float)texture.height);

RenderTexture.active = rt;

Graphics.Blit(texture, rt, colMat);

texture.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0);

It seems like aproximation used where I don’t want it, and I am sure I can fix this but I just can’t get it how.

Shader

Shader "Coloring/ColorReplace"
{
    Properties
    {
        _MainTex("Texture", 2D) = "white" {}
    _Ref("Referece Texture", 2d) = "white" {}
    _Color("Replace Color", Color) = (1,1,1,1)
        _ZoneX("ZoneX", Float) = 0
        _ZoneY("ZoneY", Float) = 0
    }
        SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always

        Pass
    {
        CGPROGRAM
#pragma vertex vert
#pragma fragment frag

#include "UnityCG.cginc"

        struct appdata
    {
        float4 vertex : POSITION;
        float2 uv : TEXCOORD0;
    };

    struct v2f
    {
        float2 uv : TEXCOORD0;
        float4 vertex : SV_POSITION;
    };

    v2f vert(appdata v)
    {
        v2f o;
        o.vertex = UnityObjectToClipPos(v.vertex);
        o.uv = v.uv;
        return o;
    }

    sampler2D _MainTex;
    sampler2D _Ref;
    fixed4 _Color;
    float _ZoneX;
    float _ZoneY;

    fixed4 frag(v2f i) : SV_Target
    {
        fixed4 zone = tex2D(_Ref, float2(_ZoneX, _ZoneY));

        fixed4 result;
        fixed4 refValue = tex2D(_Ref, i.uv);
        if (refValue.r == zone.r && refValue.g == zone.g && refValue.b == zone.b) {
            result = _Color;
        }
        else {
            result = tex2D(_MainTex, i.uv);
        }
        return result;
    }
        ENDCG
    }
    }
}


Texture compression?

“if (refValue.r == zone.r && refValue.g == zone.g && refValue.b == zone.b)” is not going to be tolerant of texture compression using a colour that looks similar but is a slightly different value.

Maybe if you can keep to 256 colours use 1 channel uncompressed?

EDIT: also quite new to Unity myself, but ReadPixels might be something to always try to avoid, at least on “textures” or what Unity thinks should be data to store in GPU memory. Have you looked to see if there is there some way to do do your colour lookup on data that’s not set as something to be used for rendering?