Add *FreeMembers functions for out structs with non-value members
The function is called automatically in the dtor of the C++ structs.
The C++ structs are also made non-copyable to prevent a double-free.
Bug: dawn:1959
Change-Id: Idfebdc1ea144d69543de8ed7671657a0617e3b82
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/141501
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Loko Kung <lokokung@google.com>
Commit-Queue: Austin Eng <enga@chromium.org>
diff --git a/dawn.json b/dawn.json
index 86f8862..53717af 100644
--- a/dawn.json
+++ b/dawn.json
@@ -136,11 +136,11 @@
"extensible": "out",
"members": [
{"name": "vendor ID", "type": "uint32_t"},
- {"name": "vendor name", "type": "char", "annotation": "const*", "length": "strlen"},
- {"name": "architecture", "type": "char", "annotation": "const*", "length": "strlen"},
+ {"name": "vendor name", "type": "char", "annotation": "const*", "length": "strlen", "default": "nullptr"},
+ {"name": "architecture", "type": "char", "annotation": "const*", "length": "strlen", "default": "nullptr"},
{"name": "device ID", "type": "uint32_t"},
- {"name": "name", "type": "char", "annotation": "const*", "length": "strlen"},
- {"name": "driver description", "type": "char", "annotation": "const*", "length": "strlen"},
+ {"name": "name", "type": "char", "annotation": "const*", "length": "strlen", "default": "nullptr"},
+ {"name": "driver description", "type": "char", "annotation": "const*", "length": "strlen", "default": "nullptr"},
{"name": "adapter type", "type": "adapter type"},
{"name": "backend type", "type": "backend type"},
{"name": "compatibility mode", "type": "bool", "default": "false", "tags": ["dawn", "emscripten"]}
diff --git a/generator/dawn_json_generator.py b/generator/dawn_json_generator.py
index daaec67..91c8ee7 100644
--- a/generator/dawn_json_generator.py
+++ b/generator/dawn_json_generator.py
@@ -273,6 +273,15 @@
def output(self):
return self.chained == "out" or self.extensible == "out"
+ @property
+ def has_free_members_function(self):
+ if not self.output:
+ return False
+ for m in self.members:
+ if m.annotation != 'value':
+ return True
+ return False
+
class ConstantDefinition():
def __init__(self, is_enabled, name, json_data):
@@ -283,11 +292,12 @@
class FunctionDeclaration():
- def __init__(self, is_enabled, name, json_data):
+ def __init__(self, is_enabled, name, json_data, no_cpp=False):
self.return_type = None
self.arguments = []
self.json_data = json_data
self.name = Name(name)
+ self.no_cpp = no_cpp
class Command(Record):
@@ -474,6 +484,23 @@
for struct in by_category['structure']:
link_structure(struct, types)
+ if struct.has_free_members_function:
+ name = struct.name.get() + " free members"
+ func_decl = FunctionDeclaration(
+ True,
+ name, {
+ "returns":
+ "void",
+ "args": [{
+ "name": "value",
+ "type": struct.name.get(),
+ "annotation": "value",
+ }]
+ },
+ no_cpp=True)
+ types[name] = func_decl
+ by_category['function'].append(func_decl)
+
for function_pointer in by_category['function pointer']:
link_function_pointer(function_pointer, types)
@@ -753,22 +780,23 @@
annotation, arg)
-def decorate(name, typ, arg):
+def decorate(name, typ, arg, make_const=False):
+ maybe_const = ' const ' if make_const else ' '
if arg.annotation == 'value':
- return typ + ' ' + name
+ return typ + maybe_const + name
elif arg.annotation == '*':
- return typ + ' * ' + name
+ return typ + ' *' + maybe_const + name
elif arg.annotation == 'const*':
- return typ + ' const * ' + name
+ return typ + ' const *' + maybe_const + name
elif arg.annotation == 'const*const*':
- return 'const ' + typ + '* const * ' + name
+ return 'const ' + typ + '* const *' + maybe_const + name
else:
assert False
-def annotated(typ, arg):
+def annotated(typ, arg, make_const=False):
name = as_varName(arg.name)
- return decorate(name, typ, arg)
+ return decorate(name, typ, arg, make_const)
def item_is_enabled(enabled_tags, json_data):
@@ -876,9 +904,9 @@
return {
'Name': lambda name: Name(name),
'as_annotated_cType': \
- lambda arg: annotated(as_cTypeEnumSpecialCase(arg.type), arg),
+ lambda arg, make_const=False: annotated(as_cTypeEnumSpecialCase(arg.type), arg, make_const),
'as_annotated_cppType': \
- lambda arg: annotated(as_cppType(arg.type.name), arg),
+ lambda arg, make_const=False: annotated(as_cppType(arg.type.name), arg, make_const),
'as_cEnum': as_cEnum,
'as_cppEnum': as_cppEnum,
'as_cMethod': as_cMethod,
diff --git a/generator/templates/api.h b/generator/templates/api.h
index a0f5821..2228f07 100644
--- a/generator/templates/api.h
+++ b/generator/templates/api.h
@@ -178,6 +178,7 @@
{% endfor %}
{% endfor %}
+
#endif // !defined({{API}}_SKIP_PROCS)
#if !defined({{API}}_SKIP_DECLARATIONS)
@@ -204,6 +205,7 @@
{% endfor %}
{% endfor %}
+
#endif // !defined({{API}}_SKIP_DECLARATIONS)
#ifdef __cplusplus
diff --git a/generator/templates/api_cpp.cpp b/generator/templates/api_cpp.cpp
index d540e0b..c326363 100644
--- a/generator/templates/api_cpp.cpp
+++ b/generator/templates/api_cpp.cpp
@@ -11,6 +11,9 @@
//* 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.
+
+#include <utility>
+
{% set api = metadata.api.lower() %}
{% if 'dawn' in enabled_tags %}
#include "dawn/{{api}}_cpp.h"
@@ -99,6 +102,55 @@
{%- endif -%}
{%- endmacro -%}
+ template <typename T>
+ static T& AsNonConstReference(const T& value) {
+ return const_cast<T&>(value);
+ }
+
+ {% for type in by_category["structure"] if type.has_free_members_function %}
+ // {{as_cppType(type.name)}}
+ {{as_cppType(type.name)}}::~{{as_cppType(type.name)}}() {
+ if (
+ {%- for member in type.members if member.annotation != 'value' %}
+ {% if not loop.first %} || {% endif -%}
+ this->{{member.name.camelCase()}} != nullptr
+ {%- endfor -%}
+ ) {
+ {{as_cMethod(type.name, Name("free members"))}}(
+ *reinterpret_cast<{{as_cType(type.name)}}*>(this));
+ }
+ }
+
+ static void Reset({{as_cppType(type.name)}}& value) {
+ {{as_cppType(type.name)}} defaultValue{};
+ {% for member in type.members %}
+ AsNonConstReference(value.{{member.name.camelCase()}}) = defaultValue.{{member.name.camelCase()}};
+ {% endfor %}
+ }
+
+ {{as_cppType(type.name)}}::{{as_cppType(type.name)}}({{as_cppType(type.name)}}&& rhs)
+ : {% for member in type.members %}
+ {%- set memberName = member.name.camelCase() -%}
+ {{memberName}}(rhs.{{memberName}}){% if not loop.last %},{{"\n "}}{% endif %}
+ {% endfor -%}
+ {
+ Reset(rhs);
+ }
+
+ {{as_cppType(type.name)}}& {{as_cppType(type.name)}}::operator=({{as_cppType(type.name)}}&& rhs) {
+ if (&rhs == this) {
+ return *this;
+ }
+ this->~{{as_cppType(type.name)}}();
+ {% for member in type.members %}
+ AsNonConstReference(this->{{member.name.camelCase()}}) = std::move(rhs.{{member.name.camelCase()}});
+ {% endfor %}
+ Reset(rhs);
+ return *this;
+ }
+
+ {% endfor %}
+
{% for type in by_category["object"] %}
{% set CppType = as_cppType(type.name) %}
{% set CType = as_cType(type.name) %}
@@ -131,6 +183,9 @@
{% for method in type.methods -%}
{{render_cpp_method_declaration(type, method)}} {
+ {% for arg in method.arguments if arg.type.has_free_members_function and arg.annotation == '*' %}
+ *{{as_varName(arg.name)}} = {{as_cppType(arg.type.name)}}();
+ {% endfor %}
{% if method.return_type.name.concatcase() == "void" %}
{{render_cpp_to_c_method_call(type, method)}};
{% else %}
@@ -153,7 +208,7 @@
// Function
- {% for function in by_category["function"] %}
+ {% for function in by_category["function"] if not function.no_cpp %}
{%- macro render_function_call(function) -%}
{{as_cMethod(None, function.name)}}(
{%- for arg in function.arguments -%}
@@ -167,8 +222,12 @@
{% if not loop.first %}, {% endif %}{{as_annotated_cppType(arg)}}
{%- endfor -%}
) {
- auto result = {{render_function_call(function)}};
- return {{convert_cType_to_cppType(function.return_type, 'value', 'result')}};
+ {% if function.return_type.name.concatcase() == "void" %}
+ {{render_function_call(function)}};
+ {% else %}
+ auto result = {{render_function_call(function)}};
+ return {{convert_cType_to_cppType(function.return_type, 'value', 'result')}};
+ {% endif %}
}
{% endfor %}
diff --git a/generator/templates/api_cpp.h b/generator/templates/api_cpp.h
index 1447fe4..c792804 100644
--- a/generator/templates/api_cpp.h
+++ b/generator/templates/api_cpp.h
@@ -175,7 +175,7 @@
CType mHandle = nullptr;
};
-{% macro render_cpp_default_value(member, is_struct=True) -%}
+{% macro render_cpp_default_value(member, is_struct=True, force_default=False) -%}
{%- if member.json_data.get("no_default", false) -%}
{%- elif member.annotation in ["*", "const*"] and member.optional or member.default_value == "nullptr" -%}
{{" "}}= nullptr
@@ -189,6 +189,9 @@
{{" "}}= {{member.default_value}}
{%- else -%}
{{assert(member.default_value == None)}}
+ {%- if force_default -%}
+ {{" "}}= {}
+ {%- endif -%}
{%- endif -%}
{%- endmacro %}
@@ -227,7 +230,7 @@
{% endfor %}
- {% for function in by_category["function"] %}
+ {% for function in by_category["function"] if not function.no_cpp %}
{{as_cppType(function.return_type.name)}} {{as_cppType(function.name)}}(
{%- for arg in function.arguments -%}
{%- if not loop.first %}, {% endif -%}
@@ -250,11 +253,19 @@
{% else %}
struct {{as_cppType(type.name)}} {
{% endif %}
+ {% if type.has_free_members_function %}
+ {{as_cppType(type.name)}}() = default;
+ ~{{as_cppType(type.name)}}();
+ {{as_cppType(type.name)}}(const {{as_cppType(type.name)}}&) = delete;
+ {{as_cppType(type.name)}}& operator=(const {{as_cppType(type.name)}}&) = delete;
+ {{as_cppType(type.name)}}({{as_cppType(type.name)}}&&);
+ {{as_cppType(type.name)}}& operator=({{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) %}
+ {% set member_declaration = as_annotated_cppType(member, type.has_free_members_function) + render_cpp_default_value(member, False, type.has_free_members_function) %}
{% 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.
diff --git a/generator/templates/dawn/native/api_structs.cpp b/generator/templates/dawn/native/api_structs.cpp
index 7e7a0b8..96cc9cf 100644
--- a/generator/templates/dawn/native/api_structs.cpp
+++ b/generator/templates/dawn/native/api_structs.cpp
@@ -72,4 +72,45 @@
}
{% endfor %}
+
+ {% for type in by_category["structure"] if type.has_free_members_function %}
+ // {{as_cppType(type.name)}}
+ {{as_cppType(type.name)}}::~{{as_cppType(type.name)}}() {
+ if (
+ {%- for member in type.members if member.annotation != 'value' %}
+ {% if not loop.first %} || {% endif -%}
+ this->{{member.name.camelCase()}} != nullptr
+ {%- endfor -%}
+ ) {
+ API{{as_MethodSuffix(type.name, Name("free members"))}}(*reinterpret_cast<{{as_cType(type.name)}}*>(this));
+ }
+ }
+
+ {{as_cppType(type.name)}}::{{as_cppType(type.name)}}({{as_cppType(type.name)}}&& rhs)
+ : {% for member in type.members %}
+ {%- set memberName = member.name.camelCase() -%}
+ {{memberName}}(rhs.{{memberName}}){% if not loop.last %},{{"\n "}}{% endif %}
+ {% endfor -%}
+ {
+ {% for member in type.members %}
+ rhs.{{member.name.camelCase()}} = {};
+ {% endfor %}
+ }
+
+ {{as_cppType(type.name)}}& {{as_cppType(type.name)}}::operator=({{as_cppType(type.name)}}&& rhs) {
+ if (&rhs == this) {
+ return *this;
+ }
+ this->~{{as_cppType(type.name)}}();
+ {% for member in type.members %}
+ this->{{member.name.camelCase()}} = std::move(rhs.{{member.name.camelCase()}});
+ {% endfor %}
+ {% for member in type.members %}
+ rhs.{{member.name.camelCase()}} = {};
+ {% endfor %}
+ return *this;
+ }
+
+ {% endfor %}
+
} // namespace {{native_namespace}}
diff --git a/generator/templates/dawn/native/api_structs.h b/generator/templates/dawn/native/api_structs.h
index 2de5805..ed77c4c 100644
--- a/generator/templates/dawn/native/api_structs.h
+++ b/generator/templates/dawn/native/api_structs.h
@@ -57,6 +57,15 @@
{% else %}
struct {{as_cppType(type.name)}} {
{% endif %}
+ {% if type.has_free_members_function %}
+ {{as_cppType(type.name)}}() = default;
+ ~{{as_cppType(type.name)}}();
+ {{as_cppType(type.name)}}(const {{as_cppType(type.name)}}&) = delete;
+ {{as_cppType(type.name)}}& operator=(const {{as_cppType(type.name)}}&) = delete;
+ {{as_cppType(type.name)}}({{as_cppType(type.name)}}&&);
+ {{as_cppType(type.name)}}& operator=({{as_cppType(type.name)}}&&);
+
+ {% endif %}
{% if type.extensible %}
{% set chainedStructType = "ChainedStructOut" if type.output else "ChainedStruct const" %}
{{chainedStructType}} * nextInChain = nullptr;
@@ -83,6 +92,11 @@
using {{as_cppType(typeDef.name)}} = {{as_cppType(typeDef.type.name)}};
{% endfor %}
+ {% for type in by_category["structure"] if type.has_free_members_function %}
+ // {{as_cppType(type.name)}}
+ void API{{as_MethodSuffix(type.name, Name("free members"))}}({{as_cType(type.name)}});
+ {% endfor %}
+
} // namespace {{native_namespace}}
#endif // {{DIR}}_{{namespace.upper()}}_STRUCTS_H_
diff --git a/generator/templates/dawn_proc_table.h b/generator/templates/dawn_proc_table.h
index 16f3fc2..10cfe3e 100644
--- a/generator/templates/dawn_proc_table.h
+++ b/generator/templates/dawn_proc_table.h
@@ -30,6 +30,7 @@
{% endfor %}
{% endfor %}
+
} {{Prefix}}ProcTable;
#endif // DAWN_{{Prefix.upper()}}_PROC_TABLE_H_
diff --git a/generator/templates/mock_api.cpp b/generator/templates/mock_api.cpp
index bf8f871..91bcfce 100644
--- a/generator/templates/mock_api.cpp
+++ b/generator/templates/mock_api.cpp
@@ -13,6 +13,7 @@
//* limitations under the License.
{% set api = metadata.api.lower() %}
+#include "dawn/common/Log.h"
#include "mock_{{api}}.h"
using namespace testing;
@@ -48,6 +49,12 @@
table->{{as_varName(type.name, method.name)}} = reinterpret_cast<{{as_cProc(type.name, method.name)}}>(Forward{{as_MethodSuffix(type.name, method.name)}});
{% endfor %}
{% endfor %}
+
+ {% for type in by_category["structure"] if type.has_free_members_function %}
+ table->{{as_varName(type.name, Name("free members"))}} = []({{as_cType(type.name)}} {{as_varName(type.name)}}) {
+ dawn::WarningLog() << "No mock available for {{as_varName(type.name, Name('free members'))}}";
+ };
+ {% endfor %}
}
{% for type in by_category["object"] %}
diff --git a/src/dawn/native/Adapter.cpp b/src/dawn/native/Adapter.cpp
index 52b5dcb..6111f71 100644
--- a/src/dawn/native/Adapter.cpp
+++ b/src/dawn/native/Adapter.cpp
@@ -93,14 +93,40 @@
powerPreferenceDesc->powerPreference = mPowerPreference;
}
properties->vendorID = mPhysicalDevice->GetVendorId();
- properties->vendorName = mPhysicalDevice->GetVendorName().c_str();
- properties->architecture = mPhysicalDevice->GetArchitectureName().c_str();
properties->deviceID = mPhysicalDevice->GetDeviceId();
- properties->name = mPhysicalDevice->GetName().c_str();
- properties->driverDescription = mPhysicalDevice->GetDriverDescription().c_str();
properties->adapterType = mPhysicalDevice->GetAdapterType();
properties->backendType = mPhysicalDevice->GetBackendType();
properties->compatibilityMode = mFeatureLevel == FeatureLevel::Compatibility;
+
+ // Get lengths, with null terminators.
+ size_t vendorNameCLen = mPhysicalDevice->GetVendorName().length() + 1;
+ size_t architectureCLen = mPhysicalDevice->GetArchitectureName().length() + 1;
+ size_t nameCLen = mPhysicalDevice->GetName().length() + 1;
+ size_t driverDescriptionCLen = mPhysicalDevice->GetDriverDescription().length() + 1;
+
+ // Allocate space for all strings.
+ char* ptr = new char[vendorNameCLen + architectureCLen + nameCLen + driverDescriptionCLen];
+
+ properties->vendorName = ptr;
+ memcpy(ptr, mPhysicalDevice->GetVendorName().c_str(), vendorNameCLen);
+ ptr += vendorNameCLen;
+
+ properties->architecture = ptr;
+ memcpy(ptr, mPhysicalDevice->GetArchitectureName().c_str(), architectureCLen);
+ ptr += architectureCLen;
+
+ properties->name = ptr;
+ memcpy(ptr, mPhysicalDevice->GetName().c_str(), nameCLen);
+ ptr += nameCLen;
+
+ properties->driverDescription = ptr;
+ memcpy(ptr, mPhysicalDevice->GetDriverDescription().c_str(), driverDescriptionCLen);
+ ptr += driverDescriptionCLen;
+}
+
+void APIAdapterPropertiesFreeMembers(WGPUAdapterProperties properties) {
+ // This single delete is enough because everything is a single allocation.
+ delete[] properties.vendorName;
}
bool AdapterBase::APIHasFeature(wgpu::FeatureName feature) const {
diff --git a/src/dawn/native/SharedTextureMemory.cpp b/src/dawn/native/SharedTextureMemory.cpp
index b097e64..d044906 100644
--- a/src/dawn/native/SharedTextureMemory.cpp
+++ b/src/dawn/native/SharedTextureMemory.cpp
@@ -55,4 +55,6 @@
DAWN_UNUSED(GetDevice()->ConsumedError(DAWN_UNIMPLEMENTED_ERROR("Not implemented")));
}
+void APISharedTextureMemoryEndAccessStateFreeMembers(WGPUSharedTextureMemoryEndAccessState state) {}
+
} // namespace dawn::native
diff --git a/src/dawn/tests/AdapterTestConfig.cpp b/src/dawn/tests/AdapterTestConfig.cpp
index 476e01a..13f1f15 100644
--- a/src/dawn/tests/AdapterTestConfig.cpp
+++ b/src/dawn/tests/AdapterTestConfig.cpp
@@ -73,7 +73,16 @@
TestAdapterProperties::TestAdapterProperties(const wgpu::AdapterProperties& properties,
bool selected)
- : wgpu::AdapterProperties(properties), adapterName(properties.name), selected(selected) {}
+ : vendorID(properties.vendorID),
+ vendorName(properties.vendorName),
+ architecture(properties.architecture),
+ deviceID(properties.deviceID),
+ name(properties.name),
+ driverDescription(properties.driverDescription),
+ adapterType(properties.adapterType),
+ backendType(properties.backendType),
+ compatibilityMode(properties.compatibilityMode),
+ selected(selected) {}
std::string TestAdapterProperties::ParamName() const {
switch (backendType) {
@@ -119,7 +128,7 @@
forceDisabledWorkarounds(config.forceDisabledWorkarounds) {}
std::ostream& operator<<(std::ostream& os, const AdapterTestParam& param) {
- os << param.adapterProperties.ParamName() << " " << param.adapterProperties.adapterName;
+ os << param.adapterProperties.ParamName() << " " << param.adapterProperties.name;
// In a Windows Remote Desktop session there are two adapters named "Microsoft Basic Render
// Driver" with different adapter types. We must differentiate them to avoid any tests using the
diff --git a/src/dawn/tests/AdapterTestConfig.h b/src/dawn/tests/AdapterTestConfig.h
index 2273559..7ce824c 100644
--- a/src/dawn/tests/AdapterTestConfig.h
+++ b/src/dawn/tests/AdapterTestConfig.h
@@ -35,17 +35,21 @@
std::vector<const char*> forceDisabledWorkarounds;
};
-struct TestAdapterProperties : wgpu::AdapterProperties {
+struct TestAdapterProperties {
TestAdapterProperties(const wgpu::AdapterProperties& properties, bool selected);
- std::string adapterName;
+ uint32_t vendorID;
+ std::string vendorName;
+ std::string architecture;
+ uint32_t deviceID;
+ std::string name;
+ std::string driverDescription;
+ wgpu::AdapterType adapterType;
+ wgpu::BackendType backendType;
+ bool compatibilityMode;
bool selected;
std::string ParamName() const;
std::string AdapterTypeName() const;
-
- private:
- // This may be temporary, so it is copied into |adapterName| and made private.
- using wgpu::AdapterProperties::name;
};
struct AdapterTestParam {
diff --git a/src/dawn/tests/DawnTest.cpp b/src/dawn/tests/DawnTest.cpp
index 07eff47..f33f41f 100644
--- a/src/dawn/tests/DawnTest.cpp
+++ b/src/dawn/tests/DawnTest.cpp
@@ -130,7 +130,7 @@
std::string DawnTestBase::PrintToStringParamName::SanitizeParamName(
std::string paramName,
- const wgpu::AdapterProperties& properties,
+ const TestAdapterProperties& properties,
size_t index) const {
// Sanitize the adapter name for GoogleTest
std::string sanitizedName = std::regex_replace(paramName, std::regex("[^a-zA-Z0-9]+"), "_") +
@@ -423,6 +423,8 @@
}
void DawnTestEnvironment::SelectPreferredAdapterProperties(const native::Instance* instance) {
+ dawnProcSetProcs(&dawn::native::GetProcs());
+
// Get the first available preferred device type.
std::optional<wgpu::AdapterType> preferredDeviceType;
[&] {
@@ -610,14 +612,14 @@
// Preparing for outputting hex numbers
log << std::showbase << std::hex << std::setfill('0') << std::setw(4) << " - \""
- << properties.adapterName << "\" - \"" << properties.driverDescription
+ << properties.name << "\" - \"" << properties.driverDescription
<< (properties.selected ? " [Selected]" : "") << "\"\n"
<< " type: " << properties.AdapterTypeName()
<< ", backend: " << properties.ParamName()
<< ", compatibilityMode: " << (properties.compatibilityMode ? "true" : "false") << "\n"
<< " vendorId: 0x" << vendorId.str() << ", deviceId: 0x" << deviceId.str() << "\n";
- if (strlen(properties.vendorName) || strlen(properties.architecture)) {
+ if (!properties.vendorName.empty() || !properties.architecture.empty()) {
log << " vendorName: " << properties.vendorName
<< ", architecture: " << properties.architecture << "\n";
}
@@ -725,7 +727,7 @@
properties.deviceID == param.adapterProperties.deviceID &&
properties.vendorID == param.adapterProperties.vendorID &&
properties.adapterType == param.adapterProperties.adapterType &&
- strcmp(properties.name, param.adapterProperties.adapterName.c_str()) == 0);
+ strcmp(properties.name, param.adapterProperties.name.c_str()) == 0);
});
ASSERT(it != adapters.end());
gCurrentTest->mBackendAdapter = *it;
@@ -843,12 +845,12 @@
}
bool DawnTestBase::IsANGLE() const {
- return !mParam.adapterProperties.adapterName.find("ANGLE");
+ return !mParam.adapterProperties.name.find("ANGLE");
}
bool DawnTestBase::IsANGLESwiftShader() const {
- return !mParam.adapterProperties.adapterName.find("ANGLE") &&
- (mParam.adapterProperties.adapterName.find("SwiftShader") != std::string::npos);
+ return !mParam.adapterProperties.name.find("ANGLE") &&
+ (mParam.adapterProperties.name.find("SwiftShader") != std::string::npos);
}
bool DawnTestBase::IsWARP() const {
@@ -989,7 +991,7 @@
return {};
}
-const wgpu::AdapterProperties& DawnTestBase::GetAdapterProperties() const {
+const TestAdapterProperties& DawnTestBase::GetAdapterProperties() const {
return mParam.adapterProperties;
}
diff --git a/src/dawn/tests/DawnTest.h b/src/dawn/tests/DawnTest.h
index 8bdbe0a..4ba3f61 100644
--- a/src/dawn/tests/DawnTest.h
+++ b/src/dawn/tests/DawnTest.h
@@ -288,7 +288,7 @@
struct PrintToStringParamName {
explicit PrintToStringParamName(const char* test);
std::string SanitizeParamName(std::string paramName,
- const wgpu::AdapterProperties& properties,
+ const TestAdapterProperties& properties,
size_t index) const;
template <class ParamType>
@@ -582,7 +582,7 @@
virtual wgpu::RequiredLimits GetRequiredLimits(const wgpu::SupportedLimits&);
- const wgpu::AdapterProperties& GetAdapterProperties() const;
+ const TestAdapterProperties& GetAdapterProperties() const;
wgpu::SupportedLimits GetAdapterLimits();
wgpu::SupportedLimits GetSupportedLimits();
diff --git a/src/dawn/tests/end2end/AdapterCreationTests.cpp b/src/dawn/tests/end2end/AdapterCreationTests.cpp
index f12370e..a756248 100644
--- a/src/dawn/tests/end2end/AdapterCreationTests.cpp
+++ b/src/dawn/tests/end2end/AdapterCreationTests.cpp
@@ -13,6 +13,7 @@
// limitations under the License.
#include <memory>
+#include <string>
#include <utility>
#include "dawn/common/GPUInfo.h"
@@ -246,5 +247,180 @@
EXPECT_EQ(adapter.GetInstance().Get(), instance.Get());
}
+// Test that calling AdapterGetProperties returns separate allocations for strings.
+// However, the string contents are equivalent.
+TEST_F(AdapterCreationTest, PropertiesUnique) {
+ wgpu::RequestAdapterOptions options = {};
+
+ MockCallback<WGPURequestAdapterCallback> cb;
+
+ WGPUAdapter cAdapter = nullptr;
+ EXPECT_CALL(cb, Call(WGPURequestAdapterStatus_Success, _, nullptr, this))
+ .WillOnce(SaveArg<1>(&cAdapter));
+ instance.RequestAdapter(&options, cb.Callback(), cb.MakeUserdata(this));
+
+ wgpu::Adapter adapter = wgpu::Adapter::Acquire(cAdapter);
+ EXPECT_EQ(adapter != nullptr, anyAdapterAvailable);
+ if (!adapter) {
+ return;
+ }
+
+ wgpu::AdapterProperties properties1;
+ wgpu::AdapterProperties properties2;
+ adapter.GetProperties(&properties1);
+ adapter.GetProperties(&properties2);
+
+ EXPECT_NE(properties1.vendorName, properties2.vendorName);
+ EXPECT_STREQ(properties1.vendorName, properties2.vendorName);
+ EXPECT_NE(properties1.architecture, properties2.architecture);
+ EXPECT_STREQ(properties1.architecture, properties2.architecture);
+ EXPECT_NE(properties1.name, properties2.name);
+ EXPECT_STREQ(properties1.name, properties2.name);
+ EXPECT_NE(properties1.driverDescription, properties2.driverDescription);
+ EXPECT_STREQ(properties1.driverDescription, properties2.driverDescription);
+}
+
+// Test move assignment of the adapter properties.
+TEST_F(AdapterCreationTest, PropertiesMoveAssign) {
+ wgpu::RequestAdapterOptions options = {};
+
+ MockCallback<WGPURequestAdapterCallback> cb;
+
+ WGPUAdapter cAdapter = nullptr;
+ EXPECT_CALL(cb, Call(WGPURequestAdapterStatus_Success, _, nullptr, this))
+ .WillOnce(SaveArg<1>(&cAdapter));
+ instance.RequestAdapter(&options, cb.Callback(), cb.MakeUserdata(this));
+
+ wgpu::Adapter adapter = wgpu::Adapter::Acquire(cAdapter);
+ EXPECT_EQ(adapter != nullptr, anyAdapterAvailable);
+ if (!adapter) {
+ return;
+ }
+
+ wgpu::AdapterProperties properties1;
+ wgpu::AdapterProperties properties2;
+ adapter.GetProperties(&properties1);
+ adapter.GetProperties(&properties2);
+
+ uint32_t vendorID = properties1.vendorID;
+ std::string vendorName = properties1.vendorName;
+ std::string architecture = properties1.architecture;
+ uint32_t deviceID = properties1.deviceID;
+ std::string name = properties1.name;
+ std::string driverDescription = properties1.driverDescription;
+ wgpu::AdapterType adapterType = properties1.adapterType;
+ wgpu::BackendType backendType = properties1.backendType;
+ bool compatibilityMode = properties1.compatibilityMode;
+
+ properties2 = std::move(properties1);
+
+ // Expect properties2 to have properties1's old contents.
+ EXPECT_EQ(properties2.vendorID, vendorID);
+ EXPECT_STREQ(properties2.vendorName, vendorName.c_str());
+ EXPECT_STREQ(properties2.architecture, architecture.c_str());
+ EXPECT_EQ(properties2.deviceID, deviceID);
+ EXPECT_STREQ(properties2.name, name.c_str());
+ EXPECT_STREQ(properties2.driverDescription, driverDescription.c_str());
+ EXPECT_EQ(properties2.adapterType, adapterType);
+ EXPECT_EQ(properties2.backendType, backendType);
+ EXPECT_EQ(properties2.compatibilityMode, compatibilityMode);
+
+ // Expect properties1 to be empty.
+ EXPECT_EQ(properties1.vendorID, 0u);
+ EXPECT_EQ(properties1.vendorName, nullptr);
+ EXPECT_EQ(properties1.architecture, nullptr);
+ EXPECT_EQ(properties1.deviceID, 0u);
+ EXPECT_EQ(properties1.name, nullptr);
+ EXPECT_EQ(properties1.driverDescription, nullptr);
+ EXPECT_EQ(properties1.adapterType, static_cast<wgpu::AdapterType>(0));
+ EXPECT_EQ(properties1.backendType, static_cast<wgpu::BackendType>(0));
+ EXPECT_EQ(properties1.compatibilityMode, false);
+}
+
+// Test move construction of the adapter properties.
+TEST_F(AdapterCreationTest, PropertiesMoveConstruct) {
+ wgpu::RequestAdapterOptions options = {};
+
+ MockCallback<WGPURequestAdapterCallback> cb;
+
+ WGPUAdapter cAdapter = nullptr;
+ EXPECT_CALL(cb, Call(WGPURequestAdapterStatus_Success, _, nullptr, this))
+ .WillOnce(SaveArg<1>(&cAdapter));
+ instance.RequestAdapter(&options, cb.Callback(), cb.MakeUserdata(this));
+
+ wgpu::Adapter adapter = wgpu::Adapter::Acquire(cAdapter);
+ EXPECT_EQ(adapter != nullptr, anyAdapterAvailable);
+ if (!adapter) {
+ return;
+ }
+
+ wgpu::AdapterProperties properties1;
+ adapter.GetProperties(&properties1);
+
+ uint32_t vendorID = properties1.vendorID;
+ std::string vendorName = properties1.vendorName;
+ std::string architecture = properties1.architecture;
+ uint32_t deviceID = properties1.deviceID;
+ std::string name = properties1.name;
+ std::string driverDescription = properties1.driverDescription;
+ wgpu::AdapterType adapterType = properties1.adapterType;
+ wgpu::BackendType backendType = properties1.backendType;
+ bool compatibilityMode = properties1.compatibilityMode;
+
+ wgpu::AdapterProperties properties2(std::move(properties1));
+
+ // Expect properties2 to have properties1's old contents.
+ EXPECT_EQ(properties2.vendorID, vendorID);
+ EXPECT_STREQ(properties2.vendorName, vendorName.c_str());
+ EXPECT_STREQ(properties2.architecture, architecture.c_str());
+ EXPECT_EQ(properties2.deviceID, deviceID);
+ EXPECT_STREQ(properties2.name, name.c_str());
+ EXPECT_STREQ(properties2.driverDescription, driverDescription.c_str());
+ EXPECT_EQ(properties2.adapterType, adapterType);
+ EXPECT_EQ(properties2.backendType, backendType);
+ EXPECT_EQ(properties2.compatibilityMode, compatibilityMode);
+
+ // Expect properties1 to be empty.
+ EXPECT_EQ(properties1.vendorID, 0u);
+ EXPECT_EQ(properties1.vendorName, nullptr);
+ EXPECT_EQ(properties1.architecture, nullptr);
+ EXPECT_EQ(properties1.deviceID, 0u);
+ EXPECT_EQ(properties1.name, nullptr);
+ EXPECT_EQ(properties1.driverDescription, nullptr);
+ EXPECT_EQ(properties1.adapterType, static_cast<wgpu::AdapterType>(0));
+ EXPECT_EQ(properties1.backendType, static_cast<wgpu::BackendType>(0));
+ EXPECT_EQ(properties1.compatibilityMode, false);
+}
+
+// Test that the adapter properties can outlive the adapter.
+TEST_F(AdapterCreationTest, PropertiesOutliveAdapter) {
+ wgpu::RequestAdapterOptions options = {};
+
+ MockCallback<WGPURequestAdapterCallback> cb;
+
+ WGPUAdapter cAdapter = nullptr;
+ EXPECT_CALL(cb, Call(WGPURequestAdapterStatus_Success, _, nullptr, this))
+ .WillOnce(SaveArg<1>(&cAdapter));
+ instance.RequestAdapter(&options, cb.Callback(), cb.MakeUserdata(this));
+
+ wgpu::Adapter adapter = wgpu::Adapter::Acquire(cAdapter);
+ EXPECT_EQ(adapter != nullptr, anyAdapterAvailable);
+ if (!adapter) {
+ return;
+ }
+
+ wgpu::AdapterProperties properties;
+ adapter.GetProperties(&properties);
+
+ // Release the adapter.
+ adapter = nullptr;
+
+ // Copy the properties to std::string, this should not be a use-after-free.
+ std::string vendorName = properties.vendorName;
+ std::string architecture = properties.architecture;
+ std::string name = properties.name;
+ std::string driverDescription = properties.driverDescription;
+}
+
} // anonymous namespace
} // namespace dawn
diff --git a/src/dawn/tests/end2end/DeviceInitializationTests.cpp b/src/dawn/tests/end2end/DeviceInitializationTests.cpp
index a79f0e3..9f86a94 100644
--- a/src/dawn/tests/end2end/DeviceInitializationTests.cpp
+++ b/src/dawn/tests/end2end/DeviceInitializationTests.cpp
@@ -86,7 +86,7 @@
continue;
}
- availableAdapterProperties.push_back(properties);
+ availableAdapterProperties.push_back(std::move(properties));
}
}
@@ -136,7 +136,7 @@
if (properties.backendType == wgpu::BackendType::D3D11) {
continue;
}
- availableAdapterProperties.push_back(properties);
+ availableAdapterProperties.push_back(std::move(properties));
}
}
diff --git a/src/dawn/tests/end2end/PhysicalDeviceDiscoveryTests.cpp b/src/dawn/tests/end2end/PhysicalDeviceDiscoveryTests.cpp
index af0288a..25271ea 100644
--- a/src/dawn/tests/end2end/PhysicalDeviceDiscoveryTests.cpp
+++ b/src/dawn/tests/end2end/PhysicalDeviceDiscoveryTests.cpp
@@ -16,6 +16,7 @@
#include <utility>
#include "dawn/common/GPUInfo.h"
+#include "dawn/dawn_proc.h"
#include "dawn/native/DawnNative.h"
#include "dawn/webgpu_cpp.h"
@@ -45,11 +46,13 @@
namespace dawn {
namespace {
-class PhysicalDeviceDiscoveryTests : public ::testing::Test {};
+class PhysicalDeviceDiscoveryTests : public ::testing::Test {
+ void SetUp() override { dawnProcSetProcs(&dawn::native::GetProcs()); }
+};
#if defined(DAWN_ENABLE_BACKEND_VULKAN)
// Test only discovering the SwiftShader physical devices
-TEST(PhysicalDeviceDiscoveryTests, OnlySwiftShader) {
+TEST_F(PhysicalDeviceDiscoveryTests, OnlySwiftShader) {
native::Instance instance;
native::vulkan::PhysicalDeviceDiscoveryOptions options;
@@ -69,7 +72,7 @@
}
// Test discovering only Vulkan physical devices
-TEST(PhysicalDeviceDiscoveryTests, OnlyVulkan) {
+TEST_F(PhysicalDeviceDiscoveryTests, OnlyVulkan) {
native::Instance instance;
native::vulkan::PhysicalDeviceDiscoveryOptions options;
@@ -87,7 +90,7 @@
#if defined(DAWN_ENABLE_BACKEND_D3D11)
// Test discovering only D3D11 physical devices
-TEST(PhysicalDeviceDiscoveryTests, OnlyD3D11) {
+TEST_F(PhysicalDeviceDiscoveryTests, OnlyD3D11) {
native::Instance instance;
native::d3d11::PhysicalDeviceDiscoveryOptions options;
@@ -103,7 +106,7 @@
}
// Test discovering a D3D11 physical device from a prexisting DXGI adapter
-TEST(PhysicalDeviceDiscoveryTests, MatchingDXGIAdapterD3D11) {
+TEST_F(PhysicalDeviceDiscoveryTests, MatchingDXGIAdapterD3D11) {
using Microsoft::WRL::ComPtr;
ComPtr<IDXGIFactory4> dxgiFactory;
@@ -135,7 +138,7 @@
#if defined(DAWN_ENABLE_BACKEND_D3D12)
// Test discovering only D3D12 physical devices
-TEST(PhysicalDeviceDiscoveryTests, OnlyD3D12) {
+TEST_F(PhysicalDeviceDiscoveryTests, OnlyD3D12) {
native::Instance instance;
native::d3d12::PhysicalDeviceDiscoveryOptions options;
@@ -151,7 +154,7 @@
}
// Test discovering a D3D12 physical device from a prexisting DXGI adapter
-TEST(PhysicalDeviceDiscoveryTests, MatchingDXGIAdapterD3D12) {
+TEST_F(PhysicalDeviceDiscoveryTests, MatchingDXGIAdapterD3D12) {
using Microsoft::WRL::ComPtr;
ComPtr<IDXGIFactory4> dxgiFactory;
@@ -183,7 +186,7 @@
#if defined(DAWN_ENABLE_BACKEND_METAL)
// Test discovering only Metal physical devices
-TEST(PhysicalDeviceDiscoveryTests, OnlyMetal) {
+TEST_F(PhysicalDeviceDiscoveryTests, OnlyMetal) {
native::Instance instance;
native::metal::PhysicalDeviceDiscoveryOptions options;
@@ -202,7 +205,7 @@
#if defined(DAWN_ENABLE_BACKEND_METAL) && defined(DAWN_ENABLE_BACKEND_VULKAN)
// Test discovering the Metal backend, then the Vulkan backend
// does not duplicate physical devices.
-TEST(PhysicalDeviceDiscoveryTests, OneBackendThenTheOther) {
+TEST_F(PhysicalDeviceDiscoveryTests, OneBackendThenTheOther) {
native::Instance instance;
uint32_t metalAdapterCount = 0;
{
@@ -239,10 +242,12 @@
}
#endif // defined(DAWN_ENABLE_BACKEND_VULKAN) && defined(DAWN_ENABLE_BACKEND_METAL)
-class AdapterEnumerationTests : public ::testing::Test {};
+class AdapterEnumerationTests : public ::testing::Test {
+ void SetUp() override { dawnProcSetProcs(&dawn::native::GetProcs()); }
+};
// Test only enumerating the fallback adapters
-TEST(AdapterEnumerationTests, OnlyFallback) {
+TEST_F(AdapterEnumerationTests, OnlyFallback) {
native::Instance instance;
wgpu::RequestAdapterOptions adapterOptions = {};
@@ -260,7 +265,7 @@
}
// Test enumerating only Vulkan physical devices
-TEST(AdapterEnumerationTests, OnlyVulkan) {
+TEST_F(AdapterEnumerationTests, OnlyVulkan) {
native::Instance instance;
wgpu::RequestAdapterOptions adapterOptions = {};
@@ -276,7 +281,7 @@
}
// Test enumerating only D3D11 physical devices
-TEST(AdapterEnumerationTests, OnlyD3D11) {
+TEST_F(AdapterEnumerationTests, OnlyD3D11) {
native::Instance instance;
wgpu::RequestAdapterOptions adapterOptions = {};
@@ -293,7 +298,7 @@
#if defined(DAWN_ENABLE_BACKEND_D3D11)
// Test enumerating a D3D11 physical device from a prexisting DXGI adapter
-TEST(AdapterEnumerationTests, MatchingDXGIAdapterD3D11) {
+TEST_F(AdapterEnumerationTests, MatchingDXGIAdapterD3D11) {
using Microsoft::WRL::ComPtr;
ComPtr<IDXGIFactory4> dxgiFactory;
@@ -337,11 +342,11 @@
adaptersAgain[0].GetProperties(&propertiesAgain);
EXPECT_EQ(properties.vendorID, propertiesAgain.vendorID);
- EXPECT_EQ(properties.vendorName, propertiesAgain.vendorName);
- EXPECT_EQ(properties.architecture, propertiesAgain.architecture);
+ EXPECT_STREQ(properties.vendorName, propertiesAgain.vendorName);
+ EXPECT_STREQ(properties.architecture, propertiesAgain.architecture);
EXPECT_EQ(properties.deviceID, propertiesAgain.deviceID);
- EXPECT_EQ(properties.name, propertiesAgain.name);
- EXPECT_EQ(properties.driverDescription, propertiesAgain.driverDescription);
+ EXPECT_STREQ(properties.name, propertiesAgain.name);
+ EXPECT_STREQ(properties.driverDescription, propertiesAgain.driverDescription);
EXPECT_EQ(properties.adapterType, propertiesAgain.adapterType);
EXPECT_EQ(properties.backendType, propertiesAgain.backendType);
EXPECT_EQ(properties.compatibilityMode, propertiesAgain.compatibilityMode);
@@ -350,7 +355,7 @@
#endif // defined(DAWN_ENABLE_BACKEND_D3D11)
// Test enumerating only D3D12 physical devices
-TEST(AdapterEnumerationTests, OnlyD3D12) {
+TEST_F(AdapterEnumerationTests, OnlyD3D12) {
native::Instance instance;
wgpu::RequestAdapterOptions adapterOptions = {};
@@ -367,7 +372,7 @@
#if defined(DAWN_ENABLE_BACKEND_D3D12)
// Test enumerating a D3D12 physical device from a prexisting DXGI adapter
-TEST(AdapterEnumerationTests, MatchingDXGIAdapterD3D12) {
+TEST_F(AdapterEnumerationTests, MatchingDXGIAdapterD3D12) {
using Microsoft::WRL::ComPtr;
ComPtr<IDXGIFactory4> dxgiFactory;
@@ -411,11 +416,11 @@
adaptersAgain[0].GetProperties(&propertiesAgain);
EXPECT_EQ(properties.vendorID, propertiesAgain.vendorID);
- EXPECT_EQ(properties.vendorName, propertiesAgain.vendorName);
- EXPECT_EQ(properties.architecture, propertiesAgain.architecture);
+ EXPECT_STREQ(properties.vendorName, propertiesAgain.vendorName);
+ EXPECT_STREQ(properties.architecture, propertiesAgain.architecture);
EXPECT_EQ(properties.deviceID, propertiesAgain.deviceID);
- EXPECT_EQ(properties.name, propertiesAgain.name);
- EXPECT_EQ(properties.driverDescription, propertiesAgain.driverDescription);
+ EXPECT_STREQ(properties.name, propertiesAgain.name);
+ EXPECT_STREQ(properties.driverDescription, propertiesAgain.driverDescription);
EXPECT_EQ(properties.adapterType, propertiesAgain.adapterType);
EXPECT_EQ(properties.backendType, propertiesAgain.backendType);
EXPECT_EQ(properties.compatibilityMode, propertiesAgain.compatibilityMode);
@@ -424,7 +429,7 @@
#endif // defined(DAWN_ENABLE_BACKEND_D3D12)
// Test enumerating only Metal physical devices
-TEST(AdapterEnumerationTests, OnlyMetal) {
+TEST_F(AdapterEnumerationTests, OnlyMetal) {
native::Instance instance;
wgpu::RequestAdapterOptions adapterOptions = {};
@@ -441,7 +446,7 @@
// Test enumerating the Metal backend, then the Vulkan backend
// does not duplicate physical devices.
-TEST(AdapterEnumerationTests, OneBackendThenTheOther) {
+TEST_F(AdapterEnumerationTests, OneBackendThenTheOther) {
wgpu::RequestAdapterOptions adapterOptions = {};
adapterOptions.backendType = wgpu::BackendType::Metal;
diff --git a/src/dawn/tests/unittests/wire/WireInstanceTests.cpp b/src/dawn/tests/unittests/wire/WireInstanceTests.cpp
index b583648..69c3b15 100644
--- a/src/dawn/tests/unittests/wire/WireInstanceTests.cpp
+++ b/src/dawn/tests/unittests/wire/WireInstanceTests.cpp
@@ -107,15 +107,15 @@
auto* userdata = cb.MakeUserdata(this);
instance.RequestAdapter(&options, cb.Callback(), userdata);
- wgpu::AdapterProperties fakeProperties = {};
+ WGPUAdapterProperties fakeProperties = {};
fakeProperties.vendorID = 0x134;
fakeProperties.vendorName = "fake-vendor";
fakeProperties.architecture = "fake-architecture";
fakeProperties.deviceID = 0x918;
fakeProperties.name = "fake adapter";
fakeProperties.driverDescription = "hello world";
- fakeProperties.backendType = wgpu::BackendType::D3D12;
- fakeProperties.adapterType = wgpu::AdapterType::IntegratedGPU;
+ fakeProperties.backendType = WGPUBackendType_D3D12;
+ fakeProperties.adapterType = WGPUAdapterType_IntegratedGPU;
wgpu::SupportedLimits fakeLimits = {};
fakeLimits.limits.maxTextureDimension1D = 433;
@@ -131,8 +131,7 @@
EXPECT_CALL(api, OnInstanceRequestAdapter(apiInstance, NotNull(), NotNull(), NotNull()))
.WillOnce(InvokeWithoutArgs([&] {
EXPECT_CALL(api, AdapterGetProperties(apiAdapter, NotNull()))
- .WillOnce(
- SetArgPointee<1>(*reinterpret_cast<WGPUAdapterProperties*>(&fakeProperties)));
+ .WillOnce(SetArgPointee<1>(fakeProperties));
EXPECT_CALL(api, AdapterGetLimits(apiAdapter, NotNull()))
.WillOnce(WithArg<1>(Invoke([&](WGPUSupportedLimits* limits) {
@@ -162,14 +161,15 @@
wgpu::AdapterProperties properties;
adapter.GetProperties(&properties);
- EXPECT_EQ(properties.vendorID, fakeProperties.vendorID);
- EXPECT_STREQ(properties.vendorName, fakeProperties.vendorName);
- EXPECT_STREQ(properties.architecture, fakeProperties.architecture);
- EXPECT_EQ(properties.deviceID, fakeProperties.deviceID);
- EXPECT_STREQ(properties.name, fakeProperties.name);
- EXPECT_STREQ(properties.driverDescription, fakeProperties.driverDescription);
- EXPECT_EQ(properties.backendType, fakeProperties.backendType);
- EXPECT_EQ(properties.adapterType, fakeProperties.adapterType);
+ const auto& rhs = *reinterpret_cast<wgpu::AdapterProperties*>(&fakeProperties);
+ EXPECT_EQ(properties.vendorID, rhs.vendorID);
+ EXPECT_STREQ(properties.vendorName, rhs.vendorName);
+ EXPECT_STREQ(properties.architecture, rhs.architecture);
+ EXPECT_EQ(properties.deviceID, rhs.deviceID);
+ EXPECT_STREQ(properties.name, rhs.name);
+ EXPECT_STREQ(properties.driverDescription, rhs.driverDescription);
+ EXPECT_EQ(properties.backendType, rhs.backendType);
+ EXPECT_EQ(properties.adapterType, rhs.adapterType);
wgpu::SupportedLimits limits;
EXPECT_TRUE(adapter.GetLimits(&limits));
diff --git a/src/dawn/wire/client/Adapter.cpp b/src/dawn/wire/client/Adapter.cpp
index 2d60b7e..d1052c4 100644
--- a/src/dawn/wire/client/Adapter.cpp
+++ b/src/dawn/wire/client/Adapter.cpp
@@ -60,6 +60,36 @@
void Adapter::GetProperties(WGPUAdapterProperties* properties) const {
*properties = mProperties;
+
+ // Get lengths, with null terminators.
+ size_t vendorNameCLen = strlen(mProperties.vendorName) + 1;
+ size_t architectureCLen = strlen(mProperties.architecture) + 1;
+ size_t nameCLen = strlen(mProperties.name) + 1;
+ size_t driverDescriptionCLen = strlen(mProperties.driverDescription) + 1;
+
+ // Allocate space for all strings.
+ char* ptr = new char[vendorNameCLen + architectureCLen + nameCLen + driverDescriptionCLen];
+
+ properties->vendorName = ptr;
+ memcpy(ptr, mProperties.vendorName, vendorNameCLen);
+ ptr += vendorNameCLen;
+
+ properties->architecture = ptr;
+ memcpy(ptr, mProperties.architecture, architectureCLen);
+ ptr += architectureCLen;
+
+ properties->name = ptr;
+ memcpy(ptr, mProperties.name, nameCLen);
+ ptr += nameCLen;
+
+ properties->driverDescription = ptr;
+ memcpy(ptr, mProperties.driverDescription, driverDescriptionCLen);
+ ptr += driverDescriptionCLen;
+}
+
+void ClientAdapterPropertiesFreeMembers(WGPUAdapterProperties properties) {
+ // This single delete is enough because everything is a single allocation.
+ delete[] properties.vendorName;
}
void Adapter::RequestDevice(const WGPUDeviceDescriptor* descriptor,
diff --git a/src/dawn/wire/client/Adapter.h b/src/dawn/wire/client/Adapter.h
index 69e8fff..ec8bb57 100644
--- a/src/dawn/wire/client/Adapter.h
+++ b/src/dawn/wire/client/Adapter.h
@@ -66,6 +66,8 @@
RequestTracker<RequestDeviceData> mRequestDeviceRequests;
};
+void ClientAdapterPropertiesFreeMembers(WGPUAdapterProperties);
+
} // namespace dawn::wire::client
#endif // SRC_DAWN_WIRE_CLIENT_ADAPTER_H_
diff --git a/src/dawn/wire/server/ServerInstance.cpp b/src/dawn/wire/server/ServerInstance.cpp
index 7fa4b17..e235a5f 100644
--- a/src/dawn/wire/server/ServerInstance.cpp
+++ b/src/dawn/wire/server/ServerInstance.cpp
@@ -79,6 +79,7 @@
cmd.limits = &limits;
SerializeCommand(cmd);
+ mProcs.adapterPropertiesFreeMembers(properties);
}
} // namespace dawn::wire::server