blob: d5ac586f85b20be1fb01c964397d8dbae6deb41e [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/viz/common/resources/bitmap_allocation.h"
#include <stdint.h>
#include "base/debug/alias.h"
#include "base/memory/shared_memory.h"
#include "base/process/memory.h"
#include "build/build_config.h"
#include "components/viz/common/resources/resource_format_utils.h"
#include "components/viz/common/resources/resource_sizes.h"
#include "mojo/public/cpp/system/platform_handle.h"
#include "ui/gfx/geometry/size.h"
namespace viz {
namespace {
// Collect extra information for debugging bitmap creation failures.
void CollectMemoryUsageAndDie(const gfx::Size& size,
ResourceFormat format,
size_t alloc_size) {
#if defined(OS_WIN)
DWORD last_error = GetLastError();
base::debug::Alias(&last_error);
#endif
int width = size.width();
int height = size.height();
base::debug::Alias(&width);
base::debug::Alias(&height);
base::debug::Alias(&format);
base::TerminateBecauseOutOfMemory(alloc_size);
}
} // namespace
namespace bitmap_allocation {
std::unique_ptr<base::SharedMemory> AllocateMappedBitmap(
const gfx::Size& size,
ResourceFormat format) {
DCHECK(IsBitmapFormatSupported(format));
size_t bytes = 0;
if (!ResourceSizes::MaybeSizeInBytes(size, format, &bytes)) {
DLOG(ERROR) << "AllocateMappedBitmap with size that overflows";
CollectMemoryUsageAndDie(size, format, std::numeric_limits<int>::max());
}
auto mojo_buf = mojo::SharedBufferHandle::Create(bytes);
if (!mojo_buf->is_valid()) {
DLOG(ERROR) << "Browser failed to allocate shared memory";
CollectMemoryUsageAndDie(size, format, bytes);
}
base::SharedMemoryHandle shared_buf;
if (mojo::UnwrapSharedMemoryHandle(std::move(mojo_buf), &shared_buf, nullptr,
nullptr) != MOJO_RESULT_OK) {
DLOG(ERROR) << "Browser failed to allocate shared memory";
CollectMemoryUsageAndDie(size, format, bytes);
}
auto memory = std::make_unique<base::SharedMemory>(shared_buf, false);
if (!memory->Map(bytes)) {
DLOG(ERROR) << "Browser failed to map shared memory";
CollectMemoryUsageAndDie(size, format, bytes);
}
return memory;
}
mojo::ScopedSharedBufferHandle DuplicateAndCloseMappedBitmap(
base::SharedMemory* memory,
const gfx::Size& size,
ResourceFormat format) {
DCHECK(IsBitmapFormatSupported(format));
base::SharedMemoryHandle dupe_handle =
base::SharedMemory::DuplicateHandle(memory->handle());
if (!base::SharedMemory::IsHandleValid(dupe_handle)) {
DLOG(ERROR) << "Failed to duplicate shared memory handle for bitmap.";
CollectMemoryUsageAndDie(size, format, memory->requested_size());
}
memory->Close();
return mojo::WrapSharedMemoryHandle(
dupe_handle, memory->mapped_size(),
mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite);
}
mojo::ScopedSharedBufferHandle DuplicateWithoutClosingMappedBitmap(
const base::SharedMemory* memory,
const gfx::Size& size,
ResourceFormat format) {
DCHECK(IsBitmapFormatSupported(format));
base::SharedMemoryHandle dupe_handle =
base::SharedMemory::DuplicateHandle(memory->handle());
if (!base::SharedMemory::IsHandleValid(dupe_handle)) {
DLOG(ERROR) << "Failed to duplicate shared memory handle for bitmap.";
CollectMemoryUsageAndDie(size, format, memory->requested_size());
}
return mojo::WrapSharedMemoryHandle(
dupe_handle, memory->mapped_size(),
mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite);
}
} // namespace bitmap_allocation
} // namespace viz