# Fast Low-Precision Computer-Generated Holography on GPU
## 3 Implementation  
This section details the GPU implementation, instructions and pseudo code. For the reference implementation, we allocate a single GPU thread per pixel, each looping over all points in the point cloud, numerically computing the expression (1) for every point. We utilize the intrinsic __sincosf function for computing the phase in the exponential function (since \(\exp{i\phi}=\cos{\phi}+i\sin{\phi}\)); this is significantly faster, but less precise, than the conventional single precision floating-point sine and cosine functions. We attempted to utilize a separable implementation for this floating-point version as well, but this resulted in a net increase in calculation time: the additional memory transfers outweigh the reduction in the amount of arithmetic operations. Therefore, a non-separated version of the PSF is used for the reference implementation. The fixed-point versions of the algorithm operate in two phases. In the first phase, the separated packed phase bytes are computed for all \(x\)- and \(y\)-coordinates for all points. Since it is separable, computing a \(M\times N\) resolution hologram with a point cloud consisting of \(Q\) points needs \((M+N)Q\) bytes in total. When \(Q\) becomes too large, the GPU memory may run out, so the calculations are performed in multiple point batches. This first phase allocates one thread for every unique pixel coordinate and group of four points. Let us consider a square hologram, where \(M=N\); since the GPU registers are 32-bit words, 4 bytes can be packed in a register. Therefore, every thread can compute an 8-bit phase value for \(\phi_{\text{x}}\) (and \(\phi_{\text{y}}\)), packing them together for four points at a time in a single word (Figure 4). In total, we obtain \(\frac{MQ}{4}\) threads, each computing two words of 4 phase bytes each: one for \(\phi_{\text{x}}\) and one for \(\phi_{\text{y}}\). In the second phase, threads are grouped in 2D thread blocks (we used \(16\times 16\) threads per block), each assigned to a different pixel. The threads collectively load the relevant phase bytes in shared memory in small batches. For example, when there are \(16\times 16=256\) threads, each loading a single word (4 packed phase bytes), mapping to \(16+16=32\) unique coordinates, every small batch processes \(4\times 256/32=32\) unique points per load. Then, every thread accesses the relevant packed phase bytes \(\text{pphase\_x}\) and \(\text{pphase\_y}\) in a short unrolled loop over all points in shared memory, cf. Figure 5.  
Figure 3: Diagrams of the implemented LUT-free approximation functions. The shown approximations are scaled so that the squared error is minimal. The next main instructions are as follows:  
unsigned pphase = __vadd4(pphase_x, pphase_y); unsigned cosval = __vabsdiffu4(pphase, 0x7F7F7F7F); if constexpr (S_EXTENSION) cosval += __vminu4(__vmaxu4(cosval, 0x2222222), 0x5E5E5E5E); real_part += __dp4a(cosval, packed_amplitudes);  
The double underscore prefix indicates the use of CUDA intrinsics, which are not standard C/C++. The unsigned are, by default, 32-bit integers. The __vadd4 SIMD, intrinsic, performs a byte-wise addition, ignoring the overflow; this effect is desired, as overflows correspond to \(2\pi\) multiples, which do not alter the outcome of the periodic sine and cosine functions. The triangular signal \(TA(\phi)\) is computed with the byte-wise absolute difference instruction, __vabsdiffu4 with 0x7F = 127 per byte. If the piecewise approximation extension flag S_EXTENSION is enabled, an extra set of instructions is executed. The \"if constexpr\" indicates that this is evaluated at compile  
Figure 4: Memory layout of packed phase bytes for \(\phi_{x}\) and \(\phi_{y}\). Every 4 point phase gets packed together in a word, written to global GPU memory. In phase 2, the requisite combination of packed \(\phi_{x}\) and \(\phi_{y}\) can be efficiently processed together, using GPU SIMD instructions. Figure 5: Simplified diagram of how hologram pixel values are computed.