Metal: Handle Buffer allocation failure

Bug: dawn:433
Change-Id: I6549c4a1e31171257761397b018090d0eb7471e6
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/22424
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Stephen White <senorblanco@chromium.org>
Commit-Queue: Austin Eng <enga@chromium.org>
This commit is contained in:
Austin Eng 2020-06-03 16:14:35 +00:00 committed by Commit Bot service account
parent d586b079f2
commit 0768ffa742
2 changed files with 22 additions and 7 deletions

View File

@ -39,23 +39,38 @@ namespace dawn_native { namespace metal {
storageMode = MTLResourceStorageModePrivate; storageMode = MTLResourceStorageModePrivate;
} }
if (GetSize() >
std::numeric_limits<uint64_t>::max() - kMinUniformOrStorageBufferAlignment) {
return DAWN_OUT_OF_MEMORY_ERROR("Buffer allocation is too large");
}
// TODO(cwallez@chromium.org): Have a global "zero" buffer that can do everything instead // TODO(cwallez@chromium.org): Have a global "zero" buffer that can do everything instead
// of creating a new 4-byte buffer? // of creating a new 4-byte buffer?
uint32_t currentSize = std::max(GetSize(), uint64_t(4u)); if (GetSize() > std::numeric_limits<NSUInteger>::max()) {
return DAWN_OUT_OF_MEMORY_ERROR("Buffer allocation is too large");
}
NSUInteger currentSize = static_cast<NSUInteger>(std::max(GetSize(), uint64_t(4u)));
// Metal validation layer requires the size of uniform buffer and storage buffer to be no // Metal validation layer requires the size of uniform buffer and storage buffer to be no
// less than the size of the buffer block defined in shader, and the overall size of the // less than the size of the buffer block defined in shader, and the overall size of the
// buffer must be aligned to the largest alignment of its members. // buffer must be aligned to the largest alignment of its members.
if (GetUsage() & (wgpu::BufferUsage::Uniform | wgpu::BufferUsage::Storage)) { if (GetUsage() & (wgpu::BufferUsage::Uniform | wgpu::BufferUsage::Storage)) {
if (currentSize >
std::numeric_limits<NSUInteger>::max() - kMinUniformOrStorageBufferAlignment) {
// Alignment would overlow.
return DAWN_OUT_OF_MEMORY_ERROR("Buffer allocation is too large");
}
currentSize = Align(currentSize, kMinUniformOrStorageBufferAlignment); currentSize = Align(currentSize, kMinUniformOrStorageBufferAlignment);
} }
if (@available(iOS 12, macOS 10.14, *)) {
NSUInteger maxBufferSize = [ToBackend(GetDevice())->GetMTLDevice() maxBufferLength];
if (currentSize > maxBufferSize) {
return DAWN_OUT_OF_MEMORY_ERROR("Buffer allocation is too large");
}
}
mMtlBuffer = [ToBackend(GetDevice())->GetMTLDevice() newBufferWithLength:currentSize mMtlBuffer = [ToBackend(GetDevice())->GetMTLDevice() newBufferWithLength:currentSize
options:storageMode]; options:storageMode];
if (mMtlBuffer == nil) {
return DAWN_OUT_OF_MEMORY_ERROR("Buffer allocation failed");
}
return {}; return {};
} }

View File

@ -429,7 +429,7 @@ TEST_P(CreateBufferMappedTests, CreateThenMapBeforeUnmapFailure) {
// Test that creating a very large buffers fails gracefully. // Test that creating a very large buffers fails gracefully.
TEST_P(CreateBufferMappedTests, LargeBufferFails) { TEST_P(CreateBufferMappedTests, LargeBufferFails) {
// TODO(http://crbug.com/dawn/27): Missing support. // TODO(http://crbug.com/dawn/27): Missing support.
DAWN_SKIP_TEST_IF(IsMetal() || IsOpenGL()); DAWN_SKIP_TEST_IF(IsOpenGL());
wgpu::BufferDescriptor descriptor; wgpu::BufferDescriptor descriptor;
descriptor.size = std::numeric_limits<uint64_t>::max(); descriptor.size = std::numeric_limits<uint64_t>::max();