Scaling is a subset of texture mapping. The texture mapping supported by all versions of OpenGL allows for arbitrary projective transformations, i.e.
u = (c11.x+c12.y+c13)/(c31.x+c32.y+c33)
v = (c21.x+c22.y+c23)/(c31.x+c32.y+c33)
A “scaled blit” (without rotation or shear) corresponds to the specific case [c12=0, c21=0, c31=0, c32=0, c33=1], i.e.
u = c11.x+c13
v = c22.y+c23
If you’re referring to the ability to render at a lower resolution then upscale, the way that would be done now (using framebuffer objects) requires OpenGL 3.0 or either the
ARB_geometry_shader4 extension. Previously, that would require rendering to some platform-specific off-screen surface (pbuffer, GLXPixmap, etc) then copying the framebuffer contents into a texture which could then be scaled via texture mapping.
Having rendered to a texture or renderbuffer, the result can then be copied to the window with scaling using
glBlitFramebuffer (which was added in 3.0 via the
EXT_framebuffer_blit extension). Or if rendered to a texture, that can then be rendered to the window using texture mapping.