Is there a faster way to get UNION ALL behavior in Postgres?
For the simple case, I can only think of minor improvements to the query:

(
  SELECT DISTINCT ON (t2_id)
         t1_id, t2_id
  FROM   t0
  WHERE  t2_id IS NOT NULL
  ORDER  BY t2_id, t1_id  -- to get consistent results
)
UNION ALL
(
  SELECT DISTINCT ON (t1_id)
         t1_id, NULL      -- cheaper
  FROM   t0
  WHERE  t2_id IS NULL
  -- if you retrieve more columns, add ORDER BY, too
)


As ypercube mentioned You need to add ORDER BY with an unambiguous list of expressions to get deterministic results.
You can use the constant NULL instead of t2_id in the second leg of the query. Also relevant for below index support.
The key to performance is indexing. Try two partial indexes matching the two parts of the query:

CREATE INDEX t0_part1_idx ON t0 (t2_id, t1_id) WHERE t2_id IS NOT NULL;
CREATE INDEX t0_part2_idx ON t0 (t1_id)        WHERE t2_id IS NULL;


You may or may not want to include additional columns to allow index-only scans.


Depending on table size and data distribution, there may be faster alternatives:


Select first row in each GROUP BY group? (last chapter)
Optimize GROUP BY query to retrieve latest record per user


Single SELECT

If you want to condense it into a single SELECT:

SELECT DISTINCT ON (coalesce(t2_id, t1_id), t2_id)
       t1_id, t2_id
FROM   t0
ORDER  BY coalesce(t2_id, t1_id), t2_id, t1_id;


Equivalent, except for sort order. If you want this to be fast, try a functional index:

CREATE INDEX t0_func_idx ON t0 (coalesce(t2_id, t1_id), t2_id, t1_id);