Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 23c3e4f7 authored by Anjana Sherin's avatar Anjana Sherin
Browse files

Extract pending vkjson_generator utility functions into separate file

This CL contains only movement of code from one file to another, and is continuation of https://googleplex-android-review.git.corp.google.com/c/platform/frameworks/native/+/33070222

These functions weren't planned for extraction initially, given their one time usage. However, while developing unit tests for the generator, it was realized that they involve enough complexity and edge cases to merit their own unit tests (following in another CL)

Moving forward, vkjson_generator should contain only the core functions (gen_h, gen_cc, and gen_instance_cc), while all supporting utility functions should reside within vkjson_gen_util. This improves code readability and separation of concerns, apart from enabling unit test mocks.

Bug: b/409448422
Flag: NONE infeasible
Test: No changes to vkjson files after re-generation

Change-Id: I95c577005b555399eda8b4bb71307ab36e7621eb
parent aa9f90b6
Loading
Loading
Loading
Loading
+225 −2
Original line number Diff line number Diff line
@@ -15,12 +15,13 @@
# limitations under the License.

"""
This file contains utility functions for vkjson_generator.py
that are reused in various parts of the same script.
This file contains all supporting utility functions for vkjson_generator.py
"""

import dataclasses
import re
import vk as VK
from typing import get_origin

COPYRIGHT_WARNINGS = """///////////////////////////////////////////////////////////////////////////////
//
@@ -122,6 +123,228 @@ def get_struct_name(struct_name):
    return special_cases.get(variable_name, variable_name)


def generate_extension_struct_definition(f):
    """Generates struct definition code for extension based structs
    Example:
    struct VkJsonKHRShaderFloatControls {
      VkJsonKHRShaderFloatControls() {
        reported = false;
        memset(&float_controls_properties_khr, 0,
              sizeof(VkPhysicalDeviceFloatControlsPropertiesKHR));
      }
      bool reported;
      VkPhysicalDeviceFloatControlsPropertiesKHR float_controls_properties_khr;
    };
    """
    vkjson_entries = []

    for extension_name, struct_list in (VK.VULKAN_EXTENSIONS_AND_STRUCTS_MAPPING["extensions"]
            .items()):
        vkjson_struct_name = get_vkjson_struct_name(extension_name)
        vkjson_struct_variable_name = get_vkjson_struct_variable_name(extension_name)
        vkjson_entries.append(f"{vkjson_struct_name} {vkjson_struct_variable_name}")

        struct_entries = []

        f.write(f"struct {vkjson_struct_name} {{\n")
        f.write(f"  {vkjson_struct_name}() {{\n")
        f.write("    reported = false;\n")

        for struct_map in struct_list:
            for struct_name, _ in struct_map.items():
                variable_name = get_struct_name(struct_name)
                f.write(f"    memset(&{variable_name}, 0, sizeof({struct_name}));\n")
                struct_entries.append(f"{struct_name} {variable_name}")

        f.write("  }\n")  # End of constructor
        f.write("  bool reported;\n")

        for entry in struct_entries:
            f.write(f"  {entry};\n")

        f.write("};\n\n")  # End of struct

    return vkjson_entries


def generate_vk_core_struct_definition(f):
    """Generates struct definition code for vulkan cores
    Example:
    struct VkJsonCore11 {
      VkPhysicalDeviceVulkan11Properties properties;
      VkPhysicalDeviceVulkan11Features features;
    };
    """
    vkjson_core_entries = []

    for version, items in VK.VULKAN_CORES_AND_STRUCTS_MAPPING["versions"].items():
        struct_name = f"VkJson{version}"
        vkjson_core_entries.append(f"{struct_name} {version.lower()}")

        f.write(f"struct {struct_name} {{\n")
        f.write(f"  {struct_name}() {{\n")  # Start of constructor
        for item in items:
            for struct_type, _ in item.items():
                field_name = "properties" if "Properties" in struct_type else "features"
                f.write(f" memset(&{field_name}, 0, sizeof({struct_type}));\n")
        f.write("  }\n")  # End of constructor

        for item in items:
            for struct_type, _ in item.items():
                field_name = "properties" if "Properties" in struct_type else "features"
                f.write(f"  {struct_type} {field_name};\n")

        if version == "Core14":
            f.write(f"std::vector<VkImageLayout> copy_src_layouts;\n")
            f.write(f"std::vector<VkImageLayout> copy_dst_layouts;\n")

        f.write("};\n\n")

    return vkjson_core_entries


def generate_memset_statements(f):
    """Generates memset statements for all independent Vulkan structs and core Vulkan versions.
    This initializes struct instances to zero before use.

    Example:
      memset(&properties, 0, sizeof(VkPhysicalDeviceProperties));
      VkPhysicalDeviceProperties properties;
    """
    entries = []

    # Process independent structs
    for dataclass_type in VK.EXTENSION_INDEPENDENT_STRUCTS:
        class_name = dataclass_type.__name__
        variable_name = get_struct_name(class_name)
        f.write(f"memset(&{variable_name}, 0, sizeof({class_name}));\n")
        entries.append(f"{class_name} {variable_name}")

    return entries


def generate_extension_struct_template():
    """Generates templates for extensions
    Example:
      template <typename Visitor>
      inline bool Iterate(Visitor* visitor, VkJsonKHRVariablePointers* structs) {
        return visitor->Visit("variablePointerFeaturesKHR",
                              &structs->variable_pointer_features_khr) &&
              visitor->Visit("variablePointersFeaturesKHR",
                              &structs->variable_pointers_features_khr);
      }
    """
    template_code = []

    for extension, struct_mappings in (VK.VULKAN_EXTENSIONS_AND_STRUCTS_MAPPING["extensions"]
            .items()):
        struct_type = get_vkjson_struct_name(extension)

        template_code.append(f"template <typename Visitor>")
        template_code.append(f"inline bool Iterate(Visitor* visitor, {struct_type}* structs) {{")
        template_code.append("  return ")

        visitor_calls = []
        for struct_map in struct_mappings:
            for struct_name in struct_map:
                json_field_name = struct_name.replace("VkPhysicalDevice", "")
                json_field_name = json_field_name[0].lower() + json_field_name[1:]

                # Special case renaming
                if json_field_name == "8BitStorageFeaturesKHR":
                    json_field_name = "bit8StorageFeaturesKHR"

                visitor_calls.append(
                    f'visitor->Visit("{json_field_name}", &structs->{get_struct_name(struct_name)})'
                )

        template_code.append(" &&\n         ".join(visitor_calls) + ";")
        template_code.append("}\n")

    return "\n".join(template_code)


def generate_core_template():
    """Generates templates for vulkan cores.
    template <typename Visitor>
    inline bool Iterate(Visitor* visitor, VkJsonCore11* core) {
      return visitor->Visit("properties", &core->properties) &&
            visitor->Visit("features", &core->features);
    }
    """
    template_code = []

    for version, struct_list in VK.VULKAN_CORES_AND_STRUCTS_MAPPING["versions"].items():
        struct_type = f"VkJson{version}"

        template_code.append(f"template <typename Visitor>")
        template_code.append(f"inline bool Iterate(Visitor* visitor, {struct_type}* core) {{")
        template_code.append("  return")

        visitor_calls = []
        for struct_map in struct_list:
            for struct_name in struct_map:
                member_name = "properties" if "Properties" in struct_name else "features"
                visitor_calls.append(f'visitor->Visit("{member_name}", &core->{member_name})')

        template_code.append(" &&\n         ".join(visitor_calls) + ";")
        template_code.append("}\n")

    return "\n".join(template_code)


def generate_struct_template(data_classes):
    """Generates templates for all the structs
    template <typename Visitor>
    inline bool Iterate(Visitor* visitor,
                        VkPhysicalDevicePointClippingProperties* properties) {
      return visitor->Visit("pointClippingBehavior",
                            &properties->pointClippingBehavior);
    }
    """
    template_code = []
    processed_classes = set()  # Track processed class names

    for dataclass_type in data_classes:
        struct_name = dataclass_type.__name__

        if struct_name in processed_classes:
            continue  # Skip already processed struct
        processed_classes.add(struct_name)

        struct_fields = dataclasses.fields(dataclass_type)
        template_code.append("template <typename Visitor>")

        # Determine the correct variable name based on the struct type
        struct_var = "properties" if "Properties" in struct_name else "features" if "Features" in struct_name else "limits" if "Limits" in struct_name else None

        if not struct_var:
            continue  # Skip structs that don't match expected patterns

        template_code.append(
            f"inline bool Iterate(Visitor* visitor, {struct_name}* {struct_var}) {{")
        template_code.append(f"return\n")

        visitor_calls = []
        for struct_field in struct_fields:
            field_name = struct_field.name
            field_type = struct_field.type

            if get_origin(field_type) is list:
                # Handle list types (VisitArray)
                size_field_name = VK.LIST_TYPE_FIELD_AND_SIZE_MAPPING[field_name]
                visitor_calls.append(
                    f'visitor->VisitArray("{field_name}", {struct_var}->{size_field_name}, &{struct_var}->{field_name})')
            else:
                # Handle other types (Visit)
                visitor_calls.append(f'visitor->Visit("{field_name}", &{struct_var}->{field_name})')

        template_code.append(" &&\n         ".join(visitor_calls) + ";")
        template_code.append("}\n\n")

    return "\n".join(template_code)


def emit_struct_visits_by_vk_version(f, version):
    """Emits visitor calls for Vulkan version structs
    """
+5 −226
Original line number Diff line number Diff line
@@ -16,114 +16,12 @@

"""Generates the vkjson files.
"""
import dataclasses
import os
from typing import get_origin

import generator_common as gencom
import vkjson_gen_util as util
import vk as VK

dataclass_field = dataclasses.field

def generate_extension_struct_definition(f):
  """Generates struct definition code for extension based structs
  Example:
  struct VkJsonKHRShaderFloatControls {
    VkJsonKHRShaderFloatControls() {
      reported = false;
      memset(&float_controls_properties_khr, 0,
            sizeof(VkPhysicalDeviceFloatControlsPropertiesKHR));
    }
    bool reported;
    VkPhysicalDeviceFloatControlsPropertiesKHR float_controls_properties_khr;
  };
  """
  vkJson_entries = []

  for extension_name, struct_list in VK.VULKAN_EXTENSIONS_AND_STRUCTS_MAPPING["extensions"].items():
    vkjson_struct_name = util.get_vkjson_struct_name(extension_name)
    vkjson_struct_variable_name = util.get_vkjson_struct_variable_name(extension_name)
    vkJson_entries.append(f"{vkjson_struct_name} {vkjson_struct_variable_name}")

    struct_entries = []

    f.write(f"struct {vkjson_struct_name} {{\n")
    f.write(f"  {vkjson_struct_name}() {{\n")
    f.write("    reported = false;\n")

    for struct_map in struct_list:
      for struct_name, _ in struct_map.items():
        variable_name = util.get_struct_name(struct_name)
        f.write(f"    memset(&{variable_name}, 0, sizeof({struct_name}));\n")
        struct_entries.append(f"{struct_name} {variable_name}")

    f.write("  }\n")  # End of constructor
    f.write("  bool reported;\n")

    for entry in struct_entries:
      f.write(f"  {entry};\n")

    f.write("};\n\n")  # End of struct

  return vkJson_entries


def generate_vk_core_struct_definition(f):
  """Generates struct definition code for vulkan cores
  Example:
  struct VkJsonCore11 {
    VkPhysicalDeviceVulkan11Properties properties;
    VkPhysicalDeviceVulkan11Features features;
  };
  """
  vkJson_core_entries = []

  for version, items in VK.VULKAN_CORES_AND_STRUCTS_MAPPING["versions"].items():
    struct_name = f"VkJson{version}"
    vkJson_core_entries.append(f"{struct_name} {version.lower()}")

    f.write(f"struct {struct_name} {{\n")
    f.write(f"  {struct_name}() {{\n") # Start of constructor
    for item in items:
      for struct_type, _ in item.items():
        field_name = "properties" if "Properties" in struct_type else "features"
        f.write(f" memset(&{field_name}, 0, sizeof({struct_type}));\n")
    f.write("  }\n")  # End of constructor

    for item in items:
      for struct_type, _ in item.items():
        field_name = "properties" if "Properties" in struct_type else "features"
        f.write(f"  {struct_type} {field_name};\n")

    if version == "Core14":
      f.write(f"std::vector<VkImageLayout> copy_src_layouts;\n")
      f.write(f"std::vector<VkImageLayout> copy_dst_layouts;\n")

    f.write("};\n\n")

  return vkJson_core_entries


def generate_memset_statements(f):
  """Generates memset statements for all independent Vulkan structs and core Vulkan versions.
  This initializes struct instances to zero before use.

  Example:
    memset(&properties, 0, sizeof(VkPhysicalDeviceProperties));
    VkPhysicalDeviceProperties properties;
  """
  entries = []

  # Process independent structs
  for dataclass_type in VK.EXTENSION_INDEPENDENT_STRUCTS:
    class_name = dataclass_type.__name__
    variable_name = util.get_struct_name(class_name)
    f.write(f"memset(&{variable_name}, 0, sizeof({class_name}));\n")
    entries.append(f"{class_name} {variable_name}")

  return entries


def gen_h():
  """Generates vkjson.h file.
@@ -160,14 +58,14 @@ struct VkJsonLayer {

\n""")

    vkjson_extension_structs = generate_extension_struct_definition(f)
    vkjson_core_structs = generate_vk_core_struct_definition(f)
    vkjson_extension_structs = util.generate_extension_struct_definition(f)
    vkjson_core_structs = util.generate_vk_core_struct_definition(f)

    f.write("""\
struct VkJsonDevice {
  VkJsonDevice() {""")

    feature_property_structs = generate_memset_statements(f)
    feature_property_structs = util.generate_memset_statements(f)

    f.write("""\
  }\n""")
@@ -243,125 +141,6 @@ inline bool VkJsonAllPropertiesFromJson(const std::string& json,
  gencom.run_clang_format(genfile)


def generate_extension_struct_template():
  """Generates templates for extensions
  Example:
    template <typename Visitor>
    inline bool Iterate(Visitor* visitor, VkJsonKHRVariablePointers* structs) {
      return visitor->Visit("variablePointerFeaturesKHR",
                            &structs->variable_pointer_features_khr) &&
            visitor->Visit("variablePointersFeaturesKHR",
                            &structs->variable_pointers_features_khr);
    }
  """
  template_code = []

  for extension, struct_mappings in VK.VULKAN_EXTENSIONS_AND_STRUCTS_MAPPING["extensions"].items():
    struct_type = util.get_vkjson_struct_name(extension)

    template_code.append(f"template <typename Visitor>")
    template_code.append(f"inline bool Iterate(Visitor* visitor, {struct_type}* structs) {{")
    template_code.append("  return ")

    visitor_calls = []
    for struct_map in struct_mappings:
      for struct_name in struct_map:
        json_field_name = struct_name.replace("VkPhysicalDevice", "")
        json_field_name = json_field_name[0].lower() + json_field_name[1:]

        # Special case renaming
        if json_field_name == "8BitStorageFeaturesKHR":
          json_field_name = "bit8StorageFeaturesKHR"

        visitor_calls.append(
            f'visitor->Visit("{json_field_name}", &structs->{util.get_struct_name(struct_name)})'
        )

    template_code.append(" &&\n         ".join(visitor_calls) + ";")
    template_code.append("}\n")

  return "\n".join(template_code)


def generate_core_template():
  """Generates templates for vulkan cores.
  template <typename Visitor>
  inline bool Iterate(Visitor* visitor, VkJsonCore11* core) {
    return visitor->Visit("properties", &core->properties) &&
          visitor->Visit("features", &core->features);
  }
  """
  template_code = []

  for version, struct_list in VK.VULKAN_CORES_AND_STRUCTS_MAPPING["versions"].items():
    struct_type = f"VkJson{version}"

    template_code.append(f"template <typename Visitor>")
    template_code.append(f"inline bool Iterate(Visitor* visitor, {struct_type}* core) {{")
    template_code.append("  return")

    visitor_calls = []
    for struct_map in struct_list:
      for struct_name in struct_map:
        member_name = "properties" if "Properties" in struct_name else "features"
        visitor_calls.append(f'visitor->Visit("{member_name}", &core->{member_name})')

    template_code.append(" &&\n         ".join(visitor_calls) + ";")
    template_code.append("}\n")

  return "\n".join(template_code)


def generate_struct_template(data_classes):
  """Generates templates for all the structs
  template <typename Visitor>
  inline bool Iterate(Visitor* visitor,
                      VkPhysicalDevicePointClippingProperties* properties) {
    return visitor->Visit("pointClippingBehavior",
                          &properties->pointClippingBehavior);
  }
  """
  template_code = []
  processed_classes = set()  # Track processed class names

  for dataclass_type in data_classes:
    struct_name = dataclass_type.__name__

    if struct_name in processed_classes:
      continue  # Skip already processed struct
    processed_classes.add(struct_name)

    struct_fields = dataclasses.fields(dataclass_type)
    template_code.append("template <typename Visitor>")

    # Determine the correct variable name based on the struct type
    struct_var = "properties" if "Properties" in struct_name else "features" if "Features" in struct_name else "limits" if "Limits" in struct_name else None

    if not struct_var:
      continue  # Skip structs that don't match expected patterns

    template_code.append(f"inline bool Iterate(Visitor* visitor, {struct_name}* {struct_var}) {{")
    template_code.append(f"return\n")

    visitor_calls = []
    for struct_field in struct_fields:
      field_name = struct_field.name
      field_type = struct_field.type

      if get_origin(field_type) is list:
        # Handle list types (VisitArray)
        size_field_name = VK.LIST_TYPE_FIELD_AND_SIZE_MAPPING[field_name]
        visitor_calls.append(f'visitor->VisitArray("{field_name}", {struct_var}->{size_field_name}, &{struct_var}->{field_name})')
      else:
        # Handle other types (Visit)
        visitor_calls.append(f'visitor->Visit("{field_name}", &{struct_var}->{field_name})')

    template_code.append(" &&\n         ".join(visitor_calls) + ";")
    template_code.append("}\n\n")

  return "\n".join(template_code)


def gen_cc():
  """Generates vkjson.cc file.
  """
@@ -870,8 +649,8 @@ inline bool Iterate(Visitor* visitor, VkMemoryHeap* heap) {
    visitor->Visit("flags", &heap->flags);
}\n\n""")

    f.write(f"{generate_core_template()}\n\n{generate_extension_struct_template()}\n\n")
    f.write(generate_struct_template(VK.ALL_STRUCTS))
    f.write(f"{util.generate_core_template()}\n\n{util.generate_extension_struct_template()}\n\n")
    f.write(util.generate_struct_template(VK.ALL_STRUCTS))

    f.write("""\
template <typename Visitor>