Protect against huge buffer allocations on macOS 10.12, 10.13

|MTLDevice maxBufferLength| is not available until 10.14, so on
lower versions of macOS, try using |recommendedMaxWorkingSetSize|

Bug: dawn:450
Change-Id: I52dc4211cf3d7014771d580a9af9c72abe92a375
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/23263
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Stephen White <senorblanco@chromium.org>
This commit is contained in:
Austin Eng 2020-06-19 18:47:33 +00:00 committed by Commit Bot service account
parent 0e9e5ee8aa
commit b75075ac7b
2 changed files with 26 additions and 25 deletions

View File

@ -24,6 +24,10 @@ namespace dawn_native { namespace metal {
// largest alignment of supported data types
static constexpr uint32_t kMinUniformOrStorageBufferAlignment = 16u;
// The maximum buffer size if querying the maximum buffer size or recommended working set size
// is not available. This is a somewhat arbitrary limit of 1 GiB.
static constexpr uint32_t kMaxBufferSizeFallback = 1024u * 1024u * 1024u;
// static
ResultOrError<Buffer*> Buffer::Create(Device* device, const BufferDescriptor* descriptor) {
Ref<Buffer> buffer = AcquireRef(new Buffer(device, descriptor));
@ -63,6 +67,17 @@ namespace dawn_native { namespace metal {
if (currentSize > maxBufferSize) {
return DAWN_OUT_OF_MEMORY_ERROR("Buffer allocation is too large");
}
} else if (@available(macOS 10.12, *)) {
// |maxBufferLength| isn't always available on older systems. If available, use
// |recommendedMaxWorkingSetSize| instead. We can probably allocate more than this,
// but don't have a way to discover a better limit. MoltenVK also uses this heuristic.
uint64_t maxWorkingSetSize =
[ToBackend(GetDevice())->GetMTLDevice() recommendedMaxWorkingSetSize];
if (currentSize > maxWorkingSetSize) {
return DAWN_OUT_OF_MEMORY_ERROR("Buffer allocation is too large");
}
} else if (currentSize > kMaxBufferSizeFallback) {
return DAWN_OUT_OF_MEMORY_ERROR("Buffer allocation is too large");
}
mMtlBuffer = [ToBackend(GetDevice())->GetMTLDevice() newBufferWithLength:currentSize

View File

@ -535,11 +535,8 @@ TEST_P(BufferTests, CreateBufferOOM) {
ASSERT_DEVICE_ERROR(device.CreateBuffer(&descriptor));
// UINT64_MAX may be special cased. Test a smaller, but really large buffer also fails
// This hangs on the Metal AMD driver
if (!(IsMetal() && IsAMD())) {
descriptor.size = 1ull << 50;
ASSERT_DEVICE_ERROR(device.CreateBuffer(&descriptor));
}
descriptor.size = 1ull << 50;
ASSERT_DEVICE_ERROR(device.CreateBuffer(&descriptor));
}
// Test that a very large CreateBufferMapped fails gracefully.
@ -562,11 +559,8 @@ TEST_P(BufferTests, CreateBufferMappedOOM) {
ASSERT_DEVICE_ERROR(device.CreateBufferMapped(&descriptor));
// UINT64_MAX may be special cased. Test a smaller, but really large buffer also fails
// This hangs on the Metal AMD driver
if (!(IsMetal() && IsAMD())) {
descriptor.size = 1ull << 50;
ASSERT_DEVICE_ERROR(device.CreateBufferMapped(&descriptor));
}
descriptor.size = 1ull << 50;
ASSERT_DEVICE_ERROR(device.CreateBufferMapped(&descriptor));
}
// Test mappable buffer
@ -582,11 +576,9 @@ TEST_P(BufferTests, CreateBufferMappedOOM) {
descriptor.size = std::numeric_limits<uint64_t>::max();
ASSERT_DEVICE_ERROR(device.CreateBufferMapped(&descriptor));
if (!(IsMetal() && IsAMD())) {
// UINT64_MAX may be special cased. Test a smaller, but really large buffer also fails
descriptor.size = 1ull << 50;
ASSERT_DEVICE_ERROR(device.CreateBufferMapped(&descriptor));
}
// UINT64_MAX may be special cased. Test a smaller, but really large buffer also fails
descriptor.size = 1ull << 50;
ASSERT_DEVICE_ERROR(device.CreateBufferMapped(&descriptor));
}
}
@ -624,11 +616,8 @@ TEST_P(BufferTests, CreateBufferOOMMapReadAsync) {
RunTest(descriptor);
// UINT64_MAX may be special cased. Test a smaller, but really large buffer also fails
// This hangs on the Metal AMD driver
if (!(IsMetal() && IsAMD())) {
descriptor.size = 1ull << 50;
RunTest(descriptor);
}
descriptor.size = 1ull << 50;
RunTest(descriptor);
}
// Test that mapping an OOM buffer for reading fails gracefully
@ -664,11 +653,8 @@ TEST_P(BufferTests, CreateBufferOOMMapWriteAsync) {
RunTest(descriptor);
// UINT64_MAX may be special cased. Test a smaller, but really large buffer also fails
// This hangs on the Metal AMD driver
if (!(IsMetal() && IsAMD())) {
descriptor.size = 1ull << 50;
RunTest(descriptor);
}
descriptor.size = 1ull << 50;
RunTest(descriptor);
}
DAWN_INSTANTIATE_TEST(BufferTests,