From 72b0516e3b21efad52bb345d4684abb43175ebf9 Mon Sep 17 00:00:00 2001 From: Frederic Plourde Date: Thu, 15 Jan 2026 13:32:01 -0500 Subject: [PATCH 1/6] Build separate runtime and client extension support pages --- Makefile | 12 +- extension_support_report.py | 5 +- openxr_inventory/extensions.py | 74 ++++++ .../client_extension_support.jinja2.html | 249 ++++++++++++++++++ .../runtime_extension_support.jinja2.html | 236 +++++++++++++++++ 5 files changed, 571 insertions(+), 5 deletions(-) create mode 100644 openxr_inventory/templates/client_extension_support.jinja2.html create mode 100644 openxr_inventory/templates/runtime_extension_support.jinja2.html diff --git a/Makefile b/Makefile index ac64584..190f835 100644 --- a/Makefile +++ b/Makefile @@ -3,10 +3,13 @@ # # SPDX-License-Identifier: Apache-2.0 -HTML_REPORT_FILES := public/extension_support.html +HTML_REPORT_FILES := public/runtime_extension_support.html public/client_extension_support.html SHARED_DEPS := $(wildcard openxr_inventory/*.py) \ $(wildcard runtimes/*.json) \ - openxr_inventory/templates/base.jinja2.html + $(wildcard clients/*.json) \ + openxr_inventory/templates/base.jinja2.html \ + openxr_inventory/templates/runtime_extension_support.jinja2.html \ + openxr_inventory/templates/client_extension_support.jinja2.html all: $(HTML_REPORT_FILES) @@ -15,5 +18,8 @@ all: $(HTML_REPORT_FILES) public: mkdir -p $@ -$(HTML_REPORT_FILES): public/%.html : %_report.py openxr_inventory/templates/%.jinja2.html public $(SHARED_DEPS) +public/runtime_extension_support.html: extension_support_report.py public $(SHARED_DEPS) + python3 $< + +public/client_extension_support.html: extension_support_report.py public $(SHARED_DEPS) python3 $< diff --git a/extension_support_report.py b/extension_support_report.py index c20176f..dced260 100755 --- a/extension_support_report.py +++ b/extension_support_report.py @@ -3,11 +3,12 @@ # # SPDX-License-Identifier: Apache-2.0 -from openxr_inventory.extensions import generate_report +from openxr_inventory.extensions import generate_report, generate_runtime_report, generate_client_report from openxr_inventory.runtime_inventory import load_all_runtimes from openxr_inventory.client_inventory import load_all_clients if __name__ == "__main__": runtimes = load_all_runtimes() clients = load_all_clients() - generate_report(runtimes, clients) + generate_runtime_report(runtimes, clients) + generate_client_report(runtimes, clients) diff --git a/openxr_inventory/extensions.py b/openxr_inventory/extensions.py index d222ae1..dec5cca 100644 --- a/openxr_inventory/extensions.py +++ b/openxr_inventory/extensions.py @@ -249,6 +249,78 @@ def generate_report( fp.write(contents) +def generate_runtime_report( + runtimes: List[RuntimeData], + clients: List[ClientData], + template_filename: str = "runtime_extension_support.jinja2.html", + out_filename: str = "public/runtime_extension_support.html", +): + """ + Write an HTML file containing information about runtime extension support. + """ + from .inventory_jinja import make_jinja_environment + + env = make_jinja_environment() + env.globals["cat"] = ExtensionCategory + env.globals["cat_captions"] = _category_captions + env.globals["categorize_ext"] = categorize_ext_name + template = env.get_template(template_filename) + spec_url = "https://www.khronos.org/registry/OpenXR/specs/1.1/html/xrspec.html" + contents = template.render( + extensions=compute_known_extensions(runtimes, clients), + extension_support=compute_extension_support(runtimes, clients), + runtime_support=compute_runtime_support(runtimes), + client_support=compute_client_support(clients), + known_form_factors=compute_known_form_factors(runtimes, clients), + form_factor_support=compute_form_factor_support(runtimes, clients), + runtimes=runtimes, + clients=clients, + spec_url=spec_url, + ) + + if contents: + out_file = Path(__file__).parent.parent / out_filename + print("Writing {}".format(out_file)) + with open(out_file, "w", encoding="utf-8") as fp: + fp.write(contents) + + +def generate_client_report( + runtimes: List[RuntimeData], + clients: List[ClientData], + template_filename: str = "client_extension_support.jinja2.html", + out_filename: str = "public/client_extension_support.html", +): + """ + Write an HTML file containing information about client extension support. + """ + from .inventory_jinja import make_jinja_environment + + env = make_jinja_environment() + env.globals["cat"] = ExtensionCategory + env.globals["cat_captions"] = _category_captions + env.globals["categorize_ext"] = categorize_ext_name + template = env.get_template(template_filename) + spec_url = "https://www.khronos.org/registry/OpenXR/specs/1.1/html/xrspec.html" + contents = template.render( + extensions=compute_known_extensions(runtimes, clients), + extension_support=compute_extension_support(runtimes, clients), + runtime_support=compute_runtime_support(runtimes), + client_support=compute_client_support(clients), + known_form_factors=compute_known_form_factors(runtimes, clients), + form_factor_support=compute_form_factor_support(runtimes, clients), + runtimes=runtimes, + clients=clients, + spec_url=spec_url, + ) + + if contents: + out_file = Path(__file__).parent.parent / out_filename + print("Writing {}".format(out_file)) + with open(out_file, "w", encoding="utf-8") as fp: + fp.write(contents) + + if __name__ == "__main__": from .runtime_inventory import load_all_runtimes from .client_inventory import load_all_clients @@ -256,3 +328,5 @@ def generate_report( runtimes = load_all_runtimes() clients = load_all_clients() generate_report(runtimes, clients) + generate_runtime_report(runtimes, clients) + generate_client_report(runtimes, clients) diff --git a/openxr_inventory/templates/client_extension_support.jinja2.html b/openxr_inventory/templates/client_extension_support.jinja2.html new file mode 100644 index 0000000..8111b71 --- /dev/null +++ b/openxr_inventory/templates/client_extension_support.jinja2.html @@ -0,0 +1,249 @@ +{# +Copyright 2022, The Khronos Group Inc. + +SPDX-License-Identifier: CC-BY-4.0 +#} + +{% extends "base.jinja2.html" %} +{% block title -%} + OpenXR Client Extension Support Report +{%- endblock title %} + +{% block navbar_brand_text -%} + OpenXR Client Extension Support Report +{%- endblock navbar_brand_text %} + +{% block navbar_list_items %} +
  • Extensions
  • +
  • Clients
  • +
  • Client Support Matrix
  • +{% endblock navbar_list_items %} + +{% block style %} +{{ super() }} + +table.table-sticky-col-headers thead tr { + position: sticky; + background: white; + z-index: 2; + /* from min height of nav bar */ + top: 50px; +} + +th.rotate { + height: 170px; + white-space: nowrap; +} + +th.rotate > div { + transform: rotate(-45deg); + width: 32px; + padding: 5px; +} + +{% endblock style %} + +{% block container_contents %} +
    + + +
    +

    Extensions

    + {% for col in extensions | slice(3) %} +
    + +
    + {% endfor %} +
    + + {% for extension_name in extensions %} + {% set support = extension_support[extension_name] %} + +
    +

    {{ extension_name }} ({{ support.client_count }} client{{ "s" if support.client_count != 1 }})

    +

    + Specification + for {{ extension_name }} +

    + {% if support.client_count > 0 %} + Clients:
    + + {% else %} +

    No clients support this extension.

    + {% endif %} +
    + {% endfor %} +
    + +
    + +
    +

    Clients

    + + +
    + + {% for client in clients %} +
    +

    {{ client.name }}

    +
      +
    • Vendor: {{ client.vendor }}
    • + {% if client.notes %} +
    • Notes: {{ client.notes }}
    • + {% endif %} + {% for component in client.components %} +
    • Component: {{ component.name }}
      + {% if component.notes %} + Notes: {{ component.notes }}
      + {% endif %} + Extensions: +
        + {% for extension in component.extensions %} +
      • {{extension.name}} {% if extension.notes %} - {{ extension.notes }} {% endif %}
      • + {% endfor %} +
      +
    • + {% endfor %} +
    +
    + {% endfor %} +
    + +
    +
    +

    Client support matrix

    +
    + + + + + {% for client in clients | sort %} + {# pragmatic check if the client name fits in the layout or if it needs to be truncated and put the full name in tooltip #} + + {% endfor %} + + + + + {% macro extension_matrix_row(extension_name) %} + + + {% for client in clients | sort %} + {% set components = client.get_component_for_extension(extension_name) %} + {% if components|length > 0 %} + + {% else %} + + {% endif %} + {% endfor %} + + {% endmacro %} + + {# Loop through all categories of extension (KHR, EXT, vendor, KHX, EXTX, Vendor-X) #} + {% for c in cat.all_categories() %} + {# Loop through all extensions in that category #} + {% for extension_name in extensions if categorize_ext(extension_name) == c %} + {% if loop.first %} + {# this header is inside the loop so it is skipped if we have no items in this category #} + {# it is inside this "if" so it only shows up once for each category. #} + + + + {% endif %} + {# Write out a row in the table for this extension #} + {{ extension_matrix_row(extension_name) }} + {% endfor %} + {% endfor %} + + + + + + {% for ff, view_configurations in known_form_factors.items() %} + + + + {% for client in clients | sort %} + + {% endfor %} + + + {% for vc, environment_blend_modes in view_configurations.items() %} + + + + {% for client in clients | sort %} + + {% endfor %} + + {% for ebm in environment_blend_modes %} + + + {% for client in clients | sort %} + {% if ff in form_factor_support[client.name] and vc in form_factor_support[client.name][ff] and ebm in form_factor_support[client.name][ff][vc] %} + + {% else %} + + {% endif %} + {% endfor %} + + {% endfor %} + + + {% endfor %} + + {% endfor %} + + +
    + {% if client.name|length < 34 %} + {{ client.name }} + {% else %} + {{ client.name|truncate(34, True) }} + {% endif %} + + +
    + {{ extension_name }} + + + + + {% for component in components %} + {{ component.abbreviation }} + {% if not loop.last %} +
    + {% endif %} + {% endfor %} +
    Not supported or not applicable
    {{ cat_captions[c] }} Extensions
    Client Features
    + {{ ff }} + + + +
    + → {{ vc }} + + + +
    + → → {{ ebm }} + + + + SupportedNot supported or not applicable
    +
    +{% endblock container_contents %} diff --git a/openxr_inventory/templates/runtime_extension_support.jinja2.html b/openxr_inventory/templates/runtime_extension_support.jinja2.html new file mode 100644 index 0000000..7d3debe --- /dev/null +++ b/openxr_inventory/templates/runtime_extension_support.jinja2.html @@ -0,0 +1,236 @@ +{# +Copyright 2022, The Khronos Group Inc. + +SPDX-License-Identifier: CC-BY-4.0 +#} + +{% extends "base.jinja2.html" %} +{% block title -%} + OpenXR Runtime Extension Support Report +{%- endblock title %} + +{% block navbar_brand_text -%} + OpenXR Runtime Extension Support Report +{%- endblock navbar_brand_text %} + +{% block navbar_list_items %} +
  • Extensions
  • +
  • Runtimes
  • +
  • Runtime Support Matrix
  • +{% endblock navbar_list_items %} + +{% block style %} +{{ super() }} + +table.table-sticky-col-headers thead tr { + position: sticky; + background: white; + z-index: 2; + /* from min height of nav bar */ + top: 50px; +} + +th.rotate { + height: 170px; + white-space: nowrap; +} + +th.rotate > div { + transform: rotate(-45deg); + width: 32px; + padding: 5px; +} + +{% endblock style %} + +{% block container_contents %} +
    + + +
    +

    Extensions

    + {% for col in extensions | slice(3) %} +
    + +
    + {% endfor %} +
    + + {% for extension_name in extensions %} + {% set support = extension_support[extension_name] %} + +
    +

    {{ extension_name }} ({{ support.runtime_count }} runtime{{ "s" if support.runtime_count != 1 }})

    +

    + Specification + for {{ extension_name }} +

    + Runtimes:
    + +
    + {% endfor %} +
    + +
    + +
    +

    Runtimes

    + + +
    + + {% for runtime in runtimes %} +
    +

    {{ runtime.name }}

    +
      +
    • Vendor: {{ runtime.vendor }}
    • + {% if runtime.conformance_submission %} +
    • Most recent conformance submission: #{{runtime.conformance_submission}}
    • + {% endif %} + {% if not runtime.conformance_submission %} +
    • Not a conformant runtime
    • + {% endif %} + {% if runtime.conformance_notes %} +
    • Conformance notes: {{ runtime.conformance_notes }}
    • + {% endif %} + {% if runtime.devices_notes %} +
    • Device support: {{ runtime.devices_notes }}
    • + {% endif %} +
    • Supported extensions: +
        + {% for extension in runtime.extensions %} +
      • {{extension.name}} {% if extension.notes %} - {{ extension.notes }} {% endif %}
      • + {% endfor %} +
      +
    • +
    +
    + {% endfor %} +
    + +
    +
    +

    Runtime support matrix

    +
    + + + + + {% for runtime in runtimes | sort %} + {# pragmatic check if the runtime name fits in the layout or if it needs to be truncated and put the full name in tooltip #} + {% if runtime.name|length < 34 %} + + {% else %} + + {% endif %} + {% endfor %} + + + + + {% macro extension_matrix_row(extension_name) %} + + + {% for runtime in runtimes | sort %} + {% if extension_name in runtime_support[runtime.name] %} + + {% else %} + + {% endif %} + {% endfor %} + + {% endmacro %} + + {# Loop through all categories of extension (KHR, EXT, vendor, KHX, EXTX, Vendor-X) #} + {% for c in cat.all_categories() %} + {# Loop through all extensions in that category #} + {% for extension_name in extensions if categorize_ext(extension_name) == c %} + {% if loop.first %} + {# this header is inside the loop so it is skipped if we have no items in this category #} + {# it is inside this "if" so it only shows up once for each category. #} + + + + {% endif %} + {# Write out a row in the table for this extension #} + {{ extension_matrix_row(extension_name) }} + {% endfor %} + {% endfor %} + + + + + + {% for ff, view_configurations in known_form_factors.items() %} + + + + {% for runtime in runtimes | sort %} + + {% endfor %} + + + {% for vc, environment_blend_modes in view_configurations.items() %} + + + + {% for runtime in runtimes | sort %} + + {% endfor %} + + {% for ebm in environment_blend_modes %} + + + {% for runtime in runtimes | sort %} + {% if ff in form_factor_support[runtime.name] and vc in form_factor_support[runtime.name][ff] and ebm in form_factor_support[runtime.name][ff][vc] %} + + {% else %} + + {% endif %} + {% endfor %} + + {% endfor %} + + + {% endfor %} + + {% endfor %} + + +
    {{ runtime.name }}
    {{ runtime.name|truncate(34, True) }}
    + {{ extension_name }} + + + + SupportedNot supported or not applicable
    {{ cat_captions[c] }} Extensions
    Runtime Features
    + {{ ff }} + + + +
    + → {{ vc }} + + + +
    + → → {{ ebm }} + + + + SupportedNot supported or not applicable
    +
    +{% endblock container_contents %} From 7929430f391b5268df3c3491c529e1290d939ab6 Mon Sep 17 00:00:00 2001 From: Frederic Plourde Date: Mon, 19 Jan 2026 14:54:01 -0500 Subject: [PATCH 2/6] Update CI configuration to include runtime and client --- .gitlab-ci.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4f92c01..024dcc0 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -19,8 +19,10 @@ verify_and_build: - python3 -m pip install -r requirements.txt script: - ./verify_schema.sh - - ./extension_support_report.py + - make artifacts: paths: - public/extension_support.html - expose_as: "Extension Support Report" + - public/runtime_extension_support.html + - public/client_extension_support.html + expose_as: "Extension Support Reports" From 1f91ca101c47578d144fec4e1a9184e4c5fbd568 Mon Sep 17 00:00:00 2001 From: Frederic Plourde Date: Thu, 15 Jan 2026 13:39:54 -0500 Subject: [PATCH 3/6] Remove usused components --- extension_support_report.py | 2 +- openxr_inventory/extensions.py | 41 -- .../templates/extension_support.jinja2.html | 410 ------------------ 3 files changed, 1 insertion(+), 452 deletions(-) delete mode 100644 openxr_inventory/templates/extension_support.jinja2.html diff --git a/extension_support_report.py b/extension_support_report.py index dced260..6f7b750 100755 --- a/extension_support_report.py +++ b/extension_support_report.py @@ -3,7 +3,7 @@ # # SPDX-License-Identifier: Apache-2.0 -from openxr_inventory.extensions import generate_report, generate_runtime_report, generate_client_report +from openxr_inventory.extensions import generate_runtime_report, generate_client_report from openxr_inventory.runtime_inventory import load_all_runtimes from openxr_inventory.client_inventory import load_all_clients diff --git a/openxr_inventory/extensions.py b/openxr_inventory/extensions.py index dec5cca..8b14690 100644 --- a/openxr_inventory/extensions.py +++ b/openxr_inventory/extensions.py @@ -209,46 +209,6 @@ def compute_extension_support( return extension_support -_FILENAME_STEM = "extension_support" - - -def generate_report( - runtimes: List[RuntimeData], - clients: List[ClientData], - template_filename: str = _FILENAME_STEM + ".jinja2.html", - out_filename: str = "public/" + _FILENAME_STEM + ".html", -): - """ - Write an HTML file in the parent directory containing information about the available extensions - and the runtimes that support them. - """ - from .inventory_jinja import make_jinja_environment - - env = make_jinja_environment() - env.globals["cat"] = ExtensionCategory - env.globals["cat_captions"] = _category_captions - env.globals["categorize_ext"] = categorize_ext_name - template = env.get_template(template_filename) - spec_url = "https://www.khronos.org/registry/OpenXR/specs/1.1/html/xrspec.html" - contents = template.render( - extensions=compute_known_extensions(runtimes, clients), - extension_support=compute_extension_support(runtimes, clients), - runtime_support=compute_runtime_support(runtimes), - client_support=compute_client_support(clients), - known_form_factors=compute_known_form_factors(runtimes, clients), - form_factor_support=compute_form_factor_support(runtimes, clients), - runtimes=runtimes, - clients=clients, - spec_url=spec_url, - ) - - if contents: - out_file = Path(__file__).parent.parent / out_filename - print("Writing {}".format(out_file)) - with open(out_file, "w", encoding="utf-8") as fp: - fp.write(contents) - - def generate_runtime_report( runtimes: List[RuntimeData], clients: List[ClientData], @@ -327,6 +287,5 @@ def generate_client_report( runtimes = load_all_runtimes() clients = load_all_clients() - generate_report(runtimes, clients) generate_runtime_report(runtimes, clients) generate_client_report(runtimes, clients) diff --git a/openxr_inventory/templates/extension_support.jinja2.html b/openxr_inventory/templates/extension_support.jinja2.html deleted file mode 100644 index 7fe215d..0000000 --- a/openxr_inventory/templates/extension_support.jinja2.html +++ /dev/null @@ -1,410 +0,0 @@ -{# -Copyright 2022, The Khronos Group Inc. - -SPDX-License-Identifier: CC-BY-4.0 -#} - -{% extends "base.jinja2.html" %} -{% block title -%} - OpenXR Runtime Extension Support Report -{%- endblock title %} - -{% block navbar_brand_text -%} - OpenXR Runtime Extension Support Report -{%- endblock navbar_brand_text %} - -{% block navbar_list_items %} -
  • Extensions
  • -
  • Runtimes
  • -
  • Runtime Support Matrix
  • -
  • Clients
  • -
  • Client Support Matrix
  • -{% endblock navbar_list_items %} - -{% block style %} -{{ super() }} - -table.table-sticky-col-headers thead tr { - position: sticky; - background: white; - z-index: 2; - /* from min height of nav bar */ - top: 50px; -} - -th.rotate { - height: 170px; - white-space: nowrap; -} - -th.rotate > div { - transform: rotate(-45deg); - width: 32px; - padding: 5px; -} - -{% endblock style %} - -{% block container_contents %} -
    - - -
    -

    Extensions

    - {% for col in extensions | slice(3) %} -
    - -
    - {% endfor %} -
    - - {% for extension_name in extensions %} - {% set support = extension_support[extension_name] %} - -
    -

    {{ extension_name }} ({{ support.runtime_count }} runtime{{ "s" if support.runtime_count != 1 }}, {{ support.client_count }} client{{ "s" if support.client_count != 1 }})

    -

    - Specification - for {{ extension_name }} -

    - Runtimes:
    - - {% if support.client_count > 0 %} - Clients:
    - - {% endif %} -
    - {% endfor %} -
    - -
    - -
    -

    Runtimes

    - - -
    - - {% for runtime in runtimes %} -
    -

    {{ runtime.name }}

    -
      -
    • Vendor: {{ runtime.vendor }}
    • - {% if runtime.conformance_submission %} -
    • Most recent conformance submission: #{{runtime.conformance_submission}}
    • - {% endif %} - {% if not runtime.conformance_submission %} -
    • Not a conformant runtime
    • - {% endif %} - {% if runtime.conformance_notes %} -
    • Conformance notes: {{ runtime.conformance_notes }}
    • - {% endif %} - {% if runtime.devices_notes %} -
    • Device support: {{ runtime.devices_notes }}
    • - {% endif %} -
    • Supported extensions: -
        - {% for extension in runtime.extensions %} -
      • {{extension.name}} {% if extension.notes %} - {{ extension.notes }} {% endif %}
      • - {% endfor %} -
      -
    • -
    -
    - {% endfor %} -
    - -
    -
    -

    Runtime support matrix

    -
    - - - - - {% for runtime in runtimes | sort %} - {# pragmatic check if the runtime name fits in the layout or if it needs to be truncated and put the full name in tooltip #} - {% if runtime.name|length < 34 %} - - {% else %} - - {% endif %} - {% endfor %} - - - - - {% macro extension_matrix_row(extension_name) %} - - - {% for runtime in runtimes | sort %} - {% if extension_name in runtime_support[runtime.name] %} - - {% else %} - - {% endif %} - {% endfor %} - - {% endmacro %} - - {# Loop through all categories of extension (KHR, EXT, vendor, KHX, EXTX, Vendor-X) #} - {% for c in cat.all_categories() %} - {# Loop through all extensions in that category #} - {% for extension_name in extensions if categorize_ext(extension_name) == c %} - {% if loop.first %} - {# this header is inside the loop so it is skipped if we have no items in this category #} - {# it is inside this "if" so it only shows up once for each category. #} - - - - {% endif %} - {# Write out a row in the table for this extension #} - {{ extension_matrix_row(extension_name) }} - {% endfor %} - {% endfor %} - - - - - - {% for ff, view_configurations in known_form_factors.items() %} - - - - {% for runtime in runtimes | sort %} - - {% endfor %} - - - {% for vc, environment_blend_modes in view_configurations.items() %} - - - - {% for runtime in runtimes | sort %} - - {% endfor %} - - {% for ebm in environment_blend_modes %} - - - {% for runtime in runtimes | sort %} - {% if ff in form_factor_support[runtime.name] and vc in form_factor_support[runtime.name][ff] and ebm in form_factor_support[runtime.name][ff][vc] %} - - {% else %} - - {% endif %} - {% endfor %} - - {% endfor %} - - - {% endfor %} - - {% endfor %} - - -
    {{ runtime.name }}
    {{ runtime.name|truncate(34, True) }}
    - {{ extension_name }} - - - - SupportedNot supported or not applicable
    {{ cat_captions[c] }} Extensions
    Runtime Features
    - {{ ff }} - - - -
    - → {{ vc }} - - - -
    - → → {{ ebm }} - - - - SupportedNot supported or not applicable
    -
    - -
    - -
    -

    Clients

    - - -
    - - {% for client in clients %} -
    -

    {{ client.name }}

    -
      -
    • Vendor: {{ client.vendor }}
    • - {% if client.notes %} -
    • Notes: {{ client.notes }}
    • - {% endif %} - {% for component in client.components %} -
    • Component: {{ component.name }}
      - {% if component.notes %} - Notes: {{ component.notes }}
      - {% endif %} - Extensions: -
        - {% for extension in component.extensions %} -
      • {{extension.name}} {% if extension.notes %} - {{ extension.notes }} {% endif %}
      • - {% endfor %} -
      -
    • - {% endfor %} -
    -
    - {% endfor %} -
    - -
    -
    -

    Client support matrix

    -
    - - - - - {% for client in clients | sort %} - {# pragmatic check if the client name fits in the layout or if it needs to be truncated and put the full name in tooltip #} - - {% endfor %} - - - - - {% macro extension_matrix_row(extension_name) %} - - - {% for client in clients | sort %} - {% set components = client.get_component_for_extension(extension_name) %} - {% if components|length > 0 %} - - {% else %} - - {% endif %} - {% endfor %} - - {% endmacro %} - - {# Loop through all categories of extension (KHR, EXT, vendor, KHX, EXTX, Vendor-X) #} - {% for c in cat.all_categories() %} - {# Loop through all extensions in that category #} - {% for extension_name in extensions if categorize_ext(extension_name) == c %} - {% if loop.first %} - {# this header is inside the loop so it is skipped if we have no items in this category #} - {# it is inside this "if" so it only shows up once for each category. #} - - - - {% endif %} - {# Write out a row in the table for this extension #} - {{ extension_matrix_row(extension_name) }} - {% endfor %} - {% endfor %} - - - - - - {% for ff, view_configurations in known_form_factors.items() %} - - - - {% for client in clients | sort %} - - {% endfor %} - - - {% for vc, environment_blend_modes in view_configurations.items() %} - - - - {% for client in clients | sort %} - - {% endfor %} - - {% for ebm in environment_blend_modes %} - - - {% for client in clients | sort %} - {% if ff in form_factor_support[client.name] and vc in form_factor_support[client.name][ff] and ebm in form_factor_support[client.name][ff][vc] %} - - {% else %} - - {% endif %} - {% endfor %} - - {% endfor %} - - - {% endfor %} - - {% endfor %} - - -
    - {% if client.name|length < 34 %} - {{ client.name }} - {% else %} - {{ client.name|truncate(34, True) }} - {% endif %} - - -
    - {{ extension_name }} - - - - - {% for component in components %} - {{ component.abbreviation }} - {% if not loop.last %} -
    - {% endif %} - {% endfor %} -
    Not supported or not applicable
    {{ cat_captions[c] }} Extensions
    Client Features
    - {{ ff }} - - - -
    - → {{ vc }} - - - -
    - → → {{ ebm }} - - - - SupportedNot supported or not applicable
    -
    -{% endblock container_contents %} From dacec407839112b10198f72b951d26dfd1438e9e Mon Sep 17 00:00:00 2001 From: Frederic Plourde Date: Mon, 19 Jan 2026 11:30:31 -0500 Subject: [PATCH 4/6] Add general extension support landing page --- Makefile | 5 ++- .../templates/extension_support.html | 39 +++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 openxr_inventory/templates/extension_support.html diff --git a/Makefile b/Makefile index 190f835..e268386 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ # # SPDX-License-Identifier: Apache-2.0 -HTML_REPORT_FILES := public/runtime_extension_support.html public/client_extension_support.html +HTML_REPORT_FILES := public/runtime_extension_support.html public/client_extension_support.html public/extension_support.html SHARED_DEPS := $(wildcard openxr_inventory/*.py) \ $(wildcard runtimes/*.json) \ $(wildcard clients/*.json) \ @@ -23,3 +23,6 @@ public/runtime_extension_support.html: extension_support_report.py public $(SHAR public/client_extension_support.html: extension_support_report.py public $(SHARED_DEPS) python3 $< + +public/extension_support.html: openxr_inventory/templates/extension_support.html public + cp $< $@ diff --git a/openxr_inventory/templates/extension_support.html b/openxr_inventory/templates/extension_support.html new file mode 100644 index 0000000..68f5454 --- /dev/null +++ b/openxr_inventory/templates/extension_support.html @@ -0,0 +1,39 @@ + + + + + + + + + OpenXR Extension Support + + + + +
    +
    +

    OpenXR Extension Support

    +

    Choose which report you'd like to view:

    + +
    +
    +

    + Maintained by the OpenXR community at + github.com/KhronosGroup/OpenXR-Inventory +

    +
    + + + From b715052d8a5766a83b1940c6e651f5350e0d5352 Mon Sep 17 00:00:00 2001 From: Frederic Plourde Date: Mon, 19 Jan 2026 14:25:35 -0500 Subject: [PATCH 5/6] Add introductory paragraph --- openxr_inventory/templates/extension_support.html | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/openxr_inventory/templates/extension_support.html b/openxr_inventory/templates/extension_support.html index 68f5454..faa3f74 100644 --- a/openxr_inventory/templates/extension_support.html +++ b/openxr_inventory/templates/extension_support.html @@ -22,6 +22,13 @@

    OpenXR Extension Support

    +

    + These reports show the support coverage for OpenXR extensions across runtimes and clients in the ecosystem.
    + OpenXR Runtimes are implementations of the OpenXR API that run on various platforms and devices. + They provide the core OpenXR functionality that applications depend on.
    + Clients (such as game engines or middleware) use the OpenXR API but do not implement it themselves; + instead, they interface with runtimes to access XR capabilities. +

    Choose which report you'd like to view:

    • Runtime Extension Support - View which extensions are supported by OpenXR runtimes
    • From 3a695470adef7ed8784d1a6d6d19036d8033cc72 Mon Sep 17 00:00:00 2001 From: Frederic Plourde Date: Mon, 19 Jan 2026 15:08:38 -0500 Subject: [PATCH 6/6] Move matrix section to the top --- .../client_extension_support.jinja2.html | 160 +++++++++--------- .../runtime_extension_support.jinja2.html | 158 ++++++++--------- 2 files changed, 159 insertions(+), 159 deletions(-) diff --git a/openxr_inventory/templates/client_extension_support.jinja2.html b/openxr_inventory/templates/client_extension_support.jinja2.html index 8111b71..3ac70b0 100644 --- a/openxr_inventory/templates/client_extension_support.jinja2.html +++ b/openxr_inventory/templates/client_extension_support.jinja2.html @@ -14,9 +14,9 @@ {%- endblock navbar_brand_text %} {% block navbar_list_items %} +
    • Client Support Matrix
    • Extensions
    • Clients
    • -
    • Client Support Matrix
    • {% endblock navbar_list_items %} {% block style %} @@ -44,85 +44,6 @@ {% endblock style %} {% block container_contents %} -
      - - -
      -

      Extensions

      - {% for col in extensions | slice(3) %} -
      - -
      - {% endfor %} -
      - - {% for extension_name in extensions %} - {% set support = extension_support[extension_name] %} - -
      -

      {{ extension_name }} ({{ support.client_count }} client{{ "s" if support.client_count != 1 }})

      -

      - Specification - for {{ extension_name }} -

      - {% if support.client_count > 0 %} - Clients:
      - - {% else %} -

      No clients support this extension.

      - {% endif %} -
      - {% endfor %} -
      - -
      - -
      -

      Clients

      - - -
      - - {% for client in clients %} -
      -

      {{ client.name }}

      -
        -
      • Vendor: {{ client.vendor }}
      • - {% if client.notes %} -
      • Notes: {{ client.notes }}
      • - {% endif %} - {% for component in client.components %} -
      • Component: {{ component.name }}
        - {% if component.notes %} - Notes: {{ component.notes }}
        - {% endif %} - Extensions: -
          - {% for extension in component.extensions %} -
        • {{extension.name}} {% if extension.notes %} - {{ extension.notes }} {% endif %}
        • - {% endfor %} -
        -
      • - {% endfor %} -
      -
      - {% endfor %} -
      -

      Client support matrix

      @@ -246,4 +167,83 @@

      Client support matrix

      + +
      + + +
      +

      Extensions

      + {% for col in extensions | slice(3) %} +
      + +
      + {% endfor %} +
      + + {% for extension_name in extensions %} + {% set support = extension_support[extension_name] %} + +
      +

      {{ extension_name }} ({{ support.client_count }} client{{ "s" if support.client_count != 1 }})

      +

      + Specification + for {{ extension_name }} +

      + {% if support.client_count > 0 %} + Clients:
      + + {% else %} +

      No clients support this extension.

      + {% endif %} +
      + {% endfor %} +
      + +
      + +
      +

      Clients

      + + +
      + + {% for client in clients %} +
      +

      {{ client.name }}

      +
        +
      • Vendor: {{ client.vendor }}
      • + {% if client.notes %} +
      • Notes: {{ client.notes }}
      • + {% endif %} + {% for component in client.components %} +
      • Component: {{ component.name }}
        + {% if component.notes %} + Notes: {{ component.notes }}
        + {% endif %} + Extensions: +
          + {% for extension in component.extensions %} +
        • {{extension.name}} {% if extension.notes %} - {{ extension.notes }} {% endif %}
        • + {% endfor %} +
        +
      • + {% endfor %} +
      +
      + {% endfor %} +
      {% endblock container_contents %} diff --git a/openxr_inventory/templates/runtime_extension_support.jinja2.html b/openxr_inventory/templates/runtime_extension_support.jinja2.html index 7d3debe..9085f77 100644 --- a/openxr_inventory/templates/runtime_extension_support.jinja2.html +++ b/openxr_inventory/templates/runtime_extension_support.jinja2.html @@ -14,9 +14,9 @@ {%- endblock navbar_brand_text %} {% block navbar_list_items %} +
    • Runtime Support Matrix
    • Extensions
    • Runtimes
    • -
    • Runtime Support Matrix
    • {% endblock navbar_list_items %} {% block style %} @@ -44,84 +44,6 @@ {% endblock style %} {% block container_contents %} -
      - - -
      -

      Extensions

      - {% for col in extensions | slice(3) %} -
      - -
      - {% endfor %} -
      - - {% for extension_name in extensions %} - {% set support = extension_support[extension_name] %} - -
      -

      {{ extension_name }} ({{ support.runtime_count }} runtime{{ "s" if support.runtime_count != 1 }})

      -

      - Specification - for {{ extension_name }} -

      - Runtimes:
      - -
      - {% endfor %} -
      - -
      - -
      -

      Runtimes

      - - -
      - - {% for runtime in runtimes %} -
      -

      {{ runtime.name }}

      -
        -
      • Vendor: {{ runtime.vendor }}
      • - {% if runtime.conformance_submission %} -
      • Most recent conformance submission: #{{runtime.conformance_submission}}
      • - {% endif %} - {% if not runtime.conformance_submission %} -
      • Not a conformant runtime
      • - {% endif %} - {% if runtime.conformance_notes %} -
      • Conformance notes: {{ runtime.conformance_notes }}
      • - {% endif %} - {% if runtime.devices_notes %} -
      • Device support: {{ runtime.devices_notes }}
      • - {% endif %} -
      • Supported extensions: -
          - {% for extension in runtime.extensions %} -
        • {{extension.name}} {% if extension.notes %} - {{ extension.notes }} {% endif %}
        • - {% endfor %} -
        -
      • -
      -
      - {% endfor %} -
      -

      Runtime support matrix

      @@ -233,4 +155,82 @@

      Runtime support matrix

      + +
      + + +
      +

      Extensions

      + {% for col in extensions | slice(3) %} +
      + +
      + {% endfor %} +
      + + {% for extension_name in extensions %} + {% set support = extension_support[extension_name] %} + +
      +

      {{ extension_name }} ({{ support.runtime_count }} runtime{{ "s" if support.runtime_count != 1 }})

      +

      + Specification + for {{ extension_name }} +

      + Runtimes:
      + +
      + {% endfor %} +
      + +
      + +
      +

      Runtimes

      + + +
      + + {% for runtime in runtimes %} +
      +

      {{ runtime.name }}

      +
        +
      • Vendor: {{ runtime.vendor }}
      • + {% if runtime.conformance_submission %} +
      • Most recent conformance submission: #{{runtime.conformance_submission}}
      • + {% endif %} + {% if not runtime.conformance_submission %} +
      • Not a conformant runtime
      • + {% endif %} + {% if runtime.conformance_notes %} +
      • Conformance notes: {{ runtime.conformance_notes }}
      • + {% endif %} + {% if runtime.devices_notes %} +
      • Device support: {{ runtime.devices_notes }}
      • + {% endif %} +
      • Supported extensions: +
          + {% for extension in runtime.extensions %} +
        • {{extension.name}} {% if extension.notes %} - {{ extension.notes }} {% endif %}
        • + {% endfor %} +
        +
      • +
      +
      + {% endfor %} +
      {% endblock container_contents %}