Add wgpuDeviceGetLimits. Split Required/Supported limit structs
Bug: dawn:685
Change-Id: Ibb5dd0479f5e887d4b2ca864c014ebaafb674dba
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/64443
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Austin Eng <enga@chromium.org>
diff --git a/dawn.json b/dawn.json
index 859df44..91107ca 100644
--- a/dawn.json
+++ b/dawn.json
@@ -20,6 +20,7 @@
"adapter properties": {
"category": "structure",
"extensible": true,
+ "output": true,
"members": [
{"name": "device ID", "type": "uint32_t"},
{"name": "vendor ID", "type": "uint32_t"},
@@ -735,6 +736,13 @@
]
},
{
+ "name": "create external texture",
+ "returns": "external texture",
+ "args": [
+ {"name": "external texture descriptor", "type": "external texture descriptor", "annotation": "const*"}
+ ]
+ },
+ {
"name": "create pipeline layout",
"returns": "pipeline layout",
"args": [
@@ -801,15 +809,15 @@
]
},
{
- "name": "get queue",
- "returns": "queue"
+ "name": "get limits",
+ "returns": "bool",
+ "args": [
+ {"name": "limits", "type": "supported limits", "annotation": "*"}
+ ]
},
{
- "name": "create external texture",
- "returns": "external texture",
- "args": [
- {"name": "external texture descriptor", "type": "external texture descriptor", "annotation": "const*"}
- ]
+ "name": "get queue",
+ "returns": "queue"
},
{
"name": "inject error",
@@ -885,7 +893,7 @@
{"name": "depth clamping", "type": "bool", "default": "false"},
{"name": "invalid extension", "type": "bool", "default": "false"},
{"name": "dawn internal usages", "type": "bool", "default": "false"},
- {"name": "limits", "type": "limits"}
+ {"name": "limits", "type": "supported limits"}
]
},
"double": {
@@ -901,7 +909,6 @@
},
"limits": {
"category": "structure",
- "extensible": true,
"members": [
{"name": "max texture dimension 1D", "type": "uint32_t", "default": "WGPU_LIMIT_U32_UNDEFINED"},
{"name": "max texture dimension 2D", "type": "uint32_t", "default": "WGPU_LIMIT_U32_UNDEFINED"},
@@ -931,6 +938,21 @@
{"name": "max compute workgroups per dimension", "type": "uint32_t", "default": "WGPU_LIMIT_U32_UNDEFINED"}
]
},
+ "required limits": {
+ "category": "structure",
+ "extensible": true,
+ "members": [
+ {"name": "limits", "type": "limits"}
+ ]
+ },
+ "supported limits": {
+ "category": "structure",
+ "extensible": true,
+ "output": true,
+ "members": [
+ {"name": "limits", "type": "limits"}
+ ]
+ },
"logging callback": {
"category": "callback",
"args": [
diff --git a/dawn_wire.json b/dawn_wire.json
index 5f881c1..7d4b89c 100644
--- a/dawn_wire.json
+++ b/dawn_wire.json
@@ -153,6 +153,7 @@
"DeviceCreateBuffer",
"DeviceCreateComputePipelineAsync",
"DeviceCreateRenderPipelineAsync",
+ "DeviceGetLimits",
"DevicePopErrorScope",
"DeviceSetDeviceLostCallback",
"DeviceSetUncapturedErrorCallback",
diff --git a/generator/dawn_json_generator.py b/generator/dawn_json_generator.py
index c6268ed..23558e6 100644
--- a/generator/dawn_json_generator.py
+++ b/generator/dawn_json_generator.py
@@ -206,6 +206,7 @@
Type.__init__(self, name, json_data)
self.chained = json_data.get("chained", False)
self.extensible = json_data.get("extensible", False)
+ self.output = json_data.get("output", False)
# Chained structs inherit from wgpu::ChainedStruct, which has
# nextInChain, so setting both extensible and chained would result in
# two nextInChain members.
diff --git a/generator/templates/dawn_wire/WireCmd.cpp b/generator/templates/dawn_wire/WireCmd.cpp
index 41809a1..c9dc5e2 100644
--- a/generator/templates/dawn_wire/WireCmd.cpp
+++ b/generator/templates/dawn_wire/WireCmd.cpp
@@ -496,13 +496,22 @@
}
size_t GetChainedStructExtraRequiredSize(const WGPUChainedStruct* chainedStruct);
- DAWN_NO_DISCARD WireResult SerializeChainedStruct(WGPUChainedStruct const* chainedStruct,
+ DAWN_NO_DISCARD WireResult SerializeChainedStruct(const WGPUChainedStruct* chainedStruct,
SerializeBuffer* buffer,
const ObjectIdProvider& provider);
WireResult DeserializeChainedStruct(const WGPUChainedStruct** outChainNext,
- DeserializeBuffer* deserializeBuffer,
- DeserializeAllocator* allocator,
- const ObjectIdResolver& resolver);
+ DeserializeBuffer* deserializeBuffer,
+ DeserializeAllocator* allocator,
+ const ObjectIdResolver& resolver);
+
+ size_t GetChainedStructExtraRequiredSize(WGPUChainedStructOut* chainedStruct);
+ DAWN_NO_DISCARD WireResult SerializeChainedStruct(WGPUChainedStructOut* chainedStruct,
+ SerializeBuffer* buffer,
+ const ObjectIdProvider& provider);
+ WireResult DeserializeChainedStruct(WGPUChainedStructOut** outChainNext,
+ DeserializeBuffer* deserializeBuffer,
+ DeserializeAllocator* allocator,
+ const ObjectIdResolver& resolver);
//* Output structure [de]serialization first because it is used by commands.
{% for type in by_category["structure"] %}
@@ -513,12 +522,19 @@
{% endif %}
{% endfor %}
- size_t GetChainedStructExtraRequiredSize(const WGPUChainedStruct* chainedStruct) {
+{% macro make_chained_struct_serialization_helpers(out) %}
+ {% set ChainedStructPtr = "WGPUChainedStructOut*" if out else "const WGPUChainedStruct*" %}
+ {% set ChainedStruct = "WGPUChainedStructOut" if out else "WGPUChainedStruct" %}
+ size_t GetChainedStructExtraRequiredSize({{ChainedStructPtr}} chainedStruct) {
ASSERT(chainedStruct != nullptr);
size_t result = 0;
while (chainedStruct != nullptr) {
switch (chainedStruct->sType) {
- {% for sType in types["s type"].values if sType.valid and sType.name.CamelCase() not in client_side_structures %}
+ {% for sType in types["s type"].values if (
+ sType.valid and
+ (sType.name.CamelCase() not in client_side_structures) and
+ (types[sType.name.get()].output == out)
+ ) %}
case {{as_cEnum(types["s type"].name, sType.name)}}: {
const auto& typedStruct = *reinterpret_cast<{{as_cType(sType.name)}} const *>(chainedStruct);
result += sizeof({{as_cType(sType.name)}}Transfer);
@@ -527,6 +543,8 @@
break;
}
{% endfor %}
+ // Explicitly list the Invalid enum. MSVC complains about no case labels.
+ case WGPUSType_Invalid:
default:
// Invalid enum. Reserve space just for the transfer header (sType and hasNext).
result += sizeof(WGPUChainedStructTransfer);
@@ -537,14 +555,18 @@
return result;
}
- DAWN_NO_DISCARD WireResult SerializeChainedStruct(WGPUChainedStruct const* chainedStruct,
+ DAWN_NO_DISCARD WireResult SerializeChainedStruct({{ChainedStructPtr}} chainedStruct,
SerializeBuffer* buffer,
const ObjectIdProvider& provider) {
ASSERT(chainedStruct != nullptr);
ASSERT(buffer != nullptr);
do {
switch (chainedStruct->sType) {
- {% for sType in types["s type"].values if sType.valid and sType.name.CamelCase() not in client_side_structures %}
+ {% for sType in types["s type"].values if (
+ sType.valid and
+ (sType.name.CamelCase() not in client_side_structures) and
+ (types[sType.name.get()].output == out)
+ ) %}
{% set CType = as_cType(sType.name) %}
case {{as_cEnum(types["s type"].name, sType.name)}}: {
@@ -562,6 +584,8 @@
chainedStruct = chainedStruct->next;
} break;
{% endfor %}
+ // Explicitly list the Invalid enum. MSVC complains about no case labels.
+ case WGPUSType_Invalid:
default: {
// Invalid enum. Serialize just the transfer header with Invalid as the sType.
// TODO(crbug.com/dawn/369): Unknown sTypes are silently discarded.
@@ -583,17 +607,21 @@
return WireResult::Success;
}
- WireResult DeserializeChainedStruct(const WGPUChainedStruct** outChainNext,
- DeserializeBuffer* deserializeBuffer,
- DeserializeAllocator* allocator,
- const ObjectIdResolver& resolver) {
+ WireResult DeserializeChainedStruct({{ChainedStructPtr}}* outChainNext,
+ DeserializeBuffer* deserializeBuffer,
+ DeserializeAllocator* allocator,
+ const ObjectIdResolver& resolver) {
bool hasNext;
do {
const volatile WGPUChainedStructTransfer* header;
WIRE_TRY(deserializeBuffer->Peek(&header));
WGPUSType sType = header->sType;
switch (sType) {
- {% for sType in types["s type"].values if sType.valid and sType.name.CamelCase() not in client_side_structures %}
+ {% for sType in types["s type"].values if (
+ sType.valid and
+ (sType.name.CamelCase() not in client_side_structures) and
+ (types[sType.name.get()].output == out)
+ ) %}
{% set CType = as_cType(sType.name) %}
case {{as_cEnum(types["s type"].name, sType.name)}}: {
const volatile {{CType}}Transfer* transfer;
@@ -616,6 +644,8 @@
hasNext = transfer->chain.hasNext;
} break;
{% endfor %}
+ // Explicitly list the Invalid enum. MSVC complains about no case labels.
+ case WGPUSType_Invalid:
default: {
// Invalid enum. Deserialize just the transfer header with Invalid as the sType.
// TODO(crbug.com/dawn/369): Unknown sTypes are silently discarded.
@@ -626,8 +656,8 @@
const volatile WGPUChainedStructTransfer* transfer;
WIRE_TRY(deserializeBuffer->Read(&transfer));
- WGPUChainedStruct* outStruct;
- WIRE_TRY(GetSpace(allocator, sizeof(WGPUChainedStruct), &outStruct));
+ {{ChainedStruct}}* outStruct;
+ WIRE_TRY(GetSpace(allocator, sizeof({{ChainedStruct}}), &outStruct));
outStruct->sType = WGPUSType_Invalid;
outStruct->next = nullptr;
@@ -642,6 +672,10 @@
return WireResult::Success;
}
+{% endmacro %}
+
+{{ make_chained_struct_serialization_helpers(False) }}
+{{ make_chained_struct_serialization_helpers(True) }}
//* Output [de]serialization helpers for commands
{% for command in cmd_records["command"] %}
@@ -730,4 +764,38 @@
nullptr, resolver) == WireResult::Success;
}
+ size_t SerializedWGPUSupportedLimitsSize(const WGPUSupportedLimits* supportedLimits) {
+ return sizeof(WGPUSupportedLimits) +
+ WGPUSupportedLimitsGetExtraRequiredSize(*supportedLimits);
+ }
+
+ void SerializeWGPUSupportedLimits(
+ const WGPUSupportedLimits* supportedLimits,
+ char* buffer) {
+ SerializeBuffer serializeBuffer(buffer, SerializedWGPUSupportedLimitsSize(supportedLimits));
+
+ WGPUSupportedLimitsTransfer* transfer;
+
+ WireResult result = serializeBuffer.Next(&transfer);
+ ASSERT(result == WireResult::Success);
+
+ ErrorObjectIdProvider provider;
+ result = WGPUSupportedLimitsSerialize(*supportedLimits, transfer, &serializeBuffer, provider);
+ ASSERT(result == WireResult::Success);
+ }
+
+ bool DeserializeWGPUSupportedLimits(WGPUSupportedLimits* supportedLimits,
+ const volatile char* buffer,
+ size_t size) {
+ const volatile WGPUSupportedLimitsTransfer* transfer;
+ DeserializeBuffer deserializeBuffer(buffer, size);
+ if (deserializeBuffer.Read(&transfer) != WireResult::Success) {
+ return false;
+ }
+
+ ErrorObjectIdResolver resolver;
+ return WGPUSupportedLimitsDeserialize(supportedLimits, transfer, &deserializeBuffer,
+ nullptr, resolver) == WireResult::Success;
+ }
+
} // namespace dawn_wire
diff --git a/generator/templates/webgpu.h b/generator/templates/webgpu.h
index 3b91306..e42c7ac 100644
--- a/generator/templates/webgpu.h
+++ b/generator/templates/webgpu.h
@@ -106,13 +106,20 @@
WGPUSType sType;
} WGPUChainedStruct;
+typedef struct WGPUChainedStructOut {
+ struct WGPUChainedStructOut * next;
+ WGPUSType sType;
+} WGPUChainedStructOut;
+
{% for type in by_category["structure"] %}
typedef struct {{as_cType(type.name)}} {
+ {% set Out = "Out" if type.output else "" %}
+ {% set const = "const" if not type.output else "" %}
{% if type.extensible %}
- WGPUChainedStruct const * nextInChain;
+ WGPUChainedStruct{{Out}} {{const}} * nextInChain;
{% endif %}
{% if type.chained %}
- WGPUChainedStruct chain;
+ WGPUChainedStruct{{Out}} chain;
{% endif %}
{% for member in type.members %}
{{as_annotated_cType(member)}};
diff --git a/generator/templates/webgpu_cpp.h b/generator/templates/webgpu_cpp.h
index dd99b11..fbb386d 100644
--- a/generator/templates/webgpu_cpp.h
+++ b/generator/templates/webgpu_cpp.h
@@ -206,9 +206,16 @@
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 %}
- struct {{as_cppType(type.name)}} : ChainedStruct {
+ struct {{as_cppType(type.name)}} : ChainedStruct{{Out}} {
{{as_cppType(type.name)}}() {
sType = SType::{{type.name.CamelCase()}};
}
@@ -216,13 +223,13 @@
struct {{as_cppType(type.name)}} {
{% endif %}
{% if type.extensible %}
- ChainedStruct const * nextInChain = nullptr;
+ 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 to ChainedStruct to match the C struct layout.
- alignas(ChainedStruct) {{member_declaration}};
+ alignas(ChainedStruct{{Out}}) {{member_declaration}};
{% else %}
{{member_declaration}};
{% endif %}
diff --git a/src/dawn_native/Adapter.cpp b/src/dawn_native/Adapter.cpp
index 87b5f9a..5c0d873 100644
--- a/src/dawn_native/Adapter.cpp
+++ b/src/dawn_native/Adapter.cpp
@@ -20,7 +20,6 @@
AdapterBase::AdapterBase(InstanceBase* instance, wgpu::BackendType backend)
: mInstance(instance), mBackend(backend) {
- mLimits.v1.nextInChain = nullptr;
GetDefaultLimits(&mLimits.v1);
mSupportedExtensions.EnableExtension(Extension::DawnInternalUsages);
}
@@ -74,16 +73,16 @@
// to store them (ex. by calling GetLimits directly instead). Currently,
// we keep this function as it's only used internally in Chromium to
// send the adapter properties across the wire.
- GetLimits(reinterpret_cast<wgpu::Limits*>(&adapterProperties.limits));
+ GetLimits(reinterpret_cast<SupportedLimits*>(&adapterProperties.limits));
return adapterProperties;
}
- bool AdapterBase::GetLimits(wgpu::Limits* limits) const {
+ bool AdapterBase::GetLimits(SupportedLimits* limits) const {
ASSERT(limits != nullptr);
if (limits->nextInChain != nullptr) {
return false;
}
- *limits = mLimits.v1;
+ limits->limits = mLimits.v1;
return true;
}
@@ -125,7 +124,8 @@
if (descriptor != nullptr && descriptor->requiredLimits != nullptr) {
DAWN_TRY(ValidateLimits(
- mLimits.v1, *reinterpret_cast<const wgpu::Limits*>(descriptor->requiredLimits)));
+ mLimits.v1,
+ reinterpret_cast<const RequiredLimits*>(descriptor->requiredLimits)->limits));
if (descriptor->requiredLimits->nextInChain != nullptr) {
return DAWN_VALIDATION_ERROR("Unsupported limit extension struct");
diff --git a/src/dawn_native/Adapter.h b/src/dawn_native/Adapter.h
index 894a7f8..32cdd71 100644
--- a/src/dawn_native/Adapter.h
+++ b/src/dawn_native/Adapter.h
@@ -52,7 +52,7 @@
const std::vector<const char*>& requestedExtensions) const;
WGPUDeviceProperties GetAdapterProperties() const;
- bool GetLimits(wgpu::Limits* limits) const;
+ bool GetLimits(SupportedLimits* limits) const;
virtual bool SupportsExternalImages() const = 0;
diff --git a/src/dawn_native/DawnNative.cpp b/src/dawn_native/DawnNative.cpp
index 906df18..8cbda6f 100644
--- a/src/dawn_native/DawnNative.cpp
+++ b/src/dawn_native/DawnNative.cpp
@@ -106,8 +106,8 @@
return mImpl->GetAdapterProperties();
}
- bool Adapter::GetLimits(WGPULimits* limits) const {
- return mImpl->GetLimits(reinterpret_cast<wgpu::Limits*>(limits));
+ bool Adapter::GetLimits(WGPUSupportedLimits* limits) const {
+ return mImpl->GetLimits(reinterpret_cast<SupportedLimits*>(limits));
}
bool Adapter::SupportsExternalImages() const {
diff --git a/src/dawn_native/Device.cpp b/src/dawn_native/Device.cpp
index 7ade6ab..c209cd1 100644
--- a/src/dawn_native/Device.cpp
+++ b/src/dawn_native/Device.cpp
@@ -175,7 +175,7 @@
if (descriptor != nullptr && descriptor->requiredLimits != nullptr) {
mLimits.v1 = ReifyDefaultLimits(
- *reinterpret_cast<const wgpu::Limits*>(descriptor->requiredLimits));
+ reinterpret_cast<const RequiredLimits*>(descriptor->requiredLimits)->limits);
} else {
GetDefaultLimits(&mLimits.v1);
}
@@ -1093,6 +1093,15 @@
}
}
+ bool DeviceBase::APIGetLimits(SupportedLimits* limits) {
+ ASSERT(limits != nullptr);
+ if (limits->nextInChain != nullptr) {
+ return false;
+ }
+ limits->limits = mLimits.v1;
+ return true;
+ }
+
void DeviceBase::APIInjectError(wgpu::ErrorType type, const char* message) {
if (ConsumedError(ValidateErrorType(type))) {
return;
diff --git a/src/dawn_native/Device.h b/src/dawn_native/Device.h
index 3688ee1..5ec6f4a 100644
--- a/src/dawn_native/Device.h
+++ b/src/dawn_native/Device.h
@@ -209,6 +209,7 @@
QueueBase* APIGetQueue();
+ bool APIGetLimits(SupportedLimits* limits);
void APIInjectError(wgpu::ErrorType type, const char* message);
bool APITick();
diff --git a/src/dawn_native/Limits.cpp b/src/dawn_native/Limits.cpp
index 98e067f..33cffdc 100644
--- a/src/dawn_native/Limits.cpp
+++ b/src/dawn_native/Limits.cpp
@@ -94,15 +94,15 @@
} // namespace
- void GetDefaultLimits(wgpu::Limits* limits) {
+ void GetDefaultLimits(Limits* limits) {
ASSERT(limits != nullptr);
#define X(Better, limitName, defaultValue) limits->limitName = defaultValue;
LIMITS(X)
#undef X
}
- wgpu::Limits ReifyDefaultLimits(const wgpu::Limits& limits) {
- wgpu::Limits out;
+ Limits ReifyDefaultLimits(const Limits& limits) {
+ Limits out;
#define X(Better, limitName, defaultValue) \
if (!IsLimitUndefined(limits.limitName)) { \
out.limitName = limits.limitName; \
@@ -114,8 +114,7 @@
return out;
}
- MaybeError ValidateLimits(const wgpu::Limits& supportedLimits,
- const wgpu::Limits& requiredLimits) {
+ MaybeError ValidateLimits(const Limits& supportedLimits, const Limits& requiredLimits) {
#define X(Better, limitName, defaultValue) \
if (!IsLimitUndefined(requiredLimits.limitName)) { \
DAWN_TRY(CheckLimit<LimitBetterDirection::Better>::Invoke(supportedLimits.limitName, \
diff --git a/src/dawn_native/Limits.h b/src/dawn_native/Limits.h
index c0358d9..76f8ec3 100644
--- a/src/dawn_native/Limits.h
+++ b/src/dawn_native/Limits.h
@@ -21,19 +21,18 @@
namespace dawn_native {
struct CombinedLimits {
- wgpu::Limits v1;
+ Limits v1;
};
// Populate |limits| with the default limits.
- void GetDefaultLimits(wgpu::Limits* limits);
+ void GetDefaultLimits(Limits* limits);
// Returns a copy of |limits| where all undefined values are replaced
// with their defaults.
- wgpu::Limits ReifyDefaultLimits(const wgpu::Limits& limits);
+ Limits ReifyDefaultLimits(const Limits& limits);
// Validate that |requiredLimits| are no better than |supportedLimits|.
- MaybeError ValidateLimits(const wgpu::Limits& supportedLimits,
- const wgpu::Limits& requiredLimits);
+ MaybeError ValidateLimits(const Limits& supportedLimits, const Limits& requiredLimits);
} // namespace dawn_native
diff --git a/src/dawn_wire/client/Device.cpp b/src/dawn_wire/client/Device.cpp
index 6ed4698..21df71e 100644
--- a/src/dawn_wire/client/Device.cpp
+++ b/src/dawn_wire/client/Device.cpp
@@ -196,6 +196,12 @@
return Buffer::CreateError(this);
}
+ bool Device::GetLimits(WGPUSupportedLimits* limits) {
+ // Not implemented in the wire.
+ UNREACHABLE();
+ return false;
+ }
+
WGPUQueue Device::GetQueue() {
// The queue is lazily created because if a Device is created by
// Reserve/Inject, we cannot send the GetQueue message until
diff --git a/src/dawn_wire/client/Device.h b/src/dawn_wire/client/Device.h
index 849364f..ae2d9fd 100644
--- a/src/dawn_wire/client/Device.h
+++ b/src/dawn_wire/client/Device.h
@@ -64,6 +64,7 @@
WGPUCreatePipelineAsyncStatus status,
const char* message);
+ bool GetLimits(WGPUSupportedLimits* limits);
WGPUQueue GetQueue();
void CancelCallbacksForDisconnect() override;
diff --git a/src/include/dawn_native/DawnNative.h b/src/include/dawn_native/DawnNative.h
index cb8de7c..b070030 100644
--- a/src/include/dawn_native/DawnNative.h
+++ b/src/include/dawn_native/DawnNative.h
@@ -67,7 +67,7 @@
std::vector<const char*> forceEnabledToggles;
std::vector<const char*> forceDisabledToggles;
- const WGPULimits* requiredLimits = nullptr;
+ const WGPURequiredLimits* requiredLimits = nullptr;
};
// A struct to record the information of a toggle. A toggle is a code path in Dawn device that
@@ -110,7 +110,7 @@
std::vector<const char*> GetSupportedExtensions() const;
WGPUDeviceProperties GetAdapterProperties() const;
- bool GetLimits(WGPULimits* limits) const;
+ bool GetLimits(WGPUSupportedLimits* limits) const;
// Check that the Adapter is able to support importing external images. This is necessary
// to implement the swapchain and interop APIs in Chromium.
diff --git a/src/include/dawn_wire/Wire.h b/src/include/dawn_wire/Wire.h
index 4d69c95..0c11d91 100644
--- a/src/include/dawn_wire/Wire.h
+++ b/src/include/dawn_wire/Wire.h
@@ -61,6 +61,16 @@
const volatile char* deserializeBuffer,
size_t deserializeBufferSize);
+ DAWN_WIRE_EXPORT size_t
+ SerializedWGPUSupportedLimitsSize(const WGPUSupportedLimits* supportedLimits);
+
+ DAWN_WIRE_EXPORT void SerializeWGPUSupportedLimits(const WGPUSupportedLimits* supportedLimits,
+ char* serializeBuffer);
+
+ DAWN_WIRE_EXPORT bool DeserializeWGPUSupportedLimits(WGPUSupportedLimits* supportedLimits,
+ const volatile char* deserializeBuffer,
+ size_t deserializeBufferSize);
+
} // namespace dawn_wire
#endif // DAWNWIRE_WIRE_H_
diff --git a/src/tests/unittests/validation/RequestDeviceValidationTests.cpp b/src/tests/unittests/validation/RequestDeviceValidationTests.cpp
index c456122..5e8bd9b 100644
--- a/src/tests/unittests/validation/RequestDeviceValidationTests.cpp
+++ b/src/tests/unittests/validation/RequestDeviceValidationTests.cpp
@@ -29,6 +29,10 @@
EXPECT_EQ(status, WGPURequestDeviceStatus_Success);
EXPECT_NE(device, nullptr);
EXPECT_STREQ(message, nullptr);
+ if (userdata != nullptr) {
+ CallCheckDevice(static_cast<std::function<void(wgpu::Device)>*>(userdata),
+ std::move(device));
+ }
}
static void ExpectRequestDeviceError(WGPURequestDeviceStatus status,
@@ -40,73 +44,136 @@
EXPECT_EQ(device, nullptr);
EXPECT_STRNE(message, nullptr);
}
+
+ template <typename F>
+ static void* CheckDevice(F&& f) {
+ return new std::function<void(wgpu::Device)>(f);
+ }
+
+ static void CallCheckDevice(std::function<void(wgpu::Device)>* f, wgpu::Device d) {
+ (*f)(std::move(d));
+ delete f;
+ }
};
// Test that requesting a device without specifying limits is valid.
TEST_F(RequestDeviceValidationTest, NoRequiredLimits) {
dawn_native::DeviceDescriptor descriptor;
- adapter.RequestDevice(&descriptor, ExpectRequestDeviceSuccess, nullptr);
+ adapter.RequestDevice(&descriptor, ExpectRequestDeviceSuccess,
+ CheckDevice([](wgpu::Device device) {
+ // Check one of the default limits.
+ wgpu::SupportedLimits limits;
+ device.GetLimits(&limits);
+ EXPECT_EQ(limits.limits.maxBindGroups, 4u);
+ }));
}
// Test that requesting a device with the default limits is valid.
TEST_F(RequestDeviceValidationTest, DefaultLimits) {
- wgpu::Limits limits = {};
+ wgpu::RequiredLimits limits = {};
dawn_native::DeviceDescriptor descriptor;
- descriptor.requiredLimits = reinterpret_cast<const WGPULimits*>(&limits);
- adapter.RequestDevice(&descriptor, ExpectRequestDeviceSuccess, nullptr);
+ descriptor.requiredLimits = reinterpret_cast<const WGPURequiredLimits*>(&limits);
+ adapter.RequestDevice(&descriptor, ExpectRequestDeviceSuccess,
+ CheckDevice([](wgpu::Device device) {
+ // Check one of the default limits.
+ wgpu::SupportedLimits limits;
+ device.GetLimits(&limits);
+ EXPECT_EQ(limits.limits.maxTextureArrayLayers, 256u);
+ }));
}
// Test that requesting a device where a required limit is above the maximum value.
TEST_F(RequestDeviceValidationTest, HigherIsBetter) {
- wgpu::Limits limits = {};
+ wgpu::RequiredLimits limits = {};
dawn_native::DeviceDescriptor descriptor;
- descriptor.requiredLimits = reinterpret_cast<const WGPULimits*>(&limits);
+ descriptor.requiredLimits = reinterpret_cast<const WGPURequiredLimits*>(&limits);
- wgpu::Limits supportedLimits;
- EXPECT_TRUE(adapter.GetLimits(reinterpret_cast<WGPULimits*>(&supportedLimits)));
+ wgpu::SupportedLimits supportedLimits;
+ EXPECT_TRUE(adapter.GetLimits(reinterpret_cast<WGPUSupportedLimits*>(&supportedLimits)));
// Test below the max.
- limits.maxBindGroups = supportedLimits.maxBindGroups - 1;
- adapter.RequestDevice(&descriptor, ExpectRequestDeviceSuccess, nullptr);
+ limits.limits.maxBindGroups = supportedLimits.limits.maxBindGroups - 1;
+ adapter.RequestDevice(
+ &descriptor, ExpectRequestDeviceSuccess, CheckDevice([&](wgpu::Device device) {
+ wgpu::SupportedLimits limits;
+ device.GetLimits(&limits);
+
+ // Check we got exactly the request.
+ EXPECT_EQ(limits.limits.maxBindGroups, supportedLimits.limits.maxBindGroups - 1);
+ // Check another default limit.
+ EXPECT_EQ(limits.limits.maxTextureArrayLayers, 256u);
+ }));
// Test the max.
- limits.maxBindGroups = supportedLimits.maxBindGroups;
- adapter.RequestDevice(&descriptor, ExpectRequestDeviceSuccess, nullptr);
+ limits.limits.maxBindGroups = supportedLimits.limits.maxBindGroups;
+ adapter.RequestDevice(
+ &descriptor, ExpectRequestDeviceSuccess, CheckDevice([&](wgpu::Device device) {
+ wgpu::SupportedLimits limits;
+ device.GetLimits(&limits);
+
+ // Check we got exactly the request.
+ EXPECT_EQ(limits.limits.maxBindGroups, supportedLimits.limits.maxBindGroups);
+ // Check another default limit.
+ EXPECT_EQ(limits.limits.maxTextureArrayLayers, 256u);
+ }));
// Test above the max.
- limits.maxBindGroups = supportedLimits.maxBindGroups + 1;
+ limits.limits.maxBindGroups = supportedLimits.limits.maxBindGroups + 1;
adapter.RequestDevice(&descriptor, ExpectRequestDeviceError, nullptr);
}
// Test that requesting a device where a required limit is below the minimum value.
TEST_F(RequestDeviceValidationTest, LowerIsBetter) {
- wgpu::Limits limits = {};
+ wgpu::RequiredLimits limits = {};
dawn_native::DeviceDescriptor descriptor;
- descriptor.requiredLimits = reinterpret_cast<const WGPULimits*>(&limits);
+ descriptor.requiredLimits = reinterpret_cast<const WGPURequiredLimits*>(&limits);
- wgpu::Limits supportedLimits;
- EXPECT_TRUE(adapter.GetLimits(reinterpret_cast<WGPULimits*>(&supportedLimits)));
+ wgpu::SupportedLimits supportedLimits;
+ EXPECT_TRUE(adapter.GetLimits(reinterpret_cast<WGPUSupportedLimits*>(&supportedLimits)));
// Test below the min.
- limits.minUniformBufferOffsetAlignment = supportedLimits.minUniformBufferOffsetAlignment / 2;
+ limits.limits.minUniformBufferOffsetAlignment =
+ supportedLimits.limits.minUniformBufferOffsetAlignment / 2;
adapter.RequestDevice(&descriptor, ExpectRequestDeviceError, nullptr);
// Test the min.
- limits.minUniformBufferOffsetAlignment = supportedLimits.minUniformBufferOffsetAlignment;
- adapter.RequestDevice(&descriptor, ExpectRequestDeviceSuccess, nullptr);
+ limits.limits.minUniformBufferOffsetAlignment =
+ supportedLimits.limits.minUniformBufferOffsetAlignment;
+ adapter.RequestDevice(&descriptor, ExpectRequestDeviceSuccess,
+ CheckDevice([&](wgpu::Device device) {
+ wgpu::SupportedLimits limits;
+ device.GetLimits(&limits);
+
+ // Check we got exactly the request.
+ EXPECT_EQ(limits.limits.minUniformBufferOffsetAlignment,
+ supportedLimits.limits.minUniformBufferOffsetAlignment);
+ // Check another default limit.
+ EXPECT_EQ(limits.limits.maxTextureArrayLayers, 256u);
+ }));
// Test above the min.
- limits.minUniformBufferOffsetAlignment = supportedLimits.minUniformBufferOffsetAlignment * 2;
- adapter.RequestDevice(&descriptor, ExpectRequestDeviceSuccess, nullptr);
+ limits.limits.minUniformBufferOffsetAlignment =
+ supportedLimits.limits.minUniformBufferOffsetAlignment * 2;
+ adapter.RequestDevice(&descriptor, ExpectRequestDeviceSuccess,
+ CheckDevice([&](wgpu::Device device) {
+ wgpu::SupportedLimits limits;
+ device.GetLimits(&limits);
+
+ // Check we got exactly the request.
+ EXPECT_EQ(limits.limits.minUniformBufferOffsetAlignment,
+ supportedLimits.limits.minUniformBufferOffsetAlignment * 2);
+ // Check another default limit.
+ EXPECT_EQ(limits.limits.maxTextureArrayLayers, 256u);
+ }));
}
// Test that it is an error to request limits with an invalid chained struct
TEST_F(RequestDeviceValidationTest, InvalidChainedStruct) {
wgpu::PrimitiveDepthClampingState depthClamp = {};
- wgpu::Limits limits = {};
+ wgpu::RequiredLimits limits = {};
limits.nextInChain = &depthClamp;
dawn_native::DeviceDescriptor descriptor;
- descriptor.requiredLimits = reinterpret_cast<const WGPULimits*>(&limits);
+ descriptor.requiredLimits = reinterpret_cast<const WGPURequiredLimits*>(&limits);
adapter.RequestDevice(&descriptor, ExpectRequestDeviceError, nullptr);
}