If I understand the question correctly and the subquery mentioned is part of the bigger query, then the problem is that you're querying all records from table
pm
from specific user to another user. In other words, you would get the same unread count for all rows.
But if that is what you really want, then you could try something like
SELECT pm.*,
(SELECT u.username FROM users u WHERE u.userid = pm.from_id) AS from_username,
(SELECT u.username FROM users u WHERE u.userid = pm.to_id) AS to_username,
(SELECT u.username FROM users u WHERE u.userid = ?) AS my_username,
(SELECT count(*) FROM pm pm2 where pm2.to_id=pm.to_id and pm2.read=0)as unread
FROM pm
WHERE pm.from_id = ?
or pm.to_id = ?
ORDER BY pm.id DESC
But as said, it looks like you're fetching completely different things in a single query so it probably would be best to split this to two different queries: On which fetches the pm data and another one which fetched the amount of unread messages. The latter would be simply
SELECT count(*) FROM pm where pm.to_id=? and pm2.read=0
Also note that my_username is again repeating data so fetching that only once should be sufficient.