Upsampling before performing pulse shaping
The reason is that you want to space the raised-cosine pulses by the symbol interval, $T_p$. Consider the signal you want to create: $$s(t) = \sum_k a_k p(t-kT_p),$$ where $p(t)$ is  your prototype raised-cosine pulse, and $a_k$ are the symbols. Notice that pulses are spaced $T_p$ seconds.

To re-create this with a filter, you can write the equation for the signal as follows: $$s(t)=\sum_k p(t) \ast a_k\delta(t-kT_p),$$ where $p(t)$ is interpreted as the filter's impulse response. Notice that the impulses are spaced $T_p$ seconds, and this results in the raised-cosine pulses being spaced by the same amount.

If you want to simulate this process in discrete-time in Matlab or similar tools, then you can create a vector p for $p(t)$, and a vector d for $a_k\delta(t-kT_p)$. Let's say your symbols are stored in vector a. Then, you can create d by upsampling a in such a way that there are $T_p$ seconds between symbols:

d = [ a[1], 0, ..., 0, a[2], 0, ..., 0, a[3], 0, .... ]


You need to insert as many 0s as necessary, according to your sampling frequency, to have $T_p$ seconds between symbols.

Then, you can generate the vector s corresponding to $s(t)$ with s=conv(p,d).