When are/aren‘t memory buffers necessary?

In most examples I‘ve seen builtin scalar parameters (ex. uint n) can be directly passed to kernels but arrays of builtin scalar and vectors (float *x and float4 *x4) are always passed using memory buffers. So does a struct always need to be packed into a memory buffer? What about a single builtin vector parameters (ex. uint4 n4)? Could someone be so kind as to explain when and why memory buffers are and aren‘t required. If it‘s not required but still used then I guess its just added overhead, but otherwise not harmful. Thanks for your help!

Non-pointer types like int, float4, etc. can be passed directly without a buffer object. Pointer types must be passed through a memory object. This is specified in section 5.7.2 of the CL 1.1. spec:

If the argument is declared to be a pointer of a built-in or user defined type with the __global or __constant qualifier, the memory object specified as argument value must be a buffer object (or NULL)

As for structs, it looks like different implementations do different things. There is no current consensus in the Working Group about whether it is allowed to pass structs outside of a buffer object. In other words, the only portable way today is to use a buffer object.