Add WGPUAdapterPropertiesMemoryHeaps
This struct may be chained on WGPUAdapterProperties to query
the size and type of memory heaps available on the adapter.
Bug: dawn:2249
Change-Id: Ia8205fde8d05c26a9e73f2093897a844617d7918
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/161240
Reviewed-by: Quyen Le <lehoangquyen@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Austin Eng <enga@chromium.org>
diff --git a/dawn.json b/dawn.json
index fc76c12..f4af0e0 100644
--- a/dawn.json
+++ b/dawn.json
@@ -1920,6 +1920,7 @@
{"value": 1024, "name": "multi planar format nv12a", "tags": ["dawn"]},
{"value": 1025, "name": "framebuffer fetch", "tags": ["dawn"]},
{"value": 1026, "name": "buffer map extended usages", "tags": ["dawn"]},
+ {"value": 1027, "name": "adapter properties memory heaps", "tags": ["dawn"]},
{"value": 1100, "name": "shared texture memory vk dedicated allocation", "tags": ["dawn", "native"]},
{"value": 1101, "name": "shared texture memory a hardware buffer", "tags": ["dawn", "native"]},
@@ -3287,6 +3288,7 @@
{"value": 1016, "name": "pipeline layout pixel local storage", "tags": ["dawn"]},
{"value": 1017, "name": "buffer host mapped pointer", "tags": ["dawn"]},
{"value": 1018, "name": "dawn experimental subgroup limits", "tags": ["dawn"]},
+ {"value": 1019, "name": "adapter properties memory heaps", "tags": ["dawn"]},
{"value": 1100, "name": "shared texture memory vk image descriptor", "tags": ["dawn", "native"]},
{"value": 1101, "name": "shared texture memory vk dedicated allocation descriptor", "tags": ["dawn", "native"]},
@@ -3755,6 +3757,36 @@
{"name": "power preference", "type": "power preference", "default": "undefined"}
]
},
+ "heap property": {
+ "category": "bitmask",
+ "tags": ["dawn"],
+ "values": [
+ {"value": 0, "name": "undefined", "valid": false},
+ {"value": 1, "name": "device local"},
+ {"value": 2, "name": "host visible"},
+ {"value": 4, "name": "host coherent"},
+ {"value": 8, "name": "host uncached"},
+ {"value": 16, "name": "host cached"}
+ ]
+ },
+ "memory heap info": {
+ "category": "structure",
+ "tags": ["dawn"],
+ "members": [
+ {"name": "properties", "type": "heap property"},
+ {"name": "size", "type": "uint64_t"}
+ ]
+ },
+ "adapter properties memory heaps": {
+ "category": "structure",
+ "chained": "out",
+ "chain roots": ["adapter properties"],
+ "tags": ["dawn"],
+ "members": [
+ {"name": "heap count", "type": "size_t"},
+ {"name": "heap info", "type": "memory heap info", "annotation": "const*", "length": "heap count"}
+ ]
+ },
"dawn buffer descriptor error info from wire client": {
"category": "structure",
"chained": "in",
diff --git a/docs/dawn/features/adapter_properties.md b/docs/dawn/features/adapter_properties.md
new file mode 100644
index 0000000..c4d348b
--- /dev/null
+++ b/docs/dawn/features/adapter_properties.md
@@ -0,0 +1,29 @@
+# Adapter Properties
+
+## Memory Heaps
+
+`wgpu::FeatureName::AdapterPropertiesMemoryHeaps` allows querying memory heap information from the adapter.
+
+`wgpu::AdapterPropertiesMemoryHeaps` may be chained on `wgpu::AdapterProperties` in a call to `wgpu::Adapter::GetProperties` in order to query information about the memory heaps on that adapter.
+The implementation will write out the number of memory heaps and information about each heap.
+
+If `wgpu::FeatureName::AdapterPropertiesMemoryHeaps` is not available, the struct will not be populated.
+
+Adds `wgpu::HeapProperty` which is a bitmask describing the type of memory a heap is. Valid bits:
+- DeviceLocal
+- HostVisible
+- HostCoherent
+- HostUncached
+- HostCached
+
+Note that both HostUncached and HostCached may be set if a heap can allocate pages with either cache property.
+
+Adds `wgpu::MemoryHeapInfo` which is a struct describing a memory heap.
+```
+struct MemoryHeapInfo {
+ HeapProperty properties;
+ uint64_t size;
+};
+```
+
+`wgpu::MemoryHeapInfo::size` is the size that should be allocated out of this heap. Allocating more than this may result in poor performance or may deterministically run out of memory.
diff --git a/generator/templates/api_cpp.h b/generator/templates/api_cpp.h
index 8c854b6..1f9ca0a 100644
--- a/generator/templates/api_cpp.h
+++ b/generator/templates/api_cpp.h
@@ -265,9 +265,11 @@
}
{% else %}
struct {{as_cppType(type.name)}} {
+ {% if type.has_free_members_function %}
+ {{as_cppType(type.name)}}() = default;
+ {% endif %}
{% 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;
diff --git a/generator/templates/dawn/native/api_structs.h b/generator/templates/dawn/native/api_structs.h
index 92c47de..f484bcd 100644
--- a/generator/templates/dawn/native/api_structs.h
+++ b/generator/templates/dawn/native/api_structs.h
@@ -69,9 +69,11 @@
}
{% else %}
struct {{as_cppType(type.name)}} {
+ {% if type.has_free_members_function %}
+ {{as_cppType(type.name)}}() = default;
+ {% endif %}
{% 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;
diff --git a/src/dawn/native/Adapter.cpp b/src/dawn/native/Adapter.cpp
index a120050..eb89ab8 100644
--- a/src/dawn/native/Adapter.cpp
+++ b/src/dawn/native/Adapter.cpp
@@ -118,8 +118,9 @@
void AdapterBase::APIGetProperties(AdapterProperties* properties) const {
DAWN_ASSERT(properties != nullptr);
- MaybeError result = ValidateSingleSType(properties->nextInChain,
- wgpu::SType::DawnAdapterPropertiesPowerPreference);
+ MaybeError result = ValidateSTypes(properties->nextInChain,
+ {{wgpu::SType::DawnAdapterPropertiesPowerPreference},
+ {wgpu::SType::AdapterPropertiesMemoryHeaps}});
if (result.IsError()) {
mPhysicalDevice->GetInstance()->ConsumedError(result.AcquireError());
return;
@@ -128,6 +129,15 @@
DawnAdapterPropertiesPowerPreference* powerPreferenceDesc = nullptr;
FindInChain(properties->nextInChain, &powerPreferenceDesc);
+ AdapterPropertiesMemoryHeaps* memoryHeaps = nullptr;
+ FindInChain(properties->nextInChain, &memoryHeaps);
+
+ if (memoryHeaps != nullptr &&
+ !mSupportedFeatures.IsEnabled(wgpu::FeatureName::AdapterPropertiesMemoryHeaps)) {
+ mPhysicalDevice->GetInstance()->ConsumedError(
+ DAWN_VALIDATION_ERROR("Feature AdapterPropertiesMemoryHeaps is not available."));
+ }
+
if (powerPreferenceDesc != nullptr) {
powerPreferenceDesc->powerPreference = mPowerPreference;
}
@@ -161,6 +171,10 @@
properties->driverDescription = ptr;
memcpy(ptr, mPhysicalDevice->GetDriverDescription().c_str(), driverDescriptionCLen);
ptr += driverDescriptionCLen;
+
+ if (memoryHeaps != nullptr) {
+ mPhysicalDevice->PopulateMemoryHeapInfo(memoryHeaps);
+ }
}
void APIAdapterPropertiesFreeMembers(WGPUAdapterProperties properties) {
@@ -168,6 +182,11 @@
delete[] properties.vendorName;
}
+void APIAdapterPropertiesMemoryHeapsFreeMembers(
+ WGPUAdapterPropertiesMemoryHeaps memoryHeapProperties) {
+ delete[] memoryHeapProperties.heapInfo;
+}
+
bool AdapterBase::APIHasFeature(wgpu::FeatureName feature) const {
return mSupportedFeatures.IsEnabled(feature);
}
diff --git a/src/dawn/native/Device.h b/src/dawn/native/Device.h
index fb1e83f..e9ead1b 100644
--- a/src/dawn/native/Device.h
+++ b/src/dawn/native/Device.h
@@ -301,6 +301,7 @@
TextureBase* APICreateTexture(const TextureDescriptor* descriptor);
wgpu::TextureUsage APIGetSupportedSurfaceUsage(Surface* surface);
+ size_t APIQueryMemoryHeapInfo(MemoryHeapInfo* info);
InternalPipelineStore* GetInternalPipelineStore();
diff --git a/src/dawn/native/Features.cpp b/src/dawn/native/Features.cpp
index 54d23d1..78e2650 100644
--- a/src/dawn/native/Features.cpp
+++ b/src/dawn/native/Features.cpp
@@ -289,6 +289,11 @@
"https://dawn.googlesource.com/dawn/+/refs/heads/main/docs/dawn/features/"
"buffer_map_extended_usages.md",
FeatureInfo::FeatureState::Experimental}},
+ {Feature::AdapterPropertiesMemoryHeaps,
+ {"Support querying memory heap info from the adapter.",
+ "https://dawn.googlesource.com/dawn/+/refs/heads/main/docs/dawn/features/"
+ "adapter_properties.md",
+ FeatureInfo::FeatureState::Stable}},
};
} // anonymous namespace
diff --git a/src/dawn/native/PhysicalDevice.h b/src/dawn/native/PhysicalDevice.h
index 8ec396b..ed917c3 100644
--- a/src/dawn/native/PhysicalDevice.h
+++ b/src/dawn/native/PhysicalDevice.h
@@ -106,6 +106,11 @@
FeatureValidationResult ValidateFeatureSupportedWithToggles(wgpu::FeatureName feature,
const TogglesState& toggles) const;
+ // Populate information about the memory heaps. Ownership of allocations written to
+ // `memoryHeapProperties` are owned by the caller.
+ virtual void PopulateMemoryHeapInfo(
+ AdapterPropertiesMemoryHeaps* memoryHeapProperties) const = 0;
+
protected:
uint32_t mVendorId = 0xFFFFFFFF;
std::string mVendorName;
diff --git a/src/dawn/native/d3d11/DeviceInfoD3D11.cpp b/src/dawn/native/d3d11/DeviceInfoD3D11.cpp
index da7959c..a09a830 100644
--- a/src/dawn/native/d3d11/DeviceInfoD3D11.cpp
+++ b/src/dawn/native/d3d11/DeviceInfoD3D11.cpp
@@ -34,7 +34,8 @@
namespace dawn::native::d3d11 {
-ResultOrError<DeviceInfo> GatherDeviceInfo(const ComPtr<ID3D11Device>& device) {
+ResultOrError<DeviceInfo> GatherDeviceInfo(IDXGIAdapter3* adapter,
+ const ComPtr<ID3D11Device>& device) {
DeviceInfo info = {};
D3D11_FEATURE_DATA_D3D11_OPTIONS2 options2;
@@ -62,6 +63,11 @@
info.supportsSharedResourceCapabilityTier2 =
featureOptions5.SharedResourceTier >= D3D11_SHARED_RESOURCE_TIER_2;
+ DXGI_ADAPTER_DESC adapterDesc;
+ DAWN_TRY(CheckHRESULT(adapter->GetDesc(&adapterDesc), "IDXGIAdapter3::GetDesc"));
+ info.dedicatedVideoMemory = adapterDesc.DedicatedVideoMemory;
+ info.sharedSystemMemory = adapterDesc.SharedSystemMemory;
+
return std::move(info);
}
diff --git a/src/dawn/native/d3d11/DeviceInfoD3D11.h b/src/dawn/native/d3d11/DeviceInfoD3D11.h
index f78a7c3..4129802 100644
--- a/src/dawn/native/d3d11/DeviceInfoD3D11.h
+++ b/src/dawn/native/d3d11/DeviceInfoD3D11.h
@@ -44,9 +44,12 @@
uint32_t shaderModel;
PerStage<std::wstring> shaderProfiles;
bool supportsSharedResourceCapabilityTier2;
+ size_t dedicatedVideoMemory;
+ size_t sharedSystemMemory;
};
-ResultOrError<DeviceInfo> GatherDeviceInfo(const ComPtr<ID3D11Device>& device);
+ResultOrError<DeviceInfo> GatherDeviceInfo(IDXGIAdapter3* adapter,
+ const ComPtr<ID3D11Device>& device);
} // namespace dawn::native::d3d11
#endif // SRC_DAWN_NATIVE_D3D11_DEVICEINFOD3D11_H_
diff --git a/src/dawn/native/d3d11/PhysicalDeviceD3D11.cpp b/src/dawn/native/d3d11/PhysicalDeviceD3D11.cpp
index 36e9fc1..86fa5f8 100644
--- a/src/dawn/native/d3d11/PhysicalDeviceD3D11.cpp
+++ b/src/dawn/native/d3d11/PhysicalDeviceD3D11.cpp
@@ -167,7 +167,7 @@
}
mFeatureLevel = mD3D11Device->GetFeatureLevel();
- DAWN_TRY_ASSIGN(mDeviceInfo, GatherDeviceInfo(mD3D11Device));
+ DAWN_TRY_ASSIGN(mDeviceInfo, GatherDeviceInfo(GetHardwareAdapter(), mD3D11Device));
// Base::InitializeImpl() cannot distinguish between discrete and integrated GPUs, so we need to
// overwrite it.
@@ -187,6 +187,7 @@
EnableFeature(Feature::MSAARenderToSingleSampled);
EnableFeature(Feature::DualSourceBlending);
EnableFeature(Feature::Norm16TextureFormats);
+ EnableFeature(Feature::AdapterPropertiesMemoryHeaps);
// To import multi planar textures, we need to at least tier 2 support.
if (mDeviceInfo.supportsSharedResourceCapabilityTier2) {
@@ -321,4 +322,33 @@
return {};
}
+void PhysicalDevice::PopulateMemoryHeapInfo(
+ AdapterPropertiesMemoryHeaps* memoryHeapProperties) const {
+ // https://microsoft.github.io/DirectX-Specs/d3d/D3D12GPUUploadHeaps.html describes
+ // the properties of D3D12 Default/Upload/Readback heaps. The assumption is that these are
+ // roughly how D3D11 allocates memory has well.
+ if (mDeviceInfo.isUMA) {
+ auto* heapInfo = new MemoryHeapInfo[1];
+ memoryHeapProperties->heapCount = 1;
+ memoryHeapProperties->heapInfo = heapInfo;
+
+ heapInfo[0].size = mDeviceInfo.dedicatedVideoMemory != 0 ? mDeviceInfo.dedicatedVideoMemory
+ : mDeviceInfo.sharedSystemMemory;
+ heapInfo[0].properties = wgpu::HeapProperty::DeviceLocal | wgpu::HeapProperty::HostVisible |
+ wgpu::HeapProperty::HostUncached | wgpu::HeapProperty::HostCached;
+ } else {
+ auto* heapInfo = new MemoryHeapInfo[2];
+ memoryHeapProperties->heapCount = 2;
+ memoryHeapProperties->heapInfo = heapInfo;
+
+ heapInfo[0].size = mDeviceInfo.dedicatedVideoMemory;
+ heapInfo[0].properties = wgpu::HeapProperty::DeviceLocal;
+
+ heapInfo[1].size = mDeviceInfo.sharedSystemMemory;
+ heapInfo[1].properties = wgpu::HeapProperty::HostVisible |
+ wgpu::HeapProperty::HostCoherent |
+ wgpu::HeapProperty::HostUncached | wgpu::HeapProperty::HostCached;
+ }
+}
+
} // namespace dawn::native::d3d11
diff --git a/src/dawn/native/d3d11/PhysicalDeviceD3D11.h b/src/dawn/native/d3d11/PhysicalDeviceD3D11.h
index ec400bf..08d1102 100644
--- a/src/dawn/native/d3d11/PhysicalDeviceD3D11.h
+++ b/src/dawn/native/d3d11/PhysicalDeviceD3D11.h
@@ -75,6 +75,8 @@
wgpu::FeatureName feature,
const TogglesState& toggles) const override;
+ void PopulateMemoryHeapInfo(AdapterPropertiesMemoryHeaps* memoryHeapProperties) const override;
+
const bool mIsSharedD3D11Device;
ComPtr<ID3D11Device> mD3D11Device;
D3D_FEATURE_LEVEL mFeatureLevel;
diff --git a/src/dawn/native/d3d12/D3D12Info.cpp b/src/dawn/native/d3d12/D3D12Info.cpp
index b8960c7..2768c9b 100644
--- a/src/dawn/native/d3d12/D3D12Info.cpp
+++ b/src/dawn/native/d3d12/D3D12Info.cpp
@@ -50,6 +50,7 @@
"ID3D12Device::CheckFeatureSupport"));
info.isUMA = arch.UMA;
+ info.isCacheCoherentUMA = arch.CacheCoherentUMA;
D3D12_FEATURE_DATA_D3D12_OPTIONS featureOptions = {};
DAWN_TRY(CheckHRESULT(physicalDevice.GetDevice()->CheckFeatureSupport(
@@ -185,6 +186,12 @@
}
}
+ DXGI_ADAPTER_DESC adapterDesc;
+ DAWN_TRY(CheckHRESULT(physicalDevice.GetHardwareAdapter()->GetDesc(&adapterDesc),
+ "IDXGIAdapter3::GetDesc"));
+ info.dedicatedVideoMemory = adapterDesc.DedicatedVideoMemory;
+ info.sharedSystemMemory = adapterDesc.SharedSystemMemory;
+
return std::move(info);
}
diff --git a/src/dawn/native/d3d12/D3D12Info.h b/src/dawn/native/d3d12/D3D12Info.h
index 9611071..3c1e486 100644
--- a/src/dawn/native/d3d12/D3D12Info.h
+++ b/src/dawn/native/d3d12/D3D12Info.h
@@ -38,6 +38,7 @@
struct D3D12DeviceInfo {
bool isUMA;
+ bool isCacheCoherentUMA;
uint32_t resourceHeapTier;
bool supportsRenderPass;
bool supportsShaderF16;
@@ -60,6 +61,8 @@
// unclear. Reference:
// https://github.com/Microsoft/DirectXShaderCompiler/wiki/Wave-Intrinsics#:~:text=UINT%20WaveLaneCountMax
uint32_t waveLaneCountMax;
+ size_t dedicatedVideoMemory;
+ size_t sharedSystemMemory;
};
ResultOrError<D3D12DeviceInfo> GatherDeviceInfo(const PhysicalDevice& physicalDevice);
diff --git a/src/dawn/native/d3d12/PhysicalDeviceD3D12.cpp b/src/dawn/native/d3d12/PhysicalDeviceD3D12.cpp
index c9b5a30..2f229b5 100644
--- a/src/dawn/native/d3d12/PhysicalDeviceD3D12.cpp
+++ b/src/dawn/native/d3d12/PhysicalDeviceD3D12.cpp
@@ -141,6 +141,7 @@
EnableFeature(Feature::Float32Filterable);
EnableFeature(Feature::DualSourceBlending);
EnableFeature(Feature::Norm16TextureFormats);
+ EnableFeature(Feature::AdapterPropertiesMemoryHeaps);
if (AreTimestampQueriesSupported()) {
EnableFeature(Feature::TimestampQuery);
@@ -710,4 +711,40 @@
return {};
}
+void PhysicalDevice::PopulateMemoryHeapInfo(
+ AdapterPropertiesMemoryHeaps* memoryHeapProperties) const {
+ // https://microsoft.github.io/DirectX-Specs/d3d/D3D12GPUUploadHeaps.html describes
+ // the properties of D3D12 Default/Upload/Readback heaps.
+ if (mDeviceInfo.isUMA) {
+ auto* heapInfo = new MemoryHeapInfo[1];
+ memoryHeapProperties->heapCount = 1;
+ memoryHeapProperties->heapInfo = heapInfo;
+
+ heapInfo[0].size = mDeviceInfo.dedicatedVideoMemory != 0 ? mDeviceInfo.dedicatedVideoMemory
+ : mDeviceInfo.sharedSystemMemory;
+
+ if (mDeviceInfo.isCacheCoherentUMA) {
+ heapInfo[0].properties =
+ wgpu::HeapProperty::DeviceLocal | wgpu::HeapProperty::HostVisible |
+ wgpu::HeapProperty::HostCoherent | wgpu::HeapProperty::HostCached;
+ } else {
+ heapInfo[0].properties =
+ wgpu::HeapProperty::DeviceLocal | wgpu::HeapProperty::HostVisible |
+ wgpu::HeapProperty::HostUncached | wgpu::HeapProperty::HostCached;
+ }
+ } else {
+ auto* heapInfo = new MemoryHeapInfo[2];
+ memoryHeapProperties->heapCount = 2;
+ memoryHeapProperties->heapInfo = heapInfo;
+
+ heapInfo[0].size = mDeviceInfo.dedicatedVideoMemory;
+ heapInfo[0].properties = wgpu::HeapProperty::DeviceLocal;
+
+ heapInfo[1].size = mDeviceInfo.sharedSystemMemory;
+ heapInfo[1].properties = wgpu::HeapProperty::HostVisible |
+ wgpu::HeapProperty::HostCoherent |
+ wgpu::HeapProperty::HostUncached | wgpu::HeapProperty::HostCached;
+ }
+}
+
} // namespace dawn::native::d3d12
diff --git a/src/dawn/native/d3d12/PhysicalDeviceD3D12.h b/src/dawn/native/d3d12/PhysicalDeviceD3D12.h
index c8a35f4..bdabed9 100644
--- a/src/dawn/native/d3d12/PhysicalDeviceD3D12.h
+++ b/src/dawn/native/d3d12/PhysicalDeviceD3D12.h
@@ -76,6 +76,8 @@
MaybeError InitializeDebugLayerFilters();
void CleanUpDebugLayerFilters();
+ void PopulateMemoryHeapInfo(AdapterPropertiesMemoryHeaps* memoryHeapProperties) const override;
+
ComPtr<ID3D12Device> mD3d12Device;
D3D12DeviceInfo mDeviceInfo = {};
diff --git a/src/dawn/native/metal/BackendMTL.mm b/src/dawn/native/metal/BackendMTL.mm
index a4de8ca..3485981 100644
--- a/src/dawn/native/metal/BackendMTL.mm
+++ b/src/dawn/native/metal/BackendMTL.mm
@@ -546,6 +546,10 @@
EnableFeature(Feature::Depth32FloatStencil8);
}
+ if (@available(macOS 10.12, iOS 16.0, *)) {
+ EnableFeature(Feature::AdapterPropertiesMemoryHeaps);
+ }
+
// Uses newTextureWithDescriptor::iosurface::plane which is available
// on ios 11.0+ and macOS 11.0+
if (@available(macOS 10.11, iOS 11.0, *)) {
@@ -884,6 +888,37 @@
return {};
}
+ void PopulateMemoryHeapInfo(AdapterPropertiesMemoryHeaps* memoryHeapProperties) const override {
+ if ([*mDevice hasUnifiedMemory]) {
+ auto* heapInfo = new MemoryHeapInfo[1];
+ memoryHeapProperties->heapCount = 1;
+ memoryHeapProperties->heapInfo = heapInfo;
+
+ heapInfo[0].properties =
+ wgpu::HeapProperty::DeviceLocal | wgpu::HeapProperty::HostVisible |
+ wgpu::HeapProperty::HostCoherent | wgpu::HeapProperty::HostCached;
+ heapInfo[0].size = [*mDevice recommendedMaxWorkingSetSize];
+ } else {
+ auto* heapInfo = new MemoryHeapInfo[2];
+ memoryHeapProperties->heapCount = 2;
+ memoryHeapProperties->heapInfo = heapInfo;
+
+ heapInfo[0].properties = wgpu::HeapProperty::DeviceLocal;
+ heapInfo[0].size = [*mDevice recommendedMaxWorkingSetSize];
+
+ mach_msg_type_number_t hostBasicInfoMsg = HOST_BASIC_INFO_COUNT;
+ host_basic_info_data_t hostInfo{};
+ DAWN_CHECK(host_info(mach_host_self(), HOST_BASIC_INFO,
+ reinterpret_cast<host_info_t>(&hostInfo),
+ &hostBasicInfoMsg) == KERN_SUCCESS);
+
+ heapInfo[1].properties = wgpu::HeapProperty::HostVisible |
+ wgpu::HeapProperty::HostCoherent |
+ wgpu::HeapProperty::HostCached;
+ heapInfo[1].size = hostInfo.max_mem;
+ }
+ }
+
NSPRef<id<MTLDevice>> mDevice;
const bool mMetalValidationEnabled;
};
diff --git a/src/dawn/native/null/DeviceNull.cpp b/src/dawn/native/null/DeviceNull.cpp
index 9997aa1..5260cd2 100644
--- a/src/dawn/native/null/DeviceNull.cpp
+++ b/src/dawn/native/null/DeviceNull.cpp
@@ -90,6 +90,17 @@
return Device::Create(adapter, descriptor, deviceToggles);
}
+void PhysicalDevice::PopulateMemoryHeapInfo(
+ AdapterPropertiesMemoryHeaps* memoryHeapProperties) const {
+ auto* heapInfo = new MemoryHeapInfo[1];
+ memoryHeapProperties->heapCount = 1;
+ memoryHeapProperties->heapInfo = heapInfo;
+
+ heapInfo[0].size = 1024 * 1024 * 1024;
+ heapInfo[0].properties = wgpu::HeapProperty::DeviceLocal | wgpu::HeapProperty::HostVisible |
+ wgpu::HeapProperty::HostCached;
+}
+
FeatureValidationResult PhysicalDevice::ValidateFeatureSupportedWithTogglesImpl(
wgpu::FeatureName feature,
const TogglesState& toggles) const {
diff --git a/src/dawn/native/null/DeviceNull.h b/src/dawn/native/null/DeviceNull.h
index 4187b07..c776bdd 100644
--- a/src/dawn/native/null/DeviceNull.h
+++ b/src/dawn/native/null/DeviceNull.h
@@ -208,6 +208,8 @@
ResultOrError<Ref<DeviceBase>> CreateDeviceImpl(AdapterBase* adapter,
const DeviceDescriptor* descriptor,
const TogglesState& deviceToggles) override;
+
+ void PopulateMemoryHeapInfo(AdapterPropertiesMemoryHeaps* memoryHeapProperties) const override;
};
// Helper class so |BindGroup| can allocate memory for its binding data,
diff --git a/src/dawn/native/opengl/PhysicalDeviceGL.cpp b/src/dawn/native/opengl/PhysicalDeviceGL.cpp
index fcf6b63..d78a66f 100644
--- a/src/dawn/native/opengl/PhysicalDeviceGL.cpp
+++ b/src/dawn/native/opengl/PhysicalDeviceGL.cpp
@@ -426,4 +426,10 @@
const TogglesState& toggles) const {
return {};
}
+
+void PhysicalDevice::PopulateMemoryHeapInfo(
+ AdapterPropertiesMemoryHeaps* memoryHeapProperties) const {
+ DAWN_UNREACHABLE();
+}
+
} // namespace dawn::native::opengl
diff --git a/src/dawn/native/opengl/PhysicalDeviceGL.h b/src/dawn/native/opengl/PhysicalDeviceGL.h
index e0bec2b..33409b4 100644
--- a/src/dawn/native/opengl/PhysicalDeviceGL.h
+++ b/src/dawn/native/opengl/PhysicalDeviceGL.h
@@ -65,6 +65,8 @@
const DeviceDescriptor* descriptor,
const TogglesState& deviceToggles) override;
+ void PopulateMemoryHeapInfo(AdapterPropertiesMemoryHeaps* memoryHeapProperties) const override;
+
OpenGLFunctions mFunctions;
EGLDisplay mDisplay;
EGLFunctions mEGLFunctions;
diff --git a/src/dawn/native/vulkan/PhysicalDeviceVk.cpp b/src/dawn/native/vulkan/PhysicalDeviceVk.cpp
index 19a1867..bcd21f1 100644
--- a/src/dawn/native/vulkan/PhysicalDeviceVk.cpp
+++ b/src/dawn/native/vulkan/PhysicalDeviceVk.cpp
@@ -203,6 +203,8 @@
}
void PhysicalDevice::InitializeSupportedFeaturesImpl() {
+ EnableFeature(Feature::AdapterPropertiesMemoryHeaps);
+
// Initialize supported extensions
if (mDeviceInfo.features.textureCompressionBC == VK_TRUE) {
EnableFeature(Feature::TextureCompressionBC);
@@ -751,4 +753,33 @@
return mDefaultComputeSubgroupSize;
}
+void PhysicalDevice::PopulateMemoryHeapInfo(
+ AdapterPropertiesMemoryHeaps* memoryHeapProperties) const {
+ size_t count = mDeviceInfo.memoryHeaps.size();
+ auto* heapInfo = new MemoryHeapInfo[count];
+ memoryHeapProperties->heapCount = count;
+ memoryHeapProperties->heapInfo = heapInfo;
+
+ for (size_t i = 0; i < count; ++i) {
+ heapInfo[i].size = mDeviceInfo.memoryHeaps[i].size;
+ heapInfo[i].properties = {};
+ if (mDeviceInfo.memoryHeaps[i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) {
+ heapInfo[i].properties |= wgpu::HeapProperty::DeviceLocal;
+ }
+ }
+ for (const auto& memoryType : mDeviceInfo.memoryTypes) {
+ if (memoryType.propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
+ heapInfo[memoryType.heapIndex].properties |= wgpu::HeapProperty::HostVisible;
+ }
+ if (memoryType.propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) {
+ heapInfo[memoryType.heapIndex].properties |= wgpu::HeapProperty::HostCoherent;
+ }
+ if (memoryType.propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) {
+ heapInfo[memoryType.heapIndex].properties |= wgpu::HeapProperty::HostCached;
+ } else {
+ heapInfo[memoryType.heapIndex].properties |= wgpu::HeapProperty::HostUncached;
+ }
+ }
+}
+
} // namespace dawn::native::vulkan
diff --git a/src/dawn/native/vulkan/PhysicalDeviceVk.h b/src/dawn/native/vulkan/PhysicalDeviceVk.h
index a0bc315..fdea0a0 100644
--- a/src/dawn/native/vulkan/PhysicalDeviceVk.h
+++ b/src/dawn/native/vulkan/PhysicalDeviceVk.h
@@ -78,6 +78,8 @@
uint32_t FindDefaultComputeSubgroupSize() const;
+ void PopulateMemoryHeapInfo(AdapterPropertiesMemoryHeaps* memoryHeapProperties) const override;
+
VkPhysicalDevice mVkPhysicalDevice;
Ref<VulkanInstance> mVulkanInstance;
VulkanDeviceInfo mDeviceInfo = {};
diff --git a/src/dawn/tests/BUILD.gn b/src/dawn/tests/BUILD.gn
index 28055ba..7e16c8e 100644
--- a/src/dawn/tests/BUILD.gn
+++ b/src/dawn/tests/BUILD.gn
@@ -566,6 +566,7 @@
"end2end/IndexFormatTests.cpp",
"end2end/MaxLimitTests.cpp",
"end2end/MemoryAllocationStressTests.cpp",
+ "end2end/MemoryHeapPropertiesTests.cpp",
"end2end/MultisampledRenderingTests.cpp",
"end2end/MultisampledSamplingTests.cpp",
"end2end/MultithreadTests.cpp",
diff --git a/src/dawn/tests/DawnTest.cpp b/src/dawn/tests/DawnTest.cpp
index 58cf777..0e111ce 100644
--- a/src/dawn/tests/DawnTest.cpp
+++ b/src/dawn/tests/DawnTest.cpp
@@ -717,7 +717,7 @@
// Override procs to provide harness-specific behavior to always select the adapter required in
// testing parameter, and to allow fixture-specific overriding of the test device with
// CreateDeviceImpl.
- procs.instanceRequestAdapter = [](WGPUInstance instance, const WGPURequestAdapterOptions*,
+ procs.instanceRequestAdapter = [](WGPUInstance cInstance, const WGPURequestAdapterOptions*,
WGPURequestAdapterCallback callback, void* userdata) {
DAWN_ASSERT(gCurrentTest);
@@ -738,9 +738,9 @@
// Find the adapter that exactly matches our adapter properties.
const auto& adapters = gTestEnv->GetInstance()->EnumerateAdapters(&adapterOptions);
const auto& it =
- std::find_if(adapters.begin(), adapters.end(), [&](const native::Adapter& adapter) {
+ std::find_if(adapters.begin(), adapters.end(), [&](const native::Adapter& candidate) {
wgpu::AdapterProperties properties;
- adapter.GetProperties(&properties);
+ candidate.GetProperties(&properties);
const auto& param = gCurrentTest->mParam;
return (param.adapterProperties.selected &&
@@ -758,7 +758,7 @@
callback(WGPURequestAdapterStatus_Success, cAdapter, nullptr, userdata);
};
- procs.adapterRequestDevice = [](WGPUAdapter adapter, const WGPUDeviceDescriptor* descriptor,
+ procs.adapterRequestDevice = [](WGPUAdapter cAdapter, const WGPUDeviceDescriptor* descriptor,
WGPURequestDeviceCallback callback, void* userdata) {
DAWN_ASSERT(gCurrentTest);
@@ -784,8 +784,8 @@
mReadbackSlots.clear();
queue = nullptr;
device = nullptr;
- mAdapter = nullptr;
- mInstance = nullptr;
+ adapter = nullptr;
+ instance = nullptr;
// D3D11 and D3D12's GPU-based validation will accumulate objects over time if the backend
// device is not destroyed and recreated, so we reset it here.
@@ -1001,7 +1001,7 @@
}
const wgpu::Instance& DawnTestBase::GetInstance() const {
- return mInstance;
+ return instance;
}
native::Adapter DawnTestBase::GetAdapter() const {
@@ -1022,7 +1022,7 @@
wgpu::SupportedLimits DawnTestBase::GetAdapterLimits() {
wgpu::SupportedLimits supportedLimits = {};
- mAdapter.GetLimits(&supportedLimits);
+ adapter.GetLimits(&supportedLimits);
return supportedLimits;
}
@@ -1104,7 +1104,7 @@
deviceDesc.deviceLostCallback = mDeviceLostCallback.Callback();
deviceDesc.deviceLostUserdata = mDeviceLostCallback.MakeUserdata(deviceUserdata);
- mAdapter.RequestDevice(
+ adapter.RequestDevice(
&deviceDesc,
[](WGPURequestDeviceStatus, WGPUDevice cDevice, const char*, void* userdata) {
*static_cast<wgpu::Device*>(userdata) = wgpu::Device::Acquire(cDevice);
@@ -1150,7 +1150,7 @@
mTestPlatform = CreateTestPlatform();
native::FromAPI(gTestEnv->GetInstance()->Get())->SetPlatformForTesting(mTestPlatform.get());
- mInstance = mWireHelper->RegisterInstance(gTestEnv->GetInstance()->Get());
+ instance = mWireHelper->RegisterInstance(gTestEnv->GetInstance()->Get());
std::string traceName =
std::string(::testing::UnitTest::GetInstance()->current_test_info()->test_suite_name()) +
@@ -1158,14 +1158,14 @@
mWireHelper->BeginWireTrace(traceName.c_str());
// RequestAdapter is overriden to ignore RequestAdapterOptions, and select based on test params.
- mInstance.RequestAdapter(
+ instance.RequestAdapter(
nullptr,
[](WGPURequestAdapterStatus, WGPUAdapter cAdapter, const char*, void* userdata) {
*static_cast<wgpu::Adapter*>(userdata) = wgpu::Adapter::Acquire(cAdapter);
},
- &mAdapter);
+ &adapter);
FlushWire();
- DAWN_ASSERT(mAdapter);
+ DAWN_ASSERT(adapter);
device = CreateDevice();
backendDevice = mLastCreatedBackendDevice;
@@ -1575,7 +1575,7 @@
void DawnTestBase::WaitABit(wgpu::Instance targetInstance) {
if (targetInstance == nullptr) {
- targetInstance = mInstance;
+ targetInstance = instance;
}
if (targetInstance != nullptr) {
targetInstance.ProcessEvents();
diff --git a/src/dawn/tests/DawnTest.h b/src/dawn/tests/DawnTest.h
index 7a3d476..513e6c2 100644
--- a/src/dawn/tests/DawnTest.h
+++ b/src/dawn/tests/DawnTest.h
@@ -319,6 +319,8 @@
void ResolveDeferredExpectationsNow();
protected:
+ wgpu::Instance instance;
+ wgpu::Adapter adapter;
wgpu::Device device;
wgpu::Queue queue;
@@ -606,8 +608,6 @@
private:
AdapterTestParam mParam;
std::unique_ptr<utils::WireHelper> mWireHelper;
- wgpu::Instance mInstance;
- wgpu::Adapter mAdapter;
// Helps generate unique userdata values passed to deviceLostUserdata.
std::atomic<uintptr_t> mNextUniqueUserdata = 0;
diff --git a/src/dawn/tests/end2end/MemoryHeapPropertiesTests.cpp b/src/dawn/tests/end2end/MemoryHeapPropertiesTests.cpp
new file mode 100644
index 0000000..532207e
--- /dev/null
+++ b/src/dawn/tests/end2end/MemoryHeapPropertiesTests.cpp
@@ -0,0 +1,77 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <vector>
+
+#include "dawn/tests/DawnTest.h"
+
+namespace dawn {
+namespace {
+
+class MemoryHeapPropertiesTest : public DawnTest {};
+
+// TODO(dawn:2257) test that is is invalid to request AdapterPropertiesMemoryHeaps if the
+// feature is not available.
+
+// Test that it is possible to query the memory, and it is populated with valid enums.
+TEST_P(MemoryHeapPropertiesTest, GetMemoryHeapProperties) {
+ DAWN_TEST_UNSUPPORTED_IF(!adapter.HasFeature(wgpu::FeatureName::AdapterPropertiesMemoryHeaps));
+
+ wgpu::AdapterProperties properties;
+ wgpu::AdapterPropertiesMemoryHeaps memoryHeapProperties;
+ properties.nextInChain = &memoryHeapProperties;
+
+ adapter.GetProperties(&properties);
+
+ EXPECT_GT(memoryHeapProperties.heapCount, 0u);
+ for (size_t i = 0; i < memoryHeapProperties.heapCount; ++i) {
+ // Check the heap is non-zero in size.
+ EXPECT_GT(memoryHeapProperties.heapInfo[i].size, 0ull);
+
+ constexpr wgpu::HeapProperty kValidProps =
+ wgpu::HeapProperty::DeviceLocal | wgpu::HeapProperty::HostVisible |
+ wgpu::HeapProperty::HostCoherent | wgpu::HeapProperty::HostUncached |
+ wgpu::HeapProperty::HostCached;
+
+ // Check the heap properties only contain the set of valid enums.
+ EXPECT_EQ(memoryHeapProperties.heapInfo[i].properties & ~kValidProps, 0u);
+
+ // Check the heap properies have at least one bit.
+ EXPECT_NE(uint32_t(memoryHeapProperties.heapInfo[i].properties), 0u);
+ }
+}
+
+DAWN_INSTANTIATE_TEST(MemoryHeapPropertiesTest,
+ D3D11Backend(),
+ D3D12Backend(),
+ MetalBackend(),
+ OpenGLBackend(),
+ OpenGLESBackend(),
+ VulkanBackend());
+
+} // anonymous namespace
+} // namespace dawn
diff --git a/src/dawn/tests/unittests/wire/WireAdapterTests.cpp b/src/dawn/tests/unittests/wire/WireAdapterTests.cpp
index b67a5ca..d3c8af7 100644
--- a/src/dawn/tests/unittests/wire/WireAdapterTests.cpp
+++ b/src/dawn/tests/unittests/wire/WireAdapterTests.cpp
@@ -72,6 +72,10 @@
apiAdapter = api.GetNewAdapter();
EXPECT_CALL(api, OnInstanceRequestAdapter(apiInstance, NotNull(), NotNull(), NotNull()))
.WillOnce(InvokeWithoutArgs([&] {
+ EXPECT_CALL(api, AdapterHasFeature(apiAdapter,
+ WGPUFeatureName_AdapterPropertiesMemoryHeaps))
+ .WillOnce(Return(false));
+
EXPECT_CALL(api, AdapterGetProperties(apiAdapter, NotNull()))
.WillOnce(WithArg<1>(Invoke([&](WGPUAdapterProperties* properties) {
*properties = {};
diff --git a/src/dawn/tests/unittests/wire/WireInstanceTests.cpp b/src/dawn/tests/unittests/wire/WireInstanceTests.cpp
index 59a2594..2caf2e0 100644
--- a/src/dawn/tests/unittests/wire/WireInstanceTests.cpp
+++ b/src/dawn/tests/unittests/wire/WireInstanceTests.cpp
@@ -40,6 +40,7 @@
namespace dawn::wire {
namespace {
+using testing::_;
using testing::Invoke;
using testing::InvokeWithoutArgs;
using testing::MockCallback;
@@ -142,6 +143,8 @@
WGPUAdapter apiAdapter = api.GetNewAdapter();
EXPECT_CALL(api, OnInstanceRequestAdapter(apiInstance, NotNull(), NotNull(), NotNull()))
.WillOnce(InvokeWithoutArgs([&] {
+ EXPECT_CALL(api, AdapterHasFeature(apiAdapter, _)).WillRepeatedly(Return(false));
+
EXPECT_CALL(api, AdapterGetProperties(apiAdapter, NotNull()))
.WillOnce(SetArgPointee<1>(fakeProperties));
@@ -204,6 +207,100 @@
});
}
+// Test that RequestAdapter forwards the memory heap properties to the client.
+TEST_P(WireInstanceTests, RequestAdapterPassesMemoryHeapProperties) {
+ WGPURequestAdapterOptions options = {};
+ InstanceRequestAdapter(instance, &options, nullptr);
+
+ WGPUMemoryHeapInfo fakeHeapInfo[3] = {
+ {WGPUHeapProperty_DeviceLocal, 64},
+ {WGPUHeapProperty_DeviceLocal | WGPUHeapProperty_HostVisible, 136},
+ {WGPUHeapProperty_HostCached | WGPUHeapProperty_HostVisible, 460},
+ };
+
+ WGPUAdapterPropertiesMemoryHeaps fakeMemoryHeapProperties = {};
+ fakeMemoryHeapProperties.chain.sType = WGPUSType_AdapterPropertiesMemoryHeaps;
+ fakeMemoryHeapProperties.heapCount = 3;
+ fakeMemoryHeapProperties.heapInfo = fakeHeapInfo;
+
+ std::initializer_list<WGPUFeatureName> fakeFeatures = {
+ WGPUFeatureName_AdapterPropertiesMemoryHeaps,
+ };
+
+ // Expect the server to receive the message. Then, mock a fake reply.
+ WGPUAdapter apiAdapter = api.GetNewAdapter();
+ EXPECT_CALL(api, OnInstanceRequestAdapter(apiInstance, NotNull(), NotNull(), NotNull()))
+ .WillOnce(InvokeWithoutArgs([&] {
+ EXPECT_CALL(api,
+ AdapterHasFeature(apiAdapter, WGPUFeatureName_AdapterPropertiesMemoryHeaps))
+ .WillOnce(Return(true));
+
+ EXPECT_CALL(api, AdapterGetProperties(apiAdapter, NotNull()))
+ .WillOnce(WithArg<1>(Invoke([&](WGPUAdapterProperties* properties) {
+ properties->vendorName = "fake-vendor";
+ properties->architecture = "fake-architecture";
+ properties->name = "fake adapter";
+ properties->driverDescription = "hello world";
+
+ EXPECT_EQ(properties->nextInChain->sType,
+ WGPUSType_AdapterPropertiesMemoryHeaps);
+ *reinterpret_cast<WGPUAdapterPropertiesMemoryHeaps*>(properties->nextInChain) =
+ fakeMemoryHeapProperties;
+ })));
+
+ EXPECT_CALL(api, AdapterGetLimits(apiAdapter, NotNull()))
+ .WillOnce(WithArg<1>(Invoke([&](WGPUSupportedLimits* limits) {
+ *limits = {};
+ return true;
+ })));
+
+ EXPECT_CALL(api, AdapterEnumerateFeatures(apiAdapter, nullptr))
+ .WillOnce(Return(fakeFeatures.size()));
+
+ EXPECT_CALL(api, AdapterEnumerateFeatures(apiAdapter, NotNull()))
+ .WillOnce(WithArg<1>(Invoke([&](WGPUFeatureName* features) {
+ for (WGPUFeatureName feature : fakeFeatures) {
+ *(features++) = feature;
+ }
+ return fakeFeatures.size();
+ })));
+ api.CallInstanceRequestAdapterCallback(apiInstance, WGPURequestAdapterStatus_Success,
+ apiAdapter, nullptr);
+ }));
+
+ FlushClient();
+ FlushFutures();
+
+ // Expect the callback in the client and the adapter information to match.
+ ExpectWireCallbacksWhen([&](auto& mockCb) {
+ EXPECT_CALL(mockCb, Call(WGPURequestAdapterStatus_Success, NotNull(), nullptr, nullptr))
+ .WillOnce(WithArg<1>(Invoke([&](WGPUAdapter adapter) {
+ // Request properties without a chained struct.
+ // It should be nullptr.
+ WGPUAdapterProperties properties = {};
+ wgpuAdapterGetProperties(adapter, &properties);
+ EXPECT_EQ(properties.nextInChain, nullptr);
+
+ // Request the memory heap properties.
+ WGPUAdapterPropertiesMemoryHeaps memoryHeapProperties = {};
+ memoryHeapProperties.chain.sType = WGPUSType_AdapterPropertiesMemoryHeaps;
+ properties.nextInChain = &memoryHeapProperties.chain;
+ wgpuAdapterGetProperties(adapter, &properties);
+
+ // Expect everything matches the fake properties returned by the server.
+ EXPECT_EQ(memoryHeapProperties.heapCount, fakeMemoryHeapProperties.heapCount);
+ for (size_t i = 0; i < fakeMemoryHeapProperties.heapCount; ++i) {
+ EXPECT_EQ(memoryHeapProperties.heapInfo[i].properties,
+ fakeMemoryHeapProperties.heapInfo[i].properties);
+ EXPECT_EQ(memoryHeapProperties.heapInfo[i].size,
+ fakeMemoryHeapProperties.heapInfo[i].size);
+ }
+ })));
+
+ FlushCallbacks();
+ });
+}
+
// Test that features returned by the implementation that aren't supported in the wire are not
// exposed.
TEST_P(WireInstanceTests, RequestAdapterWireLacksFeatureSupport) {
@@ -220,6 +317,8 @@
WGPUAdapter apiAdapter = api.GetNewAdapter();
EXPECT_CALL(api, OnInstanceRequestAdapter(apiInstance, NotNull(), NotNull(), NotNull()))
.WillOnce(InvokeWithoutArgs([&] {
+ EXPECT_CALL(api, AdapterHasFeature(apiAdapter, _)).WillRepeatedly(Return(false));
+
EXPECT_CALL(api, AdapterGetProperties(apiAdapter, NotNull()))
.WillOnce(WithArg<1>(Invoke([&](WGPUAdapterProperties* properties) {
*properties = {};
diff --git a/src/dawn/wire/SupportedFeatures.cpp b/src/dawn/wire/SupportedFeatures.cpp
index 623ebe2..bdc5d7e 100644
--- a/src/dawn/wire/SupportedFeatures.cpp
+++ b/src/dawn/wire/SupportedFeatures.cpp
@@ -93,6 +93,7 @@
case WGPUFeatureName_PixelLocalStorageNonCoherent:
case WGPUFeatureName_Norm16TextureFormats:
case WGPUFeatureName_FramebufferFetch:
+ case WGPUFeatureName_AdapterPropertiesMemoryHeaps:
return true;
}
diff --git a/src/dawn/wire/client/Adapter.cpp b/src/dawn/wire/client/Adapter.cpp
index 44e1ffc..c98cc93 100644
--- a/src/dawn/wire/client/Adapter.cpp
+++ b/src/dawn/wire/client/Adapter.cpp
@@ -69,9 +69,51 @@
void Adapter::SetProperties(const WGPUAdapterProperties* properties) {
mProperties = *properties;
mProperties.nextInChain = nullptr;
+
+ // Loop through the chained struct.
+ WGPUChainedStructOut* chain = properties->nextInChain;
+ while (chain != nullptr) {
+ switch (chain->sType) {
+ case WGPUSType_AdapterPropertiesMemoryHeaps: {
+ // Make a copy of the heap info in `mMemoryHeapInfo`.
+ const auto* memoryHeapProperties =
+ reinterpret_cast<const WGPUAdapterPropertiesMemoryHeaps*>(chain);
+ mMemoryHeapInfo = {
+ memoryHeapProperties->heapInfo,
+ memoryHeapProperties->heapInfo + memoryHeapProperties->heapCount};
+ break;
+ }
+ default:
+ DAWN_UNREACHABLE();
+ break;
+ }
+ chain = chain->next;
+ }
}
void Adapter::GetProperties(WGPUAdapterProperties* properties) const {
+ // Loop through the chained struct.
+ WGPUChainedStructOut* chain = properties->nextInChain;
+ while (chain != nullptr) {
+ switch (chain->sType) {
+ case WGPUSType_AdapterPropertiesMemoryHeaps: {
+ // Copy `mMemoryHeapInfo` into a new allocation.
+ auto* memoryHeapProperties =
+ reinterpret_cast<WGPUAdapterPropertiesMemoryHeaps*>(chain);
+ size_t heapCount = mMemoryHeapInfo.size();
+ auto* heapInfo = new WGPUMemoryHeapInfo[heapCount];
+ memcpy(heapInfo, mMemoryHeapInfo.data(), sizeof(WGPUMemoryHeapInfo) * heapCount);
+ // Write out the pointer and count to the heap properties out-struct.
+ memoryHeapProperties->heapCount = heapCount;
+ memoryHeapProperties->heapInfo = heapInfo;
+ break;
+ }
+ default:
+ break;
+ }
+ chain = chain->next;
+ }
+
*properties = mProperties;
// Get lengths, with null terminators.
@@ -105,6 +147,11 @@
delete[] properties.vendorName;
}
+void ClientAdapterPropertiesMemoryHeapsFreeMembers(
+ WGPUAdapterPropertiesMemoryHeaps memoryHeapProperties) {
+ delete[] memoryHeapProperties.heapInfo;
+}
+
void Adapter::RequestDevice(const WGPUDeviceDescriptor* descriptor,
WGPURequestDeviceCallback callback,
void* userdata) {
diff --git a/src/dawn/wire/client/Adapter.h b/src/dawn/wire/client/Adapter.h
index 1b9e6d1..b7cf683 100644
--- a/src/dawn/wire/client/Adapter.h
+++ b/src/dawn/wire/client/Adapter.h
@@ -28,8 +28,9 @@
#ifndef SRC_DAWN_WIRE_CLIENT_ADAPTER_H_
#define SRC_DAWN_WIRE_CLIENT_ADAPTER_H_
-#include "dawn/webgpu.h"
+#include <vector>
+#include "dawn/webgpu.h"
#include "dawn/wire/WireClient.h"
#include "dawn/wire/WireCmd_autogen.h"
#include "dawn/wire/client/LimitsAndFeatures.h"
@@ -70,6 +71,7 @@
private:
LimitsAndFeatures mLimitsAndFeatures;
WGPUAdapterProperties mProperties;
+ std::vector<WGPUMemoryHeapInfo> mMemoryHeapInfo;
struct RequestDeviceData {
WGPURequestDeviceCallback callback = nullptr;
@@ -80,6 +82,7 @@
};
void ClientAdapterPropertiesFreeMembers(WGPUAdapterProperties);
+void ClientAdapterPropertiesMemoryHeapsFreeMembers(WGPUAdapterPropertiesMemoryHeaps);
} // namespace dawn::wire::client
diff --git a/src/dawn/wire/server/ServerInstance.cpp b/src/dawn/wire/server/ServerInstance.cpp
index 446e089..3f3f8c4 100644
--- a/src/dawn/wire/server/ServerInstance.cpp
+++ b/src/dawn/wire/server/ServerInstance.cpp
@@ -87,6 +87,14 @@
// Query and report the adapter properties.
WGPUAdapterProperties properties = {};
+
+ // Query AdapterPropertiesMemoryHeaps if the feature is supported.
+ WGPUAdapterPropertiesMemoryHeaps memoryHeapProperties = {};
+ memoryHeapProperties.chain.sType = WGPUSType_AdapterPropertiesMemoryHeaps;
+ if (mProcs.adapterHasFeature(adapter, WGPUFeatureName_AdapterPropertiesMemoryHeaps)) {
+ properties.nextInChain = &memoryHeapProperties.chain;
+ }
+
mProcs.adapterGetProperties(adapter, &properties);
cmd.properties = &properties;
@@ -102,6 +110,7 @@
SerializeCommand(cmd);
mProcs.adapterPropertiesFreeMembers(properties);
+ mProcs.adapterPropertiesMemoryHeapsFreeMembers(memoryHeapProperties);
}
} // namespace dawn::wire::server