[2/4] utils: Merge shader header generation scripts
diff mbox series

Message ID 20260630083031.3197714-3-laurent.pinchart@ideasonboard.com
State Superseded
Headers show
Series
  • libcamera: Improve shader header generation
Related show

Commit Message

Laurent Pinchart June 30, 2026, 8:30 a.m. UTC
The shader header is generated by a combination of a shell script and a
Python script. Simplify this by merging everything into a single script.

The output of the old and new script only differ in white spaces.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 src/libcamera/shaders/meson.build |  2 +-
 utils/gen-shader-header.py        | 37 ----------------
 utils/gen-shader-headers.py       | 71 +++++++++++++++++++++++++++++++
 utils/gen-shader-headers.sh       | 54 -----------------------
 utils/meson.build                 |  2 +-
 5 files changed, 73 insertions(+), 93 deletions(-)
 delete mode 100755 utils/gen-shader-header.py
 create mode 100755 utils/gen-shader-headers.py
 delete mode 100755 utils/gen-shader-headers.sh

Comments

Milan Zamazal June 30, 2026, 10:05 a.m. UTC | #1
Laurent Pinchart <laurent.pinchart@ideasonboard.com> writes:

> The shader header is generated by a combination of a shell script and a
> Python script. Simplify this by merging everything into a single script.
>
> The output of the old and new script only differ in white spaces.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Reviewed-by: Milan Zamazal <mzamazal@redhat.com>

> ---
>  src/libcamera/shaders/meson.build |  2 +-
>  utils/gen-shader-header.py        | 37 ----------------
>  utils/gen-shader-headers.py       | 71 +++++++++++++++++++++++++++++++
>  utils/gen-shader-headers.sh       | 54 -----------------------
>  utils/meson.build                 |  2 +-
>  5 files changed, 73 insertions(+), 93 deletions(-)
>  delete mode 100755 utils/gen-shader-header.py
>  create mode 100755 utils/gen-shader-headers.py
>  delete mode 100755 utils/gen-shader-headers.sh
>
> diff --git a/src/libcamera/shaders/meson.build b/src/libcamera/shaders/meson.build
> index adac77327a3b..4f4e8da607c7 100644
> --- a/src/libcamera/shaders/meson.build
> +++ b/src/libcamera/shaders/meson.build
> @@ -14,7 +14,7 @@ libcamera_shader_headers = custom_target(
>      'gen-shader-headers',
>      input : [shader_files],
>      output : 'glsl_shaders.h',
> -    command : [gen_shader_headers, meson.project_source_root(), '@OUTPUT@', '@INPUT@'],
> +    command : [gen_shader_headers, '-o', '@OUTPUT@', '@INPUT@'],
>  )
>  
>  libcamera_internal_headers += libcamera_shader_headers
> diff --git a/utils/gen-shader-header.py b/utils/gen-shader-header.py
> deleted file mode 100755
> index 745852b4c03f..000000000000
> --- a/utils/gen-shader-header.py
> +++ /dev/null
> @@ -1,37 +0,0 @@
> -#!/usr/bin/env python3
> -# SPDX-License-Identifier: GPL-2.0-or-later
> -# Copyright (C) 2025, Bryan O'Donoghue.
> -#
> -# Author: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
> -#
> -# A Python script which takes a list of shader files and converts each of them
> -# into a C header.
> -#
> -import sys
> -
> -try:
> -    with open(sys.argv[2], "rb") as file:
> -        data = file.read()
> -        data_len = len(data)
> -
> -        name = sys.argv[1].replace(".", "_")
> -        name_len = name + "_len"
> -
> -        j = 0
> -        print("unsigned char const", name, "[] = {")
> -        for ch in data:
> -            print(f"0x{ch:02x}, ", end="")
> -            j = (j + 1) % 16
> -            if j == 0:
> -                print()
> -        if j != 0:
> -            print()
> -        print("};")
> -
> -        print()
> -        print(f"const unsigned int {name_len}={data_len};")
> -
> -except FileNotFoundError:
> -    print(f"File {sys.argv[2]} not found", file=sys.stderr)
> -except IOError:
> -    print(f"Unable to read {sys.argv[2]}", file=sys.stderr)
> diff --git a/utils/gen-shader-headers.py b/utils/gen-shader-headers.py
> new file mode 100755
> index 000000000000..908217a2bd2e
> --- /dev/null
> +++ b/utils/gen-shader-headers.py
> @@ -0,0 +1,71 @@
> +#!/usr/bin/env python3
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +#
> +# Copyright (C) 2025, Bryan O'Donoghue
> +# Copyright (C) 2026, Ideas on Board Oy
> +#
> +# Generate a C header file containing hex-encoded shader sources
> +
> +import argparse
> +import binascii
> +import math
> +import os
> +import sys
> +
> +
> +def process_file(name, out):
> +    data = open(name, 'rb').read()
> +
> +    hex_data = [f'0x{c:02x}' for c in data]
> +    var_name = os.path.basename(name).replace('.', '_')
> +
> +    out.write(f'unsigned char const {var_name}[] = {{\n')
> +
> +    for i in range(math.ceil(len(data) / 16)):
> +        out.write('\t')
> +        out.write(', '.join(hex_data[16 * i:16 * (i + 1)]))
> +        out.write(',\n')
> +
> +    out.write('};\n\n')
> +    out.write(f'const unsigned int {var_name}_len = {len(data)};\n')
> +
> +
> +def main(argv):
> +    parser = argparse.ArgumentParser(
> +        description='Generate a C header file containing hex-encoded shader sources')
> +    parser.add_argument('--output', '-o', metavar='file', default=sys.stdout,
> +                        type=argparse.FileType('w', encoding='utf-8'),
> +                        help='Output file name. Defaults to standard output if not specified.')
> +    parser.add_argument('input', nargs='+', type=str,
> +                        help='Input file names.')
> +    args = parser.parse_args(argv[1:])
> +
> +    args.output.write('''/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/* This file is auto-generated, do not edit! */
> +
> +#pragma once
> +
> +/*
> + * List the names of the shaders at the top of header for readability's sake.
> + *
> +''')
> +
> +    for name in args.input:
> +        name = os.path.basename(name).replace('.', '_')
> +        args.output.write(f' * unsigned char {name};\n')
> +
> +    args.output.write(''' */
> +
> +/* Hex encoded shader data */
> +''')
> +
> +    for name in args.input:
> +        process_file(name, args.output)
> +        args.output.write('\n')
> +
> +    return 0
> +
> +
> +if __name__ == '__main__':
> +    sys.exit(main(sys.argv))
> +
> diff --git a/utils/gen-shader-headers.sh b/utils/gen-shader-headers.sh
> deleted file mode 100755
> index 0d6649521a7a..000000000000
> --- a/utils/gen-shader-headers.sh
> +++ /dev/null
> @@ -1,54 +0,0 @@
> -#!/bin/sh
> -# SPDX-License-Identifier: GPL-2.0-or-later
> -
> -set -e
> -
> -usage() {
> -	echo "Usage: $0 <src_dir> <output_header> <shader_file1> [shader_file2 ...]"
> -	echo
> -	echo "Generates a C header file containing hex-encoded shader data."
> -	echo
> -	echo "Arguments:"
> -	echo "  src_dir             Path to the base of the source directory"
> -	echo "  output_header       Path to the generated header file"
> -	echo "  shader_file(s)      One or more shader files to embed in the header"
> -	exit 1
> -}
> -
> -if [ $# -lt 4 ]; then
> -	echo "Error: Invalid argument count."
> -	usage
> -fi
> -
> -src_dir="$1"; shift
> -build_path="$1"; shift
> -
> -cat <<EOF > "$build_path"
> -/* SPDX-License-Identifier: LGPL-2.1-or-later */
> -/* This file is auto-generated, do not edit! */
> -
> -#pragma once
> -
> -EOF
> -
> -cat <<EOF >> "$build_path"
> -/*
> - * List the names of the shaders at the top of
> - * header for readability's sake
> - *
> -EOF
> -
> -for file in "$@"; do
> -	name=$(basename "$file" | tr '.' '_')
> -	echo "[SHADER-GEN] $name"
> -	echo " * unsigned char $name;" >> "$build_path"
> -done
> -
> -echo "*/" >> "$build_path"
> -
> -echo "/* Hex encoded shader data */" >> "$build_path"
> -for file in "$@"; do
> -	name=$(basename "$file")
> -	"$src_dir/utils/gen-shader-header.py" "$name" "$file" >> "$build_path"
> -	echo >> "$build_path"
> -done
> diff --git a/utils/meson.build b/utils/meson.build
> index 9c598793035c..17a7aa7c3f5e 100644
> --- a/utils/meson.build
> +++ b/utils/meson.build
> @@ -3,7 +3,7 @@
>  subdir('codegen')
>  subdir('ipu3')
>  
> -gen_shader_headers = files('gen-shader-headers.sh')
> +gen_shader_headers = files('gen-shader-headers.py')
>  
>  ## Module signing
>  gen_ipa_priv_key = files('gen-ipa-priv-key.sh')
Barnabás Pőcze June 30, 2026, 10:47 a.m. UTC | #2
2026. 06. 30. 10:30 keltezéssel, Laurent Pinchart írta:
> The shader header is generated by a combination of a shell script and a
> Python script. Simplify this by merging everything into a single script.
> 
> The output of the old and new script only differ in white spaces.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
>   src/libcamera/shaders/meson.build |  2 +-
>   utils/gen-shader-header.py        | 37 ----------------
>   utils/gen-shader-headers.py       | 71 +++++++++++++++++++++++++++++++
>   utils/gen-shader-headers.sh       | 54 -----------------------
>   utils/meson.build                 |  2 +-
>   5 files changed, 73 insertions(+), 93 deletions(-)
>   delete mode 100755 utils/gen-shader-header.py
>   create mode 100755 utils/gen-shader-headers.py
>   delete mode 100755 utils/gen-shader-headers.sh
> 
> diff --git a/src/libcamera/shaders/meson.build b/src/libcamera/shaders/meson.build
> index adac77327a3b..4f4e8da607c7 100644
> --- a/src/libcamera/shaders/meson.build
> +++ b/src/libcamera/shaders/meson.build
> @@ -14,7 +14,7 @@ libcamera_shader_headers = custom_target(
>       'gen-shader-headers',
>       input : [shader_files],
>       output : 'glsl_shaders.h',
> -    command : [gen_shader_headers, meson.project_source_root(), '@OUTPUT@', '@INPUT@'],
> +    command : [gen_shader_headers, '-o', '@OUTPUT@', '@INPUT@'],
>   )
>   
>   libcamera_internal_headers += libcamera_shader_headers
> diff --git a/utils/gen-shader-header.py b/utils/gen-shader-header.py
> deleted file mode 100755
> index 745852b4c03f..000000000000
> --- a/utils/gen-shader-header.py
> +++ /dev/null
> @@ -1,37 +0,0 @@
> -#!/usr/bin/env python3
> -# SPDX-License-Identifier: GPL-2.0-or-later
> -# Copyright (C) 2025, Bryan O'Donoghue.
> -#
> -# Author: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
> -#
> -# A Python script which takes a list of shader files and converts each of them
> -# into a C header.
> -#
> -import sys
> -
> -try:
> -    with open(sys.argv[2], "rb") as file:
> -        data = file.read()
> -        data_len = len(data)
> -
> -        name = sys.argv[1].replace(".", "_")
> -        name_len = name + "_len"
> -
> -        j = 0
> -        print("unsigned char const", name, "[] = {")
> -        for ch in data:
> -            print(f"0x{ch:02x}, ", end="")
> -            j = (j + 1) % 16
> -            if j == 0:
> -                print()
> -        if j != 0:
> -            print()
> -        print("};")
> -
> -        print()
> -        print(f"const unsigned int {name_len}={data_len};")
> -
> -except FileNotFoundError:
> -    print(f"File {sys.argv[2]} not found", file=sys.stderr)
> -except IOError:
> -    print(f"Unable to read {sys.argv[2]}", file=sys.stderr)
> diff --git a/utils/gen-shader-headers.py b/utils/gen-shader-headers.py
> new file mode 100755
> index 000000000000..908217a2bd2e
> --- /dev/null
> +++ b/utils/gen-shader-headers.py
> @@ -0,0 +1,71 @@
> +#!/usr/bin/env python3
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +#
> +# Copyright (C) 2025, Bryan O'Donoghue
> +# Copyright (C) 2026, Ideas on Board Oy
> +#
> +# Generate a C header file containing hex-encoded shader sources
> +
> +import argparse
> +import binascii
> +import math
> +import os
> +import sys
> +
> +
> +def process_file(name, out):
> +    data = open(name, 'rb').read()
> +
> +    hex_data = [f'0x{c:02x}' for c in data]
> +    var_name = os.path.basename(name).replace('.', '_')
> +
> +    out.write(f'unsigned char const {var_name}[] = {{\n')
> +
> +    for i in range(math.ceil(len(data) / 16)):

I wanted to suggest `itertools.batched()`, but I am afraid that is too new (python 3.12).


> +        out.write('\t')
> +        out.write(', '.join(hex_data[16 * i:16 * (i + 1)]))
> +        out.write(',\n')
> +
> +    out.write('};\n\n')
> +    out.write(f'const unsigned int {var_name}_len = {len(data)};\n')
> +
> +
> +def main(argv):
> +    parser = argparse.ArgumentParser(
> +        description='Generate a C header file containing hex-encoded shader sources')
> +    parser.add_argument('--output', '-o', metavar='file', default=sys.stdout,
> +                        type=argparse.FileType('w', encoding='utf-8'),
> +                        help='Output file name. Defaults to standard output if not specified.')
> +    parser.add_argument('input', nargs='+', type=str,

Could be `type=pathlib.Path` to avoid `os.path` stuff.


> +                        help='Input file names.')
> +    args = parser.parse_args(argv[1:])
> +
> +    args.output.write('''/* SPDX-License-Identifier: LGPL-2.1-or-later */

args.output.write(
'''\
/* SPDX-License-Identifier: LGPL-2.1-or-later */

is an option to avoid having the first line be indented.


> +/* This file is auto-generated, do not edit! */
> +
> +#pragma once
> +
> +/*
> + * List the names of the shaders at the top of header for readability's sake.
> + *
> +''')
> +
> +    for name in args.input:
> +        name = os.path.basename(name).replace('.', '_')
> +        args.output.write(f' * unsigned char {name};\n')

I think the "unsigned char" part should be removed.


> +
> +    args.output.write(''' */
> +
> +/* Hex encoded shader data */
> +''')
> +
> +    for name in args.input:
> +        process_file(name, args.output)
> +        args.output.write('\n')
> +
> +    return 0
> +
> +
> +if __name__ == '__main__':
> +    sys.exit(main(sys.argv))
> +
> diff --git a/utils/gen-shader-headers.sh b/utils/gen-shader-headers.sh
> deleted file mode 100755
> index 0d6649521a7a..000000000000
> --- a/utils/gen-shader-headers.sh
> +++ /dev/null
> @@ -1,54 +0,0 @@
> -#!/bin/sh
> -# SPDX-License-Identifier: GPL-2.0-or-later
> -
> -set -e
> -
> -usage() {
> -	echo "Usage: $0 <src_dir> <output_header> <shader_file1> [shader_file2 ...]"
> -	echo
> -	echo "Generates a C header file containing hex-encoded shader data."
> -	echo
> -	echo "Arguments:"
> -	echo "  src_dir             Path to the base of the source directory"
> -	echo "  output_header       Path to the generated header file"
> -	echo "  shader_file(s)      One or more shader files to embed in the header"
> -	exit 1
> -}
> -
> -if [ $# -lt 4 ]; then
> -	echo "Error: Invalid argument count."
> -	usage
> -fi
> -
> -src_dir="$1"; shift
> -build_path="$1"; shift
> -
> -cat <<EOF > "$build_path"
> -/* SPDX-License-Identifier: LGPL-2.1-or-later */
> -/* This file is auto-generated, do not edit! */
> -
> -#pragma once
> -
> -EOF
> -
> -cat <<EOF >> "$build_path"
> -/*
> - * List the names of the shaders at the top of
> - * header for readability's sake
> - *
> -EOF
> -
> -for file in "$@"; do
> -	name=$(basename "$file" | tr '.' '_')
> -	echo "[SHADER-GEN] $name"
> -	echo " * unsigned char $name;" >> "$build_path"
> -done
> -
> -echo "*/" >> "$build_path"
> -
> -echo "/* Hex encoded shader data */" >> "$build_path"
> -for file in "$@"; do
> -	name=$(basename "$file")
> -	"$src_dir/utils/gen-shader-header.py" "$name" "$file" >> "$build_path"
> -	echo >> "$build_path"
> -done
> diff --git a/utils/meson.build b/utils/meson.build
> index 9c598793035c..17a7aa7c3f5e 100644
> --- a/utils/meson.build
> +++ b/utils/meson.build
> @@ -3,7 +3,7 @@
>   subdir('codegen')
>   subdir('ipu3')
>   
> -gen_shader_headers = files('gen-shader-headers.sh')
> +gen_shader_headers = files('gen-shader-headers.py')
>   
>   ## Module signing
>   gen_ipa_priv_key = files('gen-ipa-priv-key.sh')

Reviewed-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>
Laurent Pinchart June 30, 2026, 11:03 a.m. UTC | #3
On Tue, Jun 30, 2026 at 12:47:22PM +0200, Barnabás Pőcze wrote:
> 2026. 06. 30. 10:30 keltezéssel, Laurent Pinchart írta:
> > The shader header is generated by a combination of a shell script and a
> > Python script. Simplify this by merging everything into a single script.
> > 
> > The output of the old and new script only differ in white spaces.
> > 
> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > ---
> >   src/libcamera/shaders/meson.build |  2 +-
> >   utils/gen-shader-header.py        | 37 ----------------
> >   utils/gen-shader-headers.py       | 71 +++++++++++++++++++++++++++++++
> >   utils/gen-shader-headers.sh       | 54 -----------------------
> >   utils/meson.build                 |  2 +-
> >   5 files changed, 73 insertions(+), 93 deletions(-)
> >   delete mode 100755 utils/gen-shader-header.py
> >   create mode 100755 utils/gen-shader-headers.py
> >   delete mode 100755 utils/gen-shader-headers.sh
> > 
> > diff --git a/src/libcamera/shaders/meson.build b/src/libcamera/shaders/meson.build
> > index adac77327a3b..4f4e8da607c7 100644
> > --- a/src/libcamera/shaders/meson.build
> > +++ b/src/libcamera/shaders/meson.build
> > @@ -14,7 +14,7 @@ libcamera_shader_headers = custom_target(
> >       'gen-shader-headers',
> >       input : [shader_files],
> >       output : 'glsl_shaders.h',
> > -    command : [gen_shader_headers, meson.project_source_root(), '@OUTPUT@', '@INPUT@'],
> > +    command : [gen_shader_headers, '-o', '@OUTPUT@', '@INPUT@'],
> >   )
> >   
> >   libcamera_internal_headers += libcamera_shader_headers
> > diff --git a/utils/gen-shader-header.py b/utils/gen-shader-header.py
> > deleted file mode 100755
> > index 745852b4c03f..000000000000
> > --- a/utils/gen-shader-header.py
> > +++ /dev/null
> > @@ -1,37 +0,0 @@
> > -#!/usr/bin/env python3
> > -# SPDX-License-Identifier: GPL-2.0-or-later
> > -# Copyright (C) 2025, Bryan O'Donoghue.
> > -#
> > -# Author: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
> > -#
> > -# A Python script which takes a list of shader files and converts each of them
> > -# into a C header.
> > -#
> > -import sys
> > -
> > -try:
> > -    with open(sys.argv[2], "rb") as file:
> > -        data = file.read()
> > -        data_len = len(data)
> > -
> > -        name = sys.argv[1].replace(".", "_")
> > -        name_len = name + "_len"
> > -
> > -        j = 0
> > -        print("unsigned char const", name, "[] = {")
> > -        for ch in data:
> > -            print(f"0x{ch:02x}, ", end="")
> > -            j = (j + 1) % 16
> > -            if j == 0:
> > -                print()
> > -        if j != 0:
> > -            print()
> > -        print("};")
> > -
> > -        print()
> > -        print(f"const unsigned int {name_len}={data_len};")
> > -
> > -except FileNotFoundError:
> > -    print(f"File {sys.argv[2]} not found", file=sys.stderr)
> > -except IOError:
> > -    print(f"Unable to read {sys.argv[2]}", file=sys.stderr)
> > diff --git a/utils/gen-shader-headers.py b/utils/gen-shader-headers.py
> > new file mode 100755
> > index 000000000000..908217a2bd2e
> > --- /dev/null
> > +++ b/utils/gen-shader-headers.py
> > @@ -0,0 +1,71 @@
> > +#!/usr/bin/env python3
> > +# SPDX-License-Identifier: GPL-2.0-or-later
> > +#
> > +# Copyright (C) 2025, Bryan O'Donoghue
> > +# Copyright (C) 2026, Ideas on Board Oy
> > +#
> > +# Generate a C header file containing hex-encoded shader sources
> > +
> > +import argparse
> > +import binascii
> > +import math
> > +import os
> > +import sys
> > +
> > +
> > +def process_file(name, out):
> > +    data = open(name, 'rb').read()
> > +
> > +    hex_data = [f'0x{c:02x}' for c in data]
> > +    var_name = os.path.basename(name).replace('.', '_')
> > +
> > +    out.write(f'unsigned char const {var_name}[] = {{\n')
> > +
> > +    for i in range(math.ceil(len(data) / 16)):
> 
> I wanted to suggest `itertools.batched()`, but I am afraid that is too new (python 3.12).

Indeed, but thanks for the suggestion. I didn't know about it.

> > +        out.write('\t')
> > +        out.write(', '.join(hex_data[16 * i:16 * (i + 1)]))
> > +        out.write(',\n')
> > +
> > +    out.write('};\n\n')
> > +    out.write(f'const unsigned int {var_name}_len = {len(data)};\n')
> > +
> > +
> > +def main(argv):
> > +    parser = argparse.ArgumentParser(
> > +        description='Generate a C header file containing hex-encoded shader sources')
> > +    parser.add_argument('--output', '-o', metavar='file', default=sys.stdout,
> > +                        type=argparse.FileType('w', encoding='utf-8'),
> > +                        help='Output file name. Defaults to standard output if not specified.')
> > +    parser.add_argument('input', nargs='+', type=str,
> 
> Could be `type=pathlib.Path` to avoid `os.path` stuff.

I'll give that a try.

> > +                        help='Input file names.')
> > +    args = parser.parse_args(argv[1:])
> > +
> > +    args.output.write('''/* SPDX-License-Identifier: LGPL-2.1-or-later */
> 
> args.output.write(
> '''\
> /* SPDX-License-Identifier: LGPL-2.1-or-later */
> 
> is an option to avoid having the first line be indented.

OK.

Manual string manipulation isn't nice. I considered using jinja2
templates, but decided it wasn't worth the hassle.

> > +/* This file is auto-generated, do not edit! */
> > +
> > +#pragma once
> > +
> > +/*
> > + * List the names of the shaders at the top of header for readability's sake.
> > + *
> > +''')
> > +
> > +    for name in args.input:
> > +        name = os.path.basename(name).replace('.', '_')
> > +        args.output.write(f' * unsigned char {name};\n')
> 
> I think the "unsigned char" part should be removed.

I think so too, I'll do it in a separate patch as I wanted to minimize
the impact on the generated header here.

> > +
> > +    args.output.write(''' */
> > +
> > +/* Hex encoded shader data */
> > +''')
> > +
> > +    for name in args.input:
> > +        process_file(name, args.output)
> > +        args.output.write('\n')
> > +
> > +    return 0
> > +
> > +
> > +if __name__ == '__main__':
> > +    sys.exit(main(sys.argv))
> > +
> > diff --git a/utils/gen-shader-headers.sh b/utils/gen-shader-headers.sh
> > deleted file mode 100755
> > index 0d6649521a7a..000000000000
> > --- a/utils/gen-shader-headers.sh
> > +++ /dev/null
> > @@ -1,54 +0,0 @@
> > -#!/bin/sh
> > -# SPDX-License-Identifier: GPL-2.0-or-later
> > -
> > -set -e
> > -
> > -usage() {
> > -	echo "Usage: $0 <src_dir> <output_header> <shader_file1> [shader_file2 ...]"
> > -	echo
> > -	echo "Generates a C header file containing hex-encoded shader data."
> > -	echo
> > -	echo "Arguments:"
> > -	echo "  src_dir             Path to the base of the source directory"
> > -	echo "  output_header       Path to the generated header file"
> > -	echo "  shader_file(s)      One or more shader files to embed in the header"
> > -	exit 1
> > -}
> > -
> > -if [ $# -lt 4 ]; then
> > -	echo "Error: Invalid argument count."
> > -	usage
> > -fi
> > -
> > -src_dir="$1"; shift
> > -build_path="$1"; shift
> > -
> > -cat <<EOF > "$build_path"
> > -/* SPDX-License-Identifier: LGPL-2.1-or-later */
> > -/* This file is auto-generated, do not edit! */
> > -
> > -#pragma once
> > -
> > -EOF
> > -
> > -cat <<EOF >> "$build_path"
> > -/*
> > - * List the names of the shaders at the top of
> > - * header for readability's sake
> > - *
> > -EOF
> > -
> > -for file in "$@"; do
> > -	name=$(basename "$file" | tr '.' '_')
> > -	echo "[SHADER-GEN] $name"
> > -	echo " * unsigned char $name;" >> "$build_path"
> > -done
> > -
> > -echo "*/" >> "$build_path"
> > -
> > -echo "/* Hex encoded shader data */" >> "$build_path"
> > -for file in "$@"; do
> > -	name=$(basename "$file")
> > -	"$src_dir/utils/gen-shader-header.py" "$name" "$file" >> "$build_path"
> > -	echo >> "$build_path"
> > -done
> > diff --git a/utils/meson.build b/utils/meson.build
> > index 9c598793035c..17a7aa7c3f5e 100644
> > --- a/utils/meson.build
> > +++ b/utils/meson.build
> > @@ -3,7 +3,7 @@
> >   subdir('codegen')
> >   subdir('ipu3')
> >   
> > -gen_shader_headers = files('gen-shader-headers.sh')
> > +gen_shader_headers = files('gen-shader-headers.py')
> >   
> >   ## Module signing
> >   gen_ipa_priv_key = files('gen-ipa-priv-key.sh')
> 
> Reviewed-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>
Bryan O'Donoghue June 30, 2026, 11:49 a.m. UTC | #4
On 30/06/2026 09:30, Laurent Pinchart wrote:
> -    command : [gen_shader_headers, meson.project_source_root(), '@OUTPUT@', '@INPUT@'],
> +    command : [gen_shader_headers, '-o', '@OUTPUT@', '@INPUT@'],

I'm not a meson exprt, this was genuinely my first time wring meson 
stuff - as I recall though meson.project_source_root() fixed an issue 
for me where instead of say `meson setup build` it was `meson setup 
builds/somebuild`

Does your series survive moving to a sub-directory as above ?

---
bod
Laurent Pinchart June 30, 2026, 12:04 p.m. UTC | #5
On Tue, Jun 30, 2026 at 12:49:49PM +0100, Bryan O'Donoghue wrote:
> On 30/06/2026 09:30, Laurent Pinchart wrote:
> > -    command : [gen_shader_headers, meson.project_source_root(), '@OUTPUT@', '@INPUT@'],
> > +    command : [gen_shader_headers, '-o', '@OUTPUT@', '@INPUT@'],
> 
> I'm not a meson exprt, this was genuinely my first time wring meson 
> stuff - as I recall though meson.project_source_root() fixed an issue 
> for me where instead of say `meson setup build` it was `meson setup 
> builds/somebuild`
> 
> Does your series survive moving to a sub-directory as above ?

It does, I also build in build/something/.
Bryan O'Donoghue June 30, 2026, 12:27 p.m. UTC | #6
On 30/06/2026 09:30, Laurent Pinchart wrote:
> The shader header is generated by a combination of a shell script and a
> Python script. Simplify this by merging everything into a single script.
> 
> The output of the old and new script only differ in white spaces.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>

---
bod

Patch
diff mbox series

diff --git a/src/libcamera/shaders/meson.build b/src/libcamera/shaders/meson.build
index adac77327a3b..4f4e8da607c7 100644
--- a/src/libcamera/shaders/meson.build
+++ b/src/libcamera/shaders/meson.build
@@ -14,7 +14,7 @@  libcamera_shader_headers = custom_target(
     'gen-shader-headers',
     input : [shader_files],
     output : 'glsl_shaders.h',
-    command : [gen_shader_headers, meson.project_source_root(), '@OUTPUT@', '@INPUT@'],
+    command : [gen_shader_headers, '-o', '@OUTPUT@', '@INPUT@'],
 )
 
 libcamera_internal_headers += libcamera_shader_headers
diff --git a/utils/gen-shader-header.py b/utils/gen-shader-header.py
deleted file mode 100755
index 745852b4c03f..000000000000
--- a/utils/gen-shader-header.py
+++ /dev/null
@@ -1,37 +0,0 @@ 
-#!/usr/bin/env python3
-# SPDX-License-Identifier: GPL-2.0-or-later
-# Copyright (C) 2025, Bryan O'Donoghue.
-#
-# Author: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
-#
-# A Python script which takes a list of shader files and converts each of them
-# into a C header.
-#
-import sys
-
-try:
-    with open(sys.argv[2], "rb") as file:
-        data = file.read()
-        data_len = len(data)
-
-        name = sys.argv[1].replace(".", "_")
-        name_len = name + "_len"
-
-        j = 0
-        print("unsigned char const", name, "[] = {")
-        for ch in data:
-            print(f"0x{ch:02x}, ", end="")
-            j = (j + 1) % 16
-            if j == 0:
-                print()
-        if j != 0:
-            print()
-        print("};")
-
-        print()
-        print(f"const unsigned int {name_len}={data_len};")
-
-except FileNotFoundError:
-    print(f"File {sys.argv[2]} not found", file=sys.stderr)
-except IOError:
-    print(f"Unable to read {sys.argv[2]}", file=sys.stderr)
diff --git a/utils/gen-shader-headers.py b/utils/gen-shader-headers.py
new file mode 100755
index 000000000000..908217a2bd2e
--- /dev/null
+++ b/utils/gen-shader-headers.py
@@ -0,0 +1,71 @@ 
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (C) 2025, Bryan O'Donoghue
+# Copyright (C) 2026, Ideas on Board Oy
+#
+# Generate a C header file containing hex-encoded shader sources
+
+import argparse
+import binascii
+import math
+import os
+import sys
+
+
+def process_file(name, out):
+    data = open(name, 'rb').read()
+
+    hex_data = [f'0x{c:02x}' for c in data]
+    var_name = os.path.basename(name).replace('.', '_')
+
+    out.write(f'unsigned char const {var_name}[] = {{\n')
+
+    for i in range(math.ceil(len(data) / 16)):
+        out.write('\t')
+        out.write(', '.join(hex_data[16 * i:16 * (i + 1)]))
+        out.write(',\n')
+
+    out.write('};\n\n')
+    out.write(f'const unsigned int {var_name}_len = {len(data)};\n')
+
+
+def main(argv):
+    parser = argparse.ArgumentParser(
+        description='Generate a C header file containing hex-encoded shader sources')
+    parser.add_argument('--output', '-o', metavar='file', default=sys.stdout,
+                        type=argparse.FileType('w', encoding='utf-8'),
+                        help='Output file name. Defaults to standard output if not specified.')
+    parser.add_argument('input', nargs='+', type=str,
+                        help='Input file names.')
+    args = parser.parse_args(argv[1:])
+
+    args.output.write('''/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/* This file is auto-generated, do not edit! */
+
+#pragma once
+
+/*
+ * List the names of the shaders at the top of header for readability's sake.
+ *
+''')
+
+    for name in args.input:
+        name = os.path.basename(name).replace('.', '_')
+        args.output.write(f' * unsigned char {name};\n')
+
+    args.output.write(''' */
+
+/* Hex encoded shader data */
+''')
+
+    for name in args.input:
+        process_file(name, args.output)
+        args.output.write('\n')
+
+    return 0
+
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv))
+
diff --git a/utils/gen-shader-headers.sh b/utils/gen-shader-headers.sh
deleted file mode 100755
index 0d6649521a7a..000000000000
--- a/utils/gen-shader-headers.sh
+++ /dev/null
@@ -1,54 +0,0 @@ 
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0-or-later
-
-set -e
-
-usage() {
-	echo "Usage: $0 <src_dir> <output_header> <shader_file1> [shader_file2 ...]"
-	echo
-	echo "Generates a C header file containing hex-encoded shader data."
-	echo
-	echo "Arguments:"
-	echo "  src_dir             Path to the base of the source directory"
-	echo "  output_header       Path to the generated header file"
-	echo "  shader_file(s)      One or more shader files to embed in the header"
-	exit 1
-}
-
-if [ $# -lt 4 ]; then
-	echo "Error: Invalid argument count."
-	usage
-fi
-
-src_dir="$1"; shift
-build_path="$1"; shift
-
-cat <<EOF > "$build_path"
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/* This file is auto-generated, do not edit! */
-
-#pragma once
-
-EOF
-
-cat <<EOF >> "$build_path"
-/*
- * List the names of the shaders at the top of
- * header for readability's sake
- *
-EOF
-
-for file in "$@"; do
-	name=$(basename "$file" | tr '.' '_')
-	echo "[SHADER-GEN] $name"
-	echo " * unsigned char $name;" >> "$build_path"
-done
-
-echo "*/" >> "$build_path"
-
-echo "/* Hex encoded shader data */" >> "$build_path"
-for file in "$@"; do
-	name=$(basename "$file")
-	"$src_dir/utils/gen-shader-header.py" "$name" "$file" >> "$build_path"
-	echo >> "$build_path"
-done
diff --git a/utils/meson.build b/utils/meson.build
index 9c598793035c..17a7aa7c3f5e 100644
--- a/utils/meson.build
+++ b/utils/meson.build
@@ -3,7 +3,7 @@ 
 subdir('codegen')
 subdir('ipu3')
 
-gen_shader_headers = files('gen-shader-headers.sh')
+gen_shader_headers = files('gen-shader-headers.py')
 
 ## Module signing
 gen_ipa_priv_key = files('gen-ipa-priv-key.sh')