Corentin Wallez a45561bb8c dawn.json: Add the "chain roots" data for chained structs.
This helps output in the headers information about which structure can
be used to extend which. In the future it could also be used to generate
helpers that validate that the chain for a root structure contains only
allowed extension structs.

Fixed: dawn:1486
Change-Id: I6134332d477503e242b3bec9f8e9bedeeb352351
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/96000
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
2022-07-14 12:58:25 +00:00

272 lines
9.4 KiB
C++

//* Copyright 2017 The Dawn Authors
//*
//* Licensed under the Apache License, Version 2.0 (the "License");
//* you may not use this file except in compliance with the License.
//* You may obtain a copy of the License at
//*
//* http://www.apache.org/licenses/LICENSE-2.0
//*
//* Unless required by applicable law or agreed to in writing, software
//* distributed under the License is distributed on an "AS IS" BASIS,
//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//* See the License for the specific language governing permissions and
//* limitations under the License.
{% set API = metadata.api.upper() %}
{% set api = API.lower() %}
{% if 'dawn' not in enabled_tags %}
#ifdef __EMSCRIPTEN__
#error "Do not include this header. Emscripten already provides headers needed for {{metadata.api}}."
#endif
{% endif %}
#ifndef {{API}}_CPP_H_
#define {{API}}_CPP_H_
#include "dawn/{{api}}.h"
#include "dawn/EnumClassBitmasks.h"
#include <cmath>
namespace {{metadata.namespace}} {
namespace detail {
constexpr size_t ConstexprMax(size_t a, size_t b) {
return a > b ? a : b;
}
} // namespace detail
{% set c_prefix = metadata.c_prefix %}
{% for constant in by_category["constant"] %}
{% set type = as_cppType(constant.type.name) %}
{% set value = c_prefix + "_" + constant.name.SNAKE_CASE() %}
static constexpr {{type}} k{{as_cppType(constant.name)}} = {{ value }};
{% endfor %}
{% for type in by_category["enum"] %}
enum class {{as_cppType(type.name)}} : uint32_t {
{% for value in type.values %}
{{as_cppEnum(value.name)}} = 0x{{format(value.value, "08X")}},
{% endfor %}
};
{% endfor %}
{% for type in by_category["bitmask"] %}
enum class {{as_cppType(type.name)}} : uint32_t {
{% for value in type.values %}
{{as_cppEnum(value.name)}} = 0x{{format(value.value, "08X")}},
{% endfor %}
};
{% endfor %}
{% for type in by_category["function pointer"] %}
using {{as_cppType(type.name)}} = {{as_cType(type.name)}};
{% endfor %}
{% for type in by_category["object"] %}
class {{as_cppType(type.name)}};
{% endfor %}
{% for type in by_category["structure"] %}
struct {{as_cppType(type.name)}};
{% endfor %}
{% for typeDef in by_category["typedef"] %}
// {{as_cppType(typeDef.name)}} is deprecated.
// Use {{as_cppType(typeDef.type.name)}} instead.
using {{as_cppType(typeDef.name)}} = {{as_cppType(typeDef.type.name)}};
{% endfor %}
template<typename Derived, typename CType>
class ObjectBase {
public:
ObjectBase() = default;
ObjectBase(CType handle): mHandle(handle) {
if (mHandle) Derived::{{c_prefix}}Reference(mHandle);
}
~ObjectBase() {
if (mHandle) Derived::{{c_prefix}}Release(mHandle);
}
ObjectBase(ObjectBase const& other)
: ObjectBase(other.Get()) {
}
Derived& operator=(ObjectBase const& other) {
if (&other != this) {
if (mHandle) Derived::{{c_prefix}}Release(mHandle);
mHandle = other.mHandle;
if (mHandle) Derived::{{c_prefix}}Reference(mHandle);
}
return static_cast<Derived&>(*this);
}
ObjectBase(ObjectBase&& other) {
mHandle = other.mHandle;
other.mHandle = 0;
}
Derived& operator=(ObjectBase&& other) {
if (&other != this) {
if (mHandle) Derived::{{c_prefix}}Release(mHandle);
mHandle = other.mHandle;
other.mHandle = 0;
}
return static_cast<Derived&>(*this);
}
ObjectBase(std::nullptr_t) {}
Derived& operator=(std::nullptr_t) {
if (mHandle != nullptr) {
Derived::{{c_prefix}}Release(mHandle);
mHandle = nullptr;
}
return static_cast<Derived&>(*this);
}
bool operator==(std::nullptr_t) const {
return mHandle == nullptr;
}
bool operator!=(std::nullptr_t) const {
return mHandle != nullptr;
}
explicit operator bool() const {
return mHandle != nullptr;
}
CType Get() const {
return mHandle;
}
CType Release() {
CType result = mHandle;
mHandle = 0;
return result;
}
static Derived Acquire(CType handle) {
Derived result;
result.mHandle = handle;
return result;
}
protected:
CType mHandle = nullptr;
};
{% macro render_cpp_default_value(member, is_struct=True) -%}
{%- if member.annotation in ["*", "const*"] and member.optional or member.default_value == "nullptr" -%}
{{" "}}= nullptr
{%- elif member.type.category == "object" and member.optional and is_struct -%}
{{" "}}= nullptr
{%- elif member.type.category in ["enum", "bitmask"] and member.default_value != None -%}
{{" "}}= {{as_cppType(member.type.name)}}::{{as_cppEnum(Name(member.default_value))}}
{%- elif member.type.category == "native" and member.default_value != None -%}
{{" "}}= {{member.default_value}}
{%- elif member.default_value != None -%}
{{" "}}= {{member.default_value}}
{%- else -%}
{{assert(member.default_value == None)}}
{%- endif -%}
{%- endmacro %}
{% macro render_cpp_method_declaration(type, method) %}
{% set CppType = as_cppType(type.name) %}
{{as_cppType(method.return_type.name)}} {{method.name.CamelCase()}}(
{%- for arg in method.arguments -%}
{%- if not loop.first %}, {% endif -%}
{%- if arg.type.category == "object" and arg.annotation == "value" -%}
{{as_cppType(arg.type.name)}} const& {{as_varName(arg.name)}}
{%- else -%}
{{as_annotated_cppType(arg)}}
{%- endif -%}
{{render_cpp_default_value(arg, False)}}
{%- endfor -%}
) const
{%- endmacro %}
{% for type in by_category["object"] %}
{% set CppType = as_cppType(type.name) %}
{% set CType = as_cType(type.name) %}
class {{CppType}} : public ObjectBase<{{CppType}}, {{CType}}> {
public:
using ObjectBase::ObjectBase;
using ObjectBase::operator=;
{% for method in type.methods %}
{{render_cpp_method_declaration(type, method)}};
{% endfor %}
private:
friend ObjectBase<{{CppType}}, {{CType}}>;
static void {{c_prefix}}Reference({{CType}} handle);
static void {{c_prefix}}Release({{CType}} handle);
};
{% endfor %}
{% for function in by_category["function"] %}
{{as_cppType(function.return_type.name)}} {{as_cppType(function.name)}}(
{%- for arg in function.arguments -%}
{%- if not loop.first %}, {% endif -%}
{{as_annotated_cppType(arg)}}{{render_cpp_default_value(arg, False)}}
{%- endfor -%}
);
{% endfor %}
struct ChainedStruct {
ChainedStruct const * nextInChain = nullptr;
SType sType = SType::Invalid;
};
struct ChainedStructOut {
ChainedStruct * nextInChain = nullptr;
SType sType = SType::Invalid;
};
{% for type in by_category["structure"] %}
{% set Out = "Out" if type.output else "" %}
{% set const = "const" if not type.output else "" %}
{% if type.chained %}
{% for root in type.chain_roots %}
// Can be chained in {{as_cppType(root.name)}}
{% endfor %}
struct {{as_cppType(type.name)}} : ChainedStruct{{Out}} {
{{as_cppType(type.name)}}() {
sType = SType::{{type.name.CamelCase()}};
}
{% else %}
struct {{as_cppType(type.name)}} {
{% endif %}
{% if type.extensible %}
ChainedStruct{{Out}} {{const}} * nextInChain = nullptr;
{% endif %}
{% for member in type.members %}
{% set member_declaration = as_annotated_cppType(member) + render_cpp_default_value(member) %}
{% if type.chained and loop.first %}
//* Align the first member after ChainedStruct to match the C struct layout.
//* It has to be aligned both to its natural and ChainedStruct's alignment.
static constexpr size_t kFirstMemberAlignment = detail::ConstexprMax(alignof(ChainedStruct{{out}}), alignof({{decorate("", as_cppType(member.type.name), member)}}));
alignas(kFirstMemberAlignment) {{member_declaration}};
{% else %}
{{member_declaration}};
{% endif %}
{% endfor %}
};
{% endfor %}
// The operators of EnumClassBitmmasks in the dawn:: namespace need to be imported
// in the {{metadata.namespace}} namespace for Argument Dependent Lookup.
DAWN_IMPORT_BITMASK_OPERATORS
} // namespace {{metadata.namespace}}
namespace dawn {
{% for type in by_category["bitmask"] %}
template<>
struct IsDawnBitmask<{{metadata.namespace}}::{{as_cppType(type.name)}}> {
static constexpr bool enable = true;
};
{% endfor %}
} // namespace dawn
#endif // {{API}}_CPP_H_