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>
This commit is contained in:
Loko Kung 2022-03-19 00:21:48 +00:00 committed by Dawn LUCI CQ
parent 39c2029063
commit 4d8352542a
6 changed files with 115 additions and 55 deletions

View File

@ -684,6 +684,15 @@ def as_wireType(metadata, typ):
return as_cppType(typ.name) 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): def c_methods(params, typ):
return typ.methods + [ return typ.methods + [
x for x in [ x for x in [
@ -753,7 +762,8 @@ def make_base_render_params(metadata):
'as_jsEnumValue': as_jsEnumValue, 'as_jsEnumValue': as_jsEnumValue,
'convert_cType_to_cppType': convert_cType_to_cppType, 'convert_cType_to_cppType': convert_cType_to_cppType,
'as_varName': as_varName, 'as_varName': as_varName,
'decorate': decorate 'decorate': decorate,
'as_formatType': as_formatType
} }

View File

@ -156,7 +156,8 @@ _FileOutput = namedtuple('FileOutput', ['name', 'content'])
def _do_renders(renders, template_dir): def _do_renders(renders, template_dir):
loader = _PreprocessingLoader(template_dir) loader = _PreprocessingLoader(template_dir)
env = jinja2.Environment(loader=loader, env = jinja2.Environment(extensions=['jinja2.ext.do'],
loader=loader,
lstrip_blocks=True, lstrip_blocks=True,
trim_blocks=True, trim_blocks=True,
line_comment_prefix='//*') line_comment_prefix='//*')

View File

@ -49,6 +49,42 @@ namespace {{native_namespace}} {
{% endfor %} {% endfor %}
{% 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}} } // namespace {{native_namespace}}
{% set namespace = metadata.namespace %} {% set namespace = metadata.namespace %}
@ -59,10 +95,11 @@ namespace {{namespace}} {
// //
{% for type in by_category["enum"] %} {% 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, AbslFormatConvert({{as_cppType(type.name)}} value,
const absl::FormatConversionSpec& spec, const absl::FormatConversionSpec& spec,
absl::FormatSink* s) { absl::FormatSink* s) {
if (spec.conversion_char() == absl::FormatConversionChar::s) {
s->Append("{{as_cppType(type.name)}}::"); s->Append("{{as_cppType(type.name)}}::");
switch (value) { switch (value) {
{% for value in type.values %} {% for value in type.values %}
@ -70,8 +107,9 @@ namespace {{namespace}} {
s->Append("{{as_cppEnum(value.name)}}"); s->Append("{{as_cppEnum(value.name)}}");
break; break;
{% endfor %} {% endfor %}
default: }
s->Append(absl::StrFormat("%x", static_cast<typename std::underlying_type<{{as_cppType(type.name)}}>::type>(value))); } else {
s->Append(absl::StrFormat("%u", static_cast<typename std::underlying_type<{{as_cppType(type.name)}}>::type>(value)));
} }
return {true}; return {true};
} }
@ -82,10 +120,11 @@ namespace {{namespace}} {
// //
{% for type in by_category["bitmask"] %} {% 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, AbslFormatConvert({{as_cppType(type.name)}} value,
const absl::FormatConversionSpec& spec, const absl::FormatConversionSpec& spec,
absl::FormatSink* s) { absl::FormatSink* s) {
if (spec.conversion_char() == absl::FormatConversionChar::s) {
s->Append("{{as_cppType(type.name)}}::"); s->Append("{{as_cppType(type.name)}}::");
if (!static_cast<bool>(value)) { if (!static_cast<bool>(value)) {
{% for value in type.values if value.value == 0 %} {% for value in type.values if value.value == 0 %}
@ -124,7 +163,9 @@ namespace {{namespace}} {
if (moreThanOneBit) { if (moreThanOneBit) {
s->Append(")"); s->Append(")");
} }
} else {
s->Append(absl::StrFormat("%u", static_cast<typename std::underlying_type<{{as_cppType(type.name)}}>::type>(value)));
}
return {true}; return {true};
} }
{% endfor %} {% endfor %}

View File

@ -42,6 +42,27 @@ namespace {{native_namespace}} {
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% 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}} } // namespace {{native_namespace}}
{% set namespace = metadata.namespace %} {% set namespace = metadata.namespace %}
@ -52,7 +73,7 @@ namespace {{namespace}} {
// //
{% for type in by_category["enum"] %} {% 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, AbslFormatConvert({{as_cppType(type.name)}} value,
const absl::FormatConversionSpec& spec, const absl::FormatConversionSpec& spec,
absl::FormatSink* s); absl::FormatSink* s);
@ -63,7 +84,7 @@ namespace {{namespace}} {
// //
{% for type in by_category["bitmask"] %} {% 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, AbslFormatConvert({{as_cppType(type.name)}} value,
const absl::FormatConversionSpec& spec, const absl::FormatConversionSpec& spec,
absl::FormatSink* s); absl::FormatSink* s);

View File

@ -662,10 +662,12 @@ namespace dawn::native {
std::string BindGroupLayoutBase::EntriesToString() const { std::string BindGroupLayoutBase::EntriesToString() const {
std::string entries = "["; std::string entries = "[";
std::string sep = "";
const BindGroupLayoutBase::BindingMap& bindingMap = GetBindingMap(); const BindGroupLayoutBase::BindingMap& bindingMap = GetBindingMap();
for (const auto [bindingNumber, bindingIndex] : bindingMap) { for (const auto [bindingNumber, bindingIndex] : bindingMap) {
const BindingInfo& bindingInfo = GetBindingInfo(bindingIndex); const BindingInfo& bindingInfo = GetBindingInfo(bindingIndex);
entries += absl::StrFormat("%s, ", bindingInfo); entries += absl::StrFormat("%s%s", sep, bindingInfo);
sep = ", ";
} }
entries += "]"; entries += "]";
return entries; return entries;

View File

@ -24,19 +24,19 @@ namespace dawn::native {
absl::FormatSink* s) { absl::FormatSink* s) {
switch (value) { switch (value) {
case BindingInfoType::Buffer: case BindingInfoType::Buffer:
s->Append("Buffer"); s->Append("buffer");
break; break;
case BindingInfoType::Sampler: case BindingInfoType::Sampler:
s->Append("Sampler"); s->Append("sampler");
break; break;
case BindingInfoType::Texture: case BindingInfoType::Texture:
s->Append("Texture"); s->Append("texture");
break; break;
case BindingInfoType::StorageTexture: case BindingInfoType::StorageTexture:
s->Append("StorageTexture"); s->Append("storageTexture");
break; break;
case BindingInfoType::ExternalTexture: case BindingInfoType::ExternalTexture:
s->Append("ExternalTexture"); s->Append("externalTexture");
break; break;
default: default:
UNREACHABLE(); UNREACHABLE();
@ -48,44 +48,29 @@ namespace dawn::native {
const BindingInfo& value, const BindingInfo& value,
const absl::FormatConversionSpec& spec, const absl::FormatConversionSpec& spec,
absl::FormatSink* s) { absl::FormatSink* s) {
s->Append(absl::StrFormat("{\n binding: %u\n visibility: %s\n %s: {\n", static const auto* const fmt =
static_cast<uint32_t>(value.binding), value.visibility, new absl::ParsedFormat<'u', 's', 's', 's'>("{ binding: %u, visibility: %s, %s: %s }");
value.bindingType));
switch (value.bindingType) { switch (value.bindingType) {
case BindingInfoType::Buffer: case BindingInfoType::Buffer:
s->Append(absl::StrFormat(" type: %s\n", value.buffer.type)); s->Append(absl::StrFormat(*fmt, static_cast<uint32_t>(value.binding),
if (value.buffer.hasDynamicOffset) { value.visibility, value.bindingType, value.buffer));
s->Append(" hasDynamicOffset: true\n");
}
if (value.buffer.minBindingSize != 0) {
s->Append(
absl::StrFormat(" minBindingSize: %u\n", value.buffer.minBindingSize));
}
break; break;
case BindingInfoType::Sampler: 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; break;
case BindingInfoType::Texture: case BindingInfoType::Texture:
s->Append(absl::StrFormat(" sampleType: %s\n", value.texture.sampleType)); s->Append(absl::StrFormat(*fmt, static_cast<uint32_t>(value.binding),
s->Append(absl::StrFormat(" viewDimension: %s\n", value.texture.viewDimension)); value.visibility, value.bindingType, value.texture));
if (value.texture.multisampled) {
s->Append(" multisampled: true\n");
} else {
s->Append(" multisampled: false\n");
}
break; break;
case BindingInfoType::StorageTexture: case BindingInfoType::StorageTexture:
s->Append(absl::StrFormat(" access: %s\n", value.storageTexture.access)); s->Append(absl::StrFormat(*fmt, static_cast<uint32_t>(value.binding),
s->Append(absl::StrFormat(" format: %s\n", value.storageTexture.format)); value.visibility, value.bindingType,
s->Append( value.storageTexture));
absl::StrFormat(" viewDimension: %s\n", value.storageTexture.viewDimension));
break; break;
case BindingInfoType::ExternalTexture: case BindingInfoType::ExternalTexture:
break; break;
} }
s->Append(" }\n}");
return {true}; return {true};
} }