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:
parent
0e9e5ee8aa
commit
b75075ac7b
|
@ -24,6 +24,10 @@ namespace dawn_native { namespace metal {
|
||||||
// largest alignment of supported data types
|
// largest alignment of supported data types
|
||||||
static constexpr uint32_t kMinUniformOrStorageBufferAlignment = 16u;
|
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
|
// static
|
||||||
ResultOrError<Buffer*> Buffer::Create(Device* device, const BufferDescriptor* descriptor) {
|
ResultOrError<Buffer*> Buffer::Create(Device* device, const BufferDescriptor* descriptor) {
|
||||||
Ref<Buffer> buffer = AcquireRef(new Buffer(device, descriptor));
|
Ref<Buffer> buffer = AcquireRef(new Buffer(device, descriptor));
|
||||||
|
@ -63,6 +67,17 @@ namespace dawn_native { namespace metal {
|
||||||
if (currentSize > maxBufferSize) {
|
if (currentSize > maxBufferSize) {
|
||||||
return DAWN_OUT_OF_MEMORY_ERROR("Buffer allocation is too large");
|
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
|
mMtlBuffer = [ToBackend(GetDevice())->GetMTLDevice() newBufferWithLength:currentSize
|
||||||
|
|
|
@ -535,11 +535,8 @@ TEST_P(BufferTests, CreateBufferOOM) {
|
||||||
ASSERT_DEVICE_ERROR(device.CreateBuffer(&descriptor));
|
ASSERT_DEVICE_ERROR(device.CreateBuffer(&descriptor));
|
||||||
|
|
||||||
// UINT64_MAX may be special cased. Test a smaller, but really large buffer also fails
|
// UINT64_MAX may be special cased. Test a smaller, but really large buffer also fails
|
||||||
// This hangs on the Metal AMD driver
|
descriptor.size = 1ull << 50;
|
||||||
if (!(IsMetal() && IsAMD())) {
|
ASSERT_DEVICE_ERROR(device.CreateBuffer(&descriptor));
|
||||||
descriptor.size = 1ull << 50;
|
|
||||||
ASSERT_DEVICE_ERROR(device.CreateBuffer(&descriptor));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that a very large CreateBufferMapped fails gracefully.
|
// Test that a very large CreateBufferMapped fails gracefully.
|
||||||
|
@ -562,11 +559,8 @@ TEST_P(BufferTests, CreateBufferMappedOOM) {
|
||||||
ASSERT_DEVICE_ERROR(device.CreateBufferMapped(&descriptor));
|
ASSERT_DEVICE_ERROR(device.CreateBufferMapped(&descriptor));
|
||||||
|
|
||||||
// UINT64_MAX may be special cased. Test a smaller, but really large buffer also fails
|
// UINT64_MAX may be special cased. Test a smaller, but really large buffer also fails
|
||||||
// This hangs on the Metal AMD driver
|
descriptor.size = 1ull << 50;
|
||||||
if (!(IsMetal() && IsAMD())) {
|
ASSERT_DEVICE_ERROR(device.CreateBufferMapped(&descriptor));
|
||||||
descriptor.size = 1ull << 50;
|
|
||||||
ASSERT_DEVICE_ERROR(device.CreateBufferMapped(&descriptor));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test mappable buffer
|
// Test mappable buffer
|
||||||
|
@ -582,11 +576,9 @@ TEST_P(BufferTests, CreateBufferMappedOOM) {
|
||||||
descriptor.size = std::numeric_limits<uint64_t>::max();
|
descriptor.size = std::numeric_limits<uint64_t>::max();
|
||||||
ASSERT_DEVICE_ERROR(device.CreateBufferMapped(&descriptor));
|
ASSERT_DEVICE_ERROR(device.CreateBufferMapped(&descriptor));
|
||||||
|
|
||||||
if (!(IsMetal() && IsAMD())) {
|
// UINT64_MAX may be special cased. Test a smaller, but really large buffer also fails
|
||||||
// UINT64_MAX may be special cased. Test a smaller, but really large buffer also fails
|
descriptor.size = 1ull << 50;
|
||||||
descriptor.size = 1ull << 50;
|
ASSERT_DEVICE_ERROR(device.CreateBufferMapped(&descriptor));
|
||||||
ASSERT_DEVICE_ERROR(device.CreateBufferMapped(&descriptor));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -624,11 +616,8 @@ TEST_P(BufferTests, CreateBufferOOMMapReadAsync) {
|
||||||
RunTest(descriptor);
|
RunTest(descriptor);
|
||||||
|
|
||||||
// UINT64_MAX may be special cased. Test a smaller, but really large buffer also fails
|
// UINT64_MAX may be special cased. Test a smaller, but really large buffer also fails
|
||||||
// This hangs on the Metal AMD driver
|
descriptor.size = 1ull << 50;
|
||||||
if (!(IsMetal() && IsAMD())) {
|
RunTest(descriptor);
|
||||||
descriptor.size = 1ull << 50;
|
|
||||||
RunTest(descriptor);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that mapping an OOM buffer for reading fails gracefully
|
// Test that mapping an OOM buffer for reading fails gracefully
|
||||||
|
@ -664,11 +653,8 @@ TEST_P(BufferTests, CreateBufferOOMMapWriteAsync) {
|
||||||
RunTest(descriptor);
|
RunTest(descriptor);
|
||||||
|
|
||||||
// UINT64_MAX may be special cased. Test a smaller, but really large buffer also fails
|
// UINT64_MAX may be special cased. Test a smaller, but really large buffer also fails
|
||||||
// This hangs on the Metal AMD driver
|
descriptor.size = 1ull << 50;
|
||||||
if (!(IsMetal() && IsAMD())) {
|
RunTest(descriptor);
|
||||||
descriptor.size = 1ull << 50;
|
|
||||||
RunTest(descriptor);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DAWN_INSTANTIATE_TEST(BufferTests,
|
DAWN_INSTANTIATE_TEST(BufferTests,
|
||||||
|
|
Loading…
Reference in New Issue