GPU Paint on DX11

I am developing a GPU-based paint program that draws quads in OpenGL with a paint shader into a rendertexture canvas. The paint shader makes use of the rendertexture for blending.
This strategy works fine in DirectX9 as seen in this screenshot:


However, when I switch over to DirectX11, it looks like the paint shader treats the rendertexture as a black texture, as seen in the next screenshot.

I have stripped down the code into a single script:

using UnityEngine;
using System.Collections;

public class PaintTool : MonoBehaviour {

    public static Vector4 screenDimensions;

    private RenderTexture colorTexture;

    public Color lineColor = Color.green;
    public float brushRadius = 100;

    private Color paintColor;
    public Material paintMaterial;

    private Vector2 pos;

    public Material clearColorMaterial;

    protected void Awake()
    {
        float swf = Screen.width;
        float shf = Screen.height;
        screenDimensions = new Vector4(swf, shf, 1.0f / swf, 1.0f / shf);
        Shader.SetGlobalVector("_ScreenDimensions", screenDimensions);

        colorTexture = new RenderTexture((int)screenDimensions.x, (int)screenDimensions.y, 0, RenderTextureFormat.ARGB32);

        GetComponent<Renderer>().material.SetTexture("_MainTex", colorTexture);

        paintMaterial.SetTexture("_MainTex", colorTexture);

        colorTexture.filterMode = FilterMode.Point;

        Graphics.Blit(null, colorTexture, clearColorMaterial);
    }

    public void Update()
    {
        if (Input.GetMouseButton (0)) {

            pos = Input.mousePosition;
            paintMaterial.SetFloat("_Radius", brushRadius);
            paintMaterial.SetVector("_FromPosition", pos);
            paintMaterial.SetVector("_ToPosition", pos);

            RenderOntoTexture(paintMaterial, BoundingRect(), colorTexture);
        }
    }

    //Renders a rectangle in screen space using a certain paintMaterial ontop of a full screen background material
    protected virtual void RenderOntoTexture(Material paintMaterial, Rect paintBounds, RenderTexture renderOnto)
    {
        GL.PushMatrix();
        GL.LoadPixelMatrix(0, screenDimensions.x, 0, screenDimensions.y);
    
        RenderTexture.active = renderOnto;

        //Render the altered offsets in a bounded rectangle (should produce good performance)
        RenderMaterialRect(paintMaterial, paintBounds);
    
        RenderTexture.active = null;
    
        GL.PopMatrix();
    }

    //Subtract one due to screen's apparent "off by one" issue
    public static Rect ScreenRectToUV(Rect screenBounds)
    {
        Vector2 screenInv = new Vector2(screenDimensions.z, screenDimensions.w);
        Vector2 min = Vector2.Scale(screenBounds.min, screenInv);
        Vector2 max = Vector2.Scale(screenBounds.max, screenInv);
        return Rect.MinMaxRect(min.x, min.y, max.x, max.y);
    }

    protected virtual void RenderMaterialRect(Material m, Rect boundsRect)
    {
        //Determine UV Coordinates based on Screen Rectangle
        Rect uvRect = ScreenRectToUV(boundsRect);
    
        // activate the first pass (in this case we know it is the only pass)
        m.SetPass (0);
    
        // draw a quad
        GL.Begin (GL.QUADS);
        GL.TexCoord2 (uvRect.xMin, uvRect.yMin); GL.Vertex3 (boundsRect.xMin, boundsRect.yMin, 0.1f);
        GL.TexCoord2 (uvRect.xMax, uvRect.yMin); GL.Vertex3 (boundsRect.xMax, boundsRect.yMin, 0.1f);
        GL.TexCoord2 (uvRect.xMax, uvRect.yMax); GL.Vertex3 (boundsRect.xMax, boundsRect.yMax, 0.1f);
        GL.TexCoord2 (uvRect.xMin, uvRect.yMax); GL.Vertex3 (boundsRect.xMin, boundsRect.yMax, 0.1f);
        GL.End ();
    }

    public Rect BoundingRect()
    {
        float minX = Mathf.Max (0, pos.x - brushRadius);
        float maxX = Mathf.Min (screenDimensions.x, pos.x + brushRadius);
        float minY = Mathf.Max (0, pos.y - brushRadius);
        float maxY = Mathf.Min (screenDimensions.y, pos.y + brushRadius);
    
        return Rect.MinMaxRect(minX, minY, maxX, maxY);
    }
}

Here is the shader code that does the painting:

Shader "Custom/Paint" {
    Properties {
          _Radius ("Radius (Screen Space)", Float) = 128.0
          _FromPosition ("From Position (Screen Space)", Vector) = (0,0,0,0)
          _ToPosition("To Position (Screen Space)", Vector) = (0,0,0,0)
          _RadialPaint("Radial Ease Buffer", 2D) = "" {}
          _MainTex("Current Color Texture", 2D) = "" {}
          _Color("Main Color", Color) = (0,0,0,0)
    }
    SubShader {

        Lighting Off
        Blend One Zero, One Zero
        Cull Off
        ZWrite Off
        Fog { Mode Off }
        ZTest Always

        Pass {
            Tags { "RenderType" = "Opaque" }
            CGPROGRAM
            #pragma vertex vert_img
            #pragma fragment frag
        
            uniform float4 _Color;
            uniform sampler2D _MainTex;
            uniform sampler2D _RadialPaint;
            uniform float _Radius;
            //From Position in Screen coordinates
            uniform float4 _FromPosition;
            //To Position in Screen coordinates
            uniform float4 _ToPosition;
            //ScreenDimensions (zw are inverted)
            uniform float4 _ScreenDimensions;
        
            #include "UnityCG.cginc"
        
            inline float DistanceToSegment(float2 v, float2 p0, float2 p1)
            {
                float2 p = p1 - p0;
                float2 w = v - p0;
                float c1 = dot(w, p);
                if(c1 <= 0)
                {
                    return distance(v, p0);
                }
                else
                {
                    float c2 = dot(p, p);
                    if(c2 <= c1)
                    {
                        return distance(v, p1);
                    }
                    else
                    {
                        float b = c1 / c2;
                        float2 pb = p0 + b * p;
                        return distance(v, pb);
                    }
                }
            }
        
            float4 frag(v2f_img i) : COLOR {
            
                float2 screenPos = i.uv * _ScreenDimensions.xy;
                float2 fromPos = _FromPosition.xy;
                float2 toPos = _ToPosition.xy;
                
                float d = DistanceToSegment(screenPos, fromPos, toPos);
                float easeValue = 1.0f - d / _Radius;
                float4 currentColor = tex2D(_MainTex, i.uv);
                float radiusClamp = ceil(saturate(_Radius - d));
                //Paint amount is scaled by distance from radius (Currently linear), and by distance from starting point
                return (1.0 - easeValue * radiusClamp) * currentColor + radiusClamp * easeValue * _Color;
            }
            ENDCG
        }
    }
}

Is there some aspect of DX11 that is preventing this strategy from working?

I am attaching a unitypackage containing this test. Switch to/from DX9/11 in BuildSettings to see the effect.
Any help or advice is appreciated.

2187979–145139–PaintTest.unitypackage (15.7 KB)

     Lighting Off
        Blend One Zero, One Zero
        Cull Off
        ZWrite Off
        Fog { Mode Off }
        ZTest Always
        Pass {
            Tags { "RenderType" = "Opaque" }

Looks like blending issue for me. Try setting “RenderQueue”=“Transparent” in Tags section and change “RenderType”=“Transparent” .

I substituted these as my subshader tags: Tags { “RenderType” = “Transparent” “IgnoreProjector”=“True” “Queue” = “Transparent”}

Unfortunately no luck. If I put another texture into my SetTexture call, it works like I expect, with the texture being drawn into the rendertexture canvas. I have also tried generating another rendertexture and using it in the SetTexture call, which also results in no black background problems. It seems like the issue only crops up when I feed the canvas rendertexture back into the material that is used to render into it.