Adds strformat code-gen for helping auto-generate readable strings for structs.
- Adds generator infra for absl::StrFormat for bind group structs and types.
- Uses absl::ParsedFormat to avoid multiple parsing for format strings.
Bug: dawn:549
Change-Id: Ida4ca65eb85c4474c492161c8ae34f53bd692a3c
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/81944
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Loko Kung <lokokung@google.com>
diff --git a/generator/dawn_json_generator.py b/generator/dawn_json_generator.py
index 46691ae..29c1be9 100644
--- a/generator/dawn_json_generator.py
+++ b/generator/dawn_json_generator.py
@@ -684,6 +684,15 @@
return as_cppType(typ.name)
+def as_formatType(typ):
+ # Unsigned integral types
+ if typ.json_data['type'] in ['bool', 'uint32_t', 'uint64_t']:
+ return 'u'
+
+ # Defaults everything else to strings.
+ return 's'
+
+
def c_methods(params, typ):
return typ.methods + [
x for x in [
@@ -753,7 +762,8 @@
'as_jsEnumValue': as_jsEnumValue,
'convert_cType_to_cppType': convert_cType_to_cppType,
'as_varName': as_varName,
- 'decorate': decorate
+ 'decorate': decorate,
+ 'as_formatType': as_formatType
}
diff --git a/generator/generator_lib.py b/generator/generator_lib.py
index e3d46bd..11b3ed2 100644
--- a/generator/generator_lib.py
+++ b/generator/generator_lib.py
@@ -156,7 +156,8 @@
def _do_renders(renders, template_dir):
loader = _PreprocessingLoader(template_dir)
- env = jinja2.Environment(loader=loader,
+ env = jinja2.Environment(extensions=['jinja2.ext.do'],
+ loader=loader,
lstrip_blocks=True,
trim_blocks=True,
line_comment_prefix='//*')
diff --git a/generator/templates/dawn/native/api_absl_format.cpp b/generator/templates/dawn/native/api_absl_format.cpp
index 6a9477c..a3b7ea2 100644
--- a/generator/templates/dawn/native/api_absl_format.cpp
+++ b/generator/templates/dawn/native/api_absl_format.cpp
@@ -49,6 +49,42 @@
{% endfor %}
{% endfor %}
+ //
+ // Compatible with absl::StrFormat (Needs to be disjoint from having a 'label' for now.)
+ // Currently uses a hard-coded list to determine which structures are actually supported. If
+ // additional structures are added, be sure to update the header file's list as well.
+ //
+ using absl::ParsedFormat;
+
+ {% for type in by_category["structure"] %}
+ {% if type.name.get() in [
+ "buffer binding layout",
+ "sampler binding layout",
+ "texture binding layout",
+ "storage texture binding layout"
+ ]
+ %}
+ absl::FormatConvertResult<absl::FormatConversionCharSet::kString>
+ AbslFormatConvert(const {{as_cppType(type.name)}}& value,
+ const absl::FormatConversionSpec& spec,
+ absl::FormatSink* s) {
+ {% set members = [] %}
+ {% set format = [] %}
+ {% set template = [] %}
+ {% for member in type.members %}
+ {% set memberName = member.name.camelCase() %}
+ {% do members.append("value." + memberName) %}
+ {% do format.append(memberName + ": %" + as_formatType(member)) %}
+ {% do template.append("'" + as_formatType(member) + "'") %}
+ {% endfor %}
+ static const auto* const fmt =
+ new ParsedFormat<{{template|join(",")}}>("{ {{format|join(", ")}} }");
+ s->Append(absl::StrFormat(*fmt, {{members|join(", ")}}));
+ return {true};
+ }
+ {% endif %}
+ {% endfor %}
+
} // namespace {{native_namespace}}
{% set namespace = metadata.namespace %}
@@ -59,22 +95,24 @@
//
{% for type in by_category["enum"] %}
- absl::FormatConvertResult<absl::FormatConversionCharSet::kString>
- AbslFormatConvert({{as_cppType(type.name)}} value,
- const absl::FormatConversionSpec& spec,
- absl::FormatSink* s) {
+ absl::FormatConvertResult<absl::FormatConversionCharSet::kString|absl::FormatConversionCharSet::kIntegral>
+ AbslFormatConvert({{as_cppType(type.name)}} value,
+ const absl::FormatConversionSpec& spec,
+ absl::FormatSink* s) {
+ if (spec.conversion_char() == absl::FormatConversionChar::s) {
s->Append("{{as_cppType(type.name)}}::");
switch (value) {
{% for value in type.values %}
case {{as_cppType(type.name)}}::{{as_cppEnum(value.name)}}:
- s->Append("{{as_cppEnum(value.name)}}");
- break;
+ s->Append("{{as_cppEnum(value.name)}}");
+ break;
{% endfor %}
- default:
- s->Append(absl::StrFormat("%x", static_cast<typename std::underlying_type<{{as_cppType(type.name)}}>::type>(value)));
}
- return {true};
+ } else {
+ s->Append(absl::StrFormat("%u", static_cast<typename std::underlying_type<{{as_cppType(type.name)}}>::type>(value)));
}
+ return {true};
+ }
{% endfor %}
//
@@ -82,10 +120,11 @@
//
{% for type in by_category["bitmask"] %}
- absl::FormatConvertResult<absl::FormatConversionCharSet::kString>
- AbslFormatConvert({{as_cppType(type.name)}} value,
- const absl::FormatConversionSpec& spec,
- absl::FormatSink* s) {
+ absl::FormatConvertResult<absl::FormatConversionCharSet::kString|absl::FormatConversionCharSet::kIntegral>
+ AbslFormatConvert({{as_cppType(type.name)}} value,
+ const absl::FormatConversionSpec& spec,
+ absl::FormatSink* s) {
+ if (spec.conversion_char() == absl::FormatConversionChar::s) {
s->Append("{{as_cppType(type.name)}}::");
if (!static_cast<bool>(value)) {
{% for value in type.values if value.value == 0 %}
@@ -124,9 +163,11 @@
if (moreThanOneBit) {
s->Append(")");
}
-
- return {true};
+ } else {
+ s->Append(absl::StrFormat("%u", static_cast<typename std::underlying_type<{{as_cppType(type.name)}}>::type>(value)));
}
+ return {true};
+ }
{% endfor %}
} // namespace {{namespace}}
diff --git a/generator/templates/dawn/native/api_absl_format.h b/generator/templates/dawn/native/api_absl_format.h
index 5fa583f..ab06098 100644
--- a/generator/templates/dawn/native/api_absl_format.h
+++ b/generator/templates/dawn/native/api_absl_format.h
@@ -36,12 +36,33 @@
{% for member in type.members %}
{% if member.name.canonical_case() == "label" %}
absl::FormatConvertResult<absl::FormatConversionCharSet::kString>
- AbslFormatConvert(const {{as_cppType(type.name)}}* value,
- const absl::FormatConversionSpec& spec,
- absl::FormatSink* s);
+ AbslFormatConvert(const {{as_cppType(type.name)}}* value,
+ const absl::FormatConversionSpec& spec,
+ absl::FormatSink* s);
{% endif %}
{% endfor %}
{% endfor %}
+
+ //
+ // Compatible with absl::StrFormat (Needs to be disjoint from having a 'label' for now.)
+ // Currently uses a hard-coded list to determine which structures are actually supported. If
+ // additional structures are added, be sure to update the cpp file's list as well.
+ //
+ {% for type in by_category["structure"] %}
+ {% if type.name.get() in [
+ "buffer binding layout",
+ "sampler binding layout",
+ "texture binding layout",
+ "storage texture binding layout"
+ ]
+ %}
+ absl::FormatConvertResult<absl::FormatConversionCharSet::kString>
+ AbslFormatConvert(const {{as_cppType(type.name)}}& value,
+ const absl::FormatConversionSpec& spec,
+ absl::FormatSink* s);
+ {% endif %}
+ {% endfor %}
+
} // namespace {{native_namespace}}
{% set namespace = metadata.namespace %}
@@ -52,7 +73,7 @@
//
{% for type in by_category["enum"] %}
- absl::FormatConvertResult<absl::FormatConversionCharSet::kString>
+ absl::FormatConvertResult<absl::FormatConversionCharSet::kString|absl::FormatConversionCharSet::kIntegral>
AbslFormatConvert({{as_cppType(type.name)}} value,
const absl::FormatConversionSpec& spec,
absl::FormatSink* s);
@@ -63,7 +84,7 @@
//
{% for type in by_category["bitmask"] %}
- absl::FormatConvertResult<absl::FormatConversionCharSet::kString>
+ absl::FormatConvertResult<absl::FormatConversionCharSet::kString|absl::FormatConversionCharSet::kIntegral>
AbslFormatConvert({{as_cppType(type.name)}} value,
const absl::FormatConversionSpec& spec,
absl::FormatSink* s);
diff --git a/src/dawn/native/BindGroupLayout.cpp b/src/dawn/native/BindGroupLayout.cpp
index f535545..201aecc 100644
--- a/src/dawn/native/BindGroupLayout.cpp
+++ b/src/dawn/native/BindGroupLayout.cpp
@@ -661,11 +661,13 @@
}
std::string BindGroupLayoutBase::EntriesToString() const {
- std::string entries = " [";
+ std::string entries = "[";
+ std::string sep = "";
const BindGroupLayoutBase::BindingMap& bindingMap = GetBindingMap();
for (const auto [bindingNumber, bindingIndex] : bindingMap) {
const BindingInfo& bindingInfo = GetBindingInfo(bindingIndex);
- entries += absl::StrFormat("%s, ", bindingInfo);
+ entries += absl::StrFormat("%s%s", sep, bindingInfo);
+ sep = ", ";
}
entries += "]";
return entries;
diff --git a/src/dawn/native/BindingInfo.cpp b/src/dawn/native/BindingInfo.cpp
index af4905a..d19017d 100644
--- a/src/dawn/native/BindingInfo.cpp
+++ b/src/dawn/native/BindingInfo.cpp
@@ -24,19 +24,19 @@
absl::FormatSink* s) {
switch (value) {
case BindingInfoType::Buffer:
- s->Append("Buffer");
+ s->Append("buffer");
break;
case BindingInfoType::Sampler:
- s->Append("Sampler");
+ s->Append("sampler");
break;
case BindingInfoType::Texture:
- s->Append("Texture");
+ s->Append("texture");
break;
case BindingInfoType::StorageTexture:
- s->Append("StorageTexture");
+ s->Append("storageTexture");
break;
case BindingInfoType::ExternalTexture:
- s->Append("ExternalTexture");
+ s->Append("externalTexture");
break;
default:
UNREACHABLE();
@@ -48,44 +48,29 @@
const BindingInfo& value,
const absl::FormatConversionSpec& spec,
absl::FormatSink* s) {
- s->Append(absl::StrFormat("{\n binding: %u\n visibility: %s\n %s: {\n",
- static_cast<uint32_t>(value.binding), value.visibility,
- value.bindingType));
-
+ static const auto* const fmt =
+ new absl::ParsedFormat<'u', 's', 's', 's'>("{ binding: %u, visibility: %s, %s: %s }");
switch (value.bindingType) {
case BindingInfoType::Buffer:
- s->Append(absl::StrFormat(" type: %s\n", value.buffer.type));
- if (value.buffer.hasDynamicOffset) {
- s->Append(" hasDynamicOffset: true\n");
- }
- if (value.buffer.minBindingSize != 0) {
- s->Append(
- absl::StrFormat(" minBindingSize: %u\n", value.buffer.minBindingSize));
- }
+ s->Append(absl::StrFormat(*fmt, static_cast<uint32_t>(value.binding),
+ value.visibility, value.bindingType, value.buffer));
break;
case BindingInfoType::Sampler:
- s->Append(absl::StrFormat(" type: %s\n", value.sampler.type));
+ s->Append(absl::StrFormat(*fmt, static_cast<uint32_t>(value.binding),
+ value.visibility, value.bindingType, value.sampler));
break;
case BindingInfoType::Texture:
- s->Append(absl::StrFormat(" sampleType: %s\n", value.texture.sampleType));
- s->Append(absl::StrFormat(" viewDimension: %s\n", value.texture.viewDimension));
- if (value.texture.multisampled) {
- s->Append(" multisampled: true\n");
- } else {
- s->Append(" multisampled: false\n");
- }
+ s->Append(absl::StrFormat(*fmt, static_cast<uint32_t>(value.binding),
+ value.visibility, value.bindingType, value.texture));
break;
case BindingInfoType::StorageTexture:
- s->Append(absl::StrFormat(" access: %s\n", value.storageTexture.access));
- s->Append(absl::StrFormat(" format: %s\n", value.storageTexture.format));
- s->Append(
- absl::StrFormat(" viewDimension: %s\n", value.storageTexture.viewDimension));
+ s->Append(absl::StrFormat(*fmt, static_cast<uint32_t>(value.binding),
+ value.visibility, value.bindingType,
+ value.storageTexture));
break;
case BindingInfoType::ExternalTexture:
break;
}
-
- s->Append(" }\n}");
return {true};
}