Compress OpenCL kernel files using zlib for Android

Kernel files are embedded into the binary as the default option when
building which leads to binary size bloating.

Add `compress_kernels` option and utilize zlib for further compressing
the text kernel files and reduce the overall binary size. We use a
base64 encoding/decoding to ensure that the strings can be easily
embedded. This adds to the binary size but still the overall reduction
is significant.
Maximum compression level 9 is used.

Option is currently restricted to Android builds as android toolchain
provides a zlib library.

Initial experimentations indicate a binary size reduction of 50%

Resolves: COMPMID-4017

Signed-off-by: Georgios Pinitas <georgios.pinitas@arm.com>
Change-Id: Iee81b8c00391b26a5f41642699692928a4d6bd6e
Reviewed-on: https://review.mlplatform.org/c/ml/ComputeLibrary/+/4958
Comments-Addressed: Arm Jenkins <bsgcomp@arm.com>
Tested-by: Arm Jenkins <bsgcomp@arm.com>
Reviewed-by: Gian Marco Iodice <gianmarco.iodice@arm.com>
diff --git a/SConstruct b/SConstruct
index 94cf80d..d5461af 100644
--- a/SConstruct
+++ b/SConstruct
@@ -56,6 +56,7 @@
     BoolVariable("neon", "Enable Neon support", False),
     BoolVariable("gles_compute", "Enable OpenGL ES Compute Shader support", False),
     BoolVariable("embed_kernels", "Embed OpenCL kernels and OpenGL ES compute shaders in library binary", True),
+    BoolVariable("compress_kernels", "Compress embedded OpenCL kernels in library binary. Note embed_kernels should be enabled", False),
     BoolVariable("set_soname", "Set the library's soname and shlibversion (requires SCons 2.4 or above)", False),
     BoolVariable("tracing", "Enable runtime tracing", False),
     BoolVariable("openmp", "Enable OpenMP backend", False),
@@ -135,6 +136,10 @@
          print("ERROR: OpenMP and C++11 threads not supported in bare_metal. Use cppthreads=0 openmp=0")
          Exit(1)
 
+if env['opencl'] and env['embed_kernels'] and env['compress_kernels'] and env['os'] not in ['android']:
+    print("Compressed kernels are supported only for android builds")
+    Exit(1)
+
 if not env['exceptions']:
     if env['opencl'] or env['gles_compute']:
          print("ERROR: OpenCL and GLES are not supported when building without exceptions. Use opencl=0 gles_compute=0")
@@ -349,6 +354,9 @@
 if env['opencl'] or env['gles_compute']:
     if env['embed_kernels']:
         env.Append(CPPDEFINES = ['EMBEDDED_KERNELS'])
+    if env['compress_kernels']:
+        env.Append(CPPDEFINES = ['ARM_COMPUTE_COMPRESSED_KERNELS'])
+        env.Append(LIBS = ['z'])
 
 if env['debug']:
     env['asserts'] = True